blob: 8e1de52bf6ca339123e65c0d5de6bac345c40b43 [file] [log] [blame]
Daniel Parkc4d06402018-05-28 15:57:37 +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.openstacknode.util;
17
18import org.onosproject.net.device.DeviceService;
Jian Li51b844c2018-05-31 10:59:03 +090019import org.onosproject.openstacknode.api.OpenstackAuth;
20import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
Daniel Parkc4d06402018-05-28 15:57:37 +090021import org.onosproject.openstacknode.api.OpenstackNode;
22import org.onosproject.ovsdb.controller.OvsdbClientService;
23import org.onosproject.ovsdb.controller.OvsdbController;
24import org.onosproject.ovsdb.controller.OvsdbNodeId;
Jian Li51b844c2018-05-31 10:59:03 +090025import org.openstack4j.api.OSClient;
26import org.openstack4j.api.client.IOSClientBuilder;
27import org.openstack4j.api.exceptions.AuthenticationException;
28import org.openstack4j.api.types.Facing;
29import org.openstack4j.core.transport.Config;
30import org.openstack4j.model.common.Identifier;
31import org.openstack4j.openstack.OSFactory;
Daniel Parkc4d06402018-05-28 15:57:37 +090032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
Jian Li51b844c2018-05-31 10:59:03 +090035import javax.net.ssl.HostnameVerifier;
36import javax.net.ssl.HttpsURLConnection;
37import javax.net.ssl.SSLContext;
38import javax.net.ssl.TrustManager;
39import javax.net.ssl.X509TrustManager;
40import java.security.cert.X509Certificate;
41
Daniel Parkc4d06402018-05-28 15:57:37 +090042/**
43 * An utility that used in openstack node app.
44 */
45public final class OpenstackNodeUtil {
46 protected static final Logger log = LoggerFactory.getLogger(OpenstackNodeUtil.class);
47
Jian Li51b844c2018-05-31 10:59:03 +090048 // keystone endpoint related variables
49 private static final String DOMAIN_DEFAULT = "default";
50 private static final String KEYSTONE_V2 = "v2.0";
51 private static final String KEYSTONE_V3 = "v3";
52 private static final String IDENTITY_PATH = "identity/";
53 private static final String SSL_TYPE = "SSL";
54
Daniel Parkc4d06402018-05-28 15:57:37 +090055 /**
Jian Li51b844c2018-05-31 10:59:03 +090056 * Prevents object installation from external.
Daniel Parkc4d06402018-05-28 15:57:37 +090057 */
58 private OpenstackNodeUtil() {
59 }
60
61 /**
62 * Checks whether the controller has a connection with an OVSDB that resides
63 * inside the given openstack node.
64 *
65 * @param osNode openstack node
66 * @param ovsdbPort ovsdb port
67 * @param ovsdbController ovsdb controller
68 * @param deviceService device service
69 * @return true if the controller is connected to the OVSDB, false otherwise
70 */
71 public static boolean isOvsdbConnected(OpenstackNode osNode,
72 int ovsdbPort,
73 OvsdbController ovsdbController,
74 DeviceService deviceService) {
75 OvsdbNodeId ovsdb = new OvsdbNodeId(osNode.managementIp(), ovsdbPort);
76 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
77 return deviceService.isAvailable(osNode.ovsdb()) &&
78 client != null &&
79 client.isConnected();
80 }
Jian Li51b844c2018-05-31 10:59:03 +090081
82 /**
83 * Obtains a connected openstack client.
84 *
85 * @param osNode openstack node
86 * @return a connected openstack client
87 */
88 public static OSClient getConnectedClient(OpenstackNode osNode) {
89 OpenstackAuth auth = osNode.authentication();
90 String endpoint = buildEndpoint(osNode);
91 Perspective perspective = auth.perspective();
92
93 Config config = getSslConfig();
94
95 try {
96 if (endpoint.contains(KEYSTONE_V2)) {
97 IOSClientBuilder.V2 builder = OSFactory.builderV2()
98 .endpoint(endpoint)
99 .tenantName(auth.project())
100 .credentials(auth.username(), auth.password())
101 .withConfig(config);
102
103 if (perspective != null) {
104 builder.perspective(getFacing(perspective));
105 }
106
107 return builder.authenticate();
108 } else if (endpoint.contains(KEYSTONE_V3)) {
109
110 Identifier project = Identifier.byName(auth.project());
111 Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
112
113 IOSClientBuilder.V3 builder = OSFactory.builderV3()
114 .endpoint(endpoint)
115 .credentials(auth.username(), auth.password(), domain)
116 .scopeToProject(project, domain)
117 .withConfig(config);
118
119 if (perspective != null) {
120 builder.perspective(getFacing(perspective));
121 }
122
123 return builder.authenticate();
124 } else {
125 log.warn("Unrecognized keystone version type");
126 return null;
127 }
128 } catch (AuthenticationException e) {
129 log.error("Authentication failed due to {}", e.toString());
130 return null;
131 }
132 }
133
134 /**
135 * Builds up and a complete endpoint URL from gateway node.
136 *
137 * @param node gateway node
138 * @return a complete endpoint URL
139 */
140 private static String buildEndpoint(OpenstackNode node) {
141
142 OpenstackAuth auth = node.authentication();
143
144 StringBuilder endpointSb = new StringBuilder();
145 endpointSb.append(auth.protocol().name().toLowerCase());
146 endpointSb.append("://");
147 endpointSb.append(node.endPoint());
148 endpointSb.append(":");
149 endpointSb.append(auth.port());
150 endpointSb.append("/");
151
152 // in case the version is v3, we need to append identity path into endpoint
153 if (auth.version().equals(KEYSTONE_V3)) {
154 endpointSb.append(IDENTITY_PATH);
155 }
156
157 endpointSb.append(auth.version());
158 return endpointSb.toString();
159 }
160
161 /**
162 * Obtains the SSL config without verifying the certification.
163 *
164 * @return SSL config
165 */
166 private static Config getSslConfig() {
167 // we bypass the SSL certification verification for now
168 // TODO: verify server side SSL using a given certification
169 Config config = Config.newConfig().withSSLVerificationDisabled();
170
171 TrustManager[] trustAllCerts = new TrustManager[]{
172 new X509TrustManager() {
173 public X509Certificate[] getAcceptedIssuers() {
174 return null;
175 }
176
177 public void checkClientTrusted(X509Certificate[] certs,
178 String authType) {
179 }
180
181 public void checkServerTrusted(X509Certificate[] certs,
182 String authType) {
183 }
184 }
185 };
186
187 HostnameVerifier allHostsValid = (hostname, session) -> true;
188
189 try {
190 SSLContext sc = SSLContext.getInstance(SSL_TYPE);
191 sc.init(null, trustAllCerts,
192 new java.security.SecureRandom());
193 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
194 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
195
196 config.withSSLContext(sc);
197 } catch (Exception e) {
198 log.error("Failed to access OpenStack service due to {}", e.toString());
199 return null;
200 }
201
202 return config;
203 }
204
205 /**
206 * Obtains the facing object with given openstack perspective.
207 *
208 * @param perspective keystone perspective
209 * @return facing object
210 */
211 private static Facing getFacing(Perspective perspective) {
212
213 switch (perspective) {
214 case PUBLIC:
215 return Facing.PUBLIC;
216 case ADMIN:
217 return Facing.ADMIN;
218 case INTERNAL:
219 return Facing.INTERNAL;
220 default:
221 return null;
222 }
223 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900224}