2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.appc.adapter.iaas.impl;
25 import java.io.IOException;
26 import java.util.HashMap;
28 import java.util.Properties;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
32 import org.openecomp.appc.Constants;
33 import org.openecomp.appc.configuration.Configuration;
34 import org.openecomp.appc.configuration.ConfigurationFactory;
35 import org.openecomp.appc.i18n.Msg;
36 import org.openecomp.appc.pool.Allocator;
37 import org.openecomp.appc.pool.Destructor;
38 import org.openecomp.appc.pool.Pool;
39 import org.openecomp.appc.pool.PoolSpecificationException;
40 import com.att.cdp.exceptions.ContextConnectionException;
41 import com.att.cdp.exceptions.ZoneException;
42 import com.att.cdp.zones.Context;
43 import com.att.cdp.zones.ContextFactory;
44 import com.att.cdp.zones.Provider;
45 import com.att.eelf.configuration.EELFLogger;
46 import com.att.eelf.configuration.EELFManager;
47 import com.woorea.openstack.connector.JaxRs20Connector;
48 //import com.sun.jersey.api.client.ClientHandlerException;
49 import com.woorea.openstack.keystone.model.Access.Service.Endpoint;
52 * This class maintains a cache of tenants within a specific provider.
54 * Providers may be multi-tenant, such as OpenStack, where the available services and resources vary from one tenant to
55 * another. Therefore, the provider cache maintains a cache of tenants and the service catalogs for each, as well as the
56 * credentials used to access the tenants, and a pool of Context objects for each tenant. The context pool allows use of
57 * the CDP abstraction layer to access the services of the provider within the specific tenant.
60 public class TenantCache implements Allocator<Context>, Destructor<Context> {
62 public static final String POOL_PROVIDER_NAME = "pool.provider.name";
63 public static final String POOL_TENANT_NAME = "pool.tenant.name";
64 //public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JerseyConnector";
65 public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JaxRs20Connector";
67 * The provider we are part of
69 private ProviderCache provider;
72 * The password used to authenticate
74 private String password;
77 * The context pools by region used to access this tenant
79 private Map<String /* region */, Pool<Context>> pools = new HashMap<>();
84 private String tenantId;
89 private String tenantName;
92 * The user id used to authenticate
94 private String userid;
97 * The configuration of this adapter
99 private Configuration configuration;
102 * The service catalog for this provider
104 private ServiceCatalog catalog;
107 * Set to true when the cache has been initialized
109 private boolean initialized;
114 private EELFLogger logger;
117 * Construct the cache of tenants for the specified provider
122 public TenantCache(ProviderCache provider) {
123 configuration = ConfigurationFactory.getConfiguration();
124 logger = EELFManager.getInstance().getLogger(getClass());
125 this.provider = provider;
126 configuration = ConfigurationFactory.getConfiguration();
130 * @return True when the cache has been initialized. A tenant cache is initialized when the service catalog for the
131 * tenant on the specified provider has been loaded and processed.
133 public boolean isInitialized() {
138 * Initializes the tenant cache.
140 * This method authenticates to the provider and obtains the service catalog. For the service catalog we can
141 * determine all supported regions for this provider, as well as all published services and their endpoints. We will
142 * cache and maintain a copy of the service catalog for later queries.
145 * Once the catalog has been obtained, we create a context pool for each region defined. The context allows access
146 * to services of a single region only, so we need a separate context by region. It is possible to operate on
147 * resources that span regions, but to do so will require acquiring a context for each region of interest.
150 * The context pool maintains the reusable context objects and allocates them as needed. This class is registered as
151 * the allocator and destructor for the pool, so that we can create a new context when needed, and close it when no
155 public void initialize() {
156 logger.debug("Initializing TenantCache");
158 int min = configuration.getIntegerProperty(Constants.PROPERTY_MIN_POOL_SIZE);
159 int max = configuration.getIntegerProperty(Constants.PROPERTY_MAX_POOL_SIZE);
160 int delay = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_DELAY);
161 int limit = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_LIMIT);
163 String url = provider.getIdentityURL();
164 String tenant = tenantName == null ? tenantId : tenantName;
165 Properties properties = configuration.getProperties();
168 while (attempt <= limit) {
170 catalog = new ServiceCatalog(url, tenant, userid, password, properties);
171 tenantId = catalog.getTenantId();
172 tenantName = catalog.getTenantName();
174 for (String region : catalog.getRegions()) {
176 Pool<Context> pool = new Pool<>(min, max);
177 pool.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, url);
178 pool.setProperty(ContextFactory.PROPERTY_TENANT, tenantName);
179 pool.setProperty(ContextFactory.PROPERTY_CLIENT_CONNECTOR_CLASS, CLIENT_CONNECTOR_CLASS);
180 pool.setProperty(ContextFactory.PROPERTY_RETRY_DELAY,
181 configuration.getProperty(Constants.PROPERTY_RETRY_DELAY));
182 pool.setProperty(ContextFactory.PROPERTY_RETRY_LIMIT,
183 configuration.getProperty(Constants.PROPERTY_RETRY_LIMIT));
184 pool.setProperty(ContextFactory.PROPERTY_REGION, region);
185 if (properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS) != null) {
186 pool.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS,
187 properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS));
189 pool.setAllocator(this);
190 pool.setDestructor(this);
191 pools.put(region, pool);
192 logger.debug(String.format("Put pool for region %s", region));
193 } catch (PoolSpecificationException e) {
194 logger.error("Error creating pool", e);
200 } catch (ContextConnectionException e) {
202 if (attempt <= limit) {
203 logger.error(Msg.CONNECTION_FAILED_RETRY, provider.getProviderName(), url, tenantName, tenantId, e.getMessage(), Integer.toString(delay), Integer.toString(attempt),
204 Integer.toString(limit));
207 Thread.sleep(delay * 1000L);
208 } catch (InterruptedException ie) {
212 } catch ( ZoneException e) {
213 logger.error(e.getMessage());
219 logger.error(Msg.CONNECTION_FAILED, provider.getProviderName(), url);
224 * This method accepts a fully qualified compute node URL and uses that to determine which region of the provider
225 * hosts that compute node.
228 * The parsed URL of the compute node
229 * @return The region name, or null if no region of this tenant hosts that compute node.
231 public String determineRegion(VMURL url) {
232 logger.debug(String.format("Attempting to determine VM region for %s", url));
233 String region = null;
234 Pattern urlPattern = Pattern.compile("[^:]+://([^:/]+)(?::([0-9]+)).*");
237 for (Endpoint endpoint : catalog.getEndpoints(ServiceCatalog.COMPUTE_SERVICE)) {
238 String endpointUrl = endpoint.getPublicURL();
239 Matcher matcher = urlPattern.matcher(endpointUrl);
240 if (matcher.matches()) {
241 if (url.getHost().equals(matcher.group(1))) {
242 if (url.getPort() != null) {
243 if (!url.getPort().equals(matcher.group(2))) {
248 region = endpoint.getRegion();
254 logger.debug(String.format("Region for %s is %s", url, region));
259 * @return the value of provider
261 public ProviderCache getProvider() {
267 * the value for provider
269 public void setProvider(ProviderCache provider) {
270 this.provider = provider;
274 * @return the value of password
276 public String getPassword() {
282 * the value for password
284 public void setPassword(String password) {
285 this.password = password;
289 * @return the value of tenantId
291 public String getTenantId() {
297 * the value for tenantId
299 public void setTenantId(String tenantId) {
300 this.tenantId = tenantId;
304 * @return the value of tenantName
306 public String getTenantName() {
312 * the value for tenantName
314 public void setTenantName(String tenantName) {
315 this.tenantName = tenantName;
319 * @return the value of userid
321 public String getUserid() {
327 * the value for userid
329 public void setUserid(String userid) {
330 this.userid = userid;
334 * @return the value of pools
336 public Map<String, Pool<Context>> getPools() {
341 * @see org.openecomp.appc.pool.Allocator#allocate(org.openecomp.appc.pool.Pool)
343 @SuppressWarnings("unchecked")
345 public Context allocate(Pool<Context> pool) {
346 logger.debug("Allocationg context for pool");
347 Class<? extends Provider> providerClass;
349 providerClass = (Class<? extends Provider>) Class.forName("com.att.cdp.openstack.OpenStackProvider");
350 // String providerType = provider.getProviderType();
352 // Context context = ContextFactory.getContext(providerType, pool.getProperties());
353 Context context = ContextFactory.getContext(providerClass, pool.getProperties());
354 context.login(userid, password);
356 } catch (IllegalStateException | IllegalArgumentException | ZoneException | ClassNotFoundException e) {
357 logger.debug("Failed to allocate context for pool", e);
364 * @see org.openecomp.appc.pool.Destructor#destroy(java.lang.Object, org.openecomp.appc.pool.Pool)
367 public void destroy(Context context, Pool<Context> pool) {
370 } catch (IOException e) {
376 * @return the service catalog for this provider
378 public ServiceCatalog getServiceCatalog() {