blob: fc05eca127a5499eb7530ac8026b8ddf5de36862 [file] [log] [blame]
Jian Lif16e8852019-01-22 22:55:31 +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.util;
17
18import com.fasterxml.jackson.databind.ObjectMapper;
19import com.google.common.base.Strings;
Jian Li1cee9882019-02-13 11:25:25 +090020import io.fabric8.kubernetes.client.ConfigBuilder;
21import io.fabric8.kubernetes.client.DefaultKubernetesClient;
22import io.fabric8.kubernetes.client.KubernetesClient;
Jian Li3defa842019-02-12 00:31:35 +090023import org.apache.commons.lang.StringUtils;
24import org.onlab.packet.IpAddress;
25import org.onosproject.k8snode.api.K8sApiConfig;
26import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
Jian Lif16e8852019-01-22 22:55:31 +090027import org.onosproject.k8snode.api.K8sNode;
28import org.onosproject.net.Device;
29import org.onosproject.net.behaviour.BridgeConfig;
30import org.onosproject.net.behaviour.BridgeName;
31import org.onosproject.net.device.DeviceService;
32import org.onosproject.ovsdb.controller.OvsdbClientService;
33import org.onosproject.ovsdb.controller.OvsdbController;
34import org.onosproject.ovsdb.controller.OvsdbNodeId;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38import java.io.IOException;
39import java.util.Dictionary;
Jian Lia6f58382019-12-16 14:22:13 +090040import java.util.List;
Jian Lif16e8852019-01-22 22:55:31 +090041
42import static org.onlab.util.Tools.get;
43
44/**
45 * An utility that used in kubernetes node app.
46 */
47public final class K8sNodeUtil {
48 private static final Logger log = LoggerFactory.getLogger(K8sNodeUtil.class);
49
Jian Li3defa842019-02-12 00:31:35 +090050 private static final String COLON_SLASH = "://";
51 private static final String COLON = ":";
52
Jian Li1cee9882019-02-13 11:25:25 +090053 private static final int HEX_LENGTH = 16;
54 private static final String OF_PREFIX = "of:";
55 private static final String ZERO = "0";
56
Jian Lif16e8852019-01-22 22:55:31 +090057 /**
58 * Prevents object installation from external.
59 */
60 private K8sNodeUtil() {
61 }
62
63 /**
64 * Checks whether the controller has a connection with an OVSDB that resides
65 * inside the given kubernetes node.
66 *
67 * @param node kubernetes node
68 * @param ovsdbPort OVSDB port
69 * @param ovsdbController OVSDB controller
70 * @param deviceService device service
71 * @return true if the controller is connected to the OVSDB, false otherwise
72 */
73 public static boolean isOvsdbConnected(K8sNode node,
74 int ovsdbPort,
75 OvsdbController ovsdbController,
76 DeviceService deviceService) {
77 OvsdbClientService client = getOvsdbClient(node, ovsdbPort, ovsdbController);
78 return deviceService.isAvailable(node.ovsdb()) &&
79 client != null &&
80 client.isConnected();
81 }
82
83 /**
84 * Gets the ovsdb client with supplied openstack node.
85 *
86 * @param node kubernetes node
87 * @param ovsdbPort ovsdb port
88 * @param ovsdbController ovsdb controller
89 * @return ovsdb client
90 */
91 public static OvsdbClientService getOvsdbClient(K8sNode node,
92 int ovsdbPort,
93 OvsdbController ovsdbController) {
94 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
95 return ovsdbController.getOvsdbClient(ovsdb);
96 }
97
98 /**
99 * Adds or removes a network interface (aka port) into a given bridge of kubernetes node.
100 *
101 * @param k8sNode kubernetes node
102 * @param bridgeName bridge name
103 * @param intfName interface name
104 * @param deviceService device service
105 * @param addOrRemove add port is true, remove it otherwise
106 */
107 public static synchronized void addOrRemoveSystemInterface(K8sNode k8sNode,
108 String bridgeName,
109 String intfName,
110 DeviceService deviceService,
111 boolean addOrRemove) {
112
113
114 Device device = deviceService.getDevice(k8sNode.ovsdb());
115 if (device == null || !device.is(BridgeConfig.class)) {
116 log.info("device is null or this device if not ovsdb device");
117 return;
118 }
119 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
120
121 if (addOrRemove) {
122 bridgeConfig.addPort(BridgeName.bridgeName(bridgeName), intfName);
123 } else {
124 bridgeConfig.deletePort(BridgeName.bridgeName(bridgeName), intfName);
125 }
126 }
127
128 /**
129 * Gets Boolean property from the propertyName
130 * Return null if propertyName is not found.
131 *
132 * @param properties properties to be looked up
133 * @param propertyName the name of the property to look up
134 * @return value when the propertyName is defined or return null
135 */
136 public static Boolean getBooleanProperty(Dictionary<?, ?> properties,
137 String propertyName) {
138 Boolean value;
139 try {
140 String s = get(properties, propertyName);
141 value = Strings.isNullOrEmpty(s) ? null : Boolean.valueOf(s);
142 } catch (ClassCastException e) {
143 value = null;
144 }
145 return value;
146 }
147
148 /**
149 * Prints out the JSON string in pretty format.
150 *
151 * @param mapper Object mapper
152 * @param jsonString JSON string
153 * @return pretty formatted JSON string
154 */
155 public static String prettyJson(ObjectMapper mapper, String jsonString) {
156 try {
157 Object jsonObject = mapper.readValue(jsonString, Object.class);
158 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
159 } catch (IOException e) {
160 log.debug("Json string parsing exception caused by {}", e);
161 }
162 return null;
163 }
Jian Li3defa842019-02-12 00:31:35 +0900164
165 /**
166 * Generates endpoint URL by referring to scheme, ipAddress and port.
167 *
168 * @param scheme scheme
169 * @param ipAddress IP address
170 * @param port port number
171 * @return generated endpoint URL
172 */
173 public static String endpoint(Scheme scheme, IpAddress ipAddress, int port) {
174 StringBuilder endpoint = new StringBuilder();
175 String protocol = StringUtils.lowerCase(scheme.name());
176
177 endpoint.append(protocol);
178 endpoint.append(COLON_SLASH);
179 endpoint.append(ipAddress.toString());
180 endpoint.append(COLON);
181 endpoint.append(port);
182
183 return endpoint.toString();
184 }
185
186 /**
187 * Generates endpoint URL by referring to scheme, ipAddress and port.
188 *
189 * @param apiConfig kubernetes API config
190 * @return generated endpoint URL
191 */
192 public static String endpoint(K8sApiConfig apiConfig) {
193 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
194 }
Jian Li1cee9882019-02-13 11:25:25 +0900195
196 /**
197 * Generates a DPID (of:0000000000000001) from an index value.
198 *
199 * @param index index value
200 * @return generated DPID
201 */
202 public static String genDpid(long index) {
203 if (index < 0) {
204 return null;
205 }
206
207 String hexStr = Long.toHexString(index);
208
209 StringBuilder zeroPadding = new StringBuilder();
210 for (int i = 0; i < HEX_LENGTH - hexStr.length(); i++) {
211 zeroPadding.append(ZERO);
212 }
213
214 return OF_PREFIX + zeroPadding.toString() + hexStr;
215 }
216
217 /**
Jian Lia6f58382019-12-16 14:22:13 +0900218 * Generates string format based on the given string length list.
219 *
220 * @param stringLengths a list of string lengths
221 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
222 */
223 public static String genFormatString(List<Integer> stringLengths) {
224 StringBuilder fsb = new StringBuilder();
225 stringLengths.forEach(length -> {
226 fsb.append("%-");
227 fsb.append(length);
228 fsb.append("s");
229 });
230 return fsb.toString();
231 }
232
233 /**
Jian Li1cee9882019-02-13 11:25:25 +0900234 * Obtains workable kubernetes client.
235 *
236 * @param config kubernetes API config
237 * @return kubernetes client
238 */
239 public static KubernetesClient k8sClient(K8sApiConfig config) {
240 if (config == null) {
241 log.warn("Kubernetes API server config is empty.");
242 return null;
243 }
244
245 String endpoint = endpoint(config);
246
247 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
248
249 if (config.scheme() == K8sApiConfig.Scheme.HTTPS) {
250 configBuilder.withTrustCerts(true)
Jian Li1cee9882019-02-13 11:25:25 +0900251 .withCaCertData(config.caCertData())
252 .withClientCertData(config.clientCertData())
253 .withClientKeyData(config.clientKeyData());
Jian Li0a117e32019-12-31 00:55:54 +0900254
255 if (StringUtils.isNotEmpty(config.token())) {
256 configBuilder.withOauthToken(config.token());
257 }
Jian Li1cee9882019-02-13 11:25:25 +0900258 }
259
260 return new DefaultKubernetesClient(configBuilder.build());
261 }
Jian Li077b07e2020-09-01 16:55:25 +0900262
263 /**
264 * Auto generates DPID from the given name.
265 *
266 * @param name name
267 * @return auto generated DPID
268 */
269 public static String genDpidFromName(String name) {
270 if (name != null) {
271 String hexString = Integer.toHexString(name.hashCode());
272 return OF_PREFIX + Strings.padStart(hexString, 16, '0');
273 }
274
275 return null;
276 }
Jian Lif16e8852019-01-22 22:55:31 +0900277}