blob: 003f01c6964f6f12aa2f19f54702ec033966b9e6 [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;
Jian Li51728702019-05-17 18:38:56 +090028import org.apache.commons.lang3.StringUtils;
Jian Li6a1bcfd2020-01-30 17:41:26 +090029import org.apache.commons.net.util.SubnetUtils;
Jian Li63430202018-08-30 16:24:09 +090030import org.apache.http.HttpException;
31import org.apache.http.HttpRequest;
32import org.apache.http.HttpResponse;
33import org.apache.http.impl.io.DefaultHttpRequestParser;
34import org.apache.http.impl.io.DefaultHttpRequestWriter;
35import org.apache.http.impl.io.DefaultHttpResponseParser;
36import org.apache.http.impl.io.DefaultHttpResponseWriter;
37import org.apache.http.impl.io.HttpTransportMetricsImpl;
38import org.apache.http.impl.io.SessionInputBufferImpl;
39import org.apache.http.impl.io.SessionOutputBufferImpl;
40import org.apache.http.io.HttpMessageWriter;
Daniel Parka73c2362018-09-17 17:43:25 +090041import org.apache.sshd.client.SshClient;
42import org.apache.sshd.client.channel.ClientChannel;
43import org.apache.sshd.client.channel.ClientChannelEvent;
44import org.apache.sshd.client.future.OpenFuture;
45import org.apache.sshd.client.session.ClientSession;
46import org.apache.sshd.common.util.io.NoCloseInputStream;
Jian Li7b8c3682019-05-12 13:57:15 +090047import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090048import org.onlab.packet.ARP;
49import org.onlab.packet.Ethernet;
50import org.onlab.packet.Ip4Address;
Daniel Parka73c2362018-09-17 17:43:25 +090051import org.onlab.packet.IpAddress;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090052import org.onlab.packet.MacAddress;
53import org.onlab.packet.VlanId;
Jian Li7f70bb72018-07-06 23:35:30 +090054import org.onosproject.cfg.ConfigProperty;
Jian Li1064e4f2018-05-29 16:16:53 +090055import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090056import org.onosproject.net.PortNumber;
Daniel Park95f73312018-07-31 15:48:34 +090057import org.onosproject.net.device.DeviceService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090058import org.onosproject.net.flow.DefaultTrafficTreatment;
59import org.onosproject.net.flow.TrafficTreatment;
Jian Lid5727622019-09-11 11:15:16 +090060import org.onosproject.net.group.DefaultGroupKey;
61import org.onosproject.net.group.GroupKey;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090062import org.onosproject.net.packet.DefaultOutboundPacket;
63import org.onosproject.net.packet.PacketService;
Daniel Park7e8c4d82018-08-13 23:47:49 +090064import org.onosproject.openstacknetworking.api.Constants.VnicType;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090065import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Lia171a432018-06-11 11:52:11 +090066import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li7b8c3682019-05-12 13:57:15 +090067import org.onosproject.openstacknetworking.api.OpenstackHaService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090068import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li24ec59f2018-05-23 19:01:25 +090069import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li7f70bb72018-07-06 23:35:30 +090070import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Liebde74d2018-11-14 00:18:57 +090071import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Liec5c32b2018-07-13 14:28:58 +090072import org.onosproject.openstacknetworking.impl.DefaultInstancePort;
Jian Li51b844c2018-05-31 10:59:03 +090073import org.onosproject.openstacknode.api.OpenstackAuth;
74import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
Jian Li1064e4f2018-05-29 16:16:53 +090075import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Parka73c2362018-09-17 17:43:25 +090076import org.onosproject.openstacknode.api.OpenstackSshAuth;
Jian Li51728702019-05-17 18:38:56 +090077import org.onosproject.ovsdb.controller.OvsdbClientService;
78import org.onosproject.ovsdb.controller.OvsdbController;
79import org.onosproject.ovsdb.controller.OvsdbNodeId;
Jian Li51b844c2018-05-31 10:59:03 +090080import org.openstack4j.api.OSClient;
81import org.openstack4j.api.client.IOSClientBuilder;
82import org.openstack4j.api.exceptions.AuthenticationException;
83import org.openstack4j.api.types.Facing;
84import org.openstack4j.core.transport.Config;
Jian Li091d8d22018-02-20 10:42:06 +090085import org.openstack4j.core.transport.ObjectMapperSingleton;
86import org.openstack4j.model.ModelEntity;
Jian Li51b844c2018-05-31 10:59:03 +090087import org.openstack4j.model.common.Identifier;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090088import org.openstack4j.model.network.ExternalGateway;
Jian Li40f032a2019-10-02 20:36:09 +090089import org.openstack4j.model.network.IP;
Jian Li24ec59f2018-05-23 19:01:25 +090090import org.openstack4j.model.network.NetFloatingIP;
91import org.openstack4j.model.network.Network;
Jian Lia171a432018-06-11 11:52:11 +090092import org.openstack4j.model.network.Port;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090093import org.openstack4j.model.network.Router;
Jian Li0b564282018-06-20 00:50:53 +090094import org.openstack4j.model.network.RouterInterface;
Jian Li40f032a2019-10-02 20:36:09 +090095import org.openstack4j.model.network.SecurityGroup;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090096import org.openstack4j.model.network.Subnet;
Jian Li51b844c2018-05-31 10:59:03 +090097import org.openstack4j.openstack.OSFactory;
Jian Li0b564282018-06-20 00:50:53 +090098import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
Jian Li091d8d22018-02-20 10:42:06 +090099import org.slf4j.Logger;
100import org.slf4j.LoggerFactory;
101
Jian Li63430202018-08-30 16:24:09 +0900102import javax.crypto.Mac;
103import javax.crypto.spec.SecretKeySpec;
Jian Li51b844c2018-05-31 10:59:03 +0900104import javax.net.ssl.HostnameVerifier;
105import javax.net.ssl.HttpsURLConnection;
106import javax.net.ssl.SSLContext;
107import javax.net.ssl.TrustManager;
108import javax.net.ssl.X509TrustManager;
Jian Li7b8c3682019-05-12 13:57:15 +0900109import javax.ws.rs.client.Client;
110import javax.ws.rs.client.ClientBuilder;
111import javax.ws.rs.client.Entity;
112import javax.ws.rs.client.WebTarget;
113import javax.ws.rs.core.Response;
Jian Li63430202018-08-30 16:24:09 +0900114import java.io.ByteArrayInputStream;
115import java.io.ByteArrayOutputStream;
Jian Li0b564282018-06-20 00:50:53 +0900116import java.io.IOException;
Jian Li091d8d22018-02-20 10:42:06 +0900117import java.io.InputStream;
Daniel Parka73c2362018-09-17 17:43:25 +0900118import java.io.OutputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900119import java.nio.ByteBuffer;
Jian Li51b844c2018-05-31 10:59:03 +0900120import java.security.cert.X509Certificate;
Daniel Parka73c2362018-09-17 17:43:25 +0900121import java.util.Collection;
Jian Li1064e4f2018-05-29 16:16:53 +0900122import java.util.HashMap;
123import java.util.Iterator;
Jian Li40f032a2019-10-02 20:36:09 +0900124import java.util.List;
Jian Li1064e4f2018-05-29 16:16:53 +0900125import java.util.Map;
Daniel Park95f73312018-07-31 15:48:34 +0900126import java.util.Objects;
Jian Li7f70bb72018-07-06 23:35:30 +0900127import java.util.Optional;
Jian Li1064e4f2018-05-29 16:16:53 +0900128import java.util.Set;
129import java.util.TreeMap;
Daniel Parka73c2362018-09-17 17:43:25 +0900130import java.util.concurrent.TimeUnit;
Jian Li40f032a2019-10-02 20:36:09 +0900131import java.util.stream.Collectors;
Jian Li091d8d22018-02-20 10:42:06 +0900132
133import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
Daniel Park95f73312018-07-31 15:48:34 +0900134import static com.google.common.base.Preconditions.checkNotNull;
Jian Li7f024de2018-07-07 03:51:02 +0900135import static com.google.common.base.Strings.isNullOrEmpty;
Jian Li7b8c3682019-05-12 13:57:15 +0900136import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
137import static org.apache.commons.io.IOUtils.toInputStream;
Jian Li5ecfd1a2018-12-10 11:41:03 +0900138import static org.onlab.packet.Ip4Address.valueOf;
Daniel Park95f73312018-07-31 15:48:34 +0900139import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka73c2362018-09-17 17:43:25 +0900140import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Jian Licda74c82019-10-31 22:24:17 +0900141import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
Jian Li40f032a2019-10-02 20:36:09 +0900142import static org.onosproject.openstacknetworking.api.Constants.FLOATING_IP_FORMAT;
143import static org.onosproject.openstacknetworking.api.Constants.NETWORK_FORMAT;
Jian Li7b8c3682019-05-12 13:57:15 +0900144import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_REST_PATH;
Daniel Parkc4d06402018-05-28 15:57:37 +0900145import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
146import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
Jian Li40f032a2019-10-02 20:36:09 +0900147import static org.onosproject.openstacknetworking.api.Constants.PORT_FORMAT;
Daniel Park7e8c4d82018-08-13 23:47:49 +0900148import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
149import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
Jian Li7b8c3682019-05-12 13:57:15 +0900150import static org.onosproject.openstacknetworking.api.Constants.REST_PASSWORD;
151import static org.onosproject.openstacknetworking.api.Constants.REST_PORT;
152import static org.onosproject.openstacknetworking.api.Constants.REST_USER;
153import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
Jian Li40f032a2019-10-02 20:36:09 +0900154import static org.onosproject.openstacknetworking.api.Constants.ROUTER_FORMAT;
155import static org.onosproject.openstacknetworking.api.Constants.ROUTER_INTF_FORMAT;
156import static org.onosproject.openstacknetworking.api.Constants.SECURITY_GROUP_FORMAT;
157import static org.onosproject.openstacknetworking.api.Constants.SUBNET_FORMAT;
Daniel Parkec9d1132018-08-19 11:18:03 +0900158import static org.onosproject.openstacknetworking.api.Constants.UNSUPPORTED_VENDOR;
Ray Milkey9dc57392018-06-08 08:52:31 -0700159import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
Jian Li0b564282018-06-20 00:50:53 +0900160import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
Jian Li091d8d22018-02-20 10:42:06 +0900161
162/**
163 * An utility that used in openstack networking app.
164 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900165public final class OpenstackNetworkingUtil {
Jian Li091d8d22018-02-20 10:42:06 +0900166
Daniel Park95985382018-07-23 11:38:07 +0900167 private static final Logger log = LoggerFactory.getLogger(OpenstackNetworkingUtil.class);
Jian Li091d8d22018-02-20 10:42:06 +0900168
Daniel Parkc4d06402018-05-28 15:57:37 +0900169 private static final int HEX_RADIX = 16;
Jian Li51b844c2018-05-31 10:59:03 +0900170 private static final String ZERO_FUNCTION_NUMBER = "0";
Daniel Parkc4d06402018-05-28 15:57:37 +0900171 private static final String PREFIX_DEVICE_NUMBER = "s";
172 private static final String PREFIX_FUNCTION_NUMBER = "f";
173
Jian Li51b844c2018-05-31 10:59:03 +0900174 // keystone endpoint related variables
175 private static final String DOMAIN_DEFAULT = "default";
176 private static final String KEYSTONE_V2 = "v2.0";
177 private static final String KEYSTONE_V3 = "v3";
Jian Li51b844c2018-05-31 10:59:03 +0900178 private static final String SSL_TYPE = "SSL";
179
Jian Li7f024de2018-07-07 03:51:02 +0900180 private static final String PROXY_MODE = "proxy";
181 private static final String BROADCAST_MODE = "broadcast";
182
Jian Licad36c72018-09-13 17:44:54 +0900183 private static final String ENABLE = "enable";
184 private static final String DISABLE = "disable";
185
Jian Li63430202018-08-30 16:24:09 +0900186 private static final int HTTP_PAYLOAD_BUFFER = 8 * 1024;
187
188 private static final String HMAC_SHA256 = "HmacSHA256";
189
Jian Li24ec59f2018-05-23 19:01:25 +0900190 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
191
Daniel Parka73c2362018-09-17 17:43:25 +0900192 private static final String DL_DST = "dl_dst=";
193 private static final String NW_DST = "nw_dst=";
194 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
195 private static final String IN_PORT = "in_port=";
196 private static final String NW_SRC = "nw_src=";
197 private static final String COMMA = ",";
198 private static final String TUN_ID = "tun_id=";
199
Jian Li40f032a2019-10-02 20:36:09 +0900200 private static final String DEVICE_OWNER_GW = "network:router_gateway";
201 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
202
203 private static final String NOT_AVAILABLE = "N/A";
204
Daniel Parka73c2362018-09-17 17:43:25 +0900205 private static final long TIMEOUT_MS = 5000;
206 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
207 private static final int SSH_PORT = 22;
208
Jian Li51728702019-05-17 18:38:56 +0900209 private static final int TAP_PORT_LENGTH = 11;
Jian Lia271b3c2019-09-03 23:10:20 +0900210 private static final int PORT_NAME_MAX_LENGTH = 15;
Jian Li51728702019-05-17 18:38:56 +0900211
Jian Li091d8d22018-02-20 10:42:06 +0900212 /**
213 * Prevents object instantiation from external.
214 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900215 private OpenstackNetworkingUtil() {
Jian Li091d8d22018-02-20 10:42:06 +0900216 }
217
218 /**
219 * Interprets JSON string to corresponding openstack model entity object.
220 *
Jian Li7b8c3682019-05-12 13:57:15 +0900221 * @param inputStr JSON string
Jian Li091d8d22018-02-20 10:42:06 +0900222 * @param entityClazz openstack model entity class
223 * @return openstack model entity object
224 */
Jian Li7b8c3682019-05-12 13:57:15 +0900225 public static ModelEntity jsonToModelEntity(String inputStr, Class entityClazz) {
Jian Li091d8d22018-02-20 10:42:06 +0900226 ObjectMapper mapper = new ObjectMapper();
227 try {
Jian Li7b8c3682019-05-12 13:57:15 +0900228 InputStream input = toInputStream(inputStr, REST_UTF8);
Jian Li091d8d22018-02-20 10:42:06 +0900229 JsonNode jsonTree = mapper.enable(INDENT_OUTPUT).readTree(input);
230 log.trace(new ObjectMapper().writeValueAsString(jsonTree));
231 return ObjectMapperSingleton.getContext(entityClazz)
232 .readerFor(entityClazz)
233 .readValue(jsonTree);
234 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900235 log.error("Exception occurred because of {}", e);
Jian Li091d8d22018-02-20 10:42:06 +0900236 throw new IllegalArgumentException();
237 }
238 }
Jian Lieb9f77d2018-02-20 11:25:45 +0900239
240 /**
241 * Converts openstack model entity object into JSON object.
242 *
243 * @param entity openstack model entity object
244 * @param entityClazz openstack model entity class
245 * @return JSON object
246 */
247 public static ObjectNode modelEntityToJson(ModelEntity entity, Class entityClazz) {
248 ObjectMapper mapper = new ObjectMapper();
249 try {
250 String strModelEntity = ObjectMapperSingleton.getContext(entityClazz)
251 .writerFor(entityClazz)
252 .writeValueAsString(entity);
253 log.trace(strModelEntity);
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900254 return (ObjectNode) mapper.readTree(strModelEntity.getBytes(Charsets.UTF_8));
Daniel Park95985382018-07-23 11:38:07 +0900255 } catch (IOException e) {
256 log.error("IOException occurred because of {}", e.toString());
Jian Lieb9f77d2018-02-20 11:25:45 +0900257 throw new IllegalStateException();
258 }
259 }
Jian Li1064e4f2018-05-29 16:16:53 +0900260
261 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900262 * Obtains a floating IP associated with the given instance port.
263 *
264 * @param port instance port
265 * @param fips a collection of floating IPs
266 * @return associated floating IP
267 */
268 public static NetFloatingIP associatedFloatingIp(InstancePort port,
269 Set<NetFloatingIP> fips) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900270 for (NetFloatingIP fip : fips) {
271 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
272 continue;
Jian Li24ec59f2018-05-23 19:01:25 +0900273 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900274 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
275 continue;
276 }
Jian Li6bc29d92018-10-02 13:55:05 +0900277 if (fip.getFixedIpAddress().equals(port.ipAddress().toString()) &&
278 fip.getPortId().equals(port.portId())) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900279 return fip;
280 }
Jian Li24ec59f2018-05-23 19:01:25 +0900281 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900282
Jian Li24ec59f2018-05-23 19:01:25 +0900283 return null;
284 }
285
286 /**
287 * Checks whether the given floating IP is associated with a VM.
288 *
289 * @param service openstack network service
290 * @param fip floating IP
291 * @return true if the given floating IP associated with a VM, false otherwise
292 */
293 public static boolean isAssociatedWithVM(OpenstackNetworkService service,
294 NetFloatingIP fip) {
295 Port osPort = service.port(fip.getPortId());
296 if (osPort == null) {
297 return false;
298 }
299
300 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
301 Network osNet = service.network(osPort.getNetworkId());
302 if (osNet == null) {
303 final String errorFormat = ERR_FLOW + "no network(%s) exists";
304 final String error = String.format(errorFormat,
305 fip.getFloatingIpAddress(), osPort.getNetworkId());
306 throw new IllegalStateException(error);
307 }
308 return true;
309 } else {
310 return false;
311 }
312 }
313
314 /**
Jian Lia171a432018-06-11 11:52:11 +0900315 * Obtains the gateway node by instance port.
316 *
317 * @param gateways a collection of gateway nodes
318 * @param instPort instance port
319 * @return a gateway node
320 */
321 public static OpenstackNode getGwByInstancePort(Set<OpenstackNode> gateways,
322 InstancePort instPort) {
323 OpenstackNode gw = null;
324 if (instPort != null && instPort.deviceId() != null) {
325 gw = getGwByComputeDevId(gateways, instPort.deviceId());
326 }
327 return gw;
328 }
329
330 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900331 * Obtains the gateway node by device in compute node. Note that the gateway
332 * node is determined by device's device identifier.
333 *
334 * @param gws a collection of gateway nodes
335 * @param deviceId device identifier
336 * @return a gateway node
337 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900338 public static OpenstackNode getGwByComputeDevId(Set<OpenstackNode> gws,
339 DeviceId deviceId) {
Jian Li1064e4f2018-05-29 16:16:53 +0900340 int numOfGw = gws.size();
341
342 if (numOfGw == 0) {
343 return null;
344 }
345
346 int gwIndex = Math.abs(deviceId.hashCode()) % numOfGw;
347
348 return getGwByIndex(gws, gwIndex);
349 }
350
Jian Li51b844c2018-05-31 10:59:03 +0900351 /**
352 * Obtains a connected openstack client.
353 *
354 * @param osNode openstack node
355 * @return a connected openstack client
356 */
357 public static OSClient getConnectedClient(OpenstackNode osNode) {
Jian Lic704b672018-09-04 18:52:53 +0900358 OpenstackAuth auth = osNode.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +0900359 String endpoint = buildEndpoint(osNode);
360 Perspective perspective = auth.perspective();
Jian Li1064e4f2018-05-29 16:16:53 +0900361
Jian Li51b844c2018-05-31 10:59:03 +0900362 Config config = getSslConfig();
Jian Li1064e4f2018-05-29 16:16:53 +0900363
Jian Li51b844c2018-05-31 10:59:03 +0900364 try {
365 if (endpoint.contains(KEYSTONE_V2)) {
366 IOSClientBuilder.V2 builder = OSFactory.builderV2()
367 .endpoint(endpoint)
368 .tenantName(auth.project())
369 .credentials(auth.username(), auth.password())
370 .withConfig(config);
371
372 if (perspective != null) {
373 builder.perspective(getFacing(perspective));
374 }
375
376 return builder.authenticate();
377 } else if (endpoint.contains(KEYSTONE_V3)) {
378
379 Identifier project = Identifier.byName(auth.project());
380 Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
381
382 IOSClientBuilder.V3 builder = OSFactory.builderV3()
383 .endpoint(endpoint)
384 .credentials(auth.username(), auth.password(), domain)
385 .scopeToProject(project, domain)
386 .withConfig(config);
387
388 if (perspective != null) {
389 builder.perspective(getFacing(perspective));
390 }
391
392 return builder.authenticate();
393 } else {
394 log.warn("Unrecognized keystone version type");
395 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900396 }
Jian Li51b844c2018-05-31 10:59:03 +0900397 } catch (AuthenticationException e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900398 log.error("Authentication failed due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +0900399 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900400 }
Jian Li1064e4f2018-05-29 16:16:53 +0900401 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900402
403 /**
Jian Licda74c82019-10-31 22:24:17 +0900404 * Checks whether the given openstack port is smart NIC capable.
405 *
406 * @param port openstack port
407 * @return true if the given port is smart NIC capable, false otherwise
408 */
409 public static boolean isSmartNicCapable(Port port) {
410 if (port.getProfile() != null && port.getvNicType().equals(DIRECT)) {
411 String vendorInfo = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
412 if (portNamePrefixMap().containsKey(vendorInfo)) {
413 log.debug("Port {} is a Smart NIC capable port.", port.getId());
414 return true;
415 }
416 return false;
417 }
418 return false;
419 }
420
421 /**
Daniel Parkc4d06402018-05-28 15:57:37 +0900422 * Extract the interface name with the supplied port.
423 *
424 * @param port port
425 * @return interface name
426 */
427 public static String getIntfNameFromPciAddress(Port port) {
Daniel Parkff178ba2018-11-23 15:57:24 +0900428 String intfName;
429
Daniel Park95985382018-07-23 11:38:07 +0900430 if (port.getProfile() == null || port.getProfile().isEmpty()) {
Jian Li51b844c2018-05-31 10:59:03 +0900431 log.error("Port profile is not found");
432 return null;
433 }
434
Daniel Park95985382018-07-23 11:38:07 +0900435 if (!port.getProfile().containsKey(PCISLOT) ||
436 Strings.isNullOrEmpty(port.getProfile().get(PCISLOT).toString())) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900437 log.error("Failed to retrieve the interface name because of no " +
438 "pci_slot information from the port");
Daniel Parkc4d06402018-05-28 15:57:37 +0900439 return null;
440 }
Jian Li51b844c2018-05-31 10:59:03 +0900441
Daniel Parkff178ba2018-11-23 15:57:24 +0900442 String vendorInfoForPort = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
443
444 if (!portNamePrefixMap().containsKey(vendorInfoForPort)) {
445 log.debug("{} is an non-smart NIC prefix.", vendorInfoForPort);
446 return UNSUPPORTED_VENDOR;
447 }
448
449 String portNamePrefix = portNamePrefixMap().get(vendorInfoForPort);
450
Daniel Parkc4d06402018-05-28 15:57:37 +0900451 String busNumHex = port.getProfile().get(PCISLOT).toString().split(":")[1];
452 String busNumDecimal = String.valueOf(Integer.parseInt(busNumHex, HEX_RADIX));
453
454 String deviceNumHex = port.getProfile().get(PCISLOT).toString()
455 .split(":")[2]
456 .split("\\.")[0];
457 String deviceNumDecimal = String.valueOf(Integer.parseInt(deviceNumHex, HEX_RADIX));
458
459 String functionNumHex = port.getProfile().get(PCISLOT).toString()
460 .split(":")[2]
461 .split("\\.")[1];
462 String functionNumDecimal = String.valueOf(Integer.parseInt(functionNumHex, HEX_RADIX));
463
Daniel Parkc4d06402018-05-28 15:57:37 +0900464 if (functionNumDecimal.equals(ZERO_FUNCTION_NUMBER)) {
465 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal;
466 } else {
467 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal
468 + PREFIX_FUNCTION_NUMBER + functionNumDecimal;
469 }
470
471 return intfName;
472 }
Jian Li51b844c2018-05-31 10:59:03 +0900473
474 /**
Daniel Park95f73312018-07-31 15:48:34 +0900475 * Check if the given interface is added to the given device or not.
476 *
477 * @param deviceId device ID
478 * @param intfName interface name
479 * @param deviceService device service
480 * @return true if the given interface is added to the given device or false otherwise
481 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900482 public static boolean hasIntfAleadyInDevice(DeviceId deviceId,
483 String intfName,
484 DeviceService deviceService) {
Daniel Park95f73312018-07-31 15:48:34 +0900485 checkNotNull(deviceId);
486 checkNotNull(intfName);
487
Jian Li5ecfd1a2018-12-10 11:41:03 +0900488 return deviceService.getPorts(deviceId).stream().anyMatch(port ->
489 Objects.equals(port.annotations().value(PORT_NAME), intfName));
Daniel Park95f73312018-07-31 15:48:34 +0900490 }
491
492 /**
Jian Li0b564282018-06-20 00:50:53 +0900493 * Adds router interfaces to openstack admin service.
Jian Li0b564282018-06-20 00:50:53 +0900494 *
495 * @param osPort port
496 * @param adminService openstack admin service
497 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900498 public static void addRouterIface(Port osPort,
499 OpenstackRouterAdminService adminService) {
Jian Li0b564282018-06-20 00:50:53 +0900500 osPort.getFixedIps().forEach(p -> {
501 JsonNode jsonTree = new ObjectMapper().createObjectNode()
502 .put("id", osPort.getDeviceId())
503 .put("tenant_id", osPort.getTenantId())
504 .put("subnet_id", p.getSubnetId())
505 .put("port_id", osPort.getId());
506 try {
507 RouterInterface rIface = getContext(NeutronRouterInterface.class)
508 .readerFor(NeutronRouterInterface.class)
509 .readValue(jsonTree);
510 if (adminService.routerInterface(rIface.getPortId()) != null) {
511 adminService.updateRouterInterface(rIface);
512 } else {
513 adminService.addRouterInterface(rIface);
514 }
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900515 } catch (IOException e) {
516 log.error("IOException occurred because of {}", e);
Jian Li0b564282018-06-20 00:50:53 +0900517 }
518 });
519 }
520
521 /**
Jian Li40f032a2019-10-02 20:36:09 +0900522 * Prints openstack security group.
523 *
524 * @param osSg openstack security group
525 */
526 public static void printSecurityGroup(SecurityGroup osSg) {
527 print(SECURITY_GROUP_FORMAT, osSg.getId(), osSg.getName());
528 }
529
530 /**
531 * Prints openstack network.
532 *
533 * @param osNet openstack network
534 */
535 public static void printNetwork(Network osNet) {
536 final String strNet = String.format(NETWORK_FORMAT,
537 osNet.getId(),
538 osNet.getName(),
539 osNet.getProviderSegID(),
540 osNet.getSubnets());
541 print(strNet);
542 }
543
544 /**
545 * Prints openstack subnet.
546 *
547 * @param osSubnet openstack subnet
548 * @param osNetService openstack network service
549 */
550 public static void printSubnet(Subnet osSubnet,
551 OpenstackNetworkService osNetService) {
552 final Network network = osNetService.network(osSubnet.getNetworkId());
553 final String netName = network == null ? NOT_AVAILABLE : network.getName();
554 final String strSubnet = String.format(SUBNET_FORMAT,
555 osSubnet.getId(),
556 netName,
557 osSubnet.getCidr());
558 print(strSubnet);
559 }
560
561 /**
562 * Prints openstack port.
563 *
564 * @param osPort openstack port
565 * @param osNetService openstack network service
566 */
567 public static void printPort(Port osPort,
568 OpenstackNetworkService osNetService) {
569 List<String> fixedIps = osPort.getFixedIps().stream()
570 .map(IP::getIpAddress)
571 .collect(Collectors.toList());
572 final Network network = osNetService.network(osPort.getNetworkId());
573 final String netName = network == null ? NOT_AVAILABLE : network.getName();
574 final String strPort = String.format(PORT_FORMAT,
575 osPort.getId(),
576 netName,
577 osPort.getMacAddress(),
578 fixedIps.isEmpty() ? "" : fixedIps);
579 print(strPort);
580 }
581
582 /**
583 * Prints openstack router.
584 *
585 * @param osRouter openstack router
586 * @param osNetService openstack network service
587 */
588 public static void printRouter(Router osRouter,
589 OpenstackNetworkService osNetService) {
590 List<String> externals = osNetService.ports().stream()
591 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
592 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_GW))
593 .flatMap(osPort -> osPort.getFixedIps().stream())
594 .map(IP::getIpAddress)
595 .collect(Collectors.toList());
596
597 List<String> internals = osNetService.ports().stream()
598 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
599 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
600 .flatMap(osPort -> osPort.getFixedIps().stream())
601 .map(IP::getIpAddress)
602 .collect(Collectors.toList());
603
604 final String strRouter = String.format(ROUTER_FORMAT,
605 osRouter.getId(),
606 osRouter.getName(),
607 externals.isEmpty() ? "" : externals,
608 internals.isEmpty() ? "" : internals);
609 print(strRouter);
610 }
611
612 /**
613 * Prints openstack router interface.
614 *
615 * @param osRouterIntf openstack router interface
616 */
617 public static void printRouterIntf(RouterInterface osRouterIntf) {
618 final String strRouterIntf = String.format(ROUTER_INTF_FORMAT,
619 osRouterIntf.getId(),
620 osRouterIntf.getTenantId(),
621 osRouterIntf.getSubnetId());
622 print(strRouterIntf);
623 }
624
625 /**
626 * Prints openstack floating IP.
627 *
628 * @param floatingIp floating IP
629 */
630 public static void printFloatingIp(NetFloatingIP floatingIp) {
631 final String strFloating = String.format(FLOATING_IP_FORMAT,
632 floatingIp.getId(),
633 floatingIp.getFloatingIpAddress(),
634 Strings.isNullOrEmpty(floatingIp.getFixedIpAddress()) ?
635 "" : floatingIp.getFixedIpAddress());
636 print(strFloating);
637 }
638
639 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900640 * Obtains the property value with specified property key name.
641 *
642 * @param properties a collection of properties
643 * @param name key name
644 * @return mapping value
645 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900646 public static String getPropertyValue(Set<ConfigProperty> properties,
647 String name) {
Jian Li7f70bb72018-07-06 23:35:30 +0900648 Optional<ConfigProperty> property =
649 properties.stream().filter(p -> p.name().equals(name)).findFirst();
650 return property.map(ConfigProperty::value).orElse(null);
651 }
652
653 /**
Jian Li9d35bd62018-10-13 01:43:24 +0900654 * Obtains the boolean property value with specified property key name.
655 *
656 * @param properties a collection of properties
657 * @param name key name
658 * @return mapping value
659 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900660 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties,
661 String name) {
Jian Li9d35bd62018-10-13 01:43:24 +0900662 Optional<ConfigProperty> property =
663 properties.stream().filter(p -> p.name().equals(name)).findFirst();
664
665 return property.map(ConfigProperty::asBoolean).orElse(false);
666 }
667
668 /**
Jian Lif1efbe52018-07-17 23:20:16 +0900669 * Prints out the JSON string in pretty format.
670 *
671 * @param mapper Object mapper
672 * @param jsonString JSON string
673 * @return pretty formatted JSON string
674 */
675 public static String prettyJson(ObjectMapper mapper, String jsonString) {
676 try {
677 Object jsonObject = mapper.readValue(jsonString, Object.class);
678 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
Daniel Park2ff66b42018-08-01 11:52:45 +0900679 } catch (JsonParseException e) {
680 log.debug("JsonParseException caused by {}", e);
681 } catch (JsonMappingException e) {
682 log.debug("JsonMappingException caused by {}", e);
683 } catch (JsonProcessingException e) {
684 log.debug("JsonProcessingException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900685 }
686 return null;
687 }
688
689 /**
Jian Li7f024de2018-07-07 03:51:02 +0900690 * Checks the validity of ARP mode.
691 *
692 * @param arpMode ARP mode
693 * @return returns true if the ARP mode is valid, false otherwise
694 */
695 public static boolean checkArpMode(String arpMode) {
696
697 if (isNullOrEmpty(arpMode)) {
698 return false;
699 } else {
700 return arpMode.equals(PROXY_MODE) || arpMode.equals(BROADCAST_MODE);
701 }
702 }
703
704 /**
Jian Licad36c72018-09-13 17:44:54 +0900705 * Checks the validity of activation flag.
706 *
707 * @param activationFlag activation flag
708 * @return returns true if the activation flag is valid, false otherwise
709 */
710 public static boolean checkActivationFlag(String activationFlag) {
711
712 switch (activationFlag) {
713 case ENABLE:
714 return true;
715 case DISABLE:
716 return false;
717 default:
718 throw new IllegalArgumentException("The given activation flag is not valid!");
719 }
720 }
721
722 /**
Jian Liec5c32b2018-07-13 14:28:58 +0900723 * Swaps current location with old location info.
724 * The revised instance port will be used to mod the flow rules after migration.
725 *
726 * @param instPort instance port
727 * @return location swapped instance port
728 */
729 public static InstancePort swapStaleLocation(InstancePort instPort) {
730 return DefaultInstancePort.builder()
731 .deviceId(instPort.oldDeviceId())
732 .portNumber(instPort.oldPortNumber())
733 .state(instPort.state())
734 .ipAddress(instPort.ipAddress())
735 .macAddress(instPort.macAddress())
736 .networkId(instPort.networkId())
737 .portId(instPort.portId())
738 .build();
739 }
740
741 /**
Daniel Park2ff66b42018-08-01 11:52:45 +0900742 * Compares two router interfaces are equal.
743 * Will be remove this after Openstack4j implements equals.
744 *
745 * @param routerInterface1 router interface
746 * @param routerInterface2 router interface
747 * @return returns true if two router interfaces are equal, false otherwise
748 */
Jian Li63430202018-08-30 16:24:09 +0900749 public static boolean routerInterfacesEquals(RouterInterface routerInterface1,
750 RouterInterface routerInterface2) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900751 return Objects.equals(routerInterface1.getId(), routerInterface2.getId()) &&
752 Objects.equals(routerInterface1.getPortId(), routerInterface2.getPortId()) &&
753 Objects.equals(routerInterface1.getSubnetId(), routerInterface2.getSubnetId()) &&
754 Objects.equals(routerInterface1.getTenantId(), routerInterface2.getTenantId());
755 }
756
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900757 /**
758 * Returns the vnic type of given port.
759 *
760 * @param portName port name
761 * @return vnit type
762 */
Daniel Park7e8c4d82018-08-13 23:47:49 +0900763 public static VnicType vnicType(String portName) {
764 if (portName.startsWith(PORT_NAME_PREFIX_VM) ||
765 portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM)) {
766 return VnicType.NORMAL;
767 } else if (isDirectPort(portName)) {
768 return VnicType.DIRECT;
769 } else {
770 return VnicType.UNSUPPORTED;
771 }
772 }
773
Jian Li63430202018-08-30 16:24:09 +0900774 /**
775 * Deserializes raw payload into HttpRequest object.
776 *
777 * @param rawData raw http payload
778 * @return HttpRequest object
779 */
780 public static HttpRequest parseHttpRequest(byte[] rawData) {
781 SessionInputBufferImpl sessionInputBuffer =
782 new SessionInputBufferImpl(
783 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
784 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900785 DefaultHttpRequestParser requestParser =
786 new DefaultHttpRequestParser(sessionInputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900787 try {
788 return requestParser.parse();
789 } catch (IOException | HttpException e) {
790 log.warn("Failed to parse HttpRequest, due to {}", e);
791 }
792
793 return null;
794 }
795
796 /**
797 * Serializes HttpRequest object to byte array.
798 *
799 * @param request http request object
800 * @return byte array
801 */
802 public static byte[] unparseHttpRequest(HttpRequest request) {
803 try {
804 SessionOutputBufferImpl sessionOutputBuffer =
805 new SessionOutputBufferImpl(
806 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
807
808 ByteArrayOutputStream baos = new ByteArrayOutputStream();
809 sessionOutputBuffer.bind(baos);
810
Jian Li5ecfd1a2018-12-10 11:41:03 +0900811 HttpMessageWriter<HttpRequest> requestWriter =
812 new DefaultHttpRequestWriter(sessionOutputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900813 requestWriter.write(request);
814 sessionOutputBuffer.flush();
815
816 return baos.toByteArray();
817 } catch (HttpException | IOException e) {
818 log.warn("Failed to unparse HttpRequest, due to {}", e);
819 }
820
821 return null;
822 }
823
824 /**
825 * Deserializes raw payload into HttpResponse object.
826 *
827 * @param rawData raw http payload
828 * @return HttpResponse object
829 */
830 public static HttpResponse parseHttpResponse(byte[] rawData) {
831 SessionInputBufferImpl sessionInputBuffer =
832 new SessionInputBufferImpl(
833 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
834 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900835 DefaultHttpResponseParser responseParser =
836 new DefaultHttpResponseParser(sessionInputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900837 try {
838 return responseParser.parse();
839 } catch (IOException | HttpException e) {
840 log.warn("Failed to parse HttpResponse, due to {}", e);
841 }
842
843 return null;
844 }
845
846 /**
847 * Serializes HttpResponse header to byte array.
848 *
849 * @param response http response object
850 * @return byte array
851 */
852 public static byte[] unparseHttpResponseHeader(HttpResponse response) {
853 try {
854 SessionOutputBufferImpl sessionOutputBuffer =
855 new SessionOutputBufferImpl(
856 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
857
858 ByteArrayOutputStream headerBaos = new ByteArrayOutputStream();
859 sessionOutputBuffer.bind(headerBaos);
860
861 HttpMessageWriter<HttpResponse> responseWriter =
862 new DefaultHttpResponseWriter(sessionOutputBuffer);
863 responseWriter.write(response);
864 sessionOutputBuffer.flush();
865
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900866 log.debug(headerBaos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900867
868 return headerBaos.toByteArray();
869 } catch (IOException | HttpException e) {
870 log.warn("Failed to unparse HttpResponse headers, due to {}", e);
871 }
872
873 return null;
874 }
875
876 /**
877 * Serializes HttpResponse object to byte array.
878 *
879 * @param response http response object
880 * @return byte array
881 */
882 public static byte[] unparseHttpResponseBody(HttpResponse response) {
883 try {
884 ByteArrayOutputStream baos = new ByteArrayOutputStream();
885 response.getEntity().writeTo(baos);
886
887 log.debug(response.toString());
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900888 log.debug(baos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900889
890 return baos.toByteArray();
891 } catch (IOException e) {
892 log.warn("Failed to unparse HttpResponse, due to {}", e);
893 }
894
895 return null;
896 }
897
898 /**
899 * Encodes the given data using HmacSHA256 encryption method with given secret key.
900 *
901 * @param key secret key
902 * @param data data to be encrypted
903 * @return Hmac256 encrypted data
904 */
905 public static String hmacEncrypt(String key, String data) {
906 try {
907 Mac sha256Hmac = Mac.getInstance(HMAC_SHA256);
908 SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA256);
909 sha256Hmac.init(secretKey);
910 return Hex.encodeHexString(sha256Hmac.doFinal(data.getBytes("UTF-8")));
911 } catch (Exception e) {
912 log.warn("Failed to encrypt data {} using key {}, due to {}", data, key, e);
913 }
914 return null;
915 }
916
Daniel Parka73c2362018-09-17 17:43:25 +0900917 /**
918 * Creates flow trace request string.
919 *
920 * @param srcIp src ip address
921 * @param dstIp dst ip address
922 * @param srcInstancePort src instance port
923 * @param osNetService openstack networking service
Daniel Park5aef9822018-09-20 18:04:18 +0900924 * @param uplink true if this request is for uplink
Daniel Parka73c2362018-09-17 17:43:25 +0900925 * @return flow trace request string
926 */
927 public static String traceRequestString(String srcIp,
928 String dstIp,
929 InstancePort srcInstancePort,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900930 OpenstackNetworkService osNetService,
931 boolean uplink) {
Daniel Parka73c2362018-09-17 17:43:25 +0900932
933 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
934
935 if (uplink) {
936
937 requestStringBuilder.append(COMMA)
938 .append(IN_PORT)
939 .append(srcInstancePort.portNumber().toString())
940 .append(COMMA)
941 .append(NW_SRC)
942 .append(srcIp)
943 .append(COMMA);
944
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900945 String modifiedDstIp = dstIp;
Jian Li621f73c2018-12-15 01:49:22 +0900946 Type netType = osNetService.networkType(srcInstancePort.networkId());
947 if (netType == Type.VXLAN || netType == Type.GRE ||
948 netType == Type.VLAN || netType == Type.GENEVE) {
Daniel Parka73c2362018-09-17 17:43:25 +0900949 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900950 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900951 requestStringBuilder.append(DL_DST)
952 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
Jian Li5ecfd1a2018-12-10 11:41:03 +0900953 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(
954 IpAddress.valueOf(dstIp))) {
Daniel Parka73c2362018-09-17 17:43:25 +0900955 requestStringBuilder.append(DL_DST)
956 .append(DEFAULT_GATEWAY_MAC_STR)
957 .append(COMMA);
958 }
959 } else {
960 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900961 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900962 }
963 }
964
965 requestStringBuilder.append(NW_DST)
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900966 .append(modifiedDstIp)
Daniel Parka73c2362018-09-17 17:43:25 +0900967 .append("\n");
968 } else {
969 requestStringBuilder.append(COMMA)
970 .append(NW_SRC)
971 .append(dstIp)
972 .append(COMMA);
973
Jian Li621f73c2018-12-15 01:49:22 +0900974 Type netType = osNetService.networkType(srcInstancePort.networkId());
975
976 if (netType == Type.VXLAN || netType == Type.GRE ||
977 netType == Type.VLAN || netType == Type.GENEVE) {
Daniel Parka73c2362018-09-17 17:43:25 +0900978 requestStringBuilder.append(TUN_ID)
979 .append(osNetService.segmentId(srcInstancePort.networkId()))
980 .append(COMMA);
981 }
982 requestStringBuilder.append(NW_DST)
983 .append(srcIp)
984 .append("\n");
Daniel Parka73c2362018-09-17 17:43:25 +0900985 }
986
987 return requestStringBuilder.toString();
988 }
989
990 /**
991 * Sends flow trace string to node.
992 *
993 * @param requestString reqeust string
994 * @param node src node
995 * @return flow trace result in string format
996 */
997 public static String sendTraceRequestToNode(String requestString,
998 OpenstackNode node) {
999 String traceResult = null;
1000 OpenstackSshAuth sshAuth = node.sshAuthInfo();
1001
1002 try (SshClient client = SshClient.setUpDefaultClient()) {
1003 client.start();
1004
1005 try (ClientSession session = client
1006 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
1007 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
1008 session.addPasswordIdentity(sshAuth.password());
1009 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
1010
1011
1012 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
1013
1014 log.debug("requestString: {}", requestString);
1015 final InputStream inputStream =
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001016 new ByteArrayInputStream(requestString.getBytes(Charsets.UTF_8));
Daniel Parka73c2362018-09-17 17:43:25 +09001017
Jian Li5ecfd1a2018-12-10 11:41:03 +09001018 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Daniel Parka73c2362018-09-17 17:43:25 +09001019 OutputStream errStream = new ByteArrayOutputStream();
1020
1021 channel.setIn(new NoCloseInputStream(inputStream));
1022 channel.setErr(errStream);
1023 channel.setOut(outputStream);
1024
1025 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
1026 eventList.add(ClientChannelEvent.OPENED);
1027
1028 OpenFuture channelFuture = channel.open();
1029
1030 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
1031
1032 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
1033
1034 while (!channelFuture.isOpened()) {
1035 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
1036 log.error("Failed to open channel");
1037 return null;
1038 }
1039 }
1040 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
1041
Jian Li5ecfd1a2018-12-10 11:41:03 +09001042 traceResult = outputStream.toString(Charsets.UTF_8.name());
Daniel Parka73c2362018-09-17 17:43:25 +09001043
1044 channel.close();
1045 }
1046 } finally {
1047 session.close();
1048 }
1049 } finally {
1050 client.stop();
1051 }
1052
1053 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001054 log.error("Exception occurred because of {}", e);
Daniel Parka73c2362018-09-17 17:43:25 +09001055 }
1056
1057 return traceResult;
1058 }
1059
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001060 /**
1061 * Returns the floating ip with supplied instance port.
1062 *
1063 * @param instancePort instance port
1064 * @param osRouterAdminService openstack router admin service
1065 * @return floating ip
1066 */
1067 public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001068 OpenstackRouterAdminService
1069 osRouterAdminService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001070 return osRouterAdminService.floatingIps().stream()
1071 .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
1072 .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
1073 .findAny().orElse(null);
1074 }
1075
1076 /**
1077 * Sends GARP packet with supplied floating ip information.
1078 *
1079 * @param floatingIP floating ip
1080 * @param instancePort instance port
1081 * @param vlanId vlain id
1082 * @param gatewayNode gateway node
1083 * @param packetService packet service
1084 */
Jian Li32b03622018-11-06 17:54:24 +09001085 public static void processGarpPacketForFloatingIp(NetFloatingIP floatingIP,
1086 InstancePort instancePort,
1087 VlanId vlanId,
1088 OpenstackNode gatewayNode,
1089 PacketService packetService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001090 Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
1091
1092 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1093 .setOutput(gatewayNode.uplinkPortNum()).build();
1094
1095 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
1096 ByteBuffer.wrap(ethernet.serialize())));
1097 }
1098
1099 /**
1100 * Returns the external peer router with supplied network information.
1101 *
1102 * @param network network
1103 * @param osNetworkService openstack network service
1104 * @param osRouterAdminService openstack router admin service
1105 * @return external peer router
1106 */
1107 public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001108 OpenstackNetworkService
1109 osNetworkService,
1110 OpenstackRouterAdminService
1111 osRouterAdminService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001112 if (network == null) {
1113 return null;
1114 }
1115
Jian Lie6e609f2019-05-14 17:45:54 +09001116 Subnet subnet = osNetworkService.subnets(network.getId())
1117 .stream().findAny().orElse(null);
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001118
1119 if (subnet == null) {
1120 return null;
1121 }
1122
1123 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
1124 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1125 .findAny().orElse(null);
1126 if (osRouterIface == null) {
1127 return null;
1128 }
1129
1130 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001131 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001132 return null;
1133 }
1134
1135 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
1136 return osNetworkService.externalPeerRouter(exGatewayInfo);
1137
1138 }
1139
Jian Liebde74d2018-11-14 00:18:57 +09001140 /**
1141 * Returns the external peer router with specified subnet information.
1142 *
1143 * @param subnet openstack subnet
1144 * @param osRouterService openstack router service
1145 * @param osNetworkService openstack network service
1146 * @return external peer router
1147 */
Jian Li5ecfd1a2018-12-10 11:41:03 +09001148 public static ExternalPeerRouter externalPeerRouterFromSubnet(Subnet subnet,
1149 OpenstackRouterService
1150 osRouterService,
1151 OpenstackNetworkService
1152 osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001153 Router osRouter = getRouterFromSubnet(subnet, osRouterService);
1154 if (osRouter == null) {
1155 return null;
1156 }
1157 if (osRouter.getExternalGatewayInfo() == null) {
1158 // this router does not have external connectivity
1159 log.trace("router({}) has no external gateway",
1160 osRouter.getName());
1161 return null;
1162 }
1163
1164 return osNetworkService.externalPeerRouter(osRouter.getExternalGatewayInfo());
1165 }
1166
1167 /**
1168 * Returns the external ip address with specified router information.
1169 *
1170 * @param srcSubnet source subnet
1171 * @param osRouterService openstack router service
1172 * @param osNetworkService openstack network service
1173 * @return external ip address
1174 */
1175 public static IpAddress externalIpFromSubnet(Subnet srcSubnet,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001176 OpenstackRouterService
1177 osRouterService,
1178 OpenstackNetworkService
1179 osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001180
1181 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
1182
1183 if (osRouter.getExternalGatewayInfo() == null) {
1184 // this router does not have external connectivity
1185 log.trace("router({}) has no external gateway",
1186 osRouter.getName());
1187 return null;
1188 }
1189
1190 return getExternalIp(osRouter, osNetworkService);
1191 }
1192
1193 /**
1194 * Returns the external ip address with specified router information.
1195 *
1196 * @param router openstack router
1197 * @param osNetworkService openstack network service
1198 * @return external ip address
1199 */
Jian Li5ecfd1a2018-12-10 11:41:03 +09001200 public static IpAddress getExternalIp(Router router,
1201 OpenstackNetworkService osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001202 if (router == null) {
1203 return null;
1204 }
1205
1206 ExternalGateway externalGateway = router.getExternalGatewayInfo();
1207 if (externalGateway == null || !externalGateway.isEnableSnat()) {
Jian Li5ecfd1a2018-12-10 11:41:03 +09001208 log.trace("Failed to get externalIp for router {} because " +
1209 "externalGateway is null or SNAT is disabled",
Jian Liebde74d2018-11-14 00:18:57 +09001210 router.getId());
1211 return null;
1212 }
1213
1214 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
1215 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
1216 .stream()
1217 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
1218 .findAny().orElse(null);
1219
1220 if (exGatewayPort == null) {
1221 return null;
1222 }
1223
1224 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
1225 .findAny().get().getIpAddress());
1226 }
1227
Jian Li2d68c192018-12-13 15:52:59 +09001228 /**
1229 * Returns the tunnel port number with specified net ID and openstack node.
1230 *
1231 * @param netId network ID
1232 * @param netService network service
1233 * @param osNode openstack node
1234 * @return tunnel port number
1235 */
1236 public static PortNumber tunnelPortNumByNetId(String netId,
1237 OpenstackNetworkService netService,
1238 OpenstackNode osNode) {
SONA Project6bc5c4a2018-12-14 23:49:52 +09001239 Type netType = netService.networkType(netId);
Jian Li2d68c192018-12-13 15:52:59 +09001240
1241 if (netType == null) {
1242 return null;
1243 }
1244
1245 return tunnelPortNumByNetType(netType, osNode);
1246 }
1247
1248 /**
1249 * Returns the tunnel port number with specified net type and openstack node.
1250 *
1251 * @param netType network type
1252 * @param osNode openstack node
1253 * @return tunnel port number
1254 */
SONA Project6bc5c4a2018-12-14 23:49:52 +09001255 public static PortNumber tunnelPortNumByNetType(Type netType, OpenstackNode osNode) {
Jian Li2d68c192018-12-13 15:52:59 +09001256 switch (netType) {
1257 case VXLAN:
1258 return osNode.vxlanTunnelPortNum();
1259 case GRE:
1260 return osNode.greTunnelPortNum();
Jian Li621f73c2018-12-15 01:49:22 +09001261 case GENEVE:
1262 return osNode.geneveTunnelPortNum();
Jian Li2d68c192018-12-13 15:52:59 +09001263 default:
1264 return null;
1265 }
1266 }
1267
Jian Li7b8c3682019-05-12 13:57:15 +09001268 /**
1269 * Returns the REST URL of active node.
1270 *
1271 * @param haService openstack HA service
1272 * @return REST URL of active node
1273 */
1274 public static String getActiveUrl(OpenstackHaService haService) {
1275 return "http://" + haService.getActiveIp().toString() + ":" +
1276 REST_PORT + "/" + OPENSTACK_NETWORKING_REST_PATH + "/";
1277 }
1278
1279 /**
1280 * Returns the REST client instance with given resource path.
1281 *
1282 * @param haService openstack HA service
1283 * @param resourcePath resource path
1284 * @return REST client instance
1285 */
1286 public static WebTarget getActiveClient(OpenstackHaService haService,
1287 String resourcePath) {
1288 HttpAuthenticationFeature feature =
1289 HttpAuthenticationFeature.universal(REST_USER, REST_PASSWORD);
1290 Client client = ClientBuilder.newClient().register(feature);
1291 return client.target(getActiveUrl(haService)).path(resourcePath);
1292 }
1293
1294 /**
1295 * Returns the post response from the active node.
1296 *
1297 * @param haService openstack HA service
1298 * @param resourcePath resource path
1299 * @param input input
1300 * @return post response
1301 */
1302 public static Response syncPost(OpenstackHaService haService,
1303 String resourcePath,
1304 String input) {
1305
1306 log.debug("Sync POST request with {} on {}",
1307 haService.getActiveIp().toString(), resourcePath);
1308
1309 return getActiveClient(haService, resourcePath)
1310 .request(APPLICATION_JSON_TYPE)
1311 .post(Entity.json(input));
1312 }
1313
1314 /**
1315 * Returns the put response from the active node.
1316 *
1317 * @param haService openstack HA service
1318 * @param resourcePath resource path
1319 * @param id resource identifier
1320 * @param input input
1321 * @return put response
1322 */
1323 public static Response syncPut(OpenstackHaService haService,
1324 String resourcePath,
1325 String id, String input) {
1326 return syncPut(haService, resourcePath, null, id, input);
1327 }
1328
1329 /**
1330 * Returns the put response from the active node.
1331 *
1332 * @param haService openstack HA service
1333 * @param resourcePath resource path
1334 * @param id resource identifier
1335 * @param suffix resource suffix
1336 * @param input input
1337 * @return put response
1338 */
1339 public static Response syncPut(OpenstackHaService haService,
1340 String resourcePath,
1341 String suffix,
1342 String id, String input) {
1343
1344 log.debug("Sync PUT request with {} on {}",
1345 haService.getActiveIp().toString(), resourcePath);
1346
1347 String pathStr = "/" + id;
1348
1349 if (suffix != null) {
1350 pathStr += "/" + suffix;
1351 }
1352
1353 return getActiveClient(haService, resourcePath)
1354 .path(pathStr)
1355 .request(APPLICATION_JSON_TYPE)
1356 .put(Entity.json(input));
1357 }
1358
1359 /**
1360 * Returns the delete response from the active node.
1361 *
1362 * @param haService openstack HA service
1363 * @param resourcePath resource path
1364 * @param id resource identifier
1365 * @return delete response
1366 */
1367 public static Response syncDelete(OpenstackHaService haService,
1368 String resourcePath,
1369 String id) {
1370
1371 log.debug("Sync DELETE request with {} on {}",
1372 haService.getActiveIp().toString(), resourcePath);
1373
1374 return getActiveClient(haService, resourcePath)
1375 .path("/" + id)
1376 .request(APPLICATION_JSON_TYPE)
1377 .delete();
1378 }
1379
Jian Li51728702019-05-17 18:38:56 +09001380 /**
1381 * Gets the ovsdb client with supplied openstack node.
1382 *
1383 * @param node openstack node
1384 * @param ovsdbPort openvswitch DB port number
1385 * @param controller openvswitch DB controller instance
1386 * @return ovsdb client instance
1387 */
1388 public static OvsdbClientService getOvsdbClient(OpenstackNode node, int ovsdbPort,
1389 OvsdbController controller) {
1390 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
1391 return controller.getOvsdbClient(ovsdb);
1392 }
1393
1394 /**
1395 * Obtains the name of interface attached to the openstack VM.
1396 *
1397 * @param portId openstack port identifier
1398 * @return name of interface
1399 */
1400 public static String ifaceNameFromOsPortId(String portId) {
1401 if (portId != null) {
1402 return PORT_NAME_PREFIX_VM + StringUtils.substring(portId, 0, TAP_PORT_LENGTH);
1403 }
1404
1405 return null;
1406 }
1407
Jian Li5ecfd1a2018-12-10 11:41:03 +09001408 private static Router getRouterFromSubnet(Subnet subnet,
1409 OpenstackRouterService osRouterService) {
Jian Liebde74d2018-11-14 00:18:57 +09001410 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
1411 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1412 .findAny().orElse(null);
1413 if (osRouterIface == null) {
1414 return null;
1415 }
1416
1417 return osRouterService.router(osRouterIface.getId());
1418 }
1419
Daniel Park7e8c4d82018-08-13 23:47:49 +09001420 private static boolean isDirectPort(String portName) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001421 return portNamePrefixMap().values().stream().anyMatch(portName::startsWith);
Daniel Park7e8c4d82018-08-13 23:47:49 +09001422 }
1423
Daniel Park2ff66b42018-08-01 11:52:45 +09001424 /**
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001425 * Returns GARP packet with supplied floating ip and instance port information.
1426 *
1427 * @param floatingIP floating ip
1428 * @param instancePort instance port
1429 * @param vlanId vlan id
1430 * @return GARP packet
1431 */
1432 private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
1433 InstancePort instancePort,
1434 VlanId vlanId) {
1435 Ethernet ethernet = new Ethernet();
1436 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
1437 ethernet.setSourceMACAddress(instancePort.macAddress());
1438 ethernet.setEtherType(Ethernet.TYPE_ARP);
1439 ethernet.setVlanID(vlanId.id());
1440
1441 ARP arp = new ARP();
1442 arp.setOpCode(ARP.OP_REPLY);
1443 arp.setProtocolType(ARP.PROTO_TYPE_IP);
1444 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
1445
1446 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
1447 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
1448
1449 arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
1450 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1451
Jian Li5ecfd1a2018-12-10 11:41:03 +09001452 arp.setSenderProtocolAddress(valueOf(floatingIP.getFloatingIpAddress()).toInt());
1453 arp.setTargetProtocolAddress(valueOf(floatingIP.getFloatingIpAddress()).toInt());
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001454
1455 ethernet.setPayload(arp);
1456
1457 return ethernet;
1458 }
1459
1460 /**
Jian Lia271b3c2019-09-03 23:10:20 +09001461 * Re-structures the OVS port name.
1462 * The length of OVS port name should be not large than 15.
1463 *
1464 * @param portName original port name
1465 * @return re-structured OVS port name
1466 */
1467 public static String structurePortName(String portName) {
1468
1469 // The size of OVS port name should not be larger than 15
1470 if (portName.length() > PORT_NAME_MAX_LENGTH) {
1471 return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
1472 }
1473
1474 return portName;
1475 }
1476
1477 /**
Jian Lid5727622019-09-11 11:15:16 +09001478 * Obtains flow group key from the given id.
1479 *
1480 * @param groupId flow group identifier
1481 * @return flow group key
1482 */
1483 public static GroupKey getGroupKey(int groupId) {
1484 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
1485 }
1486
1487 /**
Jian Li6a1bcfd2020-01-30 17:41:26 +09001488 * Calculate the broadcast address from given IP address and subnet prefix length.
1489 *
1490 * @param ipAddr IP address
1491 * @param prefixLength subnet prefix length
1492 * @return broadcast address
1493 */
1494 public static String getBroadcastAddr(String ipAddr, int prefixLength) {
1495 String subnet = ipAddr + "/" + prefixLength;
1496 SubnetUtils utils = new SubnetUtils(subnet);
1497 return utils.getInfo().getBroadcastAddress();
1498 }
1499
1500 /**
Jian Li51b844c2018-05-31 10:59:03 +09001501 * Builds up and a complete endpoint URL from gateway node.
1502 *
1503 * @param node gateway node
1504 * @return a complete endpoint URL
1505 */
1506 private static String buildEndpoint(OpenstackNode node) {
1507
Jian Lic704b672018-09-04 18:52:53 +09001508 OpenstackAuth auth = node.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +09001509
1510 StringBuilder endpointSb = new StringBuilder();
1511 endpointSb.append(auth.protocol().name().toLowerCase());
1512 endpointSb.append("://");
Jian Lic704b672018-09-04 18:52:53 +09001513 endpointSb.append(node.keystoneConfig().endpoint());
Jian Li51b844c2018-05-31 10:59:03 +09001514 return endpointSb.toString();
1515 }
1516
1517 /**
1518 * Obtains the SSL config without verifying the certification.
1519 *
1520 * @return SSL config
1521 */
1522 private static Config getSslConfig() {
1523 // we bypass the SSL certification verification for now
1524 // TODO: verify server side SSL using a given certification
1525 Config config = Config.newConfig().withSSLVerificationDisabled();
1526
1527 TrustManager[] trustAllCerts = new TrustManager[]{
1528 new X509TrustManager() {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001529 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001530 public X509Certificate[] getAcceptedIssuers() {
1531 return null;
1532 }
1533
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001534 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001535 public void checkClientTrusted(X509Certificate[] certs,
1536 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001537 return;
Jian Li51b844c2018-05-31 10:59:03 +09001538 }
1539
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001540 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001541 public void checkServerTrusted(X509Certificate[] certs,
1542 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001543 return;
Jian Li51b844c2018-05-31 10:59:03 +09001544 }
1545 }
1546 };
1547
1548 HostnameVerifier allHostsValid = (hostname, session) -> true;
1549
1550 try {
1551 SSLContext sc = SSLContext.getInstance(SSL_TYPE);
1552 sc.init(null, trustAllCerts,
1553 new java.security.SecureRandom());
1554 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
1555 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
1556
1557 config.withSSLContext(sc);
1558 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001559 log.error("Failed to access OpenStack service due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +09001560 return null;
1561 }
1562
1563 return config;
1564 }
1565
1566 /**
1567 * Obtains the facing object with given openstack perspective.
1568 *
1569 * @param perspective keystone perspective
1570 * @return facing object
1571 */
1572 private static Facing getFacing(Perspective perspective) {
1573
1574 switch (perspective) {
1575 case PUBLIC:
1576 return Facing.PUBLIC;
1577 case ADMIN:
1578 return Facing.ADMIN;
1579 case INTERNAL:
1580 return Facing.INTERNAL;
1581 default:
1582 return null;
1583 }
1584 }
1585
1586 /**
1587 * Obtains gateway instance by giving index number.
1588 *
1589 * @param gws a collection of gateway nodes
1590 * @param index index number
1591 * @return gateway instance
1592 */
1593 private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
1594 Map<String, OpenstackNode> hashMap = new HashMap<>();
1595 gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
1596 TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
1597 Iterator<String> iteratorKey = treeMap.keySet().iterator();
1598
1599 int intIndex = 0;
1600 OpenstackNode gw = null;
1601 while (iteratorKey.hasNext()) {
1602 String key = iteratorKey.next();
1603
1604 if (intIndex == index) {
1605 gw = treeMap.get(key);
1606 }
1607 intIndex++;
1608 }
1609 return gw;
1610 }
Jian Li40f032a2019-10-02 20:36:09 +09001611
1612 private static void print(String format, Object... args) {
1613 System.out.println(String.format(format, args));
1614 }
Jian Li63430202018-08-30 16:24:09 +09001615}