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.provider.operation.impl.base;
27 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
28 import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER;
29 import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;
31 import com.att.cdp.exceptions.ZoneException;
32 import com.att.cdp.zones.Context;
33 import com.att.cdp.zones.model.ModelObject;
34 import com.att.cdp.zones.model.Server;
35 import com.att.eelf.configuration.EELFLogger;
36 import com.att.eelf.configuration.EELFManager;
37 import com.att.eelf.i18n.EELFResourceManager;
40 import java.util.Map.Entry;
42 import java.util.regex.Pattern;
43 import org.glassfish.grizzly.http.util.HttpStatus;
44 import org.onap.appc.adapter.iaas.ProviderAdapter;
45 import org.onap.appc.adapter.iaas.impl.IdentityURL;
46 import org.onap.appc.adapter.iaas.impl.ProviderCache;
47 import org.onap.appc.adapter.iaas.impl.RequestContext;
48 import org.onap.appc.adapter.iaas.impl.RequestFailedException;
49 import org.onap.appc.adapter.iaas.impl.TenantCache;
50 import org.onap.appc.adapter.iaas.impl.VMURL;
51 import org.onap.appc.adapter.iaas.provider.operation.api.IProviderOperation;
52 import org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants;
53 import org.onap.appc.adapter.iaas.provider.operation.common.enums.Outcome;
54 import org.onap.appc.configuration.Configuration;
55 import org.onap.appc.configuration.ConfigurationFactory;
56 import org.onap.appc.exceptions.APPCException;
57 import org.onap.appc.i18n.Msg;
58 import org.onap.appc.pool.Pool;
59 import org.onap.appc.pool.PoolExtensionException;
60 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
63 public abstract class ProviderOperation implements IProviderOperation {
65 private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);
66 protected static final Configuration configuration = ConfigurationFactory.getConfiguration();
70 * A cache of providers that are predefined.
72 private Map<String /* provider name */, ProviderCache> providerCache;
75 * The username and password to use for dynamically created connections
77 private String defaultUser;
78 private String defaultPassword;
79 private String defaultDomain;
82 public void setDefaultUser(String defaultUser) {
83 this.defaultUser = defaultUser;
87 public void setDefaultPassword(String defaultPassword) {
88 this.defaultPassword = defaultPassword;
92 public void setProviderCache(Map<String, ProviderCache> providerCache) {
93 this.providerCache = providerCache;
97 public void setDefaultDomain(String defaultDomain) {
98 this.defaultDomain = defaultDomain;
104 protected void setMDC(String service, String serviceName, String adapterName) {
105 MDC.put(MDC_ADAPTER, adapterName);
106 MDC.put(MDC_SERVICE, service);
107 MDC.put(MDC_SERVICE_NAME, serviceName);
111 * initial log of the operation
113 protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context) {
115 String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME);
116 logger.info(msg, appName);
118 debugParameters(params);
119 debugContext(context);
123 * This method is used to dump the value of the parameters to the log for debugging purposes.
125 * @param parameters The parameters to be printed to the log
127 private void debugParameters(Map<String, String> parameters) {
128 for (Entry<String, String> entry : parameters.entrySet()) {
129 logger.debug(Msg.PROPERTY_VALUE, entry.getKey(), entry.getValue());
134 * This method is used to create a diagnostic dump of the context for the log
136 * @param context The context to be dumped
138 @SuppressWarnings({"nls", "static-method"})
139 private void debugContext(SvcLogicContext context) {
140 Set<String> keys = context.getAttributeKeySet();
141 StringBuilder builder = new StringBuilder();
143 builder.append("Service Logic Context: Status ");
144 builder.append(Constants.LPAREN);
145 builder.append(context.getStatus());
146 builder.append(Constants.RPAREN);
147 builder.append(", Attribute count ");
148 builder.append(Constants.LPAREN);
149 builder.append(keys == null ? "none" : Integer.toString(keys.size()));
150 builder.append(Constants.RPAREN);
151 if (keys != null && !keys.isEmpty()) {
152 builder.append(Constants.NL);
153 for (String key : keys) {
154 String value = context.getAttribute(key);
155 builder.append("Attribute ");
156 builder.append(Constants.LPAREN);
158 builder.append(Constants.RPAREN);
159 builder.append(", value ");
160 builder.append(Constants.LPAREN);
161 builder.append(value == null ? "" : value);
162 builder.append(Constants.RPAREN);
163 builder.append(Constants.NL);
167 logger.debug(builder.toString());
172 * This method is used to validate that the parameters contain all required property names, and that the values are
173 * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.
175 * @param parameters The parameters to be checked
176 * @param propertyNames The list of property names that are required to be present.
177 * @throws RequestFailedException If the parameters are not valid
179 protected void validateParametersExist(Map<String, String> parameters, String... propertyNames)
180 throws RequestFailedException {
181 boolean success = true;
183 new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));
184 msg.append(Constants.NL);
185 for (String propertyName : propertyNames) {
186 String value = parameters.get(propertyName);
187 if (value == null || value.trim().length() == 0) {
189 msg.append(Constants.QUOTE);
190 msg.append(propertyName);
191 msg.append(Constants.QUOTE);
192 msg.append(Constants.SPACE);
197 logger.error(msg.toString());
198 throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400,
204 * @param rc The request context that manages the state and recovery of the request for the life of its processing.
206 protected void doFailure(RequestContext rc, HttpStatus code, String message) {
208 doFailure(rc, code, message, null);
209 } catch (APPCException e) {
210 logger.error("An APPC exception caught. Should never happen", e);
214 protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {
215 SvcLogicContext svcLogic = rc.getSvcLogicContext();
216 String msg = (message == null) ? code.getReasonPhrase() : message;
217 if (msg.contains("\n")) {
218 msg = msg.substring(0, msg.indexOf('\n'));
222 status = Integer.toString(code.getStatusCode());
223 } catch (Exception e) {
224 logger.error("Error when parsing status code", e);
227 svcLogic.setStatus(Outcome.FAILURE.toString());
228 svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE, status);
229 svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg);
232 throw new APPCException(cause);
237 * @param rc The request context that manages the state and recovery of the request for the life of its processing.
239 @SuppressWarnings("static-method")
240 protected void doSuccess(RequestContext rc) {
241 SvcLogicContext svcLogic = rc.getSvcLogicContext();
242 svcLogic.setStatus(Outcome.SUCCESS.toString());
243 svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE,
244 Integer.toString(HttpStatus.OK_200.getStatusCode()));
247 protected boolean validateVM(RequestContext rc, String appName, String vmUrl, VMURL vm)
248 throws RequestFailedException {
251 msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl);
253 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
260 protected void validateVMURL(VMURL vm) throws RequestFailedException {
261 String name = "vm-id";
263 throw new RequestFailedException(String.format("The value %s cannot be null.", name));
266 // Check that its a good uri
267 // This will probably never get hit bc of an earlier check while parsing
268 // the string to a VMURL
270 // noinspection ResultOfMethodCallIgnored
271 URI.create(vm.toString());
272 } catch (Exception e) {
273 logger.error("An error occurred when validating vm url", e);
274 throw new RequestFailedException(
275 String.format("The value %s is not well formed [%s].", name, vm.toString()));
278 // Check the tenant and vmid segments
279 String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";
280 Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);
282 if (!pattern.matcher(vm.getTenantId()).matches()) {
283 throw new RequestFailedException(
284 String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));
286 if (!pattern.matcher(vm.getServerId()).matches()) {
287 throw new RequestFailedException(
288 String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));
292 private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
293 if (vm != null && ident != null) {
294 ProviderCache cache = new ProviderCache();
296 cache.setIdentityURL(ident.toString());
297 cache.setProviderName(ident.toString());
299 TenantCache tenant = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain);
301 // Make sure we could initialize the the cache otherwise return null
302 if (tenant != null && tenant.isInitialized()) {
310 * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a
311 * supported provider, regardless of region(s), and to return an opened context that can be used to access that
314 * @param rc The request context that wraps and manages the state of the request
315 * @param selfLinkURL The fully-qualified self-link URL of the server
316 * @param providerName The name of the provider to be searched
317 * @return The context that can be used to access the server, or null if not found.
319 @SuppressWarnings("nls")
320 protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) {
321 VMURL vm = VMURL.parseURL(selfLinkURL);
322 IdentityURL ident = IdentityURL.parseURL(providerName);
323 String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME);
326 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
328 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
333 * Get the cache of tenants and contexts for the named provider, if one exists
335 ProviderCache cache = providerCache.get(providerName);
338 * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to
339 * the cache and continue, otherwise fail the request.
343 cache = createProviderCache(vm, ident);
346 providerCache.put(cache.getProviderName(), cache);
348 String msg = EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName,
349 providerCache.keySet().toString());
351 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
356 if (providerName == null) {
358 String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
359 cache.getIdentityURL()));
362 // get the tenant cache for the vm
363 String identityURL = cache.getIdentityURL();
364 TenantCache tenantCache = cache.getTenant(vm.getTenantId());
366 if (tenantCache == null) {
367 // no tenantCache matching tenant, add tenant to the provider cache
368 tenantCache = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain);
369 if (tenantCache == null) {
371 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
373 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
378 // reserve the context
379 String tenantName = tenantCache.getTenantName();
380 String tenantId = tenantCache.getTenantId();
381 String region = tenantCache.determineRegion(vm);
383 if (region != null) {
384 Pool<Context> pool = tenantCache.getPools().get(region);
386 while (rc.attempt()) {
388 Context context = pool.reserve();
390 * Insert logic here to test the context for connectivity because we may have gotten one from the
391 * pool that was previously created.
393 reloginIfNeeded(context);
395 } catch (PoolExtensionException e) {
396 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,
397 tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),
398 Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
399 logger.error(msg, e);
401 } catch (Exception e) {
402 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
403 e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
405 logger.error(msg, e);
406 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
411 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
413 doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
417 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
419 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
423 private void reloginIfNeeded(Context context) throws ZoneException {
424 if (context.isStale()) {
429 protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vmUrl)
430 throws RequestFailedException {
432 VMURL vm = VMURL.parseURL(vmUrl);
434 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl);
435 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
440 IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
441 String identStr = (ident == null) ? null : ident.toString();
443 return getContext(rc, vmUrl, identStr);
448 protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context)
449 throws APPCException;
452 public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
454 return executeProviderOperation(params, context);