2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 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 * ============LICENSE_END=========================================================
24 package org.onap.appc.adapter.iaas.impl;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Properties;
30 import java.util.concurrent.locks.Lock;
31 import java.util.concurrent.locks.ReadWriteLock;
32 import java.util.concurrent.locks.ReentrantReadWriteLock;
33 import com.att.cdp.exceptions.ZoneException;
34 import com.att.cdp.zones.spi.RequestState;
35 import com.att.eelf.configuration.EELFLogger;
36 import com.att.eelf.configuration.EELFManager;
37 import com.att.cdp.zones.spi.AbstractService.State;
38 import com.woorea.openstack.keystone.model.Access;
39 import com.woorea.openstack.keystone.model.Access.Service;
40 import com.woorea.openstack.keystone.model.Tenant;
43 * This class is used to capture and cache the service catalog for a specific OpenStack provider.
45 * This is needed because the way the servers are represented in the ECOMP product is as their fully qualified URL's.
46 * This is very problematic, because we cant identify their region from the URL, URL's change, and we cant identify the
47 * versions of the service implementations. In otherwords, the URL does not provide us enough information.
50 * The zone abstraction layer is designed to detect the versions of the services dynamically, and step up or down to
51 * match those reported versions. In order to do that, we need to know before hand what region we are accessing (since
52 * the supported versions may be different by regions). We will need to authenticate to the identity service in order to
53 * do this, plus we have to duplicate the code supporting proxies and trusted hosts that exists in the abstraction
54 * layer, but that cant be helped.
57 * What we do to circumvent this is connect to the provider using the lowest supported identity api, and read the entire
58 * service catalog into this object. Then, we parse the vm URL to extract the host and port and match that to the
59 * compute services defined in the catalog. When we find a compute service that has the same host name and port,
60 * whatever region that service is supporting is the region for that server.
63 * While we really only need to do this for compute nodes, there is no telling what other situations may arise where the
64 * full service catalog may be needed. Also, there is very little additional cost (additional RAM) associated with
65 * caching the full service catalog since there is no way to list only a portion of it.
68 public abstract class ServiceCatalog {
70 * The openstack connector version to use
72 public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JaxRs20Connector";
75 * The service name for the compute service endpoint
77 public static final String COMPUTE_SERVICE = "compute"; //$NON-NLS-1$
80 * The default domain for authentication
82 public static final String DEFAULT_DOMAIN = "Default";
84 * The service name for the identity service endpoint
86 public static final String IDENTITY_SERVICE = "identity"; //$NON-NLS-1$
89 * The service name for the compute service endpoint
91 public static final String IMAGE_SERVICE = "image"; //$NON-NLS-1$
94 * The service name for the metering service endpoint
96 public static final String METERING_SERVICE = "metering"; //$NON-NLS-1$
99 * The service name for the network service endpoint
101 public static final String NETWORK_SERVICE = "network"; //$NON-NLS-1$
104 * The service name for the persistent object service endpoint
106 public static final String OBJECT_SERVICE = "object-store"; //$NON-NLS-1$
109 * The service name for the orchestration service endpoint
111 public static final String ORCHESTRATION_SERVICE = "orchestration"; //$NON-NLS-1$
114 * The service name for the volume service endpoint
116 public static final String VOLUME_SERVICE = "volume"; //$NON-NLS-1$
119 * The logger to be used
121 protected static final EELFLogger logger = EELFManager.getInstance().getLogger(ServiceCatalog.class);
124 * The password for authentication
126 protected String credential;
129 * The domain for authentication
131 protected String domain;
133 * The time (local) that the token expires and we need to re-authenticate
135 protected long expiresLocal;
138 * The url of the identity service
140 protected String identityURL;
143 * The user id for authentication
145 protected String principal;
148 * The project or tenant identifier
150 protected String projectIdentifier;
153 * Properties for proxy information
155 protected Properties properties;
158 * The set of all regions that have been defined
160 protected Set<String> regions;
163 * The read/write lock used to protect the cache contents
165 protected ReadWriteLock rwLock;
168 * Create the ServiceCatalog cache
170 * @param identityURL The identity service URL to connect to
171 * @param tenantIdentifier The name or id of the tenant to authenticate with. If the ID is a UUID format
172 * (32-character hexadecimal string), then the authentication is done using the tenant ID, otherwise it is
173 * done using the name.
174 * @param principal The user id to authenticate to the provider
175 * @param credential The password to authenticate to the provider
176 * @param properties Additional properties used to configure the connection, such as proxy and trusted hosts lists
177 * @throws ZoneException
178 * @throws ClassNotFoundException
179 * @throws IllegalAccessException
180 * @throws InstantiationException
182 public ServiceCatalog(String identityURL, String projectIdentifier, String principal, String credential,
183 String domain, Properties properties) {
184 this.identityURL = identityURL;
185 this.projectIdentifier = projectIdentifier;
186 this.principal = principal;
187 this.credential = credential;
188 this.domain = domain;
189 this.properties = properties;
190 rwLock = new ReentrantReadWriteLock();
191 regions = new HashSet<>();
195 * Returns the list of service endpoints for the published service type
197 * @param serviceType The service type to obtain the endpoints for
198 * @return The list of endpoints for the service type, or null if none exist
200 public abstract List<?> getEndpoints(String serviceType);
203 * @return The project or tenant id
205 public abstract String getProjectId();
208 * @return The project or tenant name
210 public abstract String getProjectName();
213 * @return The set of all regions that are defined
215 public Set<String> getRegions() {
216 Lock readLock = rwLock.readLock();
226 * @return A list of service types that are published
228 public abstract List<String> getServiceTypes();
231 * This method accepts a fully qualified compute node URL and uses that to determine which region of the provider
232 * hosts that compute node.
234 * @param url The parsed URL of the compute node
235 * @return The region name, or null if no region of this tenant hosts that compute node.
237 public abstract String getVMRegion(VMURL url);
240 * Returns an indication if the specified service type is published by this provider
242 * @param serviceType The service type to check for
243 * @return True if a service of that type is published
245 public abstract boolean isServicePublished(String serviceType);
248 * Load the Service Catalog from the specified provider
250 * @throws ZoneException
252 public abstract void init() throws ZoneException;
255 * This method is used to provide a diagnostic listing of the service catalog
257 * @see java.lang.Object#toString()
260 public abstract String toString();
263 * Initializes the request state for the current requested service.
265 * This method is used to track requests made to the various service implementations and to provide additional
266 * information for diagnostic purposes. The <code>RequestState</code> class stores the state in thread-local storage
267 * and is available to all code on that thread.
270 * This method first obtains the stack trace and scans the stack backward for the call to this method. It then backs
271 * up one more call and assumes that method is the request that we are "tracking".
274 * @param states A variable argument list of additional state values that the caller wants to add to the request
275 * state thread-local object to track the context.
277 protected void trackRequest(State... states) {
278 RequestState.clear();
280 for (State state : states) {
281 RequestState.put(state.getName(), state.getValue());
284 Thread currentThread = Thread.currentThread();
285 StackTraceElement[] stack = currentThread.getStackTrace();
286 if (stack != null && stack.length > 0) {
288 StackTraceElement element = null;
289 for (; index < stack.length; index++) {
290 element = stack[index];
291 if ("trackRequest".equals(element.getMethodName())) { //$NON-NLS-1$
297 if (index < stack.length) {
298 element = stack[index];
299 RequestState.put(RequestState.METHOD, element.getMethodName());
300 RequestState.put(RequestState.CLASS, element.getClassName());
301 RequestState.put(RequestState.LINE_NUMBER, Integer.toString(element.getLineNumber()));
302 RequestState.put(RequestState.THREAD, currentThread.getName());
303 // RequestState.put(RequestState.PROVIDER, context.getProvider().getName());
304 // RequestState.put(RequestState.TENANT, context.getTenantName());
305 // RequestState.put(RequestState.PRINCIPAL, context.getPrincipal());