blob: 7325976e3b798aecc104dd7ef1e505ab8ef6c7cd [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 Li004526d2019-02-25 16:26:27 +090023import com.google.common.collect.Sets;
Jian Li85387732019-02-19 23:56:18 +090024import io.fabric8.kubernetes.client.ConfigBuilder;
25import io.fabric8.kubernetes.client.DefaultKubernetesClient;
26import io.fabric8.kubernetes.client.KubernetesClient;
27import org.apache.commons.lang3.StringUtils;
Jian Li9b199162019-02-10 18:00:35 +090028import org.apache.commons.net.util.SubnetUtils;
29import org.onlab.packet.IpAddress;
Jian Li4aa17642019-01-30 00:01:11 +090030import org.onosproject.cfg.ConfigProperty;
31import org.onosproject.k8snetworking.api.K8sNetwork;
32import org.onosproject.k8snetworking.api.K8sNetworkService;
Jian Li85387732019-02-19 23:56:18 +090033import org.onosproject.k8snode.api.K8sApiConfig;
Jian Li3d1111e2019-02-22 02:02:13 +090034import org.onosproject.k8snode.api.K8sApiConfigService;
Jian Li4aa17642019-01-30 00:01:11 +090035import org.onosproject.k8snode.api.K8sNode;
Jian Li2cc2b632019-02-18 00:56:40 +090036import org.onosproject.k8snode.api.K8sNodeService;
Jian Li4aa17642019-01-30 00:01:11 +090037import org.onosproject.net.PortNumber;
Jian Li2cc2b632019-02-18 00:56:40 +090038import org.onosproject.net.group.DefaultGroupKey;
39import org.onosproject.net.group.GroupKey;
Jian Libde20bf2019-01-25 17:34:43 +090040import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43import java.io.IOException;
Jian Li9b199162019-02-10 18:00:35 +090044import java.util.Arrays;
45import java.util.HashSet;
Jian Li2cc2b632019-02-18 00:56:40 +090046import java.util.Map;
Jian Li4aa17642019-01-30 00:01:11 +090047import java.util.Optional;
48import java.util.Set;
Jian Li9b199162019-02-10 18:00:35 +090049import java.util.stream.Collectors;
Jian Libde20bf2019-01-25 17:34:43 +090050
51import static org.onosproject.k8snetworking.api.Constants.PORT_NAME_PREFIX_CONTAINER;
Jian Li004526d2019-02-25 16:26:27 +090052import static org.onosproject.k8snetworking.api.Constants.SHIFTED_IP_PREFIX;
Jian Libde20bf2019-01-25 17:34:43 +090053
54/**
55 * An utility that used in kubernetes networking app.
56 */
57public final class K8sNetworkingUtil {
58
59 private static final Logger log = LoggerFactory.getLogger(K8sNetworkingUtil.class);
60
Jian Li85387732019-02-19 23:56:18 +090061 private static final String COLON_SLASH = "://";
62 private static final String COLON = ":";
63
Jian Libde20bf2019-01-25 17:34:43 +090064 private K8sNetworkingUtil() {
65 }
66
67 /**
68 * Checks that whether the port is associated with container interface.
69 *
70 * @param portName port name
71 * @return true if the port is associated with container; false otherwise
72 */
73 public static boolean isContainer(String portName) {
Jian Li4aa17642019-01-30 00:01:11 +090074 return portName != null && portName.contains(PORT_NAME_PREFIX_CONTAINER);
75 }
76
77 /**
78 * Returns the tunnel port number with specified net ID and kubernetes node.
79 *
80 * @param netId network ID
81 * @param netService network service
82 * @param node kubernetes node
83 * @return tunnel port number
84 */
85 public static PortNumber tunnelPortNumByNetId(String netId,
86 K8sNetworkService netService,
87 K8sNode node) {
88 K8sNetwork.Type netType = netService.network(netId).type();
89
90 if (netType == null) {
91 return null;
92 }
93
94 return tunnelPortNumByNetType(netType, node);
95 }
96
97 /**
98 * Returns the tunnel port number with specified net type and kubernetes node.
99 *
100 * @param netType network type
101 * @param node kubernetes node
102 * @return tunnel port number
103 */
104 public static PortNumber tunnelPortNumByNetType(K8sNetwork.Type netType,
105 K8sNode node) {
106 switch (netType) {
107 case VXLAN:
108 return node.vxlanPortNum();
109 case GRE:
110 return node.grePortNum();
111 case GENEVE:
112 return node.genevePortNum();
113 default:
114 return null;
115 }
116 }
117
118 /**
119 * Obtains the property value with specified property key name.
120 *
121 * @param properties a collection of properties
122 * @param name key name
123 * @return mapping value
124 */
125 public static String getPropertyValue(Set<ConfigProperty> properties,
126 String name) {
127 Optional<ConfigProperty> property =
128 properties.stream().filter(p -> p.name().equals(name)).findFirst();
129 return property.map(ConfigProperty::value).orElse(null);
Jian Libde20bf2019-01-25 17:34:43 +0900130 }
131
132 /**
133 * Prints out the JSON string in pretty format.
134 *
135 * @param mapper Object mapper
136 * @param jsonString JSON string
137 * @return pretty formatted JSON string
138 */
139 public static String prettyJson(ObjectMapper mapper, String jsonString) {
140 try {
141 Object jsonObject = mapper.readValue(jsonString, Object.class);
142 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
143 } catch (JsonParseException e) {
144 log.debug("JsonParseException caused by {}", e);
145 } catch (JsonMappingException e) {
146 log.debug("JsonMappingException caused by {}", e);
147 } catch (JsonProcessingException e) {
148 log.debug("JsonProcessingException caused by {}", e);
149 } catch (IOException e) {
150 log.debug("IOException caused by {}", e);
151 }
152 return null;
153 }
Jian Li9b199162019-02-10 18:00:35 +0900154
155 /**
156 * Obtains valid IP addresses of the given subnet.
157 *
158 * @param cidr CIDR
159 * @return set of IP addresses
160 */
161 public static Set<IpAddress> getSubnetIps(String cidr) {
162 SubnetUtils utils = new SubnetUtils(cidr);
163 utils.setInclusiveHostCount(true);
164 SubnetUtils.SubnetInfo info = utils.getInfo();
165 Set<String> allAddresses =
166 new HashSet<>(Arrays.asList(info.getAllAddresses()));
167
168 if (allAddresses.size() > 2) {
169 allAddresses.remove(info.getBroadcastAddress());
170 allAddresses.remove(info.getNetworkAddress());
171 }
172
173 return allAddresses.stream()
174 .map(IpAddress::valueOf).collect(Collectors.toSet());
175 }
Jian Li85387732019-02-19 23:56:18 +0900176
177 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900178 * Obtains flow group key from the given id.
179 *
180 * @param groupId flow group identifier
181 * @return flow group key
182 */
183 public static GroupKey getGroupKey(int groupId) {
184 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
185 }
186
187 /**
Jian Li85387732019-02-19 23:56:18 +0900188 * Generates endpoint URL by referring to scheme, ipAddress and port.
189 *
190 * @param scheme scheme
191 * @param ipAddress IP address
192 * @param port port number
193 * @return generated endpoint URL
194 */
195 public static String endpoint(K8sApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
196 StringBuilder endpoint = new StringBuilder();
197 String protocol = StringUtils.lowerCase(scheme.name());
198
199 endpoint.append(protocol);
200 endpoint.append(COLON_SLASH);
201 endpoint.append(ipAddress.toString());
202 endpoint.append(COLON);
203 endpoint.append(port);
204
205 return endpoint.toString();
206 }
207
208 /**
209 * Generates endpoint URL by referring to scheme, ipAddress and port.
210 *
211 * @param apiConfig kubernetes API config
212 * @return generated endpoint URL
213 */
214 public static String endpoint(K8sApiConfig apiConfig) {
215 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
216 }
217
218 /**
219 * Obtains workable kubernetes client.
220 *
221 * @param config kubernetes API config
222 * @return kubernetes client
223 */
224 public static KubernetesClient k8sClient(K8sApiConfig config) {
225 if (config == null) {
226 log.warn("Kubernetes API server config is empty.");
227 return null;
228 }
229
230 String endpoint = endpoint(config);
231
232 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
233
234 if (config.scheme() == K8sApiConfig.Scheme.HTTPS) {
235 configBuilder.withTrustCerts(true)
236 .withOauthToken(config.token())
237 .withCaCertData(config.caCertData())
238 .withClientCertData(config.clientCertData())
239 .withClientKeyData(config.clientKeyData());
240 }
241
242 return new DefaultKubernetesClient(configBuilder.build());
243 }
Jian Li3d1111e2019-02-22 02:02:13 +0900244
245 /**
246 * Obtains workable kubernetes client.
247 *
248 * @param service kubernetes API service
249 * @return kubernetes client
250 */
251 public static KubernetesClient k8sClient(K8sApiConfigService service) {
252 K8sApiConfig config =
253 service.apiConfigs().stream().findAny().orElse(null);
254 if (config == null) {
255 log.error("Failed to find valid kubernetes API configuration.");
256 return null;
257 }
258
259 KubernetesClient client = k8sClient(config);
260
261 if (client == null) {
262 log.error("Failed to connect to kubernetes API server.");
263 return null;
264 }
265
266 return client;
267 }
Jian Li2cc2b632019-02-18 00:56:40 +0900268
269 /**
270 * Obtains the kubernetes node IP and kubernetes network gateway IP map.
271 *
272 * @param nodeService kubernetes node service
273 * @param networkService kubernetes network service
274 * @return kubernetes node IP and kubernetes network gateway IP map
275 */
276 public static Map<String, String> nodeIpGatewayIpMap(K8sNodeService nodeService,
277 K8sNetworkService networkService) {
278 Map<String, String> ipMap = Maps.newConcurrentMap();
279
280 nodeService.completeNodes().forEach(n -> {
281 K8sNetwork network = networkService.network(n.hostname());
282 if (network != null) {
283 ipMap.put(n.dataIp().toString(), network.gatewayIp().toString());
284 }
285 });
286
287 return ipMap;
288 }
Jian Li004526d2019-02-25 16:26:27 +0900289
290 /**
291 * Returns a set of unshifted IP addresses.
292 *
293 * @param ipAddress shifted IP address
294 * @param service kubernetes network service
295 * @return unshifted IP addresses
296 */
297 public static Set<String> unshiftIpDomain(String ipAddress, K8sNetworkService service) {
298
299 Set<String> unshiftedIps = Sets.newConcurrentHashSet();
300
301 service.networks().forEach(n -> {
302 String cidr = n.cidr();
303 String origIpPrefix = cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
304 unshiftedIps.add(StringUtils.replace(ipAddress, SHIFTED_IP_PREFIX, origIpPrefix));
305 });
306
307 return unshiftedIps;
308 }
Jian Libde20bf2019-01-25 17:34:43 +0900309}