c078eb7b313c1d0174c6d8478fe672862efb9416
[appc.git] / appc-adapters / appc-iaas-adapter / appc-iaas-adapter-bundle / src / main / java / org / openecomp / appc / adapter / iaas / impl / ServiceCatalog.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
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
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
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.
20  * 
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.appc.adapter.iaas.impl;
26
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Properties;
30 import java.util.Set;
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;
42
43 /**
44  * This class is used to capture and cache the service catalog for a specific OpenStack provider.
45  * <p>
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.
49  * </p>
50  * <p>
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.
56  * </p>
57  * <p>
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.
62  * </p>
63  * <p>
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.
67  * </p>
68  */
69 public abstract class ServiceCatalog {
70     /**
71      * The openstack connector version to use
72      */
73     public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JaxRs20Connector";
74
75     /**
76      * The service name for the compute service endpoint
77      */
78     public static final String COMPUTE_SERVICE = "compute"; //$NON-NLS-1$
79
80     /**
81      * The default domain for authentication
82      */
83     public static final String DEFAULT_DOMAIN = "Default";
84     /**
85      * The service name for the identity service endpoint
86      */
87     public static final String IDENTITY_SERVICE = "identity"; //$NON-NLS-1$
88
89     /**
90      * The service name for the compute service endpoint
91      */
92     public static final String IMAGE_SERVICE = "image"; //$NON-NLS-1$
93
94     /**
95      * The service name for the metering service endpoint
96      */
97     public static final String METERING_SERVICE = "metering"; //$NON-NLS-1$
98
99     /**
100      * The service name for the network service endpoint
101      */
102     public static final String NETWORK_SERVICE = "network"; //$NON-NLS-1$
103
104     /**
105      * The service name for the persistent object service endpoint
106      */
107     public static final String OBJECT_SERVICE = "object-store"; //$NON-NLS-1$
108
109     /**
110      * The service name for the orchestration service endpoint
111      */
112     public static final String ORCHESTRATION_SERVICE = "orchestration"; //$NON-NLS-1$
113
114     /**
115      * The service name for the volume service endpoint
116      */
117     public static final String VOLUME_SERVICE = "volume"; //$NON-NLS-1$
118
119     /**
120      * The logger to be used
121      */
122     protected static final EELFLogger logger = EELFManager.getInstance().getLogger(ServiceCatalog.class);
123
124     /**
125      * The password for authentication
126      */
127     protected String credential;
128
129     /**
130      * The domain for authentication
131      */
132     protected String domain;
133     /**
134      * The time (local) that the token expires and we need to re-authenticate
135      */
136     protected long expiresLocal;
137
138     /**
139      * The url of the identity service
140      */
141     protected String identityURL;
142
143     /**
144      * The user id for authentication
145      */
146     protected String principal;
147
148     /**
149      * The project or tenant identifier
150      */
151     protected String projectIdentifier;
152
153     /**
154      * Properties for proxy information
155      */
156     protected Properties properties;
157
158     /**
159      * The set of all regions that have been defined
160      */
161     protected Set<String> regions;
162
163     /**
164      * The read/write lock used to protect the cache contents
165      */
166     protected ReadWriteLock rwLock;
167
168     /**
169      * Create the ServiceCatalog cache
170      * 
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
182      */
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<>();
193     }
194
195     /**
196      * Returns the list of service endpoints for the published service type
197      * 
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
200      */
201     public abstract List<?> getEndpoints(String serviceType);
202
203     /**
204      * @return The project or tenant id
205      */
206     public abstract String getProjectId();
207
208     /**
209      * @return The project or tenant name
210      */
211     public abstract String getProjectName();
212
213     /**
214      * @return The set of all regions that are defined
215      */
216     public Set<String> getRegions() {
217         Lock readLock = rwLock.readLock();
218         readLock.lock();
219         try {
220             return regions;
221         } finally {
222             readLock.unlock();
223         }
224     }
225
226     /**
227      * @return A list of service types that are published
228      */
229     public abstract List<String> getServiceTypes();
230
231     /**
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.
234      *
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.
237      */
238     public abstract String getVMRegion(VMURL url);
239
240     /**
241      * Returns an indication if the specified service type is published by this provider
242      * 
243      * @param serviceType The service type to check for
244      * @return True if a service of that type is published
245      */
246     public abstract boolean isServicePublished(String serviceType);
247
248     /**
249      * Load the Service Catalog from the specified provider
250      * 
251      * @throws ZoneException
252      */
253     public abstract void init() throws ZoneException;
254
255     /**
256      * This method is used to provide a diagnostic listing of the service catalog
257      * 
258      * @see java.lang.Object#toString()
259      */
260     @Override
261     public abstract String toString();
262
263     /**
264      * Initializes the request state for the current requested service.
265      * <p>
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.
269      * </p>
270      * <p>
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".
273      * </p>
274      * 
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.
277      */
278     protected void trackRequest(State... states) {
279         RequestState.clear();
280
281         for (State state : states) {
282             RequestState.put(state.getName(), state.getValue());
283         }
284
285         Thread currentThread = Thread.currentThread();
286         StackTraceElement[] stack = currentThread.getStackTrace();
287         if (stack != null && stack.length > 0) {
288             int index = 0;
289             StackTraceElement element = null;
290             for (; index < stack.length; index++) {
291                 element = stack[index];
292                 if ("trackRequest".equals(element.getMethodName())) { //$NON-NLS-1$
293                     break;
294                 }
295             }
296             index++;
297
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());
307             }
308         }
309     }
310 }