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