blob: 16dcc2142b7f6f53fafe453c7189c8f700ac906d [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 Li63430202018-08-30 16:24:09 +090029import org.apache.http.HttpException;
30import org.apache.http.HttpRequest;
31import org.apache.http.HttpResponse;
32import org.apache.http.impl.io.DefaultHttpRequestParser;
33import org.apache.http.impl.io.DefaultHttpRequestWriter;
34import org.apache.http.impl.io.DefaultHttpResponseParser;
35import org.apache.http.impl.io.DefaultHttpResponseWriter;
36import org.apache.http.impl.io.HttpTransportMetricsImpl;
37import org.apache.http.impl.io.SessionInputBufferImpl;
38import org.apache.http.impl.io.SessionOutputBufferImpl;
39import org.apache.http.io.HttpMessageWriter;
Daniel Parka73c2362018-09-17 17:43:25 +090040import org.apache.sshd.client.SshClient;
41import org.apache.sshd.client.channel.ClientChannel;
42import org.apache.sshd.client.channel.ClientChannelEvent;
43import org.apache.sshd.client.future.OpenFuture;
44import org.apache.sshd.client.session.ClientSession;
45import org.apache.sshd.common.util.io.NoCloseInputStream;
Jian Li7b8c3682019-05-12 13:57:15 +090046import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090047import org.onlab.packet.ARP;
48import org.onlab.packet.Ethernet;
49import org.onlab.packet.Ip4Address;
Daniel Parka73c2362018-09-17 17:43:25 +090050import org.onlab.packet.IpAddress;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090051import org.onlab.packet.MacAddress;
52import org.onlab.packet.VlanId;
Jian Li7f70bb72018-07-06 23:35:30 +090053import org.onosproject.cfg.ConfigProperty;
Jian Li1064e4f2018-05-29 16:16:53 +090054import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090055import org.onosproject.net.PortNumber;
Daniel Park95f73312018-07-31 15:48:34 +090056import org.onosproject.net.device.DeviceService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090057import org.onosproject.net.flow.DefaultTrafficTreatment;
58import org.onosproject.net.flow.TrafficTreatment;
Jian Lie87c2712019-09-11 11:15:16 +090059import org.onosproject.net.group.DefaultGroupKey;
60import org.onosproject.net.group.GroupKey;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090061import org.onosproject.net.packet.DefaultOutboundPacket;
62import org.onosproject.net.packet.PacketService;
Daniel Park7e8c4d82018-08-13 23:47:49 +090063import org.onosproject.openstacknetworking.api.Constants.VnicType;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090064import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Lia171a432018-06-11 11:52:11 +090065import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li7b8c3682019-05-12 13:57:15 +090066import org.onosproject.openstacknetworking.api.OpenstackHaService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090067import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li24ec59f2018-05-23 19:01:25 +090068import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li7f70bb72018-07-06 23:35:30 +090069import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Liebde74d2018-11-14 00:18:57 +090070import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Liec5c32b2018-07-13 14:28:58 +090071import org.onosproject.openstacknetworking.impl.DefaultInstancePort;
Jian Li51b844c2018-05-31 10:59:03 +090072import org.onosproject.openstacknode.api.OpenstackAuth;
73import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
Jian Li1064e4f2018-05-29 16:16:53 +090074import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Parka73c2362018-09-17 17:43:25 +090075import org.onosproject.openstacknode.api.OpenstackSshAuth;
Jian Li51728702019-05-17 18:38:56 +090076import org.onosproject.ovsdb.controller.OvsdbClientService;
77import org.onosproject.ovsdb.controller.OvsdbController;
78import org.onosproject.ovsdb.controller.OvsdbNodeId;
Jian Li51b844c2018-05-31 10:59:03 +090079import org.openstack4j.api.OSClient;
80import org.openstack4j.api.client.IOSClientBuilder;
81import org.openstack4j.api.exceptions.AuthenticationException;
82import org.openstack4j.api.types.Facing;
83import org.openstack4j.core.transport.Config;
Jian Li091d8d22018-02-20 10:42:06 +090084import org.openstack4j.core.transport.ObjectMapperSingleton;
85import org.openstack4j.model.ModelEntity;
Jian Li51b844c2018-05-31 10:59:03 +090086import org.openstack4j.model.common.Identifier;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090087import org.openstack4j.model.network.ExternalGateway;
Jian Liecbf10c2019-10-02 20:36:09 +090088import org.openstack4j.model.network.IP;
Jian Li24ec59f2018-05-23 19:01:25 +090089import org.openstack4j.model.network.NetFloatingIP;
90import org.openstack4j.model.network.Network;
Jian Lia171a432018-06-11 11:52:11 +090091import org.openstack4j.model.network.Port;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090092import org.openstack4j.model.network.Router;
Jian Li0b564282018-06-20 00:50:53 +090093import org.openstack4j.model.network.RouterInterface;
Jian Liecbf10c2019-10-02 20:36:09 +090094import org.openstack4j.model.network.SecurityGroup;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090095import org.openstack4j.model.network.Subnet;
Jian Li51b844c2018-05-31 10:59:03 +090096import org.openstack4j.openstack.OSFactory;
Jian Li0b564282018-06-20 00:50:53 +090097import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
Jian Li091d8d22018-02-20 10:42:06 +090098import org.slf4j.Logger;
99import org.slf4j.LoggerFactory;
100
Jian Li63430202018-08-30 16:24:09 +0900101import javax.crypto.Mac;
102import javax.crypto.spec.SecretKeySpec;
Jian Li51b844c2018-05-31 10:59:03 +0900103import javax.net.ssl.HostnameVerifier;
104import javax.net.ssl.HttpsURLConnection;
105import javax.net.ssl.SSLContext;
106import javax.net.ssl.TrustManager;
107import javax.net.ssl.X509TrustManager;
Jian Li7b8c3682019-05-12 13:57:15 +0900108import javax.ws.rs.client.Client;
109import javax.ws.rs.client.ClientBuilder;
110import javax.ws.rs.client.Entity;
111import javax.ws.rs.client.WebTarget;
112import javax.ws.rs.core.Response;
Jian Li63430202018-08-30 16:24:09 +0900113import java.io.ByteArrayInputStream;
114import java.io.ByteArrayOutputStream;
Jian Li0b564282018-06-20 00:50:53 +0900115import java.io.IOException;
Jian Li091d8d22018-02-20 10:42:06 +0900116import java.io.InputStream;
Daniel Parka73c2362018-09-17 17:43:25 +0900117import java.io.OutputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900118import java.nio.ByteBuffer;
Jian Li51b844c2018-05-31 10:59:03 +0900119import java.security.cert.X509Certificate;
Daniel Parka73c2362018-09-17 17:43:25 +0900120import java.util.Collection;
Jian Li1064e4f2018-05-29 16:16:53 +0900121import java.util.HashMap;
122import java.util.Iterator;
Jian Liecbf10c2019-10-02 20:36:09 +0900123import java.util.List;
Jian Li1064e4f2018-05-29 16:16:53 +0900124import java.util.Map;
Daniel Park95f73312018-07-31 15:48:34 +0900125import java.util.Objects;
Jian Li7f70bb72018-07-06 23:35:30 +0900126import java.util.Optional;
Jian Li1064e4f2018-05-29 16:16:53 +0900127import java.util.Set;
128import java.util.TreeMap;
Daniel Parka73c2362018-09-17 17:43:25 +0900129import java.util.concurrent.TimeUnit;
Jian Liecbf10c2019-10-02 20:36:09 +0900130import java.util.stream.Collectors;
Jian Li091d8d22018-02-20 10:42:06 +0900131
132import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
Daniel Park95f73312018-07-31 15:48:34 +0900133import static com.google.common.base.Preconditions.checkNotNull;
Jian Li7f024de2018-07-07 03:51:02 +0900134import static com.google.common.base.Strings.isNullOrEmpty;
Jian Li7b8c3682019-05-12 13:57:15 +0900135import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
136import static org.apache.commons.io.IOUtils.toInputStream;
Jian Li5ecfd1a2018-12-10 11:41:03 +0900137import static org.onlab.packet.Ip4Address.valueOf;
Daniel Park95f73312018-07-31 15:48:34 +0900138import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka73c2362018-09-17 17:43:25 +0900139import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Jian Lia97cec42019-10-31 22:24:17 +0900140import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
Jian Liecbf10c2019-10-02 20:36:09 +0900141import static org.onosproject.openstacknetworking.api.Constants.FLOATING_IP_FORMAT;
142import static org.onosproject.openstacknetworking.api.Constants.NETWORK_FORMAT;
Jian Li7b8c3682019-05-12 13:57:15 +0900143import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_REST_PATH;
Daniel Parkc4d06402018-05-28 15:57:37 +0900144import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
145import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
Jian Liecbf10c2019-10-02 20:36:09 +0900146import static org.onosproject.openstacknetworking.api.Constants.PORT_FORMAT;
Daniel Park7e8c4d82018-08-13 23:47:49 +0900147import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
148import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
Jian Li7b8c3682019-05-12 13:57:15 +0900149import static org.onosproject.openstacknetworking.api.Constants.REST_PASSWORD;
150import static org.onosproject.openstacknetworking.api.Constants.REST_PORT;
151import static org.onosproject.openstacknetworking.api.Constants.REST_USER;
152import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
Jian Liecbf10c2019-10-02 20:36:09 +0900153import static org.onosproject.openstacknetworking.api.Constants.ROUTER_FORMAT;
154import static org.onosproject.openstacknetworking.api.Constants.ROUTER_INTF_FORMAT;
155import static org.onosproject.openstacknetworking.api.Constants.SECURITY_GROUP_FORMAT;
156import static org.onosproject.openstacknetworking.api.Constants.SUBNET_FORMAT;
Daniel Parkec9d1132018-08-19 11:18:03 +0900157import static org.onosproject.openstacknetworking.api.Constants.UNSUPPORTED_VENDOR;
Ray Milkey9dc57392018-06-08 08:52:31 -0700158import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
Jian Li0b564282018-06-20 00:50:53 +0900159import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
Jian Li091d8d22018-02-20 10:42:06 +0900160
161/**
162 * An utility that used in openstack networking app.
163 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900164public final class OpenstackNetworkingUtil {
Jian Li091d8d22018-02-20 10:42:06 +0900165
Daniel Park95985382018-07-23 11:38:07 +0900166 private static final Logger log = LoggerFactory.getLogger(OpenstackNetworkingUtil.class);
Jian Li091d8d22018-02-20 10:42:06 +0900167
Daniel Parkc4d06402018-05-28 15:57:37 +0900168 private static final int HEX_RADIX = 16;
Jian Li51b844c2018-05-31 10:59:03 +0900169 private static final String ZERO_FUNCTION_NUMBER = "0";
Daniel Parkc4d06402018-05-28 15:57:37 +0900170 private static final String PREFIX_DEVICE_NUMBER = "s";
171 private static final String PREFIX_FUNCTION_NUMBER = "f";
172
Jian Li51b844c2018-05-31 10:59:03 +0900173 // keystone endpoint related variables
174 private static final String DOMAIN_DEFAULT = "default";
175 private static final String KEYSTONE_V2 = "v2.0";
176 private static final String KEYSTONE_V3 = "v3";
Jian Li51b844c2018-05-31 10:59:03 +0900177 private static final String SSL_TYPE = "SSL";
178
Jian Li7f024de2018-07-07 03:51:02 +0900179 private static final String PROXY_MODE = "proxy";
180 private static final String BROADCAST_MODE = "broadcast";
181
Jian Licad36c72018-09-13 17:44:54 +0900182 private static final String ENABLE = "enable";
183 private static final String DISABLE = "disable";
184
Jian Li63430202018-08-30 16:24:09 +0900185 private static final int HTTP_PAYLOAD_BUFFER = 8 * 1024;
186
187 private static final String HMAC_SHA256 = "HmacSHA256";
188
Jian Li24ec59f2018-05-23 19:01:25 +0900189 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
190
Daniel Parka73c2362018-09-17 17:43:25 +0900191 private static final String DL_DST = "dl_dst=";
192 private static final String NW_DST = "nw_dst=";
193 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
194 private static final String IN_PORT = "in_port=";
195 private static final String NW_SRC = "nw_src=";
196 private static final String COMMA = ",";
197 private static final String TUN_ID = "tun_id=";
198
Jian Liecbf10c2019-10-02 20:36:09 +0900199 private static final String DEVICE_OWNER_GW = "network:router_gateway";
200 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
201
202 private static final String NOT_AVAILABLE = "N/A";
203
Daniel Parka73c2362018-09-17 17:43:25 +0900204 private static final long TIMEOUT_MS = 5000;
205 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
206 private static final int SSH_PORT = 22;
207
Jian Li51728702019-05-17 18:38:56 +0900208 private static final int TAP_PORT_LENGTH = 11;
Jian Li62116942019-09-03 23:10:20 +0900209 private static final int PORT_NAME_MAX_LENGTH = 15;
Jian Li51728702019-05-17 18:38:56 +0900210
Jian Li091d8d22018-02-20 10:42:06 +0900211 /**
212 * Prevents object instantiation from external.
213 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900214 private OpenstackNetworkingUtil() {
Jian Li091d8d22018-02-20 10:42:06 +0900215 }
216
217 /**
218 * Interprets JSON string to corresponding openstack model entity object.
219 *
Jian Li7b8c3682019-05-12 13:57:15 +0900220 * @param inputStr JSON string
Jian Li091d8d22018-02-20 10:42:06 +0900221 * @param entityClazz openstack model entity class
222 * @return openstack model entity object
223 */
Jian Li7b8c3682019-05-12 13:57:15 +0900224 public static ModelEntity jsonToModelEntity(String inputStr, Class entityClazz) {
Jian Li091d8d22018-02-20 10:42:06 +0900225 ObjectMapper mapper = new ObjectMapper();
226 try {
Jian Li7b8c3682019-05-12 13:57:15 +0900227 InputStream input = toInputStream(inputStr, REST_UTF8);
Jian Li091d8d22018-02-20 10:42:06 +0900228 JsonNode jsonTree = mapper.enable(INDENT_OUTPUT).readTree(input);
229 log.trace(new ObjectMapper().writeValueAsString(jsonTree));
230 return ObjectMapperSingleton.getContext(entityClazz)
231 .readerFor(entityClazz)
232 .readValue(jsonTree);
233 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900234 log.error("Exception occurred because of {}", e);
Jian Li091d8d22018-02-20 10:42:06 +0900235 throw new IllegalArgumentException();
236 }
237 }
Jian Lieb9f77d2018-02-20 11:25:45 +0900238
239 /**
240 * Converts openstack model entity object into JSON object.
241 *
242 * @param entity openstack model entity object
243 * @param entityClazz openstack model entity class
244 * @return JSON object
245 */
246 public static ObjectNode modelEntityToJson(ModelEntity entity, Class entityClazz) {
247 ObjectMapper mapper = new ObjectMapper();
248 try {
249 String strModelEntity = ObjectMapperSingleton.getContext(entityClazz)
250 .writerFor(entityClazz)
251 .writeValueAsString(entity);
252 log.trace(strModelEntity);
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900253 return (ObjectNode) mapper.readTree(strModelEntity.getBytes(Charsets.UTF_8));
Daniel Park95985382018-07-23 11:38:07 +0900254 } catch (IOException e) {
255 log.error("IOException occurred because of {}", e.toString());
Jian Lieb9f77d2018-02-20 11:25:45 +0900256 throw new IllegalStateException();
257 }
258 }
Jian Li1064e4f2018-05-29 16:16:53 +0900259
260 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900261 * Obtains a floating IP associated with the given instance port.
262 *
263 * @param port instance port
264 * @param fips a collection of floating IPs
265 * @return associated floating IP
266 */
267 public static NetFloatingIP associatedFloatingIp(InstancePort port,
268 Set<NetFloatingIP> fips) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900269 for (NetFloatingIP fip : fips) {
270 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
271 continue;
Jian Li24ec59f2018-05-23 19:01:25 +0900272 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900273 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
274 continue;
275 }
Jian Li6bc29d92018-10-02 13:55:05 +0900276 if (fip.getFixedIpAddress().equals(port.ipAddress().toString()) &&
277 fip.getPortId().equals(port.portId())) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900278 return fip;
279 }
Jian Li24ec59f2018-05-23 19:01:25 +0900280 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900281
Jian Li24ec59f2018-05-23 19:01:25 +0900282 return null;
283 }
284
285 /**
286 * Checks whether the given floating IP is associated with a VM.
287 *
288 * @param service openstack network service
289 * @param fip floating IP
290 * @return true if the given floating IP associated with a VM, false otherwise
291 */
292 public static boolean isAssociatedWithVM(OpenstackNetworkService service,
293 NetFloatingIP fip) {
294 Port osPort = service.port(fip.getPortId());
295 if (osPort == null) {
296 return false;
297 }
298
299 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
300 Network osNet = service.network(osPort.getNetworkId());
301 if (osNet == null) {
302 final String errorFormat = ERR_FLOW + "no network(%s) exists";
303 final String error = String.format(errorFormat,
304 fip.getFloatingIpAddress(), osPort.getNetworkId());
305 throw new IllegalStateException(error);
306 }
307 return true;
308 } else {
309 return false;
310 }
311 }
312
313 /**
Jian Lia171a432018-06-11 11:52:11 +0900314 * Obtains the gateway node by instance port.
315 *
316 * @param gateways a collection of gateway nodes
317 * @param instPort instance port
318 * @return a gateway node
319 */
320 public static OpenstackNode getGwByInstancePort(Set<OpenstackNode> gateways,
321 InstancePort instPort) {
322 OpenstackNode gw = null;
323 if (instPort != null && instPort.deviceId() != null) {
324 gw = getGwByComputeDevId(gateways, instPort.deviceId());
325 }
326 return gw;
327 }
328
329 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900330 * Obtains the gateway node by device in compute node. Note that the gateway
331 * node is determined by device's device identifier.
332 *
333 * @param gws a collection of gateway nodes
334 * @param deviceId device identifier
335 * @return a gateway node
336 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900337 public static OpenstackNode getGwByComputeDevId(Set<OpenstackNode> gws,
338 DeviceId deviceId) {
Jian Li1064e4f2018-05-29 16:16:53 +0900339 int numOfGw = gws.size();
340
341 if (numOfGw == 0) {
342 return null;
343 }
344
345 int gwIndex = Math.abs(deviceId.hashCode()) % numOfGw;
346
347 return getGwByIndex(gws, gwIndex);
348 }
349
Jian Li51b844c2018-05-31 10:59:03 +0900350 /**
351 * Obtains a connected openstack client.
352 *
353 * @param osNode openstack node
354 * @return a connected openstack client
355 */
356 public static OSClient getConnectedClient(OpenstackNode osNode) {
Jian Lic704b672018-09-04 18:52:53 +0900357 OpenstackAuth auth = osNode.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +0900358 String endpoint = buildEndpoint(osNode);
359 Perspective perspective = auth.perspective();
Jian Li1064e4f2018-05-29 16:16:53 +0900360
Jian Li51b844c2018-05-31 10:59:03 +0900361 Config config = getSslConfig();
Jian Li1064e4f2018-05-29 16:16:53 +0900362
Jian Li51b844c2018-05-31 10:59:03 +0900363 try {
364 if (endpoint.contains(KEYSTONE_V2)) {
365 IOSClientBuilder.V2 builder = OSFactory.builderV2()
366 .endpoint(endpoint)
367 .tenantName(auth.project())
368 .credentials(auth.username(), auth.password())
369 .withConfig(config);
370
371 if (perspective != null) {
372 builder.perspective(getFacing(perspective));
373 }
374
375 return builder.authenticate();
376 } else if (endpoint.contains(KEYSTONE_V3)) {
377
378 Identifier project = Identifier.byName(auth.project());
379 Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
380
381 IOSClientBuilder.V3 builder = OSFactory.builderV3()
382 .endpoint(endpoint)
383 .credentials(auth.username(), auth.password(), domain)
384 .scopeToProject(project, domain)
385 .withConfig(config);
386
387 if (perspective != null) {
388 builder.perspective(getFacing(perspective));
389 }
390
391 return builder.authenticate();
392 } else {
393 log.warn("Unrecognized keystone version type");
394 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900395 }
Jian Li51b844c2018-05-31 10:59:03 +0900396 } catch (AuthenticationException e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900397 log.error("Authentication failed due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +0900398 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900399 }
Jian Li1064e4f2018-05-29 16:16:53 +0900400 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900401
402 /**
Jian Lia97cec42019-10-31 22:24:17 +0900403 * Checks whether the given openstack port is smart NIC capable.
404 *
405 * @param port openstack port
406 * @return true if the given port is smart NIC capable, false otherwise
407 */
408 public static boolean isSmartNicCapable(Port port) {
409 if (port.getProfile() != null && port.getvNicType().equals(DIRECT)) {
410 String vendorInfo = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
411 if (portNamePrefixMap().containsKey(vendorInfo)) {
412 log.debug("Port {} is a Smart NIC capable port.", port.getId());
413 return true;
414 }
415 return false;
416 }
417 return false;
418 }
419
420 /**
Daniel Parkc4d06402018-05-28 15:57:37 +0900421 * Extract the interface name with the supplied port.
422 *
423 * @param port port
424 * @return interface name
425 */
426 public static String getIntfNameFromPciAddress(Port port) {
Daniel Parkff178ba2018-11-23 15:57:24 +0900427 String intfName;
428
Daniel Park95985382018-07-23 11:38:07 +0900429 if (port.getProfile() == null || port.getProfile().isEmpty()) {
Jian Li51b844c2018-05-31 10:59:03 +0900430 log.error("Port profile is not found");
431 return null;
432 }
433
Daniel Park95985382018-07-23 11:38:07 +0900434 if (!port.getProfile().containsKey(PCISLOT) ||
435 Strings.isNullOrEmpty(port.getProfile().get(PCISLOT).toString())) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900436 log.error("Failed to retrieve the interface name because of no " +
437 "pci_slot information from the port");
Daniel Parkc4d06402018-05-28 15:57:37 +0900438 return null;
439 }
Jian Li51b844c2018-05-31 10:59:03 +0900440
Daniel Parkff178ba2018-11-23 15:57:24 +0900441 String vendorInfoForPort = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
442
443 if (!portNamePrefixMap().containsKey(vendorInfoForPort)) {
444 log.debug("{} is an non-smart NIC prefix.", vendorInfoForPort);
445 return UNSUPPORTED_VENDOR;
446 }
447
448 String portNamePrefix = portNamePrefixMap().get(vendorInfoForPort);
449
Daniel Parkc4d06402018-05-28 15:57:37 +0900450 String busNumHex = port.getProfile().get(PCISLOT).toString().split(":")[1];
451 String busNumDecimal = String.valueOf(Integer.parseInt(busNumHex, HEX_RADIX));
452
453 String deviceNumHex = port.getProfile().get(PCISLOT).toString()
454 .split(":")[2]
455 .split("\\.")[0];
456 String deviceNumDecimal = String.valueOf(Integer.parseInt(deviceNumHex, HEX_RADIX));
457
458 String functionNumHex = port.getProfile().get(PCISLOT).toString()
459 .split(":")[2]
460 .split("\\.")[1];
461 String functionNumDecimal = String.valueOf(Integer.parseInt(functionNumHex, HEX_RADIX));
462
Daniel Parkc4d06402018-05-28 15:57:37 +0900463 if (functionNumDecimal.equals(ZERO_FUNCTION_NUMBER)) {
464 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal;
465 } else {
466 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal
467 + PREFIX_FUNCTION_NUMBER + functionNumDecimal;
468 }
469
470 return intfName;
471 }
Jian Li51b844c2018-05-31 10:59:03 +0900472
473 /**
Daniel Park95f73312018-07-31 15:48:34 +0900474 * Check if the given interface is added to the given device or not.
475 *
476 * @param deviceId device ID
477 * @param intfName interface name
478 * @param deviceService device service
479 * @return true if the given interface is added to the given device or false otherwise
480 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900481 public static boolean hasIntfAleadyInDevice(DeviceId deviceId,
482 String intfName,
483 DeviceService deviceService) {
Daniel Park95f73312018-07-31 15:48:34 +0900484 checkNotNull(deviceId);
485 checkNotNull(intfName);
486
Jian Li5ecfd1a2018-12-10 11:41:03 +0900487 return deviceService.getPorts(deviceId).stream().anyMatch(port ->
488 Objects.equals(port.annotations().value(PORT_NAME), intfName));
Daniel Park95f73312018-07-31 15:48:34 +0900489 }
490
491 /**
Jian Li0b564282018-06-20 00:50:53 +0900492 * Adds router interfaces to openstack admin service.
Jian Li0b564282018-06-20 00:50:53 +0900493 *
494 * @param osPort port
495 * @param adminService openstack admin service
496 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900497 public static void addRouterIface(Port osPort,
498 OpenstackRouterAdminService adminService) {
Jian Li0b564282018-06-20 00:50:53 +0900499 osPort.getFixedIps().forEach(p -> {
500 JsonNode jsonTree = new ObjectMapper().createObjectNode()
501 .put("id", osPort.getDeviceId())
502 .put("tenant_id", osPort.getTenantId())
503 .put("subnet_id", p.getSubnetId())
504 .put("port_id", osPort.getId());
505 try {
506 RouterInterface rIface = getContext(NeutronRouterInterface.class)
507 .readerFor(NeutronRouterInterface.class)
508 .readValue(jsonTree);
509 if (adminService.routerInterface(rIface.getPortId()) != null) {
510 adminService.updateRouterInterface(rIface);
511 } else {
512 adminService.addRouterInterface(rIface);
513 }
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900514 } catch (IOException e) {
515 log.error("IOException occurred because of {}", e);
Jian Li0b564282018-06-20 00:50:53 +0900516 }
517 });
518 }
519
520 /**
Jian Liecbf10c2019-10-02 20:36:09 +0900521 * Prints openstack security group.
522 *
523 * @param osSg openstack security group
524 */
525 public static void printSecurityGroup(SecurityGroup osSg) {
526 print(SECURITY_GROUP_FORMAT, osSg.getId(), osSg.getName());
527 }
528
529 /**
530 * Prints openstack network.
531 *
532 * @param osNet openstack network
533 */
534 public static void printNetwork(Network osNet) {
535 final String strNet = String.format(NETWORK_FORMAT,
536 osNet.getId(),
537 osNet.getName(),
538 osNet.getProviderSegID(),
539 osNet.getSubnets());
540 print(strNet);
541 }
542
543 /**
544 * Prints openstack subnet.
545 *
546 * @param osSubnet openstack subnet
547 * @param osNetService openstack network service
548 */
549 public static void printSubnet(Subnet osSubnet,
550 OpenstackNetworkService osNetService) {
551 final Network network = osNetService.network(osSubnet.getNetworkId());
552 final String netName = network == null ? NOT_AVAILABLE : network.getName();
553 final String strSubnet = String.format(SUBNET_FORMAT,
554 osSubnet.getId(),
555 netName,
556 osSubnet.getCidr());
557 print(strSubnet);
558 }
559
560 /**
561 * Prints openstack port.
562 *
563 * @param osPort openstack port
564 * @param osNetService openstack network service
565 */
566 public static void printPort(Port osPort,
567 OpenstackNetworkService osNetService) {
568 List<String> fixedIps = osPort.getFixedIps().stream()
569 .map(IP::getIpAddress)
570 .collect(Collectors.toList());
571 final Network network = osNetService.network(osPort.getNetworkId());
572 final String netName = network == null ? NOT_AVAILABLE : network.getName();
573 final String strPort = String.format(PORT_FORMAT,
574 osPort.getId(),
575 netName,
576 osPort.getMacAddress(),
577 fixedIps.isEmpty() ? "" : fixedIps);
578 print(strPort);
579 }
580
581 /**
582 * Prints openstack router.
583 *
584 * @param osRouter openstack router
585 * @param osNetService openstack network service
586 */
587 public static void printRouter(Router osRouter,
588 OpenstackNetworkService osNetService) {
589 List<String> externals = osNetService.ports().stream()
590 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
591 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_GW))
592 .flatMap(osPort -> osPort.getFixedIps().stream())
593 .map(IP::getIpAddress)
594 .collect(Collectors.toList());
595
596 List<String> internals = osNetService.ports().stream()
597 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
598 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
599 .flatMap(osPort -> osPort.getFixedIps().stream())
600 .map(IP::getIpAddress)
601 .collect(Collectors.toList());
602
603 final String strRouter = String.format(ROUTER_FORMAT,
604 osRouter.getId(),
605 osRouter.getName(),
606 externals.isEmpty() ? "" : externals,
607 internals.isEmpty() ? "" : internals);
608 print(strRouter);
609 }
610
611 /**
612 * Prints openstack router interface.
613 *
614 * @param osRouterIntf openstack router interface
615 */
616 public static void printRouterIntf(RouterInterface osRouterIntf) {
617 final String strRouterIntf = String.format(ROUTER_INTF_FORMAT,
618 osRouterIntf.getId(),
619 osRouterIntf.getTenantId(),
620 osRouterIntf.getSubnetId());
621 print(strRouterIntf);
622 }
623
624 /**
625 * Prints openstack floating IP.
626 *
627 * @param floatingIp floating IP
628 */
629 public static void printFloatingIp(NetFloatingIP floatingIp) {
630 final String strFloating = String.format(FLOATING_IP_FORMAT,
631 floatingIp.getId(),
632 floatingIp.getFloatingIpAddress(),
633 Strings.isNullOrEmpty(floatingIp.getFixedIpAddress()) ?
634 "" : floatingIp.getFixedIpAddress());
635 print(strFloating);
636 }
637
638 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900639 * Obtains the property value with specified property key name.
640 *
641 * @param properties a collection of properties
642 * @param name key name
643 * @return mapping value
644 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900645 public static String getPropertyValue(Set<ConfigProperty> properties,
646 String name) {
Jian Li7f70bb72018-07-06 23:35:30 +0900647 Optional<ConfigProperty> property =
648 properties.stream().filter(p -> p.name().equals(name)).findFirst();
649 return property.map(ConfigProperty::value).orElse(null);
650 }
651
652 /**
Jian Li9d35bd62018-10-13 01:43:24 +0900653 * Obtains the boolean property value with specified property key name.
654 *
655 * @param properties a collection of properties
656 * @param name key name
657 * @return mapping value
658 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900659 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties,
660 String name) {
Jian Li9d35bd62018-10-13 01:43:24 +0900661 Optional<ConfigProperty> property =
662 properties.stream().filter(p -> p.name().equals(name)).findFirst();
663
664 return property.map(ConfigProperty::asBoolean).orElse(false);
665 }
666
667 /**
Jian Lif1efbe52018-07-17 23:20:16 +0900668 * Prints out the JSON string in pretty format.
669 *
670 * @param mapper Object mapper
671 * @param jsonString JSON string
672 * @return pretty formatted JSON string
673 */
674 public static String prettyJson(ObjectMapper mapper, String jsonString) {
675 try {
676 Object jsonObject = mapper.readValue(jsonString, Object.class);
677 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
Daniel Park2ff66b42018-08-01 11:52:45 +0900678 } catch (JsonParseException e) {
679 log.debug("JsonParseException caused by {}", e);
680 } catch (JsonMappingException e) {
681 log.debug("JsonMappingException caused by {}", e);
682 } catch (JsonProcessingException e) {
683 log.debug("JsonProcessingException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900684 } catch (IOException e) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900685 log.debug("IOException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900686 }
687 return null;
688 }
689
690 /**
Jian Li7f024de2018-07-07 03:51:02 +0900691 * Checks the validity of ARP mode.
692 *
693 * @param arpMode ARP mode
694 * @return returns true if the ARP mode is valid, false otherwise
695 */
696 public static boolean checkArpMode(String arpMode) {
697
698 if (isNullOrEmpty(arpMode)) {
699 return false;
700 } else {
701 return arpMode.equals(PROXY_MODE) || arpMode.equals(BROADCAST_MODE);
702 }
703 }
704
705 /**
Jian Licad36c72018-09-13 17:44:54 +0900706 * Checks the validity of activation flag.
707 *
708 * @param activationFlag activation flag
709 * @return returns true if the activation flag is valid, false otherwise
710 */
711 public static boolean checkActivationFlag(String activationFlag) {
712
713 switch (activationFlag) {
714 case ENABLE:
715 return true;
716 case DISABLE:
717 return false;
718 default:
719 throw new IllegalArgumentException("The given activation flag is not valid!");
720 }
721 }
722
723 /**
Jian Liec5c32b2018-07-13 14:28:58 +0900724 * Swaps current location with old location info.
725 * The revised instance port will be used to mod the flow rules after migration.
726 *
727 * @param instPort instance port
728 * @return location swapped instance port
729 */
730 public static InstancePort swapStaleLocation(InstancePort instPort) {
731 return DefaultInstancePort.builder()
732 .deviceId(instPort.oldDeviceId())
733 .portNumber(instPort.oldPortNumber())
734 .state(instPort.state())
735 .ipAddress(instPort.ipAddress())
736 .macAddress(instPort.macAddress())
737 .networkId(instPort.networkId())
738 .portId(instPort.portId())
739 .build();
740 }
741
742 /**
Daniel Park2ff66b42018-08-01 11:52:45 +0900743 * Compares two router interfaces are equal.
744 * Will be remove this after Openstack4j implements equals.
745 *
746 * @param routerInterface1 router interface
747 * @param routerInterface2 router interface
748 * @return returns true if two router interfaces are equal, false otherwise
749 */
Jian Li63430202018-08-30 16:24:09 +0900750 public static boolean routerInterfacesEquals(RouterInterface routerInterface1,
751 RouterInterface routerInterface2) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900752 return Objects.equals(routerInterface1.getId(), routerInterface2.getId()) &&
753 Objects.equals(routerInterface1.getPortId(), routerInterface2.getPortId()) &&
754 Objects.equals(routerInterface1.getSubnetId(), routerInterface2.getSubnetId()) &&
755 Objects.equals(routerInterface1.getTenantId(), routerInterface2.getTenantId());
756 }
757
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900758 /**
759 * Returns the vnic type of given port.
760 *
761 * @param portName port name
762 * @return vnit type
763 */
Daniel Park7e8c4d82018-08-13 23:47:49 +0900764 public static VnicType vnicType(String portName) {
765 if (portName.startsWith(PORT_NAME_PREFIX_VM) ||
766 portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM)) {
767 return VnicType.NORMAL;
768 } else if (isDirectPort(portName)) {
769 return VnicType.DIRECT;
770 } else {
771 return VnicType.UNSUPPORTED;
772 }
773 }
774
Jian Li63430202018-08-30 16:24:09 +0900775 /**
776 * Deserializes raw payload into HttpRequest object.
777 *
778 * @param rawData raw http payload
779 * @return HttpRequest object
780 */
781 public static HttpRequest parseHttpRequest(byte[] rawData) {
782 SessionInputBufferImpl sessionInputBuffer =
783 new SessionInputBufferImpl(
784 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
785 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900786 DefaultHttpRequestParser requestParser =
787 new DefaultHttpRequestParser(sessionInputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900788 try {
789 return requestParser.parse();
790 } catch (IOException | HttpException e) {
791 log.warn("Failed to parse HttpRequest, due to {}", e);
792 }
793
794 return null;
795 }
796
797 /**
798 * Serializes HttpRequest object to byte array.
799 *
800 * @param request http request object
801 * @return byte array
802 */
803 public static byte[] unparseHttpRequest(HttpRequest request) {
804 try {
805 SessionOutputBufferImpl sessionOutputBuffer =
806 new SessionOutputBufferImpl(
807 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
808
809 ByteArrayOutputStream baos = new ByteArrayOutputStream();
810 sessionOutputBuffer.bind(baos);
811
Jian Li5ecfd1a2018-12-10 11:41:03 +0900812 HttpMessageWriter<HttpRequest> requestWriter =
813 new DefaultHttpRequestWriter(sessionOutputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900814 requestWriter.write(request);
815 sessionOutputBuffer.flush();
816
817 return baos.toByteArray();
818 } catch (HttpException | IOException e) {
819 log.warn("Failed to unparse HttpRequest, due to {}", e);
820 }
821
822 return null;
823 }
824
825 /**
826 * Deserializes raw payload into HttpResponse object.
827 *
828 * @param rawData raw http payload
829 * @return HttpResponse object
830 */
831 public static HttpResponse parseHttpResponse(byte[] rawData) {
832 SessionInputBufferImpl sessionInputBuffer =
833 new SessionInputBufferImpl(
834 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
835 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900836 DefaultHttpResponseParser responseParser =
837 new DefaultHttpResponseParser(sessionInputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900838 try {
839 return responseParser.parse();
840 } catch (IOException | HttpException e) {
841 log.warn("Failed to parse HttpResponse, due to {}", e);
842 }
843
844 return null;
845 }
846
847 /**
848 * Serializes HttpResponse header to byte array.
849 *
850 * @param response http response object
851 * @return byte array
852 */
853 public static byte[] unparseHttpResponseHeader(HttpResponse response) {
854 try {
855 SessionOutputBufferImpl sessionOutputBuffer =
856 new SessionOutputBufferImpl(
857 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
858
859 ByteArrayOutputStream headerBaos = new ByteArrayOutputStream();
860 sessionOutputBuffer.bind(headerBaos);
861
862 HttpMessageWriter<HttpResponse> responseWriter =
863 new DefaultHttpResponseWriter(sessionOutputBuffer);
864 responseWriter.write(response);
865 sessionOutputBuffer.flush();
866
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900867 log.debug(headerBaos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900868
869 return headerBaos.toByteArray();
870 } catch (IOException | HttpException e) {
871 log.warn("Failed to unparse HttpResponse headers, due to {}", e);
872 }
873
874 return null;
875 }
876
877 /**
878 * Serializes HttpResponse object to byte array.
879 *
880 * @param response http response object
881 * @return byte array
882 */
883 public static byte[] unparseHttpResponseBody(HttpResponse response) {
884 try {
885 ByteArrayOutputStream baos = new ByteArrayOutputStream();
886 response.getEntity().writeTo(baos);
887
888 log.debug(response.toString());
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900889 log.debug(baos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900890
891 return baos.toByteArray();
892 } catch (IOException e) {
893 log.warn("Failed to unparse HttpResponse, due to {}", e);
894 }
895
896 return null;
897 }
898
899 /**
900 * Encodes the given data using HmacSHA256 encryption method with given secret key.
901 *
902 * @param key secret key
903 * @param data data to be encrypted
904 * @return Hmac256 encrypted data
905 */
906 public static String hmacEncrypt(String key, String data) {
907 try {
908 Mac sha256Hmac = Mac.getInstance(HMAC_SHA256);
909 SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA256);
910 sha256Hmac.init(secretKey);
911 return Hex.encodeHexString(sha256Hmac.doFinal(data.getBytes("UTF-8")));
912 } catch (Exception e) {
913 log.warn("Failed to encrypt data {} using key {}, due to {}", data, key, e);
914 }
915 return null;
916 }
917
Daniel Parka73c2362018-09-17 17:43:25 +0900918 /**
919 * Creates flow trace request string.
920 *
921 * @param srcIp src ip address
922 * @param dstIp dst ip address
923 * @param srcInstancePort src instance port
924 * @param osNetService openstack networking service
Daniel Park5aef9822018-09-20 18:04:18 +0900925 * @param uplink true if this request is for uplink
Daniel Parka73c2362018-09-17 17:43:25 +0900926 * @return flow trace request string
927 */
928 public static String traceRequestString(String srcIp,
929 String dstIp,
930 InstancePort srcInstancePort,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900931 OpenstackNetworkService osNetService,
932 boolean uplink) {
Daniel Parka73c2362018-09-17 17:43:25 +0900933
934 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
935
936 if (uplink) {
937
938 requestStringBuilder.append(COMMA)
939 .append(IN_PORT)
940 .append(srcInstancePort.portNumber().toString())
941 .append(COMMA)
942 .append(NW_SRC)
943 .append(srcIp)
944 .append(COMMA);
945
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900946 String modifiedDstIp = dstIp;
Jian Li621f73c2018-12-15 01:49:22 +0900947 Type netType = osNetService.networkType(srcInstancePort.networkId());
948 if (netType == Type.VXLAN || netType == Type.GRE ||
949 netType == Type.VLAN || netType == Type.GENEVE) {
Daniel Parka73c2362018-09-17 17:43:25 +0900950 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900951 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900952 requestStringBuilder.append(DL_DST)
953 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
Jian Li5ecfd1a2018-12-10 11:41:03 +0900954 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(
955 IpAddress.valueOf(dstIp))) {
Daniel Parka73c2362018-09-17 17:43:25 +0900956 requestStringBuilder.append(DL_DST)
957 .append(DEFAULT_GATEWAY_MAC_STR)
958 .append(COMMA);
959 }
960 } else {
961 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900962 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900963 }
964 }
965
966 requestStringBuilder.append(NW_DST)
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900967 .append(modifiedDstIp)
Daniel Parka73c2362018-09-17 17:43:25 +0900968 .append("\n");
969 } else {
970 requestStringBuilder.append(COMMA)
971 .append(NW_SRC)
972 .append(dstIp)
973 .append(COMMA);
974
Jian Li621f73c2018-12-15 01:49:22 +0900975 Type netType = osNetService.networkType(srcInstancePort.networkId());
976
977 if (netType == Type.VXLAN || netType == Type.GRE ||
978 netType == Type.VLAN || netType == Type.GENEVE) {
Daniel Parka73c2362018-09-17 17:43:25 +0900979 requestStringBuilder.append(TUN_ID)
980 .append(osNetService.segmentId(srcInstancePort.networkId()))
981 .append(COMMA);
982 }
983 requestStringBuilder.append(NW_DST)
984 .append(srcIp)
985 .append("\n");
Daniel Parka73c2362018-09-17 17:43:25 +0900986 }
987
988 return requestStringBuilder.toString();
989 }
990
991 /**
992 * Sends flow trace string to node.
993 *
994 * @param requestString reqeust string
995 * @param node src node
996 * @return flow trace result in string format
997 */
998 public static String sendTraceRequestToNode(String requestString,
999 OpenstackNode node) {
1000 String traceResult = null;
1001 OpenstackSshAuth sshAuth = node.sshAuthInfo();
1002
1003 try (SshClient client = SshClient.setUpDefaultClient()) {
1004 client.start();
1005
1006 try (ClientSession session = client
1007 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
1008 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
1009 session.addPasswordIdentity(sshAuth.password());
1010 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
1011
1012
1013 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
1014
1015 log.debug("requestString: {}", requestString);
1016 final InputStream inputStream =
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001017 new ByteArrayInputStream(requestString.getBytes(Charsets.UTF_8));
Daniel Parka73c2362018-09-17 17:43:25 +09001018
Jian Li5ecfd1a2018-12-10 11:41:03 +09001019 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Daniel Parka73c2362018-09-17 17:43:25 +09001020 OutputStream errStream = new ByteArrayOutputStream();
1021
1022 channel.setIn(new NoCloseInputStream(inputStream));
1023 channel.setErr(errStream);
1024 channel.setOut(outputStream);
1025
1026 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
1027 eventList.add(ClientChannelEvent.OPENED);
1028
1029 OpenFuture channelFuture = channel.open();
1030
1031 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
1032
1033 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
1034
1035 while (!channelFuture.isOpened()) {
1036 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
1037 log.error("Failed to open channel");
1038 return null;
1039 }
1040 }
1041 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
1042
Jian Li5ecfd1a2018-12-10 11:41:03 +09001043 traceResult = outputStream.toString(Charsets.UTF_8.name());
Daniel Parka73c2362018-09-17 17:43:25 +09001044
1045 channel.close();
1046 }
1047 } finally {
1048 session.close();
1049 }
1050 } finally {
1051 client.stop();
1052 }
1053
1054 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001055 log.error("Exception occurred because of {}", e);
Daniel Parka73c2362018-09-17 17:43:25 +09001056 }
1057
1058 return traceResult;
1059 }
1060
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001061 /**
1062 * Returns the floating ip with supplied instance port.
1063 *
1064 * @param instancePort instance port
1065 * @param osRouterAdminService openstack router admin service
1066 * @return floating ip
1067 */
1068 public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001069 OpenstackRouterAdminService
1070 osRouterAdminService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001071 return osRouterAdminService.floatingIps().stream()
1072 .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
1073 .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
1074 .findAny().orElse(null);
1075 }
1076
1077 /**
1078 * Sends GARP packet with supplied floating ip information.
1079 *
1080 * @param floatingIP floating ip
1081 * @param instancePort instance port
1082 * @param vlanId vlain id
1083 * @param gatewayNode gateway node
1084 * @param packetService packet service
1085 */
Jian Li32b03622018-11-06 17:54:24 +09001086 public static void processGarpPacketForFloatingIp(NetFloatingIP floatingIP,
1087 InstancePort instancePort,
1088 VlanId vlanId,
1089 OpenstackNode gatewayNode,
1090 PacketService packetService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001091 Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
1092
1093 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1094 .setOutput(gatewayNode.uplinkPortNum()).build();
1095
1096 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
1097 ByteBuffer.wrap(ethernet.serialize())));
1098 }
1099
1100 /**
1101 * Returns the external peer router with supplied network information.
1102 *
1103 * @param network network
1104 * @param osNetworkService openstack network service
1105 * @param osRouterAdminService openstack router admin service
1106 * @return external peer router
1107 */
1108 public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001109 OpenstackNetworkService
1110 osNetworkService,
1111 OpenstackRouterAdminService
1112 osRouterAdminService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001113 if (network == null) {
1114 return null;
1115 }
1116
Jian Lie6e609f2019-05-14 17:45:54 +09001117 Subnet subnet = osNetworkService.subnets(network.getId())
1118 .stream().findAny().orElse(null);
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001119
1120 if (subnet == null) {
1121 return null;
1122 }
1123
1124 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
1125 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1126 .findAny().orElse(null);
1127 if (osRouterIface == null) {
1128 return null;
1129 }
1130
1131 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001132 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001133 return null;
1134 }
1135
1136 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
1137 return osNetworkService.externalPeerRouter(exGatewayInfo);
1138
1139 }
1140
Jian Liebde74d2018-11-14 00:18:57 +09001141 /**
1142 * Returns the external peer router with specified subnet information.
1143 *
1144 * @param subnet openstack subnet
1145 * @param osRouterService openstack router service
1146 * @param osNetworkService openstack network service
1147 * @return external peer router
1148 */
Jian Li5ecfd1a2018-12-10 11:41:03 +09001149 public static ExternalPeerRouter externalPeerRouterFromSubnet(Subnet subnet,
1150 OpenstackRouterService
1151 osRouterService,
1152 OpenstackNetworkService
1153 osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001154 Router osRouter = getRouterFromSubnet(subnet, osRouterService);
1155 if (osRouter == null) {
1156 return null;
1157 }
1158 if (osRouter.getExternalGatewayInfo() == null) {
1159 // this router does not have external connectivity
1160 log.trace("router({}) has no external gateway",
1161 osRouter.getName());
1162 return null;
1163 }
1164
1165 return osNetworkService.externalPeerRouter(osRouter.getExternalGatewayInfo());
1166 }
1167
1168 /**
1169 * Returns the external ip address with specified router information.
1170 *
1171 * @param srcSubnet source subnet
1172 * @param osRouterService openstack router service
1173 * @param osNetworkService openstack network service
1174 * @return external ip address
1175 */
1176 public static IpAddress externalIpFromSubnet(Subnet srcSubnet,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001177 OpenstackRouterService
1178 osRouterService,
1179 OpenstackNetworkService
1180 osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001181
1182 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
1183
1184 if (osRouter.getExternalGatewayInfo() == null) {
1185 // this router does not have external connectivity
1186 log.trace("router({}) has no external gateway",
1187 osRouter.getName());
1188 return null;
1189 }
1190
1191 return getExternalIp(osRouter, osNetworkService);
1192 }
1193
1194 /**
1195 * Returns the external ip address with specified router information.
1196 *
1197 * @param router openstack router
1198 * @param osNetworkService openstack network service
1199 * @return external ip address
1200 */
Jian Li5ecfd1a2018-12-10 11:41:03 +09001201 public static IpAddress getExternalIp(Router router,
1202 OpenstackNetworkService osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001203 if (router == null) {
1204 return null;
1205 }
1206
1207 ExternalGateway externalGateway = router.getExternalGatewayInfo();
1208 if (externalGateway == null || !externalGateway.isEnableSnat()) {
Jian Li5ecfd1a2018-12-10 11:41:03 +09001209 log.trace("Failed to get externalIp for router {} because " +
1210 "externalGateway is null or SNAT is disabled",
Jian Liebde74d2018-11-14 00:18:57 +09001211 router.getId());
1212 return null;
1213 }
1214
1215 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
1216 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
1217 .stream()
1218 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
1219 .findAny().orElse(null);
1220
1221 if (exGatewayPort == null) {
1222 return null;
1223 }
1224
1225 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
1226 .findAny().get().getIpAddress());
1227 }
1228
Jian Li2d68c192018-12-13 15:52:59 +09001229 /**
1230 * Returns the tunnel port number with specified net ID and openstack node.
1231 *
1232 * @param netId network ID
1233 * @param netService network service
1234 * @param osNode openstack node
1235 * @return tunnel port number
1236 */
1237 public static PortNumber tunnelPortNumByNetId(String netId,
1238 OpenstackNetworkService netService,
1239 OpenstackNode osNode) {
SONA Project6bc5c4a2018-12-14 23:49:52 +09001240 Type netType = netService.networkType(netId);
Jian Li2d68c192018-12-13 15:52:59 +09001241
1242 if (netType == null) {
1243 return null;
1244 }
1245
1246 return tunnelPortNumByNetType(netType, osNode);
1247 }
1248
1249 /**
1250 * Returns the tunnel port number with specified net type and openstack node.
1251 *
1252 * @param netType network type
1253 * @param osNode openstack node
1254 * @return tunnel port number
1255 */
SONA Project6bc5c4a2018-12-14 23:49:52 +09001256 public static PortNumber tunnelPortNumByNetType(Type netType, OpenstackNode osNode) {
Jian Li2d68c192018-12-13 15:52:59 +09001257 switch (netType) {
1258 case VXLAN:
1259 return osNode.vxlanTunnelPortNum();
1260 case GRE:
1261 return osNode.greTunnelPortNum();
Jian Li621f73c2018-12-15 01:49:22 +09001262 case GENEVE:
1263 return osNode.geneveTunnelPortNum();
Jian Li2d68c192018-12-13 15:52:59 +09001264 default:
1265 return null;
1266 }
1267 }
1268
Jian Li7b8c3682019-05-12 13:57:15 +09001269 /**
1270 * Returns the REST URL of active node.
1271 *
1272 * @param haService openstack HA service
1273 * @return REST URL of active node
1274 */
1275 public static String getActiveUrl(OpenstackHaService haService) {
1276 return "http://" + haService.getActiveIp().toString() + ":" +
1277 REST_PORT + "/" + OPENSTACK_NETWORKING_REST_PATH + "/";
1278 }
1279
1280 /**
1281 * Returns the REST client instance with given resource path.
1282 *
1283 * @param haService openstack HA service
1284 * @param resourcePath resource path
1285 * @return REST client instance
1286 */
1287 public static WebTarget getActiveClient(OpenstackHaService haService,
1288 String resourcePath) {
1289 HttpAuthenticationFeature feature =
1290 HttpAuthenticationFeature.universal(REST_USER, REST_PASSWORD);
1291 Client client = ClientBuilder.newClient().register(feature);
1292 return client.target(getActiveUrl(haService)).path(resourcePath);
1293 }
1294
1295 /**
1296 * Returns the post response from the active node.
1297 *
1298 * @param haService openstack HA service
1299 * @param resourcePath resource path
1300 * @param input input
1301 * @return post response
1302 */
1303 public static Response syncPost(OpenstackHaService haService,
1304 String resourcePath,
1305 String input) {
1306
1307 log.debug("Sync POST request with {} on {}",
1308 haService.getActiveIp().toString(), resourcePath);
1309
1310 return getActiveClient(haService, resourcePath)
1311 .request(APPLICATION_JSON_TYPE)
1312 .post(Entity.json(input));
1313 }
1314
1315 /**
1316 * Returns the put response from the active node.
1317 *
1318 * @param haService openstack HA service
1319 * @param resourcePath resource path
1320 * @param id resource identifier
1321 * @param input input
1322 * @return put response
1323 */
1324 public static Response syncPut(OpenstackHaService haService,
1325 String resourcePath,
1326 String id, String input) {
1327 return syncPut(haService, resourcePath, null, id, input);
1328 }
1329
1330 /**
1331 * Returns the put response from the active node.
1332 *
1333 * @param haService openstack HA service
1334 * @param resourcePath resource path
1335 * @param id resource identifier
1336 * @param suffix resource suffix
1337 * @param input input
1338 * @return put response
1339 */
1340 public static Response syncPut(OpenstackHaService haService,
1341 String resourcePath,
1342 String suffix,
1343 String id, String input) {
1344
1345 log.debug("Sync PUT request with {} on {}",
1346 haService.getActiveIp().toString(), resourcePath);
1347
1348 String pathStr = "/" + id;
1349
1350 if (suffix != null) {
1351 pathStr += "/" + suffix;
1352 }
1353
1354 return getActiveClient(haService, resourcePath)
1355 .path(pathStr)
1356 .request(APPLICATION_JSON_TYPE)
1357 .put(Entity.json(input));
1358 }
1359
1360 /**
1361 * Returns the delete response from the active node.
1362 *
1363 * @param haService openstack HA service
1364 * @param resourcePath resource path
1365 * @param id resource identifier
1366 * @return delete response
1367 */
1368 public static Response syncDelete(OpenstackHaService haService,
1369 String resourcePath,
1370 String id) {
1371
1372 log.debug("Sync DELETE request with {} on {}",
1373 haService.getActiveIp().toString(), resourcePath);
1374
1375 return getActiveClient(haService, resourcePath)
1376 .path("/" + id)
1377 .request(APPLICATION_JSON_TYPE)
1378 .delete();
1379 }
1380
Jian Li51728702019-05-17 18:38:56 +09001381 /**
1382 * Gets the ovsdb client with supplied openstack node.
1383 *
1384 * @param node openstack node
1385 * @param ovsdbPort openvswitch DB port number
1386 * @param controller openvswitch DB controller instance
1387 * @return ovsdb client instance
1388 */
1389 public static OvsdbClientService getOvsdbClient(OpenstackNode node, int ovsdbPort,
1390 OvsdbController controller) {
1391 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
1392 return controller.getOvsdbClient(ovsdb);
1393 }
1394
1395 /**
1396 * Obtains the name of interface attached to the openstack VM.
1397 *
1398 * @param portId openstack port identifier
1399 * @return name of interface
1400 */
1401 public static String ifaceNameFromOsPortId(String portId) {
1402 if (portId != null) {
1403 return PORT_NAME_PREFIX_VM + StringUtils.substring(portId, 0, TAP_PORT_LENGTH);
1404 }
1405
1406 return null;
1407 }
1408
Jian Li5ecfd1a2018-12-10 11:41:03 +09001409 private static Router getRouterFromSubnet(Subnet subnet,
1410 OpenstackRouterService osRouterService) {
Jian Liebde74d2018-11-14 00:18:57 +09001411 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
1412 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1413 .findAny().orElse(null);
1414 if (osRouterIface == null) {
1415 return null;
1416 }
1417
1418 return osRouterService.router(osRouterIface.getId());
1419 }
1420
Daniel Park7e8c4d82018-08-13 23:47:49 +09001421 private static boolean isDirectPort(String portName) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001422 return portNamePrefixMap().values().stream().anyMatch(portName::startsWith);
Daniel Park7e8c4d82018-08-13 23:47:49 +09001423 }
1424
Daniel Park2ff66b42018-08-01 11:52:45 +09001425 /**
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001426 * Returns GARP packet with supplied floating ip and instance port information.
1427 *
1428 * @param floatingIP floating ip
1429 * @param instancePort instance port
1430 * @param vlanId vlan id
1431 * @return GARP packet
1432 */
1433 private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
1434 InstancePort instancePort,
1435 VlanId vlanId) {
1436 Ethernet ethernet = new Ethernet();
1437 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
1438 ethernet.setSourceMACAddress(instancePort.macAddress());
1439 ethernet.setEtherType(Ethernet.TYPE_ARP);
1440 ethernet.setVlanID(vlanId.id());
1441
1442 ARP arp = new ARP();
1443 arp.setOpCode(ARP.OP_REPLY);
1444 arp.setProtocolType(ARP.PROTO_TYPE_IP);
1445 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
1446
1447 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
1448 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
1449
1450 arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
1451 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1452
Jian Li5ecfd1a2018-12-10 11:41:03 +09001453 arp.setSenderProtocolAddress(valueOf(floatingIP.getFloatingIpAddress()).toInt());
1454 arp.setTargetProtocolAddress(valueOf(floatingIP.getFloatingIpAddress()).toInt());
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001455
1456 ethernet.setPayload(arp);
1457
1458 return ethernet;
1459 }
1460
1461 /**
Jian Li62116942019-09-03 23:10:20 +09001462 * Re-structures the OVS port name.
1463 * The length of OVS port name should be not large than 15.
1464 *
1465 * @param portName original port name
1466 * @return re-structured OVS port name
1467 */
1468 public static String structurePortName(String portName) {
1469
1470 // The size of OVS port name should not be larger than 15
1471 if (portName.length() > PORT_NAME_MAX_LENGTH) {
1472 return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
1473 }
1474
1475 return portName;
1476 }
1477
1478 /**
Jian Lie87c2712019-09-11 11:15:16 +09001479 * Obtains flow group key from the given id.
1480 *
1481 * @param groupId flow group identifier
1482 * @return flow group key
1483 */
1484 public static GroupKey getGroupKey(int groupId) {
1485 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
1486 }
1487
1488 /**
Jian Li51b844c2018-05-31 10:59:03 +09001489 * Builds up and a complete endpoint URL from gateway node.
1490 *
1491 * @param node gateway node
1492 * @return a complete endpoint URL
1493 */
1494 private static String buildEndpoint(OpenstackNode node) {
1495
Jian Lic704b672018-09-04 18:52:53 +09001496 OpenstackAuth auth = node.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +09001497
1498 StringBuilder endpointSb = new StringBuilder();
1499 endpointSb.append(auth.protocol().name().toLowerCase());
1500 endpointSb.append("://");
Jian Lic704b672018-09-04 18:52:53 +09001501 endpointSb.append(node.keystoneConfig().endpoint());
Jian Li51b844c2018-05-31 10:59:03 +09001502 return endpointSb.toString();
1503 }
1504
1505 /**
1506 * Obtains the SSL config without verifying the certification.
1507 *
1508 * @return SSL config
1509 */
1510 private static Config getSslConfig() {
1511 // we bypass the SSL certification verification for now
1512 // TODO: verify server side SSL using a given certification
1513 Config config = Config.newConfig().withSSLVerificationDisabled();
1514
1515 TrustManager[] trustAllCerts = new TrustManager[]{
1516 new X509TrustManager() {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001517 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001518 public X509Certificate[] getAcceptedIssuers() {
1519 return null;
1520 }
1521
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001522 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001523 public void checkClientTrusted(X509Certificate[] certs,
1524 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001525 return;
Jian Li51b844c2018-05-31 10:59:03 +09001526 }
1527
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001528 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001529 public void checkServerTrusted(X509Certificate[] certs,
1530 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001531 return;
Jian Li51b844c2018-05-31 10:59:03 +09001532 }
1533 }
1534 };
1535
1536 HostnameVerifier allHostsValid = (hostname, session) -> true;
1537
1538 try {
1539 SSLContext sc = SSLContext.getInstance(SSL_TYPE);
1540 sc.init(null, trustAllCerts,
1541 new java.security.SecureRandom());
1542 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
1543 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
1544
1545 config.withSSLContext(sc);
1546 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001547 log.error("Failed to access OpenStack service due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +09001548 return null;
1549 }
1550
1551 return config;
1552 }
1553
1554 /**
1555 * Obtains the facing object with given openstack perspective.
1556 *
1557 * @param perspective keystone perspective
1558 * @return facing object
1559 */
1560 private static Facing getFacing(Perspective perspective) {
1561
1562 switch (perspective) {
1563 case PUBLIC:
1564 return Facing.PUBLIC;
1565 case ADMIN:
1566 return Facing.ADMIN;
1567 case INTERNAL:
1568 return Facing.INTERNAL;
1569 default:
1570 return null;
1571 }
1572 }
1573
1574 /**
1575 * Obtains gateway instance by giving index number.
1576 *
1577 * @param gws a collection of gateway nodes
1578 * @param index index number
1579 * @return gateway instance
1580 */
1581 private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
1582 Map<String, OpenstackNode> hashMap = new HashMap<>();
1583 gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
1584 TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
1585 Iterator<String> iteratorKey = treeMap.keySet().iterator();
1586
1587 int intIndex = 0;
1588 OpenstackNode gw = null;
1589 while (iteratorKey.hasNext()) {
1590 String key = iteratorKey.next();
1591
1592 if (intIndex == index) {
1593 gw = treeMap.get(key);
1594 }
1595 intIndex++;
1596 }
1597 return gw;
1598 }
Jian Liecbf10c2019-10-02 20:36:09 +09001599
1600 private static void print(String format, Object... args) {
1601 System.out.println(String.format(format, args));
1602 }
Jian Li63430202018-08-30 16:24:09 +09001603}