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