2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.openecomp.appc.adapter.iaas.impl;
27 import java.net.NoRouteToHostException;
28 import java.net.SocketException;
29 import java.util.ArrayList;
30 import java.util.Calendar;
31 import java.util.Date;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
36 import java.util.Properties;
38 import java.util.concurrent.locks.Lock;
39 import java.util.concurrent.locks.ReadWriteLock;
40 import java.util.concurrent.locks.ReentrantReadWriteLock;
41 import com.att.cdp.exceptions.ContextConnectionException;
42 import com.att.cdp.exceptions.ZoneException;
43 import com.att.cdp.openstack.util.ExceptionMapper;
44 import com.att.cdp.pal.util.Time;
45 import com.att.cdp.zones.ContextFactory;
46 import com.att.cdp.zones.spi.AbstractService;
47 import com.att.cdp.zones.spi.RequestState;
48 import com.att.eelf.configuration.EELFLogger;
49 import com.att.eelf.configuration.EELFManager;
50 import com.att.cdp.zones.spi.AbstractService.State;
51 import com.woorea.openstack.base.client.OpenStackBaseException;
52 import com.woorea.openstack.base.client.OpenStackClientConnector;
53 import com.woorea.openstack.base.client.OpenStackResponseException;
54 import com.woorea.openstack.base.client.OpenStackSimpleTokenProvider;
55 import com.woorea.openstack.keystone.Keystone;
56 import com.woorea.openstack.keystone.api.TokensResource;
57 import com.woorea.openstack.keystone.model.Access;
58 import com.woorea.openstack.keystone.model.Access.Service;
59 import com.woorea.openstack.keystone.model.Access.Service.Endpoint;
60 import com.woorea.openstack.keystone.model.Authentication;
61 import com.woorea.openstack.keystone.model.Tenant;
62 import com.woorea.openstack.keystone.model.authentication.UsernamePassword;
65 * This class is used to capture and cache the service catalog for a specific OpenStack provider.
67 * This is needed because the way the servers are represented in the ECOMP product is as their fully qualified URL's.
68 * This is very problematic, because we cant identify their region from the URL, URL's change, and we cant identify the
69 * versions of the service implementations. In otherwords, the URL does not provide us enough information.
72 * The zone abstraction layer is designed to detect the versions of the services dynamically, and step up or down to
73 * match those reported versions. In order to do that, we need to know before hand what region we are accessing (since
74 * the supported versions may be different by regions). We will need to authenticate to the identity service in order to
75 * do this, plus we have to duplicate the code supporting proxies and trusted hosts that exists in the abstraction
76 * layer, but that cant be helped.
79 * What we do to circumvent this is connect to the provider using the lowest supported identity api, and read the entire
80 * service catalog into this object. Then, we parse the vm URL to extract the host and port and match that to the
81 * compute services defined in the catalog. When we find a compute service that has the same host name and port,
82 * whatever region that service is supporting is the region for that server.
85 * While we really only need to do this for compute nodes, there is no telling what other situations may arise where the
86 * full service catalog may be needed. Also, there is very little additional cost (additional RAM) associated with
87 * caching the full service catalog since there is no way to list only a portion of it.
90 public abstract class ServiceCatalog {
92 * The openstack connector version to use
94 public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JaxRs20Connector";
97 * The service name for the compute service endpoint
99 public static final String COMPUTE_SERVICE = "compute"; //$NON-NLS-1$
102 * The default domain for authentication
104 public static final String DEFAULT_DOMAIN = "Default";
106 * The service name for the identity service endpoint
108 public static final String IDENTITY_SERVICE = "identity"; //$NON-NLS-1$
111 * The service name for the compute service endpoint
113 public static final String IMAGE_SERVICE = "image"; //$NON-NLS-1$
116 * The service name for the metering service endpoint
118 public static final String METERING_SERVICE = "metering"; //$NON-NLS-1$
121 * The service name for the network service endpoint
123 public static final String NETWORK_SERVICE = "network"; //$NON-NLS-1$
126 * The service name for the persistent object service endpoint
128 public static final String OBJECT_SERVICE = "object-store"; //$NON-NLS-1$
131 * The service name for the orchestration service endpoint
133 public static final String ORCHESTRATION_SERVICE = "orchestration"; //$NON-NLS-1$
136 * The service name for the volume service endpoint
138 public static final String VOLUME_SERVICE = "volume"; //$NON-NLS-1$
141 * The logger to be used
143 protected static final EELFLogger logger = EELFManager.getInstance().getLogger(ServiceCatalog.class);
146 * The password for authentication
148 protected String credential;
151 * The domain for authentication
153 protected String domain;
155 * The time (local) that the token expires and we need to re-authenticate
157 protected long expiresLocal;
160 * The url of the identity service
162 protected String identityURL;
165 * The user id for authentication
167 protected String principal;
170 * The project or tenant identifier
172 protected String projectIdentifier;
175 * Properties for proxy information
177 protected Properties properties;
180 * The set of all regions that have been defined
182 protected Set<String> regions;
185 * The read/write lock used to protect the cache contents
187 protected ReadWriteLock rwLock;
190 * Create the ServiceCatalog cache
192 * @param identityURL The identity service URL to connect to
193 * @param tenantIdentifier The name or id of the tenant to authenticate with. If the ID is a UUID format
194 * (32-character hexadecimal string), then the authentication is done using the tenant ID, otherwise it is
195 * done using the name.
196 * @param principal The user id to authenticate to the provider
197 * @param credential The password to authenticate to the provider
198 * @param properties Additional properties used to configure the connection, such as proxy and trusted hosts lists
199 * @throws ZoneException
200 * @throws ClassNotFoundException
201 * @throws IllegalAccessException
202 * @throws InstantiationException
204 public ServiceCatalog(String identityURL, String projectIdentifier, String principal, String credential,
205 String domain, Properties properties) {
206 this.identityURL = identityURL;
207 this.projectIdentifier = projectIdentifier;
208 this.principal = principal;
209 this.credential = credential;
210 this.domain = domain;
211 this.properties = properties;
212 rwLock = new ReentrantReadWriteLock();
213 regions = new HashSet<>();
217 * Returns the list of service endpoints for the published service type
219 * @param serviceType The service type to obtain the endpoints for
220 * @return The list of endpoints for the service type, or null if none exist
222 public abstract List<?> getEndpoints(String serviceType);
225 * @return The project or tenant id
227 public abstract String getProjectId();
230 * @return The project or tenant name
232 public abstract String getProjectName();
235 * @return The set of all regions that are defined
237 public Set<String> getRegions() {
238 Lock readLock = rwLock.readLock();
248 * @return A list of service types that are published
250 public abstract List<String> getServiceTypes();
253 * This method accepts a fully qualified compute node URL and uses that to determine which region of the provider
254 * hosts that compute node.
256 * @param url The parsed URL of the compute node
257 * @return The region name, or null if no region of this tenant hosts that compute node.
259 public abstract String getVMRegion(VMURL url);
262 * Returns an indication if the specified service type is published by this provider
264 * @param serviceType The service type to check for
265 * @return True if a service of that type is published
267 public abstract boolean isServicePublished(String serviceType);
270 * Load the Service Catalog from the specified provider
272 * @throws ZoneException
274 public abstract void init() throws ZoneException;
277 * This method is used to provide a diagnostic listing of the service catalog
279 * @see java.lang.Object#toString()
282 public abstract String toString();
285 * Initializes the request state for the current requested service.
287 * This method is used to track requests made to the various service implementations and to provide additional
288 * information for diagnostic purposes. The <code>RequestState</code> class stores the state in thread-local storage
289 * and is available to all code on that thread.
292 * This method first obtains the stack trace and scans the stack backward for the call to this method. It then backs
293 * up one more call and assumes that method is the request that we are "tracking".
296 * @param states A variable argument list of additional state values that the caller wants to add to the request
297 * state thread-local object to track the context.
299 protected void trackRequest(State... states) {
300 RequestState.clear();
302 for (State state : states) {
303 RequestState.put(state.getName(), state.getValue());
306 Thread currentThread = Thread.currentThread();
307 StackTraceElement[] stack = currentThread.getStackTrace();
308 if (stack != null && stack.length > 0) {
310 StackTraceElement element = null;
311 for (; index < stack.length; index++) {
312 element = stack[index];
313 if ("trackRequest".equals(element.getMethodName())) { //$NON-NLS-1$
319 if (index < stack.length) {
320 element = stack[index];
321 RequestState.put(RequestState.METHOD, element.getMethodName());
322 RequestState.put(RequestState.CLASS, element.getClassName());
323 RequestState.put(RequestState.LINE_NUMBER, Integer.toString(element.getLineNumber()));
324 RequestState.put(RequestState.THREAD, currentThread.getName());
325 // RequestState.put(RequestState.PROVIDER, context.getProvider().getName());
326 // RequestState.put(RequestState.TENANT, context.getTenantName());
327 // RequestState.put(RequestState.PRINCIPAL, context.getPrincipal());