blob: f9791cd495c8f6c0d6bb1f9416285f7bed9e7a0a [file] [log] [blame]
Jian Li091d8d22018-02-20 10:42:06 +09001/*
2 * Copyright 2018-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.openstacknetworking.util;
17
Daniel Park2ff66b42018-08-01 11:52:45 +090018import com.fasterxml.jackson.core.JsonParseException;
19import com.fasterxml.jackson.core.JsonProcessingException;
20import com.fasterxml.jackson.databind.JsonMappingException;
Jian Li091d8d22018-02-20 10:42:06 +090021import com.fasterxml.jackson.databind.JsonNode;
22import com.fasterxml.jackson.databind.ObjectMapper;
Jian Lieb9f77d2018-02-20 11:25:45 +090023import com.fasterxml.jackson.databind.node.ObjectNode;
Daniel Parka73c2362018-09-17 17:43:25 +090024import com.google.common.base.Charsets;
Jian Li24ec59f2018-05-23 19:01:25 +090025import com.google.common.base.Strings;
Daniel Parka73c2362018-09-17 17:43:25 +090026import com.google.common.collect.Lists;
Jian Li63430202018-08-30 16:24:09 +090027import org.apache.commons.codec.binary.Hex;
28import org.apache.http.HttpException;
29import org.apache.http.HttpRequest;
30import org.apache.http.HttpResponse;
31import org.apache.http.impl.io.DefaultHttpRequestParser;
32import org.apache.http.impl.io.DefaultHttpRequestWriter;
33import org.apache.http.impl.io.DefaultHttpResponseParser;
34import org.apache.http.impl.io.DefaultHttpResponseWriter;
35import org.apache.http.impl.io.HttpTransportMetricsImpl;
36import org.apache.http.impl.io.SessionInputBufferImpl;
37import org.apache.http.impl.io.SessionOutputBufferImpl;
38import org.apache.http.io.HttpMessageWriter;
Daniel Parka73c2362018-09-17 17:43:25 +090039import org.apache.sshd.client.SshClient;
40import org.apache.sshd.client.channel.ClientChannel;
41import org.apache.sshd.client.channel.ClientChannelEvent;
42import org.apache.sshd.client.future.OpenFuture;
43import org.apache.sshd.client.session.ClientSession;
44import org.apache.sshd.common.util.io.NoCloseInputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090045import org.onlab.packet.ARP;
46import org.onlab.packet.Ethernet;
47import org.onlab.packet.Ip4Address;
Daniel Parka73c2362018-09-17 17:43:25 +090048import org.onlab.packet.IpAddress;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090049import org.onlab.packet.MacAddress;
50import org.onlab.packet.VlanId;
Jian Li7f70bb72018-07-06 23:35:30 +090051import org.onosproject.cfg.ConfigProperty;
Jian Li1064e4f2018-05-29 16:16:53 +090052import org.onosproject.net.DeviceId;
Daniel Park95f73312018-07-31 15:48:34 +090053import org.onosproject.net.device.DeviceService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090054import org.onosproject.net.flow.DefaultTrafficTreatment;
55import org.onosproject.net.flow.TrafficTreatment;
56import org.onosproject.net.packet.DefaultOutboundPacket;
57import org.onosproject.net.packet.PacketService;
Daniel Park7e8c4d82018-08-13 23:47:49 +090058import org.onosproject.openstacknetworking.api.Constants.VnicType;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090059import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Lia171a432018-06-11 11:52:11 +090060import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090061import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li7f70bb72018-07-06 23:35:30 +090062import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Liebde74d2018-11-14 00:18:57 +090063import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Liec5c32b2018-07-13 14:28:58 +090064import org.onosproject.openstacknetworking.impl.DefaultInstancePort;
Jian Li51b844c2018-05-31 10:59:03 +090065import org.onosproject.openstacknode.api.OpenstackAuth;
66import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
Jian Li1064e4f2018-05-29 16:16:53 +090067import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Parka73c2362018-09-17 17:43:25 +090068import org.onosproject.openstacknode.api.OpenstackSshAuth;
Jian Li51b844c2018-05-31 10:59:03 +090069import org.openstack4j.api.OSClient;
70import org.openstack4j.api.client.IOSClientBuilder;
71import org.openstack4j.api.exceptions.AuthenticationException;
72import org.openstack4j.api.types.Facing;
73import org.openstack4j.core.transport.Config;
Jian Li091d8d22018-02-20 10:42:06 +090074import org.openstack4j.core.transport.ObjectMapperSingleton;
75import org.openstack4j.model.ModelEntity;
Jian Li51b844c2018-05-31 10:59:03 +090076import org.openstack4j.model.common.Identifier;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090077import org.openstack4j.model.network.ExternalGateway;
Jian Li24ec59f2018-05-23 19:01:25 +090078import org.openstack4j.model.network.NetFloatingIP;
79import org.openstack4j.model.network.Network;
Jian Lia171a432018-06-11 11:52:11 +090080import org.openstack4j.model.network.Port;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090081import org.openstack4j.model.network.Router;
Jian Li0b564282018-06-20 00:50:53 +090082import org.openstack4j.model.network.RouterInterface;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090083import org.openstack4j.model.network.Subnet;
Jian Li51b844c2018-05-31 10:59:03 +090084import org.openstack4j.openstack.OSFactory;
Jian Li0b564282018-06-20 00:50:53 +090085import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
Jian Li091d8d22018-02-20 10:42:06 +090086import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Jian Li63430202018-08-30 16:24:09 +090089import javax.crypto.Mac;
90import javax.crypto.spec.SecretKeySpec;
Jian Li51b844c2018-05-31 10:59:03 +090091import javax.net.ssl.HostnameVerifier;
92import javax.net.ssl.HttpsURLConnection;
93import javax.net.ssl.SSLContext;
94import javax.net.ssl.TrustManager;
95import javax.net.ssl.X509TrustManager;
Jian Li63430202018-08-30 16:24:09 +090096import java.io.ByteArrayInputStream;
97import java.io.ByteArrayOutputStream;
Jian Li0b564282018-06-20 00:50:53 +090098import java.io.IOException;
Jian Li091d8d22018-02-20 10:42:06 +090099import java.io.InputStream;
Daniel Parka73c2362018-09-17 17:43:25 +0900100import java.io.OutputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900101import java.nio.ByteBuffer;
Jian Li51b844c2018-05-31 10:59:03 +0900102import java.security.cert.X509Certificate;
Daniel Parka73c2362018-09-17 17:43:25 +0900103import java.util.Collection;
Jian Li1064e4f2018-05-29 16:16:53 +0900104import java.util.HashMap;
105import java.util.Iterator;
106import java.util.Map;
Daniel Park95f73312018-07-31 15:48:34 +0900107import java.util.Objects;
Jian Li7f70bb72018-07-06 23:35:30 +0900108import java.util.Optional;
Jian Li1064e4f2018-05-29 16:16:53 +0900109import java.util.Set;
110import java.util.TreeMap;
Daniel Parka73c2362018-09-17 17:43:25 +0900111import java.util.concurrent.TimeUnit;
Jian Li091d8d22018-02-20 10:42:06 +0900112
113import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
Daniel Park95f73312018-07-31 15:48:34 +0900114import static com.google.common.base.Preconditions.checkNotNull;
Jian Li7f024de2018-07-07 03:51:02 +0900115import static com.google.common.base.Strings.isNullOrEmpty;
Daniel Park95f73312018-07-31 15:48:34 +0900116import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka73c2362018-09-17 17:43:25 +0900117import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Daniel Parkc4d06402018-05-28 15:57:37 +0900118import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
119import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
Daniel Park7e8c4d82018-08-13 23:47:49 +0900120import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
121import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
Daniel Parkec9d1132018-08-19 11:18:03 +0900122import static org.onosproject.openstacknetworking.api.Constants.UNSUPPORTED_VENDOR;
Ray Milkey9dc57392018-06-08 08:52:31 -0700123import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
Jian Li0b564282018-06-20 00:50:53 +0900124import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
Jian Li091d8d22018-02-20 10:42:06 +0900125
126/**
127 * An utility that used in openstack networking app.
128 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900129public final class OpenstackNetworkingUtil {
Jian Li091d8d22018-02-20 10:42:06 +0900130
Daniel Park95985382018-07-23 11:38:07 +0900131 private static final Logger log = LoggerFactory.getLogger(OpenstackNetworkingUtil.class);
Jian Li091d8d22018-02-20 10:42:06 +0900132
Daniel Parkc4d06402018-05-28 15:57:37 +0900133 private static final int HEX_RADIX = 16;
Jian Li51b844c2018-05-31 10:59:03 +0900134 private static final String ZERO_FUNCTION_NUMBER = "0";
Daniel Parkc4d06402018-05-28 15:57:37 +0900135 private static final String PREFIX_DEVICE_NUMBER = "s";
136 private static final String PREFIX_FUNCTION_NUMBER = "f";
137
Jian Li51b844c2018-05-31 10:59:03 +0900138 // keystone endpoint related variables
139 private static final String DOMAIN_DEFAULT = "default";
140 private static final String KEYSTONE_V2 = "v2.0";
141 private static final String KEYSTONE_V3 = "v3";
Jian Li51b844c2018-05-31 10:59:03 +0900142 private static final String SSL_TYPE = "SSL";
143
Jian Li7f024de2018-07-07 03:51:02 +0900144 private static final String PROXY_MODE = "proxy";
145 private static final String BROADCAST_MODE = "broadcast";
146
Jian Licad36c72018-09-13 17:44:54 +0900147 private static final String ENABLE = "enable";
148 private static final String DISABLE = "disable";
149
Jian Li63430202018-08-30 16:24:09 +0900150 private static final int HTTP_PAYLOAD_BUFFER = 8 * 1024;
151
152 private static final String HMAC_SHA256 = "HmacSHA256";
153
Jian Li24ec59f2018-05-23 19:01:25 +0900154 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
155
Daniel Parka73c2362018-09-17 17:43:25 +0900156 private static final String FLAT = "FLAT";
157 private static final String VXLAN = "VXLAN";
158 private static final String VLAN = "VLAN";
159 private static final String DL_DST = "dl_dst=";
160 private static final String NW_DST = "nw_dst=";
161 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
162 private static final String IN_PORT = "in_port=";
163 private static final String NW_SRC = "nw_src=";
164 private static final String COMMA = ",";
165 private static final String TUN_ID = "tun_id=";
166
167 private static final long TIMEOUT_MS = 5000;
168 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
169 private static final int SSH_PORT = 22;
170
Jian Li091d8d22018-02-20 10:42:06 +0900171 /**
172 * Prevents object instantiation from external.
173 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900174 private OpenstackNetworkingUtil() {
Jian Li091d8d22018-02-20 10:42:06 +0900175 }
176
177 /**
178 * Interprets JSON string to corresponding openstack model entity object.
179 *
180 * @param input JSON string
181 * @param entityClazz openstack model entity class
182 * @return openstack model entity object
183 */
184 public static ModelEntity jsonToModelEntity(InputStream input, Class entityClazz) {
185 ObjectMapper mapper = new ObjectMapper();
186 try {
187 JsonNode jsonTree = mapper.enable(INDENT_OUTPUT).readTree(input);
188 log.trace(new ObjectMapper().writeValueAsString(jsonTree));
189 return ObjectMapperSingleton.getContext(entityClazz)
190 .readerFor(entityClazz)
191 .readValue(jsonTree);
192 } catch (Exception e) {
193 throw new IllegalArgumentException();
194 }
195 }
Jian Lieb9f77d2018-02-20 11:25:45 +0900196
197 /**
198 * Converts openstack model entity object into JSON object.
199 *
200 * @param entity openstack model entity object
201 * @param entityClazz openstack model entity class
202 * @return JSON object
203 */
204 public static ObjectNode modelEntityToJson(ModelEntity entity, Class entityClazz) {
205 ObjectMapper mapper = new ObjectMapper();
206 try {
207 String strModelEntity = ObjectMapperSingleton.getContext(entityClazz)
208 .writerFor(entityClazz)
209 .writeValueAsString(entity);
210 log.trace(strModelEntity);
211 return (ObjectNode) mapper.readTree(strModelEntity.getBytes());
Daniel Park95985382018-07-23 11:38:07 +0900212 } catch (IOException e) {
213 log.error("IOException occurred because of {}", e.toString());
Jian Lieb9f77d2018-02-20 11:25:45 +0900214 throw new IllegalStateException();
215 }
216 }
Jian Li1064e4f2018-05-29 16:16:53 +0900217
218 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900219 * Obtains a floating IP associated with the given instance port.
220 *
221 * @param port instance port
222 * @param fips a collection of floating IPs
223 * @return associated floating IP
224 */
225 public static NetFloatingIP associatedFloatingIp(InstancePort port,
226 Set<NetFloatingIP> fips) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900227 for (NetFloatingIP fip : fips) {
228 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
229 continue;
Jian Li24ec59f2018-05-23 19:01:25 +0900230 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900231 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
232 continue;
233 }
Jian Li6bc29d92018-10-02 13:55:05 +0900234 if (fip.getFixedIpAddress().equals(port.ipAddress().toString()) &&
235 fip.getPortId().equals(port.portId())) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900236 return fip;
237 }
Jian Li24ec59f2018-05-23 19:01:25 +0900238 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900239
Jian Li24ec59f2018-05-23 19:01:25 +0900240 return null;
241 }
242
243 /**
244 * Checks whether the given floating IP is associated with a VM.
245 *
246 * @param service openstack network service
247 * @param fip floating IP
248 * @return true if the given floating IP associated with a VM, false otherwise
249 */
250 public static boolean isAssociatedWithVM(OpenstackNetworkService service,
251 NetFloatingIP fip) {
252 Port osPort = service.port(fip.getPortId());
253 if (osPort == null) {
254 return false;
255 }
256
257 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
258 Network osNet = service.network(osPort.getNetworkId());
259 if (osNet == null) {
260 final String errorFormat = ERR_FLOW + "no network(%s) exists";
261 final String error = String.format(errorFormat,
262 fip.getFloatingIpAddress(), osPort.getNetworkId());
263 throw new IllegalStateException(error);
264 }
265 return true;
266 } else {
267 return false;
268 }
269 }
270
271 /**
Jian Lia171a432018-06-11 11:52:11 +0900272 * Obtains the gateway node by instance port.
273 *
274 * @param gateways a collection of gateway nodes
275 * @param instPort instance port
276 * @return a gateway node
277 */
278 public static OpenstackNode getGwByInstancePort(Set<OpenstackNode> gateways,
279 InstancePort instPort) {
280 OpenstackNode gw = null;
281 if (instPort != null && instPort.deviceId() != null) {
282 gw = getGwByComputeDevId(gateways, instPort.deviceId());
283 }
284 return gw;
285 }
286
287 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900288 * Obtains the gateway node by device in compute node. Note that the gateway
289 * node is determined by device's device identifier.
290 *
291 * @param gws a collection of gateway nodes
292 * @param deviceId device identifier
293 * @return a gateway node
294 */
295 public static OpenstackNode getGwByComputeDevId(Set<OpenstackNode> gws, DeviceId deviceId) {
296 int numOfGw = gws.size();
297
298 if (numOfGw == 0) {
299 return null;
300 }
301
302 int gwIndex = Math.abs(deviceId.hashCode()) % numOfGw;
303
304 return getGwByIndex(gws, gwIndex);
305 }
306
Jian Li51b844c2018-05-31 10:59:03 +0900307 /**
308 * Obtains a connected openstack client.
309 *
310 * @param osNode openstack node
311 * @return a connected openstack client
312 */
313 public static OSClient getConnectedClient(OpenstackNode osNode) {
Jian Lic704b672018-09-04 18:52:53 +0900314 OpenstackAuth auth = osNode.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +0900315 String endpoint = buildEndpoint(osNode);
316 Perspective perspective = auth.perspective();
Jian Li1064e4f2018-05-29 16:16:53 +0900317
Jian Li51b844c2018-05-31 10:59:03 +0900318 Config config = getSslConfig();
Jian Li1064e4f2018-05-29 16:16:53 +0900319
Jian Li51b844c2018-05-31 10:59:03 +0900320 try {
321 if (endpoint.contains(KEYSTONE_V2)) {
322 IOSClientBuilder.V2 builder = OSFactory.builderV2()
323 .endpoint(endpoint)
324 .tenantName(auth.project())
325 .credentials(auth.username(), auth.password())
326 .withConfig(config);
327
328 if (perspective != null) {
329 builder.perspective(getFacing(perspective));
330 }
331
332 return builder.authenticate();
333 } else if (endpoint.contains(KEYSTONE_V3)) {
334
335 Identifier project = Identifier.byName(auth.project());
336 Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
337
338 IOSClientBuilder.V3 builder = OSFactory.builderV3()
339 .endpoint(endpoint)
340 .credentials(auth.username(), auth.password(), domain)
341 .scopeToProject(project, domain)
342 .withConfig(config);
343
344 if (perspective != null) {
345 builder.perspective(getFacing(perspective));
346 }
347
348 return builder.authenticate();
349 } else {
350 log.warn("Unrecognized keystone version type");
351 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900352 }
Jian Li51b844c2018-05-31 10:59:03 +0900353 } catch (AuthenticationException e) {
354 log.error("Authentication failed due to {}", e.toString());
355 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900356 }
Jian Li1064e4f2018-05-29 16:16:53 +0900357 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900358
359 /**
360 * Extract the interface name with the supplied port.
361 *
362 * @param port port
363 * @return interface name
364 */
365 public static String getIntfNameFromPciAddress(Port port) {
Daniel Parkff178ba2018-11-23 15:57:24 +0900366 String intfName;
367
Daniel Park95985382018-07-23 11:38:07 +0900368 if (port.getProfile() == null || port.getProfile().isEmpty()) {
Jian Li51b844c2018-05-31 10:59:03 +0900369 log.error("Port profile is not found");
370 return null;
371 }
372
Daniel Park95985382018-07-23 11:38:07 +0900373 if (!port.getProfile().containsKey(PCISLOT) ||
374 Strings.isNullOrEmpty(port.getProfile().get(PCISLOT).toString())) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900375 log.error("Failed to retrieve the interface name because of no pci_slot information from the port");
376 return null;
377 }
Jian Li51b844c2018-05-31 10:59:03 +0900378
Daniel Parkff178ba2018-11-23 15:57:24 +0900379 String vendorInfoForPort = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
380
381 if (!portNamePrefixMap().containsKey(vendorInfoForPort)) {
382 log.debug("{} is an non-smart NIC prefix.", vendorInfoForPort);
383 return UNSUPPORTED_VENDOR;
384 }
385
386 String portNamePrefix = portNamePrefixMap().get(vendorInfoForPort);
387
Daniel Parkc4d06402018-05-28 15:57:37 +0900388 String busNumHex = port.getProfile().get(PCISLOT).toString().split(":")[1];
389 String busNumDecimal = String.valueOf(Integer.parseInt(busNumHex, HEX_RADIX));
390
391 String deviceNumHex = port.getProfile().get(PCISLOT).toString()
392 .split(":")[2]
393 .split("\\.")[0];
394 String deviceNumDecimal = String.valueOf(Integer.parseInt(deviceNumHex, HEX_RADIX));
395
396 String functionNumHex = port.getProfile().get(PCISLOT).toString()
397 .split(":")[2]
398 .split("\\.")[1];
399 String functionNumDecimal = String.valueOf(Integer.parseInt(functionNumHex, HEX_RADIX));
400
Daniel Parkc4d06402018-05-28 15:57:37 +0900401 if (functionNumDecimal.equals(ZERO_FUNCTION_NUMBER)) {
402 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal;
403 } else {
404 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal
405 + PREFIX_FUNCTION_NUMBER + functionNumDecimal;
406 }
407
408 return intfName;
409 }
Jian Li51b844c2018-05-31 10:59:03 +0900410
411 /**
Daniel Park95f73312018-07-31 15:48:34 +0900412 * Check if the given interface is added to the given device or not.
413 *
414 * @param deviceId device ID
415 * @param intfName interface name
416 * @param deviceService device service
417 * @return true if the given interface is added to the given device or false otherwise
418 */
419 public static boolean hasIntfAleadyInDevice(DeviceId deviceId, String intfName, DeviceService deviceService) {
420 checkNotNull(deviceId);
421 checkNotNull(intfName);
422
423 return deviceService.getPorts(deviceId).stream()
424 .anyMatch(port -> Objects.equals(port.annotations().value(PORT_NAME), intfName));
425 }
426
427 /**
Jian Li0b564282018-06-20 00:50:53 +0900428 * Adds router interfaces to openstack admin service.
429 * TODO fix the logic to add router interface to router
430 *
431 * @param osPort port
432 * @param adminService openstack admin service
433 */
434 public static void addRouterIface(Port osPort, OpenstackRouterAdminService adminService) {
435 osPort.getFixedIps().forEach(p -> {
436 JsonNode jsonTree = new ObjectMapper().createObjectNode()
437 .put("id", osPort.getDeviceId())
438 .put("tenant_id", osPort.getTenantId())
439 .put("subnet_id", p.getSubnetId())
440 .put("port_id", osPort.getId());
441 try {
442 RouterInterface rIface = getContext(NeutronRouterInterface.class)
443 .readerFor(NeutronRouterInterface.class)
444 .readValue(jsonTree);
445 if (adminService.routerInterface(rIface.getPortId()) != null) {
446 adminService.updateRouterInterface(rIface);
447 } else {
448 adminService.addRouterInterface(rIface);
449 }
450 } catch (IOException ignore) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900451 log.error("Exception occurred because of {}", ignore.toString());
Jian Li0b564282018-06-20 00:50:53 +0900452 }
453 });
454 }
455
456 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900457 * Obtains the property value with specified property key name.
458 *
459 * @param properties a collection of properties
460 * @param name key name
461 * @return mapping value
462 */
463 public static String getPropertyValue(Set<ConfigProperty> properties, String name) {
464 Optional<ConfigProperty> property =
465 properties.stream().filter(p -> p.name().equals(name)).findFirst();
466 return property.map(ConfigProperty::value).orElse(null);
467 }
468
469 /**
Jian Li9d35bd62018-10-13 01:43:24 +0900470 * Obtains the boolean property value with specified property key name.
471 *
472 * @param properties a collection of properties
473 * @param name key name
474 * @return mapping value
475 */
476 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties, String name) {
477 Optional<ConfigProperty> property =
478 properties.stream().filter(p -> p.name().equals(name)).findFirst();
479
480 return property.map(ConfigProperty::asBoolean).orElse(false);
481 }
482
483 /**
Jian Lif1efbe52018-07-17 23:20:16 +0900484 * Prints out the JSON string in pretty format.
485 *
486 * @param mapper Object mapper
487 * @param jsonString JSON string
488 * @return pretty formatted JSON string
489 */
490 public static String prettyJson(ObjectMapper mapper, String jsonString) {
491 try {
492 Object jsonObject = mapper.readValue(jsonString, Object.class);
493 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
Daniel Park2ff66b42018-08-01 11:52:45 +0900494 } catch (JsonParseException e) {
495 log.debug("JsonParseException caused by {}", e);
496 } catch (JsonMappingException e) {
497 log.debug("JsonMappingException caused by {}", e);
498 } catch (JsonProcessingException e) {
499 log.debug("JsonProcessingException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900500 } catch (IOException e) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900501 log.debug("IOException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900502 }
503 return null;
504 }
505
506 /**
Jian Li7f024de2018-07-07 03:51:02 +0900507 * Checks the validity of ARP mode.
508 *
509 * @param arpMode ARP mode
510 * @return returns true if the ARP mode is valid, false otherwise
511 */
512 public static boolean checkArpMode(String arpMode) {
513
514 if (isNullOrEmpty(arpMode)) {
515 return false;
516 } else {
517 return arpMode.equals(PROXY_MODE) || arpMode.equals(BROADCAST_MODE);
518 }
519 }
520
521 /**
Jian Licad36c72018-09-13 17:44:54 +0900522 * Checks the validity of activation flag.
523 *
524 * @param activationFlag activation flag
525 * @return returns true if the activation flag is valid, false otherwise
526 */
527 public static boolean checkActivationFlag(String activationFlag) {
528
529 switch (activationFlag) {
530 case ENABLE:
531 return true;
532 case DISABLE:
533 return false;
534 default:
535 throw new IllegalArgumentException("The given activation flag is not valid!");
536 }
537 }
538
539 /**
Jian Liec5c32b2018-07-13 14:28:58 +0900540 * Swaps current location with old location info.
541 * The revised instance port will be used to mod the flow rules after migration.
542 *
543 * @param instPort instance port
544 * @return location swapped instance port
545 */
546 public static InstancePort swapStaleLocation(InstancePort instPort) {
547 return DefaultInstancePort.builder()
548 .deviceId(instPort.oldDeviceId())
549 .portNumber(instPort.oldPortNumber())
550 .state(instPort.state())
551 .ipAddress(instPort.ipAddress())
552 .macAddress(instPort.macAddress())
553 .networkId(instPort.networkId())
554 .portId(instPort.portId())
555 .build();
556 }
557
558 /**
Daniel Park2ff66b42018-08-01 11:52:45 +0900559 * Compares two router interfaces are equal.
560 * Will be remove this after Openstack4j implements equals.
561 *
562 * @param routerInterface1 router interface
563 * @param routerInterface2 router interface
564 * @return returns true if two router interfaces are equal, false otherwise
565 */
Jian Li63430202018-08-30 16:24:09 +0900566 public static boolean routerInterfacesEquals(RouterInterface routerInterface1,
567 RouterInterface routerInterface2) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900568 return Objects.equals(routerInterface1.getId(), routerInterface2.getId()) &&
569 Objects.equals(routerInterface1.getPortId(), routerInterface2.getPortId()) &&
570 Objects.equals(routerInterface1.getSubnetId(), routerInterface2.getSubnetId()) &&
571 Objects.equals(routerInterface1.getTenantId(), routerInterface2.getTenantId());
572 }
573
Daniel Park7e8c4d82018-08-13 23:47:49 +0900574 public static VnicType vnicType(String portName) {
575 if (portName.startsWith(PORT_NAME_PREFIX_VM) ||
576 portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM)) {
577 return VnicType.NORMAL;
578 } else if (isDirectPort(portName)) {
579 return VnicType.DIRECT;
580 } else {
581 return VnicType.UNSUPPORTED;
582 }
583 }
584
Jian Li63430202018-08-30 16:24:09 +0900585 /**
586 * Deserializes raw payload into HttpRequest object.
587 *
588 * @param rawData raw http payload
589 * @return HttpRequest object
590 */
591 public static HttpRequest parseHttpRequest(byte[] rawData) {
592 SessionInputBufferImpl sessionInputBuffer =
593 new SessionInputBufferImpl(
594 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
595 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
596 DefaultHttpRequestParser requestParser = new DefaultHttpRequestParser(sessionInputBuffer);
597 try {
598 return requestParser.parse();
599 } catch (IOException | HttpException e) {
600 log.warn("Failed to parse HttpRequest, due to {}", e);
601 }
602
603 return null;
604 }
605
606 /**
607 * Serializes HttpRequest object to byte array.
608 *
609 * @param request http request object
610 * @return byte array
611 */
612 public static byte[] unparseHttpRequest(HttpRequest request) {
613 try {
614 SessionOutputBufferImpl sessionOutputBuffer =
615 new SessionOutputBufferImpl(
616 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
617
618 ByteArrayOutputStream baos = new ByteArrayOutputStream();
619 sessionOutputBuffer.bind(baos);
620
621 HttpMessageWriter<HttpRequest> requestWriter = new DefaultHttpRequestWriter(
622 sessionOutputBuffer);
623 requestWriter.write(request);
624 sessionOutputBuffer.flush();
625
626 return baos.toByteArray();
627 } catch (HttpException | IOException e) {
628 log.warn("Failed to unparse HttpRequest, due to {}", e);
629 }
630
631 return null;
632 }
633
634 /**
635 * Deserializes raw payload into HttpResponse object.
636 *
637 * @param rawData raw http payload
638 * @return HttpResponse object
639 */
640 public static HttpResponse parseHttpResponse(byte[] rawData) {
641 SessionInputBufferImpl sessionInputBuffer =
642 new SessionInputBufferImpl(
643 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
644 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
645 DefaultHttpResponseParser responseParser = new DefaultHttpResponseParser(sessionInputBuffer);
646 try {
647 return responseParser.parse();
648 } catch (IOException | HttpException e) {
649 log.warn("Failed to parse HttpResponse, due to {}", e);
650 }
651
652 return null;
653 }
654
655 /**
656 * Serializes HttpResponse header to byte array.
657 *
658 * @param response http response object
659 * @return byte array
660 */
661 public static byte[] unparseHttpResponseHeader(HttpResponse response) {
662 try {
663 SessionOutputBufferImpl sessionOutputBuffer =
664 new SessionOutputBufferImpl(
665 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
666
667 ByteArrayOutputStream headerBaos = new ByteArrayOutputStream();
668 sessionOutputBuffer.bind(headerBaos);
669
670 HttpMessageWriter<HttpResponse> responseWriter =
671 new DefaultHttpResponseWriter(sessionOutputBuffer);
672 responseWriter.write(response);
673 sessionOutputBuffer.flush();
674
675 log.debug(headerBaos.toString());
676
677 return headerBaos.toByteArray();
678 } catch (IOException | HttpException e) {
679 log.warn("Failed to unparse HttpResponse headers, due to {}", e);
680 }
681
682 return null;
683 }
684
685 /**
686 * Serializes HttpResponse object to byte array.
687 *
688 * @param response http response object
689 * @return byte array
690 */
691 public static byte[] unparseHttpResponseBody(HttpResponse response) {
692 try {
693 ByteArrayOutputStream baos = new ByteArrayOutputStream();
694 response.getEntity().writeTo(baos);
695
696 log.debug(response.toString());
697 log.debug(baos.toString());
698
699 return baos.toByteArray();
700 } catch (IOException e) {
701 log.warn("Failed to unparse HttpResponse, due to {}", e);
702 }
703
704 return null;
705 }
706
707 /**
708 * Encodes the given data using HmacSHA256 encryption method with given secret key.
709 *
710 * @param key secret key
711 * @param data data to be encrypted
712 * @return Hmac256 encrypted data
713 */
714 public static String hmacEncrypt(String key, String data) {
715 try {
716 Mac sha256Hmac = Mac.getInstance(HMAC_SHA256);
717 SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA256);
718 sha256Hmac.init(secretKey);
719 return Hex.encodeHexString(sha256Hmac.doFinal(data.getBytes("UTF-8")));
720 } catch (Exception e) {
721 log.warn("Failed to encrypt data {} using key {}, due to {}", data, key, e);
722 }
723 return null;
724 }
725
Daniel Parka73c2362018-09-17 17:43:25 +0900726 /**
727 * Creates flow trace request string.
728 *
729 * @param srcIp src ip address
730 * @param dstIp dst ip address
731 * @param srcInstancePort src instance port
732 * @param osNetService openstack networking service
Daniel Park5aef9822018-09-20 18:04:18 +0900733 * @param uplink true if this request is for uplink
Daniel Parka73c2362018-09-17 17:43:25 +0900734 * @return flow trace request string
735 */
736 public static String traceRequestString(String srcIp,
737 String dstIp,
738 InstancePort srcInstancePort,
739 OpenstackNetworkService osNetService, boolean uplink) {
740
741 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
742
743 if (uplink) {
744
745 requestStringBuilder.append(COMMA)
746 .append(IN_PORT)
747 .append(srcInstancePort.portNumber().toString())
748 .append(COMMA)
749 .append(NW_SRC)
750 .append(srcIp)
751 .append(COMMA);
752
753 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
754 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
755 if (srcIp.equals(dstIp)) {
756 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
757 requestStringBuilder.append(DL_DST)
758 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
759 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(IpAddress.valueOf(dstIp))) {
760 requestStringBuilder.append(DL_DST)
761 .append(DEFAULT_GATEWAY_MAC_STR)
762 .append(COMMA);
763 }
764 } else {
765 if (srcIp.equals(dstIp)) {
766 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
767 }
768 }
769
770 requestStringBuilder.append(NW_DST)
771 .append(dstIp)
772 .append("\n");
773 } else {
774 requestStringBuilder.append(COMMA)
775 .append(NW_SRC)
776 .append(dstIp)
777 .append(COMMA);
778
779 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
780 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
781 requestStringBuilder.append(TUN_ID)
782 .append(osNetService.segmentId(srcInstancePort.networkId()))
783 .append(COMMA);
784 }
785 requestStringBuilder.append(NW_DST)
786 .append(srcIp)
787 .append("\n");
788
789 }
790
791 return requestStringBuilder.toString();
792 }
793
794 /**
795 * Sends flow trace string to node.
796 *
797 * @param requestString reqeust string
798 * @param node src node
799 * @return flow trace result in string format
800 */
801 public static String sendTraceRequestToNode(String requestString,
802 OpenstackNode node) {
803 String traceResult = null;
804 OpenstackSshAuth sshAuth = node.sshAuthInfo();
805
806 try (SshClient client = SshClient.setUpDefaultClient()) {
807 client.start();
808
809 try (ClientSession session = client
810 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
811 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
812 session.addPasswordIdentity(sshAuth.password());
813 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
814
815
816 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
817
818 log.debug("requestString: {}", requestString);
819 final InputStream inputStream =
820 new ByteArrayInputStream(requestString.getBytes());
821
822 OutputStream outputStream = new ByteArrayOutputStream();
823 OutputStream errStream = new ByteArrayOutputStream();
824
825 channel.setIn(new NoCloseInputStream(inputStream));
826 channel.setErr(errStream);
827 channel.setOut(outputStream);
828
829 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
830 eventList.add(ClientChannelEvent.OPENED);
831
832 OpenFuture channelFuture = channel.open();
833
834 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
835
836 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
837
838 while (!channelFuture.isOpened()) {
839 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
840 log.error("Failed to open channel");
841 return null;
842 }
843 }
844 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
845
846 traceResult = ((ByteArrayOutputStream) outputStream).toString(Charsets.UTF_8.name());
847
848 channel.close();
849 }
850 } finally {
851 session.close();
852 }
853 } finally {
854 client.stop();
855 }
856
857 } catch (Exception e) {
858 log.error("Exception occurred because of {}", e.toString());
859 }
860
861 return traceResult;
862 }
863
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900864 /**
865 * Returns the floating ip with supplied instance port.
866 *
867 * @param instancePort instance port
868 * @param osRouterAdminService openstack router admin service
869 * @return floating ip
870 */
871 public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
872 OpenstackRouterAdminService osRouterAdminService) {
873 return osRouterAdminService.floatingIps().stream()
874 .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
875 .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
876 .findAny().orElse(null);
877 }
878
879 /**
880 * Sends GARP packet with supplied floating ip information.
881 *
882 * @param floatingIP floating ip
883 * @param instancePort instance port
884 * @param vlanId vlain id
885 * @param gatewayNode gateway node
886 * @param packetService packet service
887 */
Jian Li32b03622018-11-06 17:54:24 +0900888 public static void processGarpPacketForFloatingIp(NetFloatingIP floatingIP,
889 InstancePort instancePort,
890 VlanId vlanId,
891 OpenstackNode gatewayNode,
892 PacketService packetService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900893 Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
894
895 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
896 .setOutput(gatewayNode.uplinkPortNum()).build();
897
898 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
899 ByteBuffer.wrap(ethernet.serialize())));
900 }
901
902 /**
903 * Returns the external peer router with supplied network information.
904 *
905 * @param network network
906 * @param osNetworkService openstack network service
907 * @param osRouterAdminService openstack router admin service
908 * @return external peer router
909 */
910 public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
911 OpenstackNetworkService osNetworkService,
912 OpenstackRouterAdminService osRouterAdminService) {
913 if (network == null) {
914 return null;
915 }
916
917 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
918
919 if (subnet == null) {
920 return null;
921 }
922
923 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
924 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
925 .findAny().orElse(null);
926 if (osRouterIface == null) {
927 return null;
928 }
929
930 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
931 if (osRouter == null) {
932 return null;
933 }
934 if (osRouter.getExternalGatewayInfo() == null) {
935 return null;
936 }
937
938 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
939 return osNetworkService.externalPeerRouter(exGatewayInfo);
940
941 }
942
Jian Liebde74d2018-11-14 00:18:57 +0900943 /**
944 * Returns the external peer router with specified subnet information.
945 *
946 * @param subnet openstack subnet
947 * @param osRouterService openstack router service
948 * @param osNetworkService openstack network service
949 * @return external peer router
950 */
951 public static ExternalPeerRouter externalPeerRouterFromSubnet(Subnet subnet, OpenstackRouterService osRouterService,
952 OpenstackNetworkService osNetworkService) {
953 Router osRouter = getRouterFromSubnet(subnet, osRouterService);
954 if (osRouter == null) {
955 return null;
956 }
957 if (osRouter.getExternalGatewayInfo() == null) {
958 // this router does not have external connectivity
959 log.trace("router({}) has no external gateway",
960 osRouter.getName());
961 return null;
962 }
963
964 return osNetworkService.externalPeerRouter(osRouter.getExternalGatewayInfo());
965 }
966
967 /**
968 * Returns the external ip address with specified router information.
969 *
970 * @param srcSubnet source subnet
971 * @param osRouterService openstack router service
972 * @param osNetworkService openstack network service
973 * @return external ip address
974 */
975 public static IpAddress externalIpFromSubnet(Subnet srcSubnet,
976 OpenstackRouterService osRouterService,
977 OpenstackNetworkService osNetworkService) {
978
979 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
980
981 if (osRouter.getExternalGatewayInfo() == null) {
982 // this router does not have external connectivity
983 log.trace("router({}) has no external gateway",
984 osRouter.getName());
985 return null;
986 }
987
988 return getExternalIp(osRouter, osNetworkService);
989 }
990
991 /**
992 * Returns the external ip address with specified router information.
993 *
994 * @param router openstack router
995 * @param osNetworkService openstack network service
996 * @return external ip address
997 */
998 public static IpAddress getExternalIp(Router router, OpenstackNetworkService osNetworkService) {
999 if (router == null) {
1000 return null;
1001 }
1002
1003 ExternalGateway externalGateway = router.getExternalGatewayInfo();
1004 if (externalGateway == null || !externalGateway.isEnableSnat()) {
1005 log.trace("Failed to get externalIp for router {} because externalGateway is null or SNAT is disabled",
1006 router.getId());
1007 return null;
1008 }
1009
1010 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
1011 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
1012 .stream()
1013 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
1014 .findAny().orElse(null);
1015
1016 if (exGatewayPort == null) {
1017 return null;
1018 }
1019
1020 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
1021 .findAny().get().getIpAddress());
1022 }
1023
1024 private static Router getRouterFromSubnet(Subnet subnet, OpenstackRouterService osRouterService) {
1025 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
1026 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1027 .findAny().orElse(null);
1028 if (osRouterIface == null) {
1029 return null;
1030 }
1031
1032 return osRouterService.router(osRouterIface.getId());
1033 }
1034
Daniel Park7e8c4d82018-08-13 23:47:49 +09001035 private static boolean isDirectPort(String portName) {
Daniel Parkec9d1132018-08-19 11:18:03 +09001036 return portNamePrefixMap().values().stream().anyMatch(p -> portName.startsWith(p));
Daniel Park7e8c4d82018-08-13 23:47:49 +09001037 }
1038
Daniel Park2ff66b42018-08-01 11:52:45 +09001039 /**
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001040 * Returns GARP packet with supplied floating ip and instance port information.
1041 *
1042 * @param floatingIP floating ip
1043 * @param instancePort instance port
1044 * @param vlanId vlan id
1045 * @return GARP packet
1046 */
1047 private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
1048 InstancePort instancePort,
1049 VlanId vlanId) {
1050 Ethernet ethernet = new Ethernet();
1051 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
1052 ethernet.setSourceMACAddress(instancePort.macAddress());
1053 ethernet.setEtherType(Ethernet.TYPE_ARP);
1054 ethernet.setVlanID(vlanId.id());
1055
1056 ARP arp = new ARP();
1057 arp.setOpCode(ARP.OP_REPLY);
1058 arp.setProtocolType(ARP.PROTO_TYPE_IP);
1059 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
1060
1061 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
1062 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
1063
1064 arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
1065 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1066
1067 arp.setSenderProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
1068 arp.setTargetProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
1069
1070 ethernet.setPayload(arp);
1071
1072 return ethernet;
1073 }
1074
1075 /**
Jian Li51b844c2018-05-31 10:59:03 +09001076 * Builds up and a complete endpoint URL from gateway node.
1077 *
1078 * @param node gateway node
1079 * @return a complete endpoint URL
1080 */
1081 private static String buildEndpoint(OpenstackNode node) {
1082
Jian Lic704b672018-09-04 18:52:53 +09001083 OpenstackAuth auth = node.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +09001084
1085 StringBuilder endpointSb = new StringBuilder();
1086 endpointSb.append(auth.protocol().name().toLowerCase());
1087 endpointSb.append("://");
Jian Lic704b672018-09-04 18:52:53 +09001088 endpointSb.append(node.keystoneConfig().endpoint());
Jian Li51b844c2018-05-31 10:59:03 +09001089 return endpointSb.toString();
1090 }
1091
1092 /**
1093 * Obtains the SSL config without verifying the certification.
1094 *
1095 * @return SSL config
1096 */
1097 private static Config getSslConfig() {
1098 // we bypass the SSL certification verification for now
1099 // TODO: verify server side SSL using a given certification
1100 Config config = Config.newConfig().withSSLVerificationDisabled();
1101
1102 TrustManager[] trustAllCerts = new TrustManager[]{
1103 new X509TrustManager() {
1104 public X509Certificate[] getAcceptedIssuers() {
1105 return null;
1106 }
1107
1108 public void checkClientTrusted(X509Certificate[] certs,
1109 String authType) {
1110 }
1111
1112 public void checkServerTrusted(X509Certificate[] certs,
1113 String authType) {
1114 }
1115 }
1116 };
1117
1118 HostnameVerifier allHostsValid = (hostname, session) -> true;
1119
1120 try {
1121 SSLContext sc = SSLContext.getInstance(SSL_TYPE);
1122 sc.init(null, trustAllCerts,
1123 new java.security.SecureRandom());
1124 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
1125 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
1126
1127 config.withSSLContext(sc);
1128 } catch (Exception e) {
1129 log.error("Failed to access OpenStack service due to {}", e.toString());
1130 return null;
1131 }
1132
1133 return config;
1134 }
1135
1136 /**
1137 * Obtains the facing object with given openstack perspective.
1138 *
1139 * @param perspective keystone perspective
1140 * @return facing object
1141 */
1142 private static Facing getFacing(Perspective perspective) {
1143
1144 switch (perspective) {
1145 case PUBLIC:
1146 return Facing.PUBLIC;
1147 case ADMIN:
1148 return Facing.ADMIN;
1149 case INTERNAL:
1150 return Facing.INTERNAL;
1151 default:
1152 return null;
1153 }
1154 }
1155
1156 /**
1157 * Obtains gateway instance by giving index number.
1158 *
1159 * @param gws a collection of gateway nodes
1160 * @param index index number
1161 * @return gateway instance
1162 */
1163 private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
1164 Map<String, OpenstackNode> hashMap = new HashMap<>();
1165 gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
1166 TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
1167 Iterator<String> iteratorKey = treeMap.keySet().iterator();
1168
1169 int intIndex = 0;
1170 OpenstackNode gw = null;
1171 while (iteratorKey.hasNext()) {
1172 String key = iteratorKey.next();
1173
1174 if (intIndex == index) {
1175 gw = treeMap.get(key);
1176 }
1177 intIndex++;
1178 }
1179 return gw;
1180 }
Jian Li63430202018-08-30 16:24:09 +09001181}