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.io.IOException;
28 import java.util.HashMap;
30 import java.util.Properties;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33 import org.onap.appc.Constants;
34 import org.onap.appc.configuration.Configuration;
35 import org.onap.appc.configuration.ConfigurationFactory;
36 import org.onap.appc.i18n.Msg;
37 import org.onap.appc.pool.Allocator;
38 import org.onap.appc.pool.Destructor;
39 import org.onap.appc.pool.Pool;
40 import org.onap.appc.pool.PoolSpecificationException;
41 import com.att.cdp.exceptions.ContextConnectionException;
42 import com.att.cdp.exceptions.ZoneException;
43 import com.att.cdp.zones.Context;
44 import com.att.cdp.zones.ContextFactory;
45 import com.att.cdp.zones.Provider;
46 import com.att.eelf.configuration.EELFLogger;
47 import com.att.eelf.configuration.EELFManager;
48 import com.woorea.openstack.connector.JaxRs20Connector;
49 // import com.sun.jersey.api.client.ClientHandlerException;
50 import com.woorea.openstack.keystone.model.Access.Service.Endpoint;
53 * This class maintains a cache of tenants within a specific provider.
55 * Providers may be multi-tenant, such as OpenStack, where the available services and resources vary from one tenant to
56 * another. Therefore, the provider cache maintains a cache of tenants and the service catalogs for each, as well as the
57 * credentials used to access the tenants, and a pool of Context objects for each tenant. The context pool allows use of
58 * the CDP abstraction layer to access the services of the provider within the specific tenant.
61 public class TenantCache implements Allocator<Context>, Destructor<Context> {
63 public static final String POOL_PROVIDER_NAME = "pool.provider.name";
64 public static final String POOL_TENANT_NAME = "pool.tenant.name";
65 // public static final String CLIENT_CONNECTOR_CLASS =
66 // "com.woorea.openstack.connector.JerseyConnector";
67 public static final String CLIENT_CONNECTOR_CLASS = "com.woorea.openstack.connector.JaxRs20Connector";
69 * The domain to use to authenticate
71 private String domain;
74 * The provider we are part of
76 private ProviderCache provider;
79 * The password used to authenticate
81 private String password;
84 * The context pools by region used to access this tenant
86 private Map<String /* region */, Pool<Context>> pools = new HashMap<>();
91 private String tenantId;
96 private String tenantName;
99 * The user id used to authenticate
101 private String userid;
104 * The configuration of this adapter
106 private Configuration configuration;
109 * The service catalog for this provider
111 private ServiceCatalog catalog;
114 * Set to true when the cache has been initialized
116 private boolean initialized;
121 private EELFLogger logger;
124 * Construct the cache of tenants for the specified provider
126 * @param provider The provider
128 public TenantCache(ProviderCache provider) {
129 configuration = ConfigurationFactory.getConfiguration();
130 logger = EELFManager.getInstance().getLogger(getClass());
131 this.provider = provider;
132 configuration = ConfigurationFactory.getConfiguration();
136 * @return True when the cache has been initialized. A tenant cache is initialized when the service catalog for the
137 * tenant on the specified provider has been loaded and processed.
139 public boolean isInitialized() {
144 * Initializes the tenant cache.
146 * This method authenticates to the provider and obtains the service catalog. For the service catalog we can
147 * determine all supported regions for this provider, as well as all published services and their endpoints. We will
148 * cache and maintain a copy of the service catalog for later queries.
151 * Once the catalog has been obtained, we create a context pool for each region defined. The context allows access
152 * to services of a single region only, so we need a separate context by region. It is possible to operate on
153 * resources that span regions, but to do so will require acquiring a context for each region of interest.
156 * The context pool maintains the reusable context objects and allocates them as needed. This class is registered as
157 * the allocator and destructor for the pool, so that we can create a new context when needed, and close it when no
161 public void initialize() {
162 logger.debug("Initializing TenantCache");
164 int min = configuration.getIntegerProperty(Constants.PROPERTY_MIN_POOL_SIZE);
165 int max = configuration.getIntegerProperty(Constants.PROPERTY_MAX_POOL_SIZE);
166 int delay = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_DELAY);
167 int limit = configuration.getIntegerProperty(Constants.PROPERTY_RETRY_LIMIT);
169 String url = provider.getIdentityURL();
170 String tenant = tenantName == null ? tenantId : tenantName;
171 Properties properties = configuration.getProperties();
172 catalog = ServiceCatalogFactory.getServiceCatalog(url, tenant, userid, password, domain, properties);
174 if (catalog == null) {
175 logger.error(Msg.IAAS_UNSUPPORTED_IDENTITY_SERVICE, url);
180 while (attempt <= limit) {
183 tenantId = catalog.getProjectId();
184 tenantName = catalog.getProjectName();
186 for (String region : catalog.getRegions()) {
188 Pool<Context> pool = new Pool<>(min, max);
189 pool.setProperty(ContextFactory.PROPERTY_IDENTITY_URL, url);
190 pool.setProperty(ContextFactory.PROPERTY_TENANT, tenantName);
191 pool.setProperty(ContextFactory.PROPERTY_CLIENT_CONNECTOR_CLASS, CLIENT_CONNECTOR_CLASS);
192 pool.setProperty(ContextFactory.PROPERTY_RETRY_DELAY,
193 configuration.getProperty(Constants.PROPERTY_RETRY_DELAY));
194 pool.setProperty(ContextFactory.PROPERTY_RETRY_LIMIT,
195 configuration.getProperty(Constants.PROPERTY_RETRY_LIMIT));
196 pool.setProperty(ContextFactory.PROPERTY_REGION, region);
197 if (properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS) != null) {
198 pool.setProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS,
199 properties.getProperty(ContextFactory.PROPERTY_TRUSTED_HOSTS));
201 pool.setAllocator(this);
202 pool.setDestructor(this);
203 pools.put(region, pool);
204 logger.debug(String.format("Put pool for region %s", region));
205 } catch (PoolSpecificationException e) {
206 logger.error("Error creating pool", e);
212 } catch (ContextConnectionException e) {
214 if (attempt <= limit) {
215 logger.error(Msg.CONNECTION_FAILED_RETRY, provider.getProviderName(), url, tenantName, tenantId,
216 e.getMessage(), Integer.toString(delay), Integer.toString(attempt),
217 Integer.toString(limit));
220 Thread.sleep(delay * 1000L);
221 } catch (InterruptedException ie) {
225 } catch (ZoneException e) {
226 logger.error(e.getMessage());
232 logger.error(Msg.CONNECTION_FAILED, provider.getProviderName(), url);
237 * This method accepts a fully qualified compute node URL and uses that to determine which region of the provider
238 * hosts that compute node.
240 * @param url The parsed URL of the compute node
241 * @return The region name, or null if no region of this tenant hosts that compute node.
243 public String determineRegion(VMURL url) {
244 logger.debug(String.format("Attempting to determine VM region for %s", url));
245 String region = catalog.getVMRegion(url);
246 logger.debug(String.format("Region for %s is %s", url, region));
251 * @return the value of the domain
253 public String getDomain() {
258 * @param domain the value for domain
260 public void setDomain(String domain) {
261 this.domain = domain;
265 * @return the value of provider
267 public ProviderCache getProvider() {
272 * @param provider the value for provider
274 public void setProvider(ProviderCache provider) {
275 this.provider = provider;
279 * @return the value of password
281 public String getPassword() {
286 * @param password the value for password
288 public void setPassword(String password) {
289 this.password = password;
293 * @return the value of tenantId
295 public String getTenantId() {
300 * @param tenantId the value for tenantId
302 public void setTenantId(String tenantId) {
303 this.tenantId = tenantId;
307 * @return the value of tenantName
309 public String getTenantName() {
314 * @param tenantName the value for tenantName
316 public void setTenantName(String tenantName) {
317 this.tenantName = tenantName;
321 * @return the value of userid
323 public String getUserid() {
328 * @param userid the value for userid
330 public void setUserid(String userid) {
331 this.userid = userid;
335 * @return the value of pools
337 public Map<String, Pool<Context>> getPools() {
342 * @see org.onap.appc.pool.Allocator#allocate(org.onap.appc.pool.Pool)
344 @SuppressWarnings("unchecked")
346 public Context allocate(Pool<Context> pool) {
347 logger.debug("Allocationg context for pool");
348 Class<? extends Provider> providerClass;
350 providerClass = (Class<? extends Provider>) Class.forName("com.att.cdp.openstack.OpenStackProvider");
351 // String providerType = provider.getProviderType();
353 // Context context = ContextFactory.getContext(providerType, pool.getProperties());
354 Context context = ContextFactory.getContext(providerClass, pool.getProperties());
355 context.login(userid, password);
357 } catch (IllegalStateException | IllegalArgumentException | ZoneException | ClassNotFoundException e) {
358 logger.debug("Failed to allocate context for pool", e);
365 * @see org.onap.appc.pool.Destructor#destroy(java.lang.Object, org.onap.appc.pool.Pool)
368 public void destroy(Context context, Pool<Context> pool) {
371 } catch (IOException e) {
377 * @return the service catalog for this provider
379 public ServiceCatalog getServiceCatalog() {