blob: e63a685c42a1c1d5e3c2f1b594131ad780359638 [file] [log] [blame]
Jian Libde20bf2019-01-25 17:34:43 +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.k8snetworking.util;
17
18import com.fasterxml.jackson.core.JsonParseException;
19import com.fasterxml.jackson.core.JsonProcessingException;
20import com.fasterxml.jackson.databind.JsonMappingException;
21import com.fasterxml.jackson.databind.ObjectMapper;
Jian Li2cc2b632019-02-18 00:56:40 +090022import com.google.common.collect.Maps;
Jian Lie1a5b8f2019-07-23 17:13:19 +090023import io.fabric8.kubernetes.api.model.Container;
24import io.fabric8.kubernetes.api.model.ContainerPort;
25import io.fabric8.kubernetes.api.model.Namespace;
26import io.fabric8.kubernetes.api.model.Pod;
Jian Li85387732019-02-19 23:56:18 +090027import io.fabric8.kubernetes.client.ConfigBuilder;
28import io.fabric8.kubernetes.client.DefaultKubernetesClient;
29import io.fabric8.kubernetes.client.KubernetesClient;
30import org.apache.commons.lang3.StringUtils;
Jian Li9b199162019-02-10 18:00:35 +090031import org.apache.commons.net.util.SubnetUtils;
Jian Li732c3422020-09-07 17:01:11 +090032import org.onlab.osgi.DefaultServiceDirectory;
Jian Li9b199162019-02-10 18:00:35 +090033import org.onlab.packet.IpAddress;
Jian Li4bd6f2b2019-08-16 21:39:27 +090034import org.onlab.packet.MacAddress;
Jian Li140d8a22019-04-24 23:41:44 +090035import org.onlab.packet.TpPort;
Jian Li4aa17642019-01-30 00:01:11 +090036import org.onosproject.cfg.ConfigProperty;
Jian Li4bd6f2b2019-08-16 21:39:27 +090037import org.onosproject.k8snetworking.api.DefaultK8sPort;
Jian Lie1a5b8f2019-07-23 17:13:19 +090038import org.onosproject.k8snetworking.api.K8sNamespaceService;
Jian Li4aa17642019-01-30 00:01:11 +090039import org.onosproject.k8snetworking.api.K8sNetwork;
Jian Li4bd6f2b2019-08-16 21:39:27 +090040import org.onosproject.k8snetworking.api.K8sNetworkAdminService;
Jian Li4aa17642019-01-30 00:01:11 +090041import org.onosproject.k8snetworking.api.K8sNetworkService;
Jian Lie1a5b8f2019-07-23 17:13:19 +090042import org.onosproject.k8snetworking.api.K8sPodService;
Jian Li4bd6f2b2019-08-16 21:39:27 +090043import org.onosproject.k8snetworking.api.K8sPort;
Jian Lie1a5b8f2019-07-23 17:13:19 +090044import org.onosproject.k8snetworking.api.K8sServiceService;
Jian Li85387732019-02-19 23:56:18 +090045import org.onosproject.k8snode.api.K8sApiConfig;
Jian Li3d1111e2019-02-22 02:02:13 +090046import org.onosproject.k8snode.api.K8sApiConfigService;
Jian Li732c3422020-09-07 17:01:11 +090047import org.onosproject.k8snode.api.K8sHost;
48import org.onosproject.k8snode.api.K8sHostService;
Jian Li4aa17642019-01-30 00:01:11 +090049import org.onosproject.k8snode.api.K8sNode;
Jian Li2cc2b632019-02-18 00:56:40 +090050import org.onosproject.k8snode.api.K8sNodeService;
Jian Li732c3422020-09-07 17:01:11 +090051import org.onosproject.k8snode.api.K8sTunnelBridge;
Jian Li4bd6f2b2019-08-16 21:39:27 +090052import org.onosproject.net.DeviceId;
Jian Li732c3422020-09-07 17:01:11 +090053import org.onosproject.net.Port;
Jian Li4aa17642019-01-30 00:01:11 +090054import org.onosproject.net.PortNumber;
Jian Li732c3422020-09-07 17:01:11 +090055import org.onosproject.net.device.DeviceService;
Jian Li2cc2b632019-02-18 00:56:40 +090056import org.onosproject.net.group.DefaultGroupKey;
57import org.onosproject.net.group.GroupKey;
Jian Libde20bf2019-01-25 17:34:43 +090058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
61import java.io.IOException;
Jian Li9b199162019-02-10 18:00:35 +090062import java.util.Arrays;
63import java.util.HashSet;
Jian Lia6f58382019-12-16 14:22:13 +090064import java.util.List;
Jian Li2cc2b632019-02-18 00:56:40 +090065import java.util.Map;
Jian Li140d8a22019-04-24 23:41:44 +090066import java.util.Objects;
Jian Li4aa17642019-01-30 00:01:11 +090067import java.util.Optional;
68import java.util.Set;
Jian Li9b199162019-02-10 18:00:35 +090069import java.util.stream.Collectors;
Jian Libde20bf2019-01-25 17:34:43 +090070
Jian Lie1a5b8f2019-07-23 17:13:19 +090071import static org.onosproject.k8snetworking.api.Constants.DEFAULT_NAMESPACE_HASH;
Jian Li732c3422020-09-07 17:01:11 +090072import static org.onosproject.k8snetworking.api.Constants.NORMAL_PORT_NAME_PREFIX_CONTAINER;
73import static org.onosproject.k8snetworking.api.Constants.NORMAL_PORT_PREFIX_LENGTH;
74import static org.onosproject.k8snetworking.api.Constants.PT_PORT_NAME_PREFIX_CONTAINER;
75import static org.onosproject.k8snetworking.api.Constants.PT_PORT_PREFIX_LENGTH;
Jian Li4bd6f2b2019-08-16 21:39:27 +090076import static org.onosproject.k8snetworking.api.K8sPort.State.INACTIVE;
Jian Li732c3422020-09-07 17:01:11 +090077import static org.onosproject.k8snode.api.K8sApiConfig.Mode.PASSTHROUGH;
78import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Jian Libde20bf2019-01-25 17:34:43 +090079
80/**
81 * An utility that used in kubernetes networking app.
82 */
83public final class K8sNetworkingUtil {
84
85 private static final Logger log = LoggerFactory.getLogger(K8sNetworkingUtil.class);
86
Jian Li85387732019-02-19 23:56:18 +090087 private static final String COLON_SLASH = "://";
88 private static final String COLON = ":";
89
Jian Li140d8a22019-04-24 23:41:44 +090090 private static final String STR_ZERO = "0";
91 private static final String STR_ONE = "1";
92 private static final String STR_PADDING = "0000000000000000";
93 private static final int MASK_BEGIN_IDX = 0;
94 private static final int MASK_MAX_IDX = 16;
95 private static final int MASK_RADIX = 2;
96 private static final int PORT_RADIX = 16;
97
Jian Li4bd6f2b2019-08-16 21:39:27 +090098 private static final String PORT_ID = "portId";
99 private static final String DEVICE_ID = "deviceId";
100 private static final String PORT_NUMBER = "portNumber";
101 private static final String IP_ADDRESS = "ipAddress";
102 private static final String MAC_ADDRESS = "macAddress";
103 private static final String NETWORK_ID = "networkId";
104
Jian Libde20bf2019-01-25 17:34:43 +0900105 private K8sNetworkingUtil() {
106 }
107
108 /**
109 * Checks that whether the port is associated with container interface.
110 *
111 * @param portName port name
112 * @return true if the port is associated with container; false otherwise
113 */
114 public static boolean isContainer(String portName) {
Jian Li732c3422020-09-07 17:01:11 +0900115 return portName != null && (portName.contains(NORMAL_PORT_NAME_PREFIX_CONTAINER) ||
116 portName.contains(PT_PORT_NAME_PREFIX_CONTAINER));
117 }
118
119 /**
120 * Checks that whether the compared ports exist in the source name.
121 *
122 * @param sourceName source port name
123 * @param comparedName port name to be compared
124 * @return true if the compared port name exists, false otherwise
125 */
126 public static boolean existingContainerPort(String sourceName, String comparedName) {
127 if (comparedName == null) {
128 return false;
129 }
130
131 if (comparedName.contains(NORMAL_PORT_NAME_PREFIX_CONTAINER)) {
132 return sourceName.contains(comparedName.substring(NORMAL_PORT_PREFIX_LENGTH));
133 }
134
135 if (comparedName.contains(PT_PORT_NAME_PREFIX_CONTAINER)) {
136 return sourceName.contains(comparedName.substring(PT_PORT_PREFIX_LENGTH));
137 }
138
139 return false;
Jian Li4aa17642019-01-30 00:01:11 +0900140 }
141
142 /**
143 * Returns the tunnel port number with specified net ID and kubernetes node.
144 *
145 * @param netId network ID
146 * @param netService network service
147 * @param node kubernetes node
148 * @return tunnel port number
149 */
150 public static PortNumber tunnelPortNumByNetId(String netId,
151 K8sNetworkService netService,
152 K8sNode node) {
153 K8sNetwork.Type netType = netService.network(netId).type();
154
155 if (netType == null) {
156 return null;
157 }
158
159 return tunnelPortNumByNetType(netType, node);
160 }
161
162 /**
163 * Returns the tunnel port number with specified net type and kubernetes node.
164 *
165 * @param netType network type
166 * @param node kubernetes node
167 * @return tunnel port number
168 */
169 public static PortNumber tunnelPortNumByNetType(K8sNetwork.Type netType,
170 K8sNode node) {
Jian Li732c3422020-09-07 17:01:11 +0900171 if (node.mode() == PASSTHROUGH) {
172 K8sHostService hostService =
173 DefaultServiceDirectory.getService(K8sHostService.class);
174 Port port = null;
175 for (K8sHost host : hostService.hosts()) {
176 if (host.nodeNames().contains(node.hostname())) {
177 for (K8sTunnelBridge bridge : host.tunBridges()) {
178 if (bridge.tunnelId() == node.segmentId()) {
179 String portName = netType.name().toLowerCase() +
180 "-" + node.segmentId();
181 port = port(bridge.deviceId(), portName);
182 }
183 }
184 }
185 }
186
187 if (port == null) {
Jian Li4aa17642019-01-30 00:01:11 +0900188 return null;
Jian Li732c3422020-09-07 17:01:11 +0900189 } else {
190 return port.number();
191 }
192
193 } else {
194 switch (netType) {
195 case VXLAN:
196 return node.vxlanPortNum();
197 case GRE:
198 return node.grePortNum();
199 case GENEVE:
200 return node.genevePortNum();
201 default:
202 return null;
203 }
Jian Li4aa17642019-01-30 00:01:11 +0900204 }
205 }
206
207 /**
Jian Li732c3422020-09-07 17:01:11 +0900208 * Obtains the port from the device with the given port name.
209 *
210 * @param deviceId device identifier
211 * @param portName port name
212 * @return port object
213 */
214 public static Port port(DeviceId deviceId, String portName) {
215 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
216 return deviceService.getPorts(deviceId).stream()
217 .filter(p -> p.isEnabled() &&
218 Objects.equals(p.annotations().value(PORT_NAME), portName))
219 .findAny().orElse(null);
220 }
221
222 /**
Jian Li4aa17642019-01-30 00:01:11 +0900223 * Obtains the property value with specified property key name.
224 *
225 * @param properties a collection of properties
226 * @param name key name
227 * @return mapping value
228 */
229 public static String getPropertyValue(Set<ConfigProperty> properties,
230 String name) {
231 Optional<ConfigProperty> property =
232 properties.stream().filter(p -> p.name().equals(name)).findFirst();
233 return property.map(ConfigProperty::value).orElse(null);
Jian Libde20bf2019-01-25 17:34:43 +0900234 }
235
236 /**
237 * Prints out the JSON string in pretty format.
238 *
239 * @param mapper Object mapper
240 * @param jsonString JSON string
241 * @return pretty formatted JSON string
242 */
243 public static String prettyJson(ObjectMapper mapper, String jsonString) {
244 try {
245 Object jsonObject = mapper.readValue(jsonString, Object.class);
246 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
247 } catch (JsonParseException e) {
Jian Li003d5692019-08-26 23:19:38 +0900248 log.debug("JsonParseException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900249 } catch (JsonMappingException e) {
Jian Li003d5692019-08-26 23:19:38 +0900250 log.debug("JsonMappingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900251 } catch (JsonProcessingException e) {
Jian Li003d5692019-08-26 23:19:38 +0900252 log.debug("JsonProcessingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900253 } catch (IOException e) {
Jian Li003d5692019-08-26 23:19:38 +0900254 log.debug("IOException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900255 }
256 return null;
257 }
Jian Li9b199162019-02-10 18:00:35 +0900258
259 /**
260 * Obtains valid IP addresses of the given subnet.
261 *
262 * @param cidr CIDR
263 * @return set of IP addresses
264 */
265 public static Set<IpAddress> getSubnetIps(String cidr) {
266 SubnetUtils utils = new SubnetUtils(cidr);
Jian Li7970b712019-05-03 20:58:21 +0900267 utils.setInclusiveHostCount(false);
Jian Li9b199162019-02-10 18:00:35 +0900268 SubnetUtils.SubnetInfo info = utils.getInfo();
269 Set<String> allAddresses =
270 new HashSet<>(Arrays.asList(info.getAllAddresses()));
271
272 if (allAddresses.size() > 2) {
Jian Li7970b712019-05-03 20:58:21 +0900273 allAddresses.remove(info.getLowAddress());
274 allAddresses.remove(info.getHighAddress());
Jian Li9b199162019-02-10 18:00:35 +0900275 }
276
277 return allAddresses.stream()
278 .map(IpAddress::valueOf).collect(Collectors.toSet());
279 }
Jian Li85387732019-02-19 23:56:18 +0900280
281 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900282 * Obtains flow group key from the given id.
283 *
284 * @param groupId flow group identifier
285 * @return flow group key
286 */
287 public static GroupKey getGroupKey(int groupId) {
288 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
289 }
290
291 /**
Jian Li85387732019-02-19 23:56:18 +0900292 * Generates endpoint URL by referring to scheme, ipAddress and port.
293 *
294 * @param scheme scheme
295 * @param ipAddress IP address
296 * @param port port number
297 * @return generated endpoint URL
298 */
299 public static String endpoint(K8sApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
300 StringBuilder endpoint = new StringBuilder();
301 String protocol = StringUtils.lowerCase(scheme.name());
302
303 endpoint.append(protocol);
304 endpoint.append(COLON_SLASH);
305 endpoint.append(ipAddress.toString());
306 endpoint.append(COLON);
307 endpoint.append(port);
308
309 return endpoint.toString();
310 }
311
312 /**
313 * Generates endpoint URL by referring to scheme, ipAddress and port.
314 *
315 * @param apiConfig kubernetes API config
316 * @return generated endpoint URL
317 */
318 public static String endpoint(K8sApiConfig apiConfig) {
319 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
320 }
321
322 /**
323 * Obtains workable kubernetes client.
324 *
325 * @param config kubernetes API config
326 * @return kubernetes client
327 */
328 public static KubernetesClient k8sClient(K8sApiConfig config) {
329 if (config == null) {
330 log.warn("Kubernetes API server config is empty.");
331 return null;
332 }
333
334 String endpoint = endpoint(config);
335
336 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
337
338 if (config.scheme() == K8sApiConfig.Scheme.HTTPS) {
339 configBuilder.withTrustCerts(true)
340 .withOauthToken(config.token())
341 .withCaCertData(config.caCertData())
342 .withClientCertData(config.clientCertData())
343 .withClientKeyData(config.clientKeyData());
344 }
345
346 return new DefaultKubernetesClient(configBuilder.build());
347 }
Jian Li3d1111e2019-02-22 02:02:13 +0900348
349 /**
350 * Obtains workable kubernetes client.
351 *
352 * @param service kubernetes API service
353 * @return kubernetes client
354 */
355 public static KubernetesClient k8sClient(K8sApiConfigService service) {
356 K8sApiConfig config =
357 service.apiConfigs().stream().findAny().orElse(null);
358 if (config == null) {
359 log.error("Failed to find valid kubernetes API configuration.");
360 return null;
361 }
362
363 KubernetesClient client = k8sClient(config);
364
365 if (client == null) {
366 log.error("Failed to connect to kubernetes API server.");
367 return null;
368 }
369
370 return client;
371 }
Jian Li2cc2b632019-02-18 00:56:40 +0900372
373 /**
374 * Obtains the kubernetes node IP and kubernetes network gateway IP map.
375 *
376 * @param nodeService kubernetes node service
377 * @param networkService kubernetes network service
378 * @return kubernetes node IP and kubernetes network gateway IP map
379 */
380 public static Map<String, String> nodeIpGatewayIpMap(K8sNodeService nodeService,
381 K8sNetworkService networkService) {
382 Map<String, String> ipMap = Maps.newConcurrentMap();
383
384 nodeService.completeNodes().forEach(n -> {
385 K8sNetwork network = networkService.network(n.hostname());
386 if (network != null) {
387 ipMap.put(n.dataIp().toString(), network.gatewayIp().toString());
388 }
389 });
390
391 return ipMap;
392 }
Jian Li004526d2019-02-25 16:26:27 +0900393
394 /**
Jian Li73d3b6a2019-07-08 18:07:53 +0900395 * Returns a shifted IP address.
396 *
397 * @param ipAddress IP address to be shifted
398 * @param shiftPrefix A IP prefix used in shifted IP address
399 * @return shifted Ip address
400 */
401 public static String shiftIpDomain(String ipAddress, String shiftPrefix) {
402 String origIpPrefix = ipAddress.split("\\.")[0] + "." + ipAddress.split("\\.")[1];
403 return StringUtils.replace(ipAddress, origIpPrefix, shiftPrefix);
404 }
405
406 /**
Jian Li140d8a22019-04-24 23:41:44 +0900407 * Returns an unshifted IP address.
Jian Li004526d2019-02-25 16:26:27 +0900408 *
Jian Li140d8a22019-04-24 23:41:44 +0900409 * @param ipAddress IP address to be unshifted
410 * @param ipPrefix IP prefix which to be used for unshifting
411 * @param cidr a POD network CIDR
412 * @return unshifted IP address
Jian Li004526d2019-02-25 16:26:27 +0900413 */
Jian Li140d8a22019-04-24 23:41:44 +0900414 public static String unshiftIpDomain(String ipAddress,
415 String ipPrefix,
416 String cidr) {
Jian Li004526d2019-02-25 16:26:27 +0900417
Jian Li140d8a22019-04-24 23:41:44 +0900418 String origIpPrefix = cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
419 return StringUtils.replace(ipAddress, ipPrefix, origIpPrefix);
420 }
Jian Li004526d2019-02-25 16:26:27 +0900421
Jian Li140d8a22019-04-24 23:41:44 +0900422 /**
423 * Returns the B class IP prefix of the given CIDR.
424 *
425 * @param cidr CIDR
426 * @return IP prefix
427 */
428 public static String getBclassIpPrefixFromCidr(String cidr) {
429 if (cidr == null) {
430 return null;
431 }
432 return cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
433 }
Jian Li004526d2019-02-25 16:26:27 +0900434
Jian Li140d8a22019-04-24 23:41:44 +0900435 /**
436 * Returns the A class IP prefix of the given CIDR.
437 *
438 * @param cidr CIDR
439 * @return IP prefix
440 */
441 public static String getAclassIpPrefixFromCidr(String cidr) {
442 if (cidr == null) {
443 return null;
444 }
445 return cidr.split("\\.")[0];
446 }
447
448 /**
449 * Returns the map of port range.
450 *
451 * @param portMin minimum port number
452 * @param portMax maximum port number
453 * @return map of port range
454 */
455 public static Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
456
457 boolean processing = true;
458 int start = portMin;
459 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
460 while (processing) {
461 String minStr = Integer.toBinaryString(start);
462 String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
463
464 int mask = testMasks(binStrMinPadded, start, portMax);
465 int maskStart = binLower(binStrMinPadded, mask);
466 int maskEnd = binHigher(binStrMinPadded, mask);
467
468 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
469 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
470 Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
471
472 start = maskEnd + 1;
473 if (start > portMax) {
474 processing = false;
475 }
476 }
477
478 return portMaskMap;
479 }
480
Jian Lie1a5b8f2019-07-23 17:13:19 +0900481 /**
482 * Returns the namespace hash value by given POD IP.
483 *
484 * @param k8sPodService kubernetes POD service
485 * @param k8sNamespaceService kubernetes namespace service
486 * @param podIp POD IP address
487 * @return namespace hash value
488 */
489 public static Integer namespaceHashByPodIp(K8sPodService k8sPodService,
490 K8sNamespaceService k8sNamespaceService,
491 String podIp) {
492 String ns = k8sPodService.pods().stream()
493 .filter(pod -> pod.getStatus().getPodIP() != null)
494 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
495 .map(pod -> pod.getMetadata().getNamespace())
496 .findAny().orElse(null);
497
498 if (ns != null) {
499 return k8sNamespaceService.namespaces().stream()
500 .filter(n -> n.getMetadata().getName().equals(ns))
501 .map(Namespace::hashCode).findAny().orElse(null);
502 } else {
503 return null;
504 }
505 }
506
507 /**
508 * Returns the namespace hash value by given service IP.
509 *
510 * @param k8sServiceService kubernetes service service
511 * @param k8sNamespaceService kubernetes namespace service
512 * @param serviceIp service IP address
513 * @return namespace hash value
514 */
515 public static int namespaceHashByServiceIp(K8sServiceService k8sServiceService,
516 K8sNamespaceService k8sNamespaceService,
517 String serviceIp) {
518 String ns = k8sServiceService.services().stream()
519 .filter(service -> service.getSpec().getClusterIP() != null)
520 .filter(service -> service.getSpec().getClusterIP().equalsIgnoreCase(serviceIp))
521 .map(service -> service.getMetadata().getNamespace())
522 .findAny().orElse(null);
523
524 if (ns != null) {
525 return namespaceHashByNamespace(k8sNamespaceService, ns);
526 } else {
527 return DEFAULT_NAMESPACE_HASH;
528 }
529 }
530
531 /**
532 * Returns the namespace hash value by given namespace name.
533 *
534 * @param k8sNamespaceService kubernetes namespace service
535 * @param ns namespace name
536 * @return namespace hash value
537 */
538 public static int namespaceHashByNamespace(K8sNamespaceService k8sNamespaceService,
539 String ns) {
540
541 return k8sNamespaceService.namespaces().stream()
542 .filter(n -> n.getMetadata().getName() != null)
543 .filter(n -> n.getMetadata().getName().equalsIgnoreCase(ns))
544 .map(Namespace::hashCode).findAny().orElse(DEFAULT_NAMESPACE_HASH);
545 }
546
547 /**
548 * Returns POD instance by POD IP address.
549 *
550 * @param podService kubernetes POD service
551 * @param podIp POD IP address
552 * @return POD instance
553 */
554 public static Pod podByIp(K8sPodService podService, String podIp) {
555 return podService.pods().stream()
556 .filter(pod -> pod.getStatus().getPodIP() != null)
557 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
558 .findAny().orElse(null);
559 }
560
561 /**
562 * Returns the container port number by given container port name.
563 *
564 * @param pod kubernetes POD
565 * @param portName port name
566 * @return container port number,
567 * return 0 if there is no port number mapped with the given port name
568 */
569 public static int portNumberByName(Pod pod, String portName) {
Jian Li5cf3b002019-08-30 17:57:53 +0900570
571 if (pod == null || pod.getSpec() == null) {
572 return 0;
573 }
574
Jian Lie1a5b8f2019-07-23 17:13:19 +0900575 for (Container container : pod.getSpec().getContainers()) {
576 for (ContainerPort cp : container.getPorts()) {
577 if (cp.getName() != null && cp.getName().equals(portName)) {
578 return cp.getContainerPort();
579 }
580 }
581 }
582
583 return 0;
584 }
585
Jian Li4bd6f2b2019-08-16 21:39:27 +0900586 /**
587 * Synchronizes port from kubernetes POD.
588 *
589 * @param pod kubernetes POD
590 * @param adminService admin service
591 */
592 public static void syncPortFromPod(Pod pod, K8sNetworkAdminService adminService) {
593 Map<String, String> annotations = pod.getMetadata().getAnnotations();
594 if (annotations != null && !annotations.isEmpty() &&
595 annotations.get(PORT_ID) != null) {
596 String portId = annotations.get(PORT_ID);
597
598 K8sPort oldPort = adminService.port(portId);
599
600 String networkId = annotations.get(NETWORK_ID);
601 DeviceId deviceId = DeviceId.deviceId(annotations.get(DEVICE_ID));
602 PortNumber portNumber = PortNumber.portNumber(annotations.get(PORT_NUMBER));
603 IpAddress ipAddress = IpAddress.valueOf(annotations.get(IP_ADDRESS));
604 MacAddress macAddress = MacAddress.valueOf(annotations.get(MAC_ADDRESS));
605
606 K8sPort newPort = DefaultK8sPort.builder()
607 .portId(portId)
608 .networkId(networkId)
609 .deviceId(deviceId)
610 .ipAddress(ipAddress)
611 .macAddress(macAddress)
612 .portNumber(portNumber)
613 .state(INACTIVE)
614 .build();
615
616 if (oldPort == null) {
617 adminService.createPort(newPort);
618 } else {
619 adminService.updatePort(newPort);
620 }
621 }
622 }
623
Jian Lia6f58382019-12-16 14:22:13 +0900624 /**
625 * Generates string format based on the given string length list.
626 *
627 * @param stringLengths a list of string lengths
628 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
629 */
630 public static String genFormatString(List<Integer> stringLengths) {
631 StringBuilder fsb = new StringBuilder();
632 stringLengths.forEach(length -> {
633 fsb.append("%-");
634 fsb.append(length);
635 fsb.append("s");
636 });
637 return fsb.toString();
638 }
639
Jian Li140d8a22019-04-24 23:41:44 +0900640 private static int binLower(String binStr, int bits) {
641 StringBuilder outBin = new StringBuilder(
642 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
643 for (int i = 0; i < bits; i++) {
644 outBin.append(STR_ZERO);
645 }
646
647 return Integer.parseInt(outBin.toString(), MASK_RADIX);
648 }
649
650 private static int binHigher(String binStr, int bits) {
651 StringBuilder outBin = new StringBuilder(
652 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
653 for (int i = 0; i < bits; i++) {
654 outBin.append(STR_ONE);
655 }
656
657 return Integer.parseInt(outBin.toString(), MASK_RADIX);
658 }
659
660 private static int testMasks(String binStr, int start, int end) {
661 int mask = MASK_BEGIN_IDX;
662 for (; mask <= MASK_MAX_IDX; mask++) {
663 int maskStart = binLower(binStr, mask);
664 int maskEnd = binHigher(binStr, mask);
665 if (maskStart < start || maskEnd > end) {
666 return mask - 1;
667 }
668 }
669
670 return mask;
671 }
672
673 private static String getMask(int bits) {
674 switch (bits) {
675 case 0: return "ffff";
676 case 1: return "fffe";
677 case 2: return "fffc";
678 case 3: return "fff8";
679 case 4: return "fff0";
680 case 5: return "ffe0";
681 case 6: return "ffc0";
682 case 7: return "ff80";
683 case 8: return "ff00";
684 case 9: return "fe00";
685 case 10: return "fc00";
686 case 11: return "f800";
687 case 12: return "f000";
688 case 13: return "e000";
689 case 14: return "c000";
690 case 15: return "8000";
691 case 16: return "0000";
692 default: return null;
693 }
Jian Li004526d2019-02-25 16:26:27 +0900694 }
Jian Libde20bf2019-01-25 17:34:43 +0900695}