blob: 7be1e9a541a66fe2c3dc5392fd17c7c825f5cff4 [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;
Jian Lieb488ea2019-04-16 01:50:02 +090035import static org.onosproject.k8snode.api.Constants.EXTERNAL_BRIDGE;
Jian Li49109b52019-01-22 00:17:28 +090036import static org.onosproject.k8snode.api.Constants.GENEVE_TUNNEL;
37import static org.onosproject.k8snode.api.Constants.GRE_TUNNEL;
Jian Li4aa17642019-01-30 00:01:11 +090038import static org.onosproject.k8snode.api.Constants.INTEGRATION_BRIDGE;
Jian Lieb488ea2019-04-16 01:50:02 +090039import static org.onosproject.k8snode.api.Constants.INTEGRATION_TO_EXTERNAL_BRIDGE;
40import static org.onosproject.k8snode.api.Constants.PHYSICAL_EXTERNAL_BRIDGE;
Jian Li49109b52019-01-22 00:17:28 +090041import static org.onosproject.k8snode.api.Constants.VXLAN_TUNNEL;
42import static org.onosproject.net.AnnotationKeys.PORT_NAME;
43
44/**
45 * Representation of a kubernetes node.
46 */
47public class DefaultK8sNode implements K8sNode {
48
Jian Li7d111d72019-04-12 13:58:44 +090049 private static final int DEFAULT_OVSDB_PORT = 6640;
Jian Lieb488ea2019-04-16 01:50:02 +090050 private static final String IP_ADDRESS = "ip_address";
Jian Li7d111d72019-04-12 13:58:44 +090051 private static final String MAC_ADDRESS = "mac_address";
Jian Lieb488ea2019-04-16 01:50:02 +090052 private static final String EXT_INTF = "ext_interface";
53 private static final String EXT_GW_IP = "ext_gw_ip_address";
54 private static final String EXT_GW_MAC = "ext_gw_mac_address";
Jian Li7d111d72019-04-12 13:58:44 +090055
Jian Li49109b52019-01-22 00:17:28 +090056 private final String hostname;
57 private final Type type;
58 private final DeviceId intgBridge;
Jian Libf562c22019-04-15 18:07:14 +090059 private final DeviceId extBridge;
Jian Li49109b52019-01-22 00:17:28 +090060 private final IpAddress managementIp;
61 private final IpAddress dataIp;
62 private final K8sNodeState state;
63
64 private static final String NOT_NULL_MSG = "Node % cannot be null";
65
66 private static final String OVSDB = "ovsdb:";
67
68 /**
69 * A default constructor of kubernetes Node.
70 *
71 * @param hostname hostname
72 * @param type node type
73 * @param intgBridge integration bridge
Jian Libf562c22019-04-15 18:07:14 +090074 * @param extBridge external bridge
Jian Li49109b52019-01-22 00:17:28 +090075 * @param managementIp management IP address
76 * @param dataIp data IP address
77 * @param state node state
78 */
79 protected DefaultK8sNode(String hostname, Type type, DeviceId intgBridge,
Jian Libf562c22019-04-15 18:07:14 +090080 DeviceId extBridge, IpAddress managementIp,
81 IpAddress dataIp, K8sNodeState state) {
Jian Li49109b52019-01-22 00:17:28 +090082 this.hostname = hostname;
83 this.type = type;
84 this.intgBridge = intgBridge;
Jian Libf562c22019-04-15 18:07:14 +090085 this.extBridge = extBridge;
Jian Li49109b52019-01-22 00:17:28 +090086 this.managementIp = managementIp;
87 this.dataIp = dataIp;
88 this.state = state;
89 }
90
91 @Override
92 public String hostname() {
93 return hostname;
94 }
95
96 @Override
97 public Type type() {
98 return type;
99 }
100
101 @Override
102 public DeviceId ovsdb() {
103 return DeviceId.deviceId(OVSDB + managementIp().toString());
104 }
105
106 @Override
107 public DeviceId intgBridge() {
108 return intgBridge;
109 }
110
111 @Override
Jian Libf562c22019-04-15 18:07:14 +0900112 public DeviceId extBridge() {
113 return extBridge;
114 }
115
116 @Override
Jian Li1cee9882019-02-13 11:25:25 +0900117 public K8sNode updateIntgBridge(DeviceId deviceId) {
118 return new Builder()
119 .hostname(hostname)
120 .type(type)
121 .intgBridge(deviceId)
Jian Libf562c22019-04-15 18:07:14 +0900122 .extBridge(extBridge)
123 .managementIp(managementIp)
124 .dataIp(dataIp)
125 .state(state)
126 .build();
127 }
128
129 @Override
130 public K8sNode updateExtBridge(DeviceId deviceId) {
131 return new Builder()
132 .hostname(hostname)
133 .type(type)
134 .intgBridge(intgBridge)
135 .extBridge(deviceId)
Jian Li1cee9882019-02-13 11:25:25 +0900136 .managementIp(managementIp)
137 .dataIp(dataIp)
138 .state(state)
139 .build();
140 }
141
142 @Override
Jian Li49109b52019-01-22 00:17:28 +0900143 public IpAddress managementIp() {
144 return managementIp;
145 }
146
147 @Override
148 public IpAddress dataIp() {
149 return dataIp;
150 }
151
152 @Override
153 public K8sNodeState state() {
154 return state;
155 }
156
157 @Override
158 public K8sNode updateState(K8sNodeState newState) {
159 return new Builder()
160 .hostname(hostname)
161 .type(type)
162 .intgBridge(intgBridge)
163 .managementIp(managementIp)
164 .dataIp(dataIp)
165 .state(newState)
166 .build();
167 }
168
169 @Override
170 public PortNumber grePortNum() {
171 return tunnelPortNum(GRE_TUNNEL);
172 }
173
174 @Override
175 public PortNumber vxlanPortNum() {
176 return tunnelPortNum(VXLAN_TUNNEL);
177 }
178
179 @Override
180 public PortNumber genevePortNum() {
181 return tunnelPortNum(GENEVE_TUNNEL);
182 }
183
184 @Override
Jian Lieb488ea2019-04-16 01:50:02 +0900185 public PortNumber intgBridgePortNum() {
Jian Li4aa17642019-01-30 00:01:11 +0900186 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
187 Port port = deviceService.getPorts(intgBridge).stream()
188 .filter(p -> p.isEnabled() &&
189 Objects.equals(p.annotations().value(PORT_NAME), INTEGRATION_BRIDGE))
190 .findAny().orElse(null);
191 return port != null ? port.number() : null;
192 }
193
194 @Override
Jian Lieb488ea2019-04-16 01:50:02 +0900195 public MacAddress intgBridgeMac() {
196 OvsdbClientService client = getOvsClient();
197
Jian Li7d111d72019-04-12 13:58:44 +0900198 if (client == null) {
199 return null;
200 }
201
Jian Lieb488ea2019-04-16 01:50:02 +0900202 Interface iface = getOvsClient().getInterface(INTEGRATION_BRIDGE);
Jian Li7d111d72019-04-12 13:58:44 +0900203 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
204 return MacAddress.valueOf((String) data.map().get(MAC_ADDRESS));
205 }
206
207 @Override
Jian Lieb488ea2019-04-16 01:50:02 +0900208 public IpAddress extBridgeIp() {
209 OvsdbClientService client = getOvsClient();
210
211 if (client == null) {
212 return null;
213 }
214
215 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
216 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
217 return IpAddress.valueOf((String) data.map().get(IP_ADDRESS));
218 }
219
220 @Override
221 public MacAddress extBridgeMac() {
222 OvsdbClientService client = getOvsClient();
223
224 if (client == null) {
225 return null;
226 }
227
228 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
229 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
230 return MacAddress.valueOf((String) data.map().get(MAC_ADDRESS));
231 }
232
233 @Override
234 public IpAddress extGatewayIp() {
235 OvsdbClientService client = getOvsClient();
236
237 if (client == null) {
238 return null;
239 }
240
241 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
242 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
243 return IpAddress.valueOf((String) data.map().get(EXT_GW_IP));
244 }
245
246 @Override
247 public MacAddress extGatewayMac() {
248 OvsdbClientService client = getOvsClient();
249
250 if (client == null) {
251 return null;
252 }
253
254 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
255 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
256 return MacAddress.valueOf((String) data.map().get(EXT_GW_MAC));
257 }
258
259 @Override
260 public PortNumber intgToExtPatchPortNum() {
261 return portNumber(intgBridge, INTEGRATION_TO_EXTERNAL_BRIDGE);
262 }
263
264 @Override
265 public PortNumber extToIntgPatchPortNum() {
266 return portNumber(extBridge, PHYSICAL_EXTERNAL_BRIDGE);
267 }
268
269 @Override
270 public PortNumber extBridgePortNum() {
271 OvsdbClientService client = getOvsClient();
272
273 if (client == null) {
274 return null;
275 }
276
277 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
278 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
279 String extIface = (String) data.map().get(EXT_INTF);
280 if (extIface == null) {
281 return null;
282 }
283
284 return portNumber(extBridge, extIface);
285 }
286
287 @Override
Jian Li49109b52019-01-22 00:17:28 +0900288 public boolean equals(Object obj) {
289 if (this == obj) {
290 return true;
291 }
292
293 if (obj instanceof DefaultK8sNode) {
294 DefaultK8sNode that = (DefaultK8sNode) obj;
295
296 return hostname.equals(that.hostname) &&
297 type == that.type &&
298 intgBridge.equals(that.intgBridge) &&
Jian Libf562c22019-04-15 18:07:14 +0900299 extBridge.equals(that.extBridge) &&
Jian Li49109b52019-01-22 00:17:28 +0900300 managementIp.equals(that.managementIp) &&
301 dataIp.equals(that.dataIp) &&
302 state == that.state;
303 }
304
305 return false;
306 }
307
308 @Override
309 public int hashCode() {
Jian Libf562c22019-04-15 18:07:14 +0900310 return Objects.hash(hostname, type, intgBridge, extBridge,
311 managementIp, dataIp, state);
Jian Li49109b52019-01-22 00:17:28 +0900312 }
313
314 @Override
315 public String toString() {
316 return MoreObjects.toStringHelper(this)
317 .add("hostname", hostname)
318 .add("type", type)
319 .add("intgBridge", intgBridge)
Jian Libf562c22019-04-15 18:07:14 +0900320 .add("extBridge", extBridge)
Jian Li49109b52019-01-22 00:17:28 +0900321 .add("managementIp", managementIp)
322 .add("dataIp", dataIp)
323 .add("state", state)
324 .toString();
325 }
326
327 private PortNumber tunnelPortNum(String tunnelType) {
328 if (dataIp == null) {
329 return null;
330 }
Jian Lieb488ea2019-04-16 01:50:02 +0900331
332 return portNumber(intgBridge, tunnelType);
333 }
334
335 private PortNumber portNumber(DeviceId deviceId, String portName) {
Jian Li49109b52019-01-22 00:17:28 +0900336 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Jian Lieb488ea2019-04-16 01:50:02 +0900337 Port port = deviceService.getPorts(deviceId).stream()
Jian Li49109b52019-01-22 00:17:28 +0900338 .filter(p -> p.isEnabled() &&
Jian Lieb488ea2019-04-16 01:50:02 +0900339 Objects.equals(p.annotations().value(PORT_NAME), portName))
Jian Li49109b52019-01-22 00:17:28 +0900340 .findAny().orElse(null);
341 return port != null ? port.number() : null;
342 }
343
Jian Lieb488ea2019-04-16 01:50:02 +0900344 private OvsdbClientService getOvsClient() {
345 OvsdbController ovsdbController =
346 DefaultServiceDirectory.getService(OvsdbController.class);
347 OvsdbNodeId ovsdb = new OvsdbNodeId(this.managementIp, DEFAULT_OVSDB_PORT);
348 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
349 if (client == null) {
350 return null;
351 }
352
353 return client;
354 }
355
Jian Li49109b52019-01-22 00:17:28 +0900356 /**
357 * Returns new builder instance.
358 *
359 * @return kubernetes node builder
360 */
361 public static Builder builder() {
362 return new Builder();
363 }
364
365 /**
366 * Returns new builder instance with the given node as a default value.
367 *
368 * @param node kubernetes node
369 * @return kubernetes node builder
370 */
371 public static Builder from(K8sNode node) {
372 return new Builder()
373 .hostname(node.hostname())
374 .type(node.type())
375 .intgBridge(node.intgBridge())
Jian Libf562c22019-04-15 18:07:14 +0900376 .extBridge(node.extBridge())
Jian Li49109b52019-01-22 00:17:28 +0900377 .managementIp(node.managementIp())
378 .dataIp(node.dataIp())
379 .state(node.state());
380 }
381
382 public static final class Builder implements K8sNode.Builder {
383
384 private String hostname;
385 private Type type;
386 private DeviceId intgBridge;
Jian Libf562c22019-04-15 18:07:14 +0900387 private DeviceId extBridge;
Jian Li49109b52019-01-22 00:17:28 +0900388 private IpAddress managementIp;
389 private IpAddress dataIp;
390 private K8sNodeState state;
Jian Li3defa842019-02-12 00:31:35 +0900391 private K8sApiConfig apiConfig;
Jian Li49109b52019-01-22 00:17:28 +0900392
393 // private constructor not intended to use from external
394 private Builder() {
395 }
396
397 @Override
398 public K8sNode build() {
399 checkArgument(hostname != null, NOT_NULL_MSG, "hostname");
400 checkArgument(type != null, NOT_NULL_MSG, "type");
401 checkArgument(state != null, NOT_NULL_MSG, "state");
402 checkArgument(managementIp != null, NOT_NULL_MSG, "management IP");
403
404 return new DefaultK8sNode(hostname,
405 type,
406 intgBridge,
Jian Libf562c22019-04-15 18:07:14 +0900407 extBridge,
Jian Li49109b52019-01-22 00:17:28 +0900408 managementIp,
409 dataIp,
410 state);
411 }
412
413 @Override
414 public Builder hostname(String hostname) {
415 this.hostname = hostname;
416 return this;
417 }
418
419 @Override
420 public Builder type(Type type) {
421 this.type = type;
422 return this;
423 }
424
425 @Override
426 public Builder intgBridge(DeviceId deviceId) {
427 this.intgBridge = deviceId;
428 return this;
429 }
430
431 @Override
Jian Libf562c22019-04-15 18:07:14 +0900432 public Builder extBridge(DeviceId deviceId) {
433 this.extBridge = deviceId;
434 return this;
435 }
436
437 @Override
Jian Li49109b52019-01-22 00:17:28 +0900438 public Builder managementIp(IpAddress managementIp) {
439 this.managementIp = managementIp;
440 return this;
441 }
442
443 @Override
444 public Builder dataIp(IpAddress dataIp) {
445 this.dataIp = dataIp;
446 return this;
447 }
448
449 @Override
450 public Builder state(K8sNodeState state) {
451 this.state = state;
452 return this;
453 }
454 }
455}