blob: c7c08d31bb8fe72999df13fb03f67b66b37b8aae [file] [log] [blame]
Jian Li49109b52019-01-22 00:17:28 +09001/*
2 * Copyright 2019-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.k8snode.api;
17
18import com.google.common.base.MoreObjects;
19import org.onlab.osgi.DefaultServiceDirectory;
20import org.onlab.packet.IpAddress;
Jian Li7d111d72019-04-12 13:58:44 +090021import org.onlab.packet.MacAddress;
Jian Li49109b52019-01-22 00:17:28 +090022import org.onosproject.net.DeviceId;
23import org.onosproject.net.Port;
24import org.onosproject.net.PortNumber;
25import org.onosproject.net.device.DeviceService;
Jian Li7d111d72019-04-12 13:58:44 +090026import org.onosproject.ovsdb.controller.OvsdbClientService;
27import org.onosproject.ovsdb.controller.OvsdbController;
28import org.onosproject.ovsdb.controller.OvsdbNodeId;
29import org.onosproject.ovsdb.rfc.notation.OvsdbMap;
30import org.onosproject.ovsdb.rfc.table.Interface;
Jian Li49109b52019-01-22 00:17:28 +090031
32import java.util.Objects;
33
34import static com.google.common.base.Preconditions.checkArgument;
35import static org.onosproject.k8snode.api.Constants.GENEVE_TUNNEL;
36import static org.onosproject.k8snode.api.Constants.GRE_TUNNEL;
Jian Li4aa17642019-01-30 00:01:11 +090037import static org.onosproject.k8snode.api.Constants.INTEGRATION_BRIDGE;
Jian Li49109b52019-01-22 00:17:28 +090038import static org.onosproject.k8snode.api.Constants.VXLAN_TUNNEL;
39import static org.onosproject.net.AnnotationKeys.PORT_NAME;
40
41/**
42 * Representation of a kubernetes node.
43 */
44public class DefaultK8sNode implements K8sNode {
45
Jian Li7d111d72019-04-12 13:58:44 +090046 private static final int DEFAULT_OVSDB_PORT = 6640;
47 private static final String MAC_ADDRESS = "mac_address";
48
Jian Li49109b52019-01-22 00:17:28 +090049 private final String hostname;
50 private final Type type;
51 private final DeviceId intgBridge;
52 private final IpAddress managementIp;
53 private final IpAddress dataIp;
54 private final K8sNodeState state;
55
56 private static final String NOT_NULL_MSG = "Node % cannot be null";
57
58 private static final String OVSDB = "ovsdb:";
59
60 /**
61 * A default constructor of kubernetes Node.
62 *
63 * @param hostname hostname
64 * @param type node type
65 * @param intgBridge integration bridge
66 * @param managementIp management IP address
67 * @param dataIp data IP address
68 * @param state node state
69 */
70 protected DefaultK8sNode(String hostname, Type type, DeviceId intgBridge,
Jian Li3defa842019-02-12 00:31:35 +090071 IpAddress managementIp, IpAddress dataIp,
72 K8sNodeState state) {
Jian Li49109b52019-01-22 00:17:28 +090073 this.hostname = hostname;
74 this.type = type;
75 this.intgBridge = intgBridge;
76 this.managementIp = managementIp;
77 this.dataIp = dataIp;
78 this.state = state;
79 }
80
81 @Override
82 public String hostname() {
83 return hostname;
84 }
85
86 @Override
87 public Type type() {
88 return type;
89 }
90
91 @Override
92 public DeviceId ovsdb() {
93 return DeviceId.deviceId(OVSDB + managementIp().toString());
94 }
95
96 @Override
97 public DeviceId intgBridge() {
98 return intgBridge;
99 }
100
101 @Override
Jian Li1cee9882019-02-13 11:25:25 +0900102 public K8sNode updateIntgBridge(DeviceId deviceId) {
103 return new Builder()
104 .hostname(hostname)
105 .type(type)
106 .intgBridge(deviceId)
107 .managementIp(managementIp)
108 .dataIp(dataIp)
109 .state(state)
110 .build();
111 }
112
113 @Override
Jian Li49109b52019-01-22 00:17:28 +0900114 public IpAddress managementIp() {
115 return managementIp;
116 }
117
118 @Override
119 public IpAddress dataIp() {
120 return dataIp;
121 }
122
123 @Override
124 public K8sNodeState state() {
125 return state;
126 }
127
128 @Override
129 public K8sNode updateState(K8sNodeState newState) {
130 return new Builder()
131 .hostname(hostname)
132 .type(type)
133 .intgBridge(intgBridge)
134 .managementIp(managementIp)
135 .dataIp(dataIp)
136 .state(newState)
137 .build();
138 }
139
140 @Override
141 public PortNumber grePortNum() {
142 return tunnelPortNum(GRE_TUNNEL);
143 }
144
145 @Override
146 public PortNumber vxlanPortNum() {
147 return tunnelPortNum(VXLAN_TUNNEL);
148 }
149
150 @Override
151 public PortNumber genevePortNum() {
152 return tunnelPortNum(GENEVE_TUNNEL);
153 }
154
155 @Override
Jian Li4aa17642019-01-30 00:01:11 +0900156 public PortNumber intBridgePortNum() {
157 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
158 Port port = deviceService.getPorts(intgBridge).stream()
159 .filter(p -> p.isEnabled() &&
160 Objects.equals(p.annotations().value(PORT_NAME), INTEGRATION_BRIDGE))
161 .findAny().orElse(null);
162 return port != null ? port.number() : null;
163 }
164
165 @Override
Jian Li7d111d72019-04-12 13:58:44 +0900166 public MacAddress intBridgeMac() {
167 OvsdbController ovsdbController =
168 DefaultServiceDirectory.getService(OvsdbController.class);
169 OvsdbNodeId ovsdb = new OvsdbNodeId(this.managementIp, DEFAULT_OVSDB_PORT);
170 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
171 if (client == null) {
172 return null;
173 }
174
175 Interface iface = client.getInterface(INTEGRATION_BRIDGE);
176 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
177 return MacAddress.valueOf((String) data.map().get(MAC_ADDRESS));
178 }
179
180 @Override
Jian Li49109b52019-01-22 00:17:28 +0900181 public boolean equals(Object obj) {
182 if (this == obj) {
183 return true;
184 }
185
186 if (obj instanceof DefaultK8sNode) {
187 DefaultK8sNode that = (DefaultK8sNode) obj;
188
189 return hostname.equals(that.hostname) &&
190 type == that.type &&
191 intgBridge.equals(that.intgBridge) &&
192 managementIp.equals(that.managementIp) &&
193 dataIp.equals(that.dataIp) &&
194 state == that.state;
195 }
196
197 return false;
198 }
199
200 @Override
201 public int hashCode() {
202 return Objects.hash(hostname, type, intgBridge, managementIp, dataIp, state);
203 }
204
205 @Override
206 public String toString() {
207 return MoreObjects.toStringHelper(this)
208 .add("hostname", hostname)
209 .add("type", type)
210 .add("intgBridge", intgBridge)
211 .add("managementIp", managementIp)
212 .add("dataIp", dataIp)
213 .add("state", state)
214 .toString();
215 }
216
217 private PortNumber tunnelPortNum(String tunnelType) {
218 if (dataIp == null) {
219 return null;
220 }
221 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
222 Port port = deviceService.getPorts(intgBridge).stream()
223 .filter(p -> p.isEnabled() &&
224 Objects.equals(p.annotations().value(PORT_NAME), tunnelType))
225 .findAny().orElse(null);
226 return port != null ? port.number() : null;
227 }
228
229 /**
230 * Returns new builder instance.
231 *
232 * @return kubernetes node builder
233 */
234 public static Builder builder() {
235 return new Builder();
236 }
237
238 /**
239 * Returns new builder instance with the given node as a default value.
240 *
241 * @param node kubernetes node
242 * @return kubernetes node builder
243 */
244 public static Builder from(K8sNode node) {
245 return new Builder()
246 .hostname(node.hostname())
247 .type(node.type())
248 .intgBridge(node.intgBridge())
249 .managementIp(node.managementIp())
250 .dataIp(node.dataIp())
251 .state(node.state());
252 }
253
254 public static final class Builder implements K8sNode.Builder {
255
256 private String hostname;
257 private Type type;
258 private DeviceId intgBridge;
259 private IpAddress managementIp;
260 private IpAddress dataIp;
261 private K8sNodeState state;
Jian Li3defa842019-02-12 00:31:35 +0900262 private K8sApiConfig apiConfig;
Jian Li49109b52019-01-22 00:17:28 +0900263
264 // private constructor not intended to use from external
265 private Builder() {
266 }
267
268 @Override
269 public K8sNode build() {
270 checkArgument(hostname != null, NOT_NULL_MSG, "hostname");
271 checkArgument(type != null, NOT_NULL_MSG, "type");
272 checkArgument(state != null, NOT_NULL_MSG, "state");
273 checkArgument(managementIp != null, NOT_NULL_MSG, "management IP");
274
275 return new DefaultK8sNode(hostname,
276 type,
277 intgBridge,
278 managementIp,
279 dataIp,
280 state);
281 }
282
283 @Override
284 public Builder hostname(String hostname) {
285 this.hostname = hostname;
286 return this;
287 }
288
289 @Override
290 public Builder type(Type type) {
291 this.type = type;
292 return this;
293 }
294
295 @Override
296 public Builder intgBridge(DeviceId deviceId) {
297 this.intgBridge = deviceId;
298 return this;
299 }
300
301 @Override
302 public Builder managementIp(IpAddress managementIp) {
303 this.managementIp = managementIp;
304 return this;
305 }
306
307 @Override
308 public Builder dataIp(IpAddress dataIp) {
309 this.dataIp = dataIp;
310 return this;
311 }
312
313 @Override
314 public Builder state(K8sNodeState state) {
315 this.state = state;
316 return this;
317 }
318 }
319}