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.onap.appc.adapter.iaas.impl;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Properties;
31 import java.util.concurrent.locks.Lock;
32 import java.util.concurrent.locks.ReadWriteLock;
33 import java.util.concurrent.locks.ReentrantReadWriteLock;
34 import com.att.cdp.exceptions.ZoneException;
35 import com.att.cdp.zones.spi.RequestState;
36 import com.att.eelf.configuration.EELFLogger;
37 import com.att.eelf.configuration.EELFManager;
38 import com.att.cdp.zones.spi.AbstractService.State;
39 import com.woorea.openstack.keystone.model.Access;
40 import com.woorea.openstack.keystone.model.Access.Service;
41 import com.woorea.openstack.keystone.model.Tenant;
44 * This class is used to capture and cache the service catalog for a specific OpenStack provider.
46 * This is needed because the way the servers are represented in the ECOMP product is as their fully qualified URL's.
47 * This is very problematic, because we cant identify their region from the URL, URL's change, and we cant identify the
48 * versions of the service implementations. In otherwords, the URL does not provide us enough information.
51 * The zone abstraction layer is designed to detect the versions of the services dynamically, and step up or down to
52 * match those reported versions. In order to do that, we need to know before hand what region we are accessing (since
53 * the supported versions may be different by regions). We will need to authenticate to the identity service in order to
54 * do this, plus we have to duplicate the code supporting proxies and trusted hosts that exists in the abstraction
55 * layer, but that cant be helped.
58 * What we do to circumvent this is connect to the provider using the lowest supported identity api, and read the entire
59 * service catalog into this object. Then, we parse the vm URL to extract the host and port and match that to the
60 * compute services defined in the catalog. When we find a compute service that has the same host name and port,
61 * whatever region that service is supporting is the region for that server.
64 * While we really only need to do this for compute nodes, there is no telling what other situations may arise where the
65 * full service catalog may be needed. Also, there is very little additional cost (additional RAM) associated with
66 * caching the full service catalog since there is no way to list only a portion of it.
69 public abstract class ServiceCatalog {
71 * The openstack connector version to use
73 public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JaxRs20Connector";
76 * The service name for the compute service endpoint
78 public static final String COMPUTE_SERVICE = "compute"; //$NON-NLS-1$
81 * The default domain for authentication
83 public static final String DEFAULT_DOMAIN = "Default";
85 * The service name for the identity service endpoint
87 public static final String IDENTITY_SERVICE = "identity"; //$NON-NLS-1$
90 * The service name for the compute service endpoint
92 public static final String IMAGE_SERVICE = "image"; //$NON-NLS-1$
95 * The service name for the metering service endpoint
97 public static final String METERING_SERVICE = "metering"; //$NON-NLS-1$
100 * The service name for the network service endpoint
102 public static final String NETWORK_SERVICE = "network"; //$NON-NLS-1$
105 * The service name for the persistent object service endpoint
107 public static final String OBJECT_SERVICE = "object-store"; //$NON-NLS-1$
110 * The service name for the orchestration service endpoint
112 public static final String ORCHESTRATION_SERVICE = "orchestration"; //$NON-NLS-1$
115 * The service name for the volume service endpoint
117 public static final String VOLUME_SERVICE = "volume"; //$NON-NLS-1$
120 * The logger to be used
122 protected static final EELFLogger logger = EELFManager.getInstance().getLogger(ServiceCatalog.class);
125 * The password for authentication
127 protected String credential;
130 * The domain for authentication
132 protected String domain;
134 * The time (local) that the token expires and we need to re-authenticate
136 protected long expiresLocal;
139 * The url of the identity service
141 protected String identityURL;
144 * The user id for authentication
146 protected String principal;
149 * The project or tenant identifier
151 protected String projectIdentifier;
154 * Properties for proxy information
156 protected Properties properties;
159 * The set of all regions that have been defined
161 protected Set<String> regions;
164 * The read/write lock used to protect the cache contents
166 protected ReadWriteLock rwLock;
169 * Create the ServiceCatalog cache
171 * @param identityURL The identity service URL to connect to
172 * @param tenantIdentifier The name or id of the tenant to authenticate with. If the ID is a UUID format
173 * (32-character hexadecimal string), then the authentication is done using the tenant ID, otherwise it is
174 * done using the name.
175 * @param principal The user id to authenticate to the provider
176 * @param credential The password to authenticate to the provider
177 * @param properties Additional properties used to configure the connection, such as proxy and trusted hosts lists
178 * @throws ZoneException
179 * @throws ClassNotFoundException
180 * @throws IllegalAccessException
181 * @throws InstantiationException
183 public ServiceCatalog(String identityURL, String projectIdentifier, String principal, String credential,
184 String domain, Properties properties) {
185 this.identityURL = identityURL;
186 this.projectIdentifier = projectIdentifier;
187 this.principal = principal;
188 this.credential = credential;
189 this.domain = domain;
190 this.properties = properties;
191 rwLock = new ReentrantReadWriteLock();
192 regions = new HashSet<>();
196 * Returns the list of service endpoints for the published service type
198 * @param serviceType The service type to obtain the endpoints for
199 * @return The list of endpoints for the service type, or null if none exist
201 public abstract List<?> getEndpoints(String serviceType);
204 * @return The project or tenant id
206 public abstract String getProjectId();
209 * @return The project or tenant name
211 public abstract String getProjectName();
214 * @return The set of all regions that are defined
216 public Set<String> getRegions() {
217 Lock readLock = rwLock.readLock();
227 * @return A list of service types that are published
229 public abstract List<String> getServiceTypes();
232 * This method accepts a fully qualified compute node URL and uses that to determine which region of the provider
233 * hosts that compute node.
235 * @param url The parsed URL of the compute node
236 * @return The region name, or null if no region of this tenant hosts that compute node.
238 public abstract String getVMRegion(VMURL url);
241 * Returns an indication if the specified service type is published by this provider
243 * @param serviceType The service type to check for
244 * @return True if a service of that type is published
246 public abstract boolean isServicePublished(String serviceType);
249 * Load the Service Catalog from the specified provider
251 * @throws ZoneException
253 public abstract void init() throws ZoneException;
256 * This method is used to provide a diagnostic listing of the service catalog
258 * @see java.lang.Object#toString()
261 public abstract String toString();
264 * Initializes the request state for the current requested service.
266 * This method is used to track requests made to the various service implementations and to provide additional
267 * information for diagnostic purposes. The <code>RequestState</code> class stores the state in thread-local storage
268 * and is available to all code on that thread.
271 * This method first obtains the stack trace and scans the stack backward for the call to this method. It then backs
272 * up one more call and assumes that method is the request that we are "tracking".
275 * @param states A variable argument list of additional state values that the caller wants to add to the request
276 * state thread-local object to track the context.
278 protected void trackRequest(State... states) {
279 RequestState.clear();
281 for (State state : states) {
282 RequestState.put(state.getName(), state.getValue());
285 Thread currentThread = Thread.currentThread();
286 StackTraceElement[] stack = currentThread.getStackTrace();
287 if (stack != null && stack.length > 0) {
289 StackTraceElement element = null;
290 for (; index < stack.length; index++) {
291 element = stack[index];
292 if ("trackRequest".equals(element.getMethodName())) { //$NON-NLS-1$
298 if (index < stack.length) {
299 element = stack[index];
300 RequestState.put(RequestState.METHOD, element.getMethodName());
301 RequestState.put(RequestState.CLASS, element.getClassName());
302 RequestState.put(RequestState.LINE_NUMBER, Integer.toString(element.getLineNumber()));
303 RequestState.put(RequestState.THREAD, currentThread.getName());
304 // RequestState.put(RequestState.PROVIDER, context.getProvider().getName());
305 // RequestState.put(RequestState.TENANT, context.getTenantName());
306 // RequestState.put(RequestState.PRINCIPAL, context.getPrincipal());