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