blob: ff0f9de7e23f7608ccb38ec66fbfe4aaa53b0c62 [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 Li2778ffa2019-05-07 13:21:52 +090022import org.onosproject.net.Annotations;
Jian Li49109b52019-01-22 00:17:28 +090023import org.onosproject.net.DeviceId;
24import org.onosproject.net.Port;
25import org.onosproject.net.PortNumber;
26import org.onosproject.net.device.DeviceService;
Jian Li7d111d72019-04-12 13:58:44 +090027import org.onosproject.ovsdb.controller.OvsdbClientService;
28import org.onosproject.ovsdb.controller.OvsdbController;
29import org.onosproject.ovsdb.controller.OvsdbNodeId;
30import org.onosproject.ovsdb.rfc.notation.OvsdbMap;
31import org.onosproject.ovsdb.rfc.table.Interface;
Jian Li49109b52019-01-22 00:17:28 +090032
33import java.util.Objects;
34
35import static com.google.common.base.Preconditions.checkArgument;
Jian Lieb488ea2019-04-16 01:50:02 +090036import static org.onosproject.k8snode.api.Constants.EXTERNAL_BRIDGE;
Jian Li49109b52019-01-22 00:17:28 +090037import static org.onosproject.k8snode.api.Constants.GENEVE_TUNNEL;
38import static org.onosproject.k8snode.api.Constants.GRE_TUNNEL;
Jian Li4aa17642019-01-30 00:01:11 +090039import static org.onosproject.k8snode.api.Constants.INTEGRATION_BRIDGE;
Jian Lieb488ea2019-04-16 01:50:02 +090040import static org.onosproject.k8snode.api.Constants.INTEGRATION_TO_EXTERNAL_BRIDGE;
41import static org.onosproject.k8snode.api.Constants.PHYSICAL_EXTERNAL_BRIDGE;
Jian Li49109b52019-01-22 00:17:28 +090042import static org.onosproject.k8snode.api.Constants.VXLAN_TUNNEL;
43import static org.onosproject.net.AnnotationKeys.PORT_NAME;
44
45/**
46 * Representation of a kubernetes node.
47 */
48public class DefaultK8sNode implements K8sNode {
49
Jian Li7d111d72019-04-12 13:58:44 +090050 private static final int DEFAULT_OVSDB_PORT = 6640;
Jian Lieb488ea2019-04-16 01:50:02 +090051 private static final String IP_ADDRESS = "ip_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";
Jian Li2778ffa2019-05-07 13:21:52 +090054 private static final String PORT_MAC = "portMac";
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;
Jian Li1b08d652019-05-02 17:28:09 +090063 private final MacAddress extGatewayMac;
Jian Li49109b52019-01-22 00:17:28 +090064
65 private static final String NOT_NULL_MSG = "Node % cannot be null";
66
67 private static final String OVSDB = "ovsdb:";
68
69 /**
70 * A default constructor of kubernetes Node.
71 *
72 * @param hostname hostname
73 * @param type node type
74 * @param intgBridge integration bridge
Jian Libf562c22019-04-15 18:07:14 +090075 * @param extBridge external bridge
Jian Li49109b52019-01-22 00:17:28 +090076 * @param managementIp management IP address
77 * @param dataIp data IP address
78 * @param state node state
Jian Li1b08d652019-05-02 17:28:09 +090079 * @param extGatewayMac external gateway MAC address
Jian Li49109b52019-01-22 00:17:28 +090080 */
81 protected DefaultK8sNode(String hostname, Type type, DeviceId intgBridge,
Jian Libf562c22019-04-15 18:07:14 +090082 DeviceId extBridge, IpAddress managementIp,
Jian Li1b08d652019-05-02 17:28:09 +090083 IpAddress dataIp, K8sNodeState state,
84 MacAddress extGatewayMac) {
Jian Li49109b52019-01-22 00:17:28 +090085 this.hostname = hostname;
86 this.type = type;
87 this.intgBridge = intgBridge;
Jian Libf562c22019-04-15 18:07:14 +090088 this.extBridge = extBridge;
Jian Li49109b52019-01-22 00:17:28 +090089 this.managementIp = managementIp;
90 this.dataIp = dataIp;
91 this.state = state;
Jian Li1b08d652019-05-02 17:28:09 +090092 this.extGatewayMac = extGatewayMac;
Jian Li49109b52019-01-22 00:17:28 +090093 }
94
95 @Override
96 public String hostname() {
97 return hostname;
98 }
99
100 @Override
101 public Type type() {
102 return type;
103 }
104
105 @Override
106 public DeviceId ovsdb() {
107 return DeviceId.deviceId(OVSDB + managementIp().toString());
108 }
109
110 @Override
111 public DeviceId intgBridge() {
112 return intgBridge;
113 }
114
115 @Override
Jian Libf562c22019-04-15 18:07:14 +0900116 public DeviceId extBridge() {
117 return extBridge;
118 }
119
120 @Override
Jian Li1cee9882019-02-13 11:25:25 +0900121 public K8sNode updateIntgBridge(DeviceId deviceId) {
122 return new Builder()
123 .hostname(hostname)
124 .type(type)
125 .intgBridge(deviceId)
Jian Libf562c22019-04-15 18:07:14 +0900126 .extBridge(extBridge)
127 .managementIp(managementIp)
128 .dataIp(dataIp)
129 .state(state)
Jian Li1b08d652019-05-02 17:28:09 +0900130 .extGatewayMac(extGatewayMac)
Jian Libf562c22019-04-15 18:07:14 +0900131 .build();
132 }
133
134 @Override
135 public K8sNode updateExtBridge(DeviceId deviceId) {
136 return new Builder()
137 .hostname(hostname)
138 .type(type)
139 .intgBridge(intgBridge)
140 .extBridge(deviceId)
Jian Li1cee9882019-02-13 11:25:25 +0900141 .managementIp(managementIp)
142 .dataIp(dataIp)
143 .state(state)
Jian Li1b08d652019-05-02 17:28:09 +0900144 .extGatewayMac(extGatewayMac)
Jian Li1cee9882019-02-13 11:25:25 +0900145 .build();
146 }
147
148 @Override
Jian Li49109b52019-01-22 00:17:28 +0900149 public IpAddress managementIp() {
150 return managementIp;
151 }
152
153 @Override
154 public IpAddress dataIp() {
155 return dataIp;
156 }
157
158 @Override
159 public K8sNodeState state() {
160 return state;
161 }
162
163 @Override
164 public K8sNode updateState(K8sNodeState newState) {
165 return new Builder()
166 .hostname(hostname)
167 .type(type)
168 .intgBridge(intgBridge)
169 .managementIp(managementIp)
170 .dataIp(dataIp)
171 .state(newState)
Jian Li1b08d652019-05-02 17:28:09 +0900172 .extGatewayMac(extGatewayMac)
Jian Li49109b52019-01-22 00:17:28 +0900173 .build();
174 }
175
176 @Override
Jian Li1b08d652019-05-02 17:28:09 +0900177 public K8sNode updateExtGatewayMac(MacAddress newMac) {
178 return new Builder()
179 .hostname(hostname)
180 .type(type)
181 .intgBridge(intgBridge)
182 .managementIp(managementIp)
183 .dataIp(dataIp)
184 .state(state)
185 .extGatewayMac(newMac)
186 .build();
187
188 }
189
190 @Override
Jian Li49109b52019-01-22 00:17:28 +0900191 public PortNumber grePortNum() {
192 return tunnelPortNum(GRE_TUNNEL);
193 }
194
195 @Override
196 public PortNumber vxlanPortNum() {
197 return tunnelPortNum(VXLAN_TUNNEL);
198 }
199
200 @Override
201 public PortNumber genevePortNum() {
202 return tunnelPortNum(GENEVE_TUNNEL);
203 }
204
205 @Override
Jian Lieb488ea2019-04-16 01:50:02 +0900206 public PortNumber intgBridgePortNum() {
Jian Li2778ffa2019-05-07 13:21:52 +0900207 return portNumber(intgBridge, INTEGRATION_BRIDGE);
Jian Lieb488ea2019-04-16 01:50:02 +0900208 }
209
210 @Override
211 public PortNumber intgToExtPatchPortNum() {
212 return portNumber(intgBridge, INTEGRATION_TO_EXTERNAL_BRIDGE);
213 }
214
215 @Override
216 public PortNumber extToIntgPatchPortNum() {
217 return portNumber(extBridge, PHYSICAL_EXTERNAL_BRIDGE);
218 }
219
220 @Override
221 public PortNumber extBridgePortNum() {
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 String extIface = (String) data.map().get(EXT_INTF);
231 if (extIface == null) {
232 return null;
233 }
234
235 return portNumber(extBridge, extIface);
236 }
237
238 @Override
Jian Li2778ffa2019-05-07 13:21:52 +0900239 public MacAddress intgBridgeMac() {
240 return macAddress(intgBridge, INTEGRATION_BRIDGE);
241 }
242
243 @Override
244 public IpAddress extBridgeIp() {
245 OvsdbClientService client = getOvsClient();
246
247 if (client == null) {
248 return null;
249 }
250
251 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
252 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
253 return IpAddress.valueOf((String) data.map().get(IP_ADDRESS));
254 }
255
256 @Override
257 public MacAddress extBridgeMac() {
258 return macAddress(extBridge, EXTERNAL_BRIDGE);
259 }
260
261 @Override
262 public IpAddress extGatewayIp() {
263 OvsdbClientService client = getOvsClient();
264
265 if (client == null) {
266 return null;
267 }
268
269 Interface iface = getOvsClient().getInterface(EXTERNAL_BRIDGE);
270 OvsdbMap data = (OvsdbMap) iface.getExternalIdsColumn().data();
271 return IpAddress.valueOf((String) data.map().get(EXT_GW_IP));
272 }
273
274 @Override
275 public MacAddress extGatewayMac() {
276 return extGatewayMac;
277 }
278
279 @Override
Jian Li49109b52019-01-22 00:17:28 +0900280 public boolean equals(Object obj) {
281 if (this == obj) {
282 return true;
283 }
284
285 if (obj instanceof DefaultK8sNode) {
286 DefaultK8sNode that = (DefaultK8sNode) obj;
287
288 return hostname.equals(that.hostname) &&
289 type == that.type &&
290 intgBridge.equals(that.intgBridge) &&
Jian Libf562c22019-04-15 18:07:14 +0900291 extBridge.equals(that.extBridge) &&
Jian Li49109b52019-01-22 00:17:28 +0900292 managementIp.equals(that.managementIp) &&
293 dataIp.equals(that.dataIp) &&
294 state == that.state;
295 }
296
297 return false;
298 }
299
300 @Override
301 public int hashCode() {
Jian Libf562c22019-04-15 18:07:14 +0900302 return Objects.hash(hostname, type, intgBridge, extBridge,
Jian Li1b08d652019-05-02 17:28:09 +0900303 managementIp, dataIp, state, extGatewayMac);
Jian Li49109b52019-01-22 00:17:28 +0900304 }
305
306 @Override
307 public String toString() {
308 return MoreObjects.toStringHelper(this)
309 .add("hostname", hostname)
310 .add("type", type)
311 .add("intgBridge", intgBridge)
Jian Libf562c22019-04-15 18:07:14 +0900312 .add("extBridge", extBridge)
Jian Li49109b52019-01-22 00:17:28 +0900313 .add("managementIp", managementIp)
314 .add("dataIp", dataIp)
315 .add("state", state)
Jian Li1b08d652019-05-02 17:28:09 +0900316 .add("extGatewayMac", extGatewayMac)
Jian Li49109b52019-01-22 00:17:28 +0900317 .toString();
318 }
319
320 private PortNumber tunnelPortNum(String tunnelType) {
321 if (dataIp == null) {
322 return null;
323 }
Jian Lieb488ea2019-04-16 01:50:02 +0900324
325 return portNumber(intgBridge, tunnelType);
326 }
327
Jian Li2778ffa2019-05-07 13:21:52 +0900328 private MacAddress macAddress(DeviceId deviceId, String portName) {
329 Port port = port(deviceId, portName);
330 Annotations annots = port.annotations();
331 return annots != null ? MacAddress.valueOf(annots.value(PORT_MAC)) : null;
332 }
333
Jian Lieb488ea2019-04-16 01:50:02 +0900334 private PortNumber portNumber(DeviceId deviceId, String portName) {
Jian Li2778ffa2019-05-07 13:21:52 +0900335 Port port = port(deviceId, portName);
336 return port != null ? port.number() : null;
337 }
338
339 private Port port(DeviceId deviceId, String portName) {
Jian Li49109b52019-01-22 00:17:28 +0900340 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Jian Li2778ffa2019-05-07 13:21:52 +0900341 return deviceService.getPorts(deviceId).stream()
Jian Li49109b52019-01-22 00:17:28 +0900342 .filter(p -> p.isEnabled() &&
Jian Lieb488ea2019-04-16 01:50:02 +0900343 Objects.equals(p.annotations().value(PORT_NAME), portName))
Jian Li49109b52019-01-22 00:17:28 +0900344 .findAny().orElse(null);
Jian Li49109b52019-01-22 00:17:28 +0900345 }
346
Jian Lieb488ea2019-04-16 01:50:02 +0900347 private OvsdbClientService getOvsClient() {
348 OvsdbController ovsdbController =
349 DefaultServiceDirectory.getService(OvsdbController.class);
350 OvsdbNodeId ovsdb = new OvsdbNodeId(this.managementIp, DEFAULT_OVSDB_PORT);
351 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
352 if (client == null) {
353 return null;
354 }
355
356 return client;
357 }
358
Jian Li49109b52019-01-22 00:17:28 +0900359 /**
360 * Returns new builder instance.
361 *
362 * @return kubernetes node builder
363 */
364 public static Builder builder() {
365 return new Builder();
366 }
367
368 /**
369 * Returns new builder instance with the given node as a default value.
370 *
371 * @param node kubernetes node
372 * @return kubernetes node builder
373 */
374 public static Builder from(K8sNode node) {
375 return new Builder()
376 .hostname(node.hostname())
377 .type(node.type())
378 .intgBridge(node.intgBridge())
Jian Libf562c22019-04-15 18:07:14 +0900379 .extBridge(node.extBridge())
Jian Li49109b52019-01-22 00:17:28 +0900380 .managementIp(node.managementIp())
381 .dataIp(node.dataIp())
Jian Li1b08d652019-05-02 17:28:09 +0900382 .state(node.state())
383 .extGatewayMac(node.extGatewayMac());
Jian Li49109b52019-01-22 00:17:28 +0900384 }
385
386 public static final class Builder implements K8sNode.Builder {
387
388 private String hostname;
389 private Type type;
390 private DeviceId intgBridge;
Jian Libf562c22019-04-15 18:07:14 +0900391 private DeviceId extBridge;
Jian Li49109b52019-01-22 00:17:28 +0900392 private IpAddress managementIp;
393 private IpAddress dataIp;
394 private K8sNodeState state;
Jian Li3defa842019-02-12 00:31:35 +0900395 private K8sApiConfig apiConfig;
Jian Li1b08d652019-05-02 17:28:09 +0900396 private MacAddress extGatewayMac;
Jian Li49109b52019-01-22 00:17:28 +0900397
398 // private constructor not intended to use from external
399 private Builder() {
400 }
401
402 @Override
403 public K8sNode build() {
404 checkArgument(hostname != null, NOT_NULL_MSG, "hostname");
405 checkArgument(type != null, NOT_NULL_MSG, "type");
406 checkArgument(state != null, NOT_NULL_MSG, "state");
407 checkArgument(managementIp != null, NOT_NULL_MSG, "management IP");
408
409 return new DefaultK8sNode(hostname,
410 type,
411 intgBridge,
Jian Libf562c22019-04-15 18:07:14 +0900412 extBridge,
Jian Li49109b52019-01-22 00:17:28 +0900413 managementIp,
414 dataIp,
Jian Li1b08d652019-05-02 17:28:09 +0900415 state,
416 extGatewayMac);
Jian Li49109b52019-01-22 00:17:28 +0900417 }
418
419 @Override
420 public Builder hostname(String hostname) {
421 this.hostname = hostname;
422 return this;
423 }
424
425 @Override
426 public Builder type(Type type) {
427 this.type = type;
428 return this;
429 }
430
431 @Override
432 public Builder intgBridge(DeviceId deviceId) {
433 this.intgBridge = deviceId;
434 return this;
435 }
436
437 @Override
Jian Libf562c22019-04-15 18:07:14 +0900438 public Builder extBridge(DeviceId deviceId) {
439 this.extBridge = deviceId;
440 return this;
441 }
442
443 @Override
Jian Li49109b52019-01-22 00:17:28 +0900444 public Builder managementIp(IpAddress managementIp) {
445 this.managementIp = managementIp;
446 return this;
447 }
448
449 @Override
450 public Builder dataIp(IpAddress dataIp) {
451 this.dataIp = dataIp;
452 return this;
453 }
454
455 @Override
456 public Builder state(K8sNodeState state) {
457 this.state = state;
458 return this;
459 }
Jian Li1b08d652019-05-02 17:28:09 +0900460
461 @Override
462 public Builder extGatewayMac(MacAddress extGatewayMac) {
463 this.extGatewayMac = extGatewayMac;
464 return this;
465 }
Jian Li49109b52019-01-22 00:17:28 +0900466 }
467}