From 151be4c7b1da50c85553e11328a72c5207749a29 Mon Sep 17 00:00:00 2001 From: "Modaboina, Kusumakumari (km583p)" Date: Mon, 19 Mar 2018 22:09:28 -0400 Subject: bugfix for error handling while detaching volumes Change-Id: I96f7d017a63b0741d87666f4608356567932ff77 Issue-ID: APPC-762 Signed-off-by: Modaboina, Kusumakumari (km583p) --- .../operation/impl/DettachVolumeServer.java | 130 ++- .../provider/operation/impl/MigrateServer.java | 2 +- .../operation/impl/base/ProviderOperation.java | 888 ++++++++++----------- 3 files changed, 533 insertions(+), 487 deletions(-) (limited to 'appc-adapters') diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/DettachVolumeServer.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/DettachVolumeServer.java index d9b30cbb8..5874939b3 100644 --- a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/DettachVolumeServer.java +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/DettachVolumeServer.java @@ -37,21 +37,29 @@ import com.att.eelf.configuration.EELFManager; import com.att.eelf.i18n.EELFResourceManager; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Iterator; import org.glassfish.grizzly.http.util.HttpStatus; import org.onap.appc.Constants; import org.onap.appc.adapter.iaas.ProviderAdapter; import org.onap.appc.adapter.iaas.impl.IdentityURL; import org.onap.appc.adapter.iaas.impl.RequestContext; import org.onap.appc.adapter.iaas.impl.RequestFailedException; +import org.onap.appc.configuration.Configuration; +import org.onap.appc.configuration.ConfigurationFactory; import org.onap.appc.adapter.iaas.impl.VMURL; import org.onap.appc.adapter.iaas.provider.operation.common.enums.Operation; import org.onap.appc.adapter.iaas.provider.operation.impl.base.ProviderServerOperation; import org.onap.appc.exceptions.APPCException; +import com.att.cdp.exceptions.TimeoutException; +import com.att.cdp.openstack.util.ExceptionMapper; import org.onap.appc.i18n.Msg; +import com.woorea.openstack.base.client.OpenStackBaseException; import org.onap.ccsdk.sli.core.sli.SvcLogicContext; public class DettachVolumeServer extends ProviderServerOperation { private final EELFLogger logger = EELFManager.getInstance().getLogger(DettachVolumeServer.class); + private static final Configuration config = ConfigurationFactory.getConfiguration(); @Override protected ModelObject executeProviderOperation(Map params, SvcLogicContext context) @@ -87,31 +95,32 @@ public class DettachVolumeServer extends ProviderServerOperation { logger.debug(Msg.SERVER_FOUND, vmUrl, context.getTenantName(), server.getStatus().toString()); Context contx = server.getContext(); ComputeService service = contx.getComputeService(); - VolumeService volumeService = contx.getVolumeService(); - logger.info("collecting volume status for volume -id: " + volumeId); - List volumes = volumeService.getVolumes(); Volume volume = new Volume(); - logger.info("Size of volume list: " + volumes.size()); - if (volumes != null && !volumes.isEmpty()) { - if (volumes.contains(volumeId)) { - volume.setId(volumeId); - logger.info("Ready to Detach Volume from the server: " + Volume.Status.DETACHING); - service.detachVolume(server, volume); - logger.info("Volume status after performing detach: " + volume.getStatus()); - if (validateDetach(volumeService, volumeId)) { - doSuccess(requestContext); - } else { - String msg = "Volume with volume id " + volumeId + " cannot be detached "; - ctx.setAttribute("VOLUME_STATUS", "FAILURE"); - doFailure(requestContext, HttpStatus.NOT_IMPLEMENTED_501, msg); - logger.info("unable to detach volume from the server"); - } - } else { - String msg = "Volume with volume id " + volumeId + " cannot be detached as it doesn't exists"; + VolumeService vs = contx.getVolumeService(); + Volume s = vs.getVolume(volumeId); + boolean flag = false; + if (validateDetach(service, vm.getServerId(), volumeId)) { + volume.setId(volumeId); + logger.info("Ready to Detach Volume from the server:"); + service.detachVolume(server, volume); + flag = true; + } else { + String msg = "Volume with volume id " + volumeId + " cannot be detached as it does not exists"; + logger.info("Volume doesnot exists:"); + ctx.setAttribute("VOLUME_STATUS", "FAILURE"); + doFailure(requestContext, HttpStatus.METHOD_NOT_ALLOWED_405, msg); + flag = false; + } + if (flag) { + if (validateDetach(requestContext, service, vm.getServerId(), volumeId)) { + String msg = "Volume with volume id " + volumeId + " cannot be detached "; ctx.setAttribute("VOLUME_STATUS", "FAILURE"); - doFailure(requestContext, HttpStatus.NOT_IMPLEMENTED_501, msg); + doFailure(requestContext, HttpStatus.CONFLICT_409, msg); + } else { + logger.info("status of detaching volume"); + ctx.setAttribute("VOLUME_STATUS", "SUCCESS"); + doSuccess(requestContext); } - logger.info("volumestatus:" + ctx.getAttribute("VOLUME_STATUS")); } context.close(); } else { @@ -125,24 +134,85 @@ public class DettachVolumeServer extends ProviderServerOperation { logger.error("An error occurred when processing the request", e); doFailure(requestContext, e.getStatus(), e.getMessage()); } catch (Exception e) { - String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e, e.getClass().getSimpleName(), + String msg = EELFResourceManager.format(Msg.DETTACHINGVOLUME_SERVER, e, e.getClass().getSimpleName(), DETACHVOLUME_SERVICE.toString(), vmUrl, tenantName); logger.error(msg, e); + try { + ExceptionMapper.mapException((OpenStackBaseException) e); + } catch (ZoneException e1) { + logger.error(e1.getMessage()); + } + doFailure(requestContext, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); } return server; } - protected boolean validateDetach(VolumeService volumeService, String volId) + protected boolean validateDetach(ComputeService ser, String vm, String volumeId) + throws RequestFailedException, ZoneException { + boolean flag = false; + Map map = ser.getAttachments(vm); + if (map != null && !(map.isEmpty())) { + Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry volumes = (Map.Entry) it.next(); + logger.info("volumes available in before detach"); + logger.info("device" + volumes.getKey() + "volume" + volumes.getValue()); + if (volumes.getValue().equals(volumeId)) { + flag = true; + } + } + } + logger.info("DettachVolume Flag" + flag); + return flag; + } + + protected boolean validateDetach(RequestContext rc, ComputeService ser, String vm, String volumeId) throws RequestFailedException, ZoneException { boolean flag = false; - List volumes = volumeService.getVolumes(); - if (!volumes.contains(volId)) { - flag = true; - } else { - flag = false; + String msg = null; + config.setProperty(Constants.PROPERTY_RETRY_DELAY, "10"); + config.setProperty(Constants.PROPERTY_RETRY_LIMIT, "30"); + while (rc.attempt()) { + Map map = ser.getAttachments(vm); + if (map != null && !(map.isEmpty())) { + Iterator> it = map.entrySet().iterator(); + logger.info("volumes available after detach "); + while (it.hasNext()) { + Map.Entry volumes = (Map.Entry) it.next(); + logger.info(" devices " + volumes.getKey() + " volumes" + volumes.getValue()); + if (volumes.getValue().equals(volumeId)) { + logger.info("Device" + volumes.getKey() + "Volume" + volumes.getValue()); + flag = true; + break; + } else { + flag = false; + } + logger.info("Dettachvolume flag-->" + flag+"Attempts"+rc.getAttempts()); + } + if (flag) { + rc.delay(); + } else { + flag = false; + break; + } } - logger.info("validateDetach flag-->" + flag); + else + { + flag = false; + logger.info( rc.getAttempts() + "No.of attempts"); + break; + } + } + if ((rc.getAttempts() == 30) && (!flag)) { + msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, Long.toString(rc.getRetryDelay()), + Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit())); + logger.error(msg); + logger.info(msg); + throw new TimeoutException(msg); + } + logger.info("DettachVolume Flag -->" + flag); return flag; } + } diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/MigrateServer.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/MigrateServer.java index b93511ae2..cb08c7742 100644 --- a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/MigrateServer.java +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/MigrateServer.java @@ -56,7 +56,7 @@ import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.TimeZone; - +import java.util.Iterator; import static org.onap.appc.adapter.iaas.provider.operation.common.enums.Operation.MIGRATE_SERVICE; import static org.onap.appc.adapter.utils.Constants.ADAPTER_NAME; diff --git a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/base/ProviderOperation.java b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/base/ProviderOperation.java index 2a48e27b6..87d287271 100644 --- a/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/base/ProviderOperation.java +++ b/appc-adapters/appc-iaas-adapter/appc-iaas-adapter-bundle/src/main/java/org/onap/appc/adapter/iaas/provider/operation/impl/base/ProviderOperation.java @@ -1,456 +1,432 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP : APPC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Copyright (C) 2017 Amdocs - * ============================================================================= - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ECOMP is a trademark and service mark of AT&T Intellectual Property. - * ============LICENSE_END========================================================= - */ - -package org.onap.appc.adapter.iaas.provider.operation.impl.base; - -import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; -import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER; -import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE; - -import com.att.cdp.exceptions.ZoneException; -import com.att.cdp.zones.Context; -import com.att.cdp.zones.model.ModelObject; -import com.att.cdp.zones.model.Server; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import com.att.eelf.i18n.EELFResourceManager; -import java.net.URI; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Pattern; -import org.glassfish.grizzly.http.util.HttpStatus; -import org.onap.appc.adapter.iaas.ProviderAdapter; -import org.onap.appc.adapter.iaas.impl.IdentityURL; -import org.onap.appc.adapter.iaas.impl.ProviderCache; -import org.onap.appc.adapter.iaas.impl.RequestContext; -import org.onap.appc.adapter.iaas.impl.RequestFailedException; -import org.onap.appc.adapter.iaas.impl.TenantCache; -import org.onap.appc.adapter.iaas.impl.VMURL; -import org.onap.appc.adapter.iaas.provider.operation.api.IProviderOperation; -import org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants; -import org.onap.appc.adapter.iaas.provider.operation.common.enums.Outcome; -import org.onap.appc.configuration.Configuration; -import org.onap.appc.configuration.ConfigurationFactory; -import org.onap.appc.exceptions.APPCException; -import org.onap.appc.i18n.Msg; -import org.onap.appc.pool.Pool; -import org.onap.appc.pool.PoolExtensionException; -import org.onap.ccsdk.sli.core.sli.SvcLogicContext; -import org.slf4j.MDC; - -public abstract class ProviderOperation implements IProviderOperation { - - private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class); - protected static final Configuration configuration = ConfigurationFactory.getConfiguration(); - - - /** - * A cache of providers that are predefined. - */ - private Map providerCache; - - /** - * The username and password to use for dynamically created connections - */ - private String defaultUser; - private String defaultPassword; - private String defaultDomain; - - @Override - public void setDefaultUser(String defaultUser) { - this.defaultUser = defaultUser; - } - - @Override - public void setDefaultPassword(String defaultPassword) { - this.defaultPassword = defaultPassword; - } - - @Override - public void setProviderCache(Map providerCache) { - this.providerCache = providerCache; - } - - @Override - public void setDefaultDomain(String defaultDomain) { - this.defaultDomain = defaultDomain; - } - - /** - * set MDC props - */ - protected void setMDC(String service, String serviceName, String adapterName) { - MDC.put(MDC_ADAPTER, adapterName); - MDC.put(MDC_SERVICE, service); - MDC.put(MDC_SERVICE_NAME, serviceName); - } - - /** - * initial log of the operation - */ - protected void logOperation(Msg msg, Map params, SvcLogicContext context) { - - String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME); - logger.info(msg, appName); - - debugParameters(params); - debugContext(context); - } - - /** - * This method is used to dump the value of the parameters to the log for debugging purposes. - * - * @param parameters The parameters to be printed to the log - */ - private void debugParameters(Map parameters) { - for (Entry entry : parameters.entrySet()) { - logger.debug(Msg.PROPERTY_VALUE, entry.getKey(), entry.getValue()); - } - } - - /** - * This method is used to create a diagnostic dump of the context for the log - * - * @param context The context to be dumped - */ - @SuppressWarnings({"nls", "static-method"}) - private void debugContext(SvcLogicContext context) { - Set keys = context.getAttributeKeySet(); - StringBuilder builder = new StringBuilder(); - - builder.append("Service Logic Context: Status "); - builder.append(Constants.LPAREN); - builder.append(context.getStatus()); - builder.append(Constants.RPAREN); - builder.append(", Attribute count "); - builder.append(Constants.LPAREN); - builder.append(keys == null ? "none" : Integer.toString(keys.size())); - builder.append(Constants.RPAREN); - if (keys != null && !keys.isEmpty()) { - builder.append(Constants.NL); - for (String key : keys) { - String value = context.getAttribute(key); - builder.append("Attribute "); - builder.append(Constants.LPAREN); - builder.append(key); - builder.append(Constants.RPAREN); - builder.append(", value "); - builder.append(Constants.LPAREN); - builder.append(value == null ? "" : value); - builder.append(Constants.RPAREN); - builder.append(Constants.NL); - } - } - - logger.debug(builder.toString()); - } - - - /** - * This method is used to validate that the parameters contain all required property names, and that the values are - * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists. - * - * @param parameters The parameters to be checked - * @param propertyNames The list of property names that are required to be present. - * @throws RequestFailedException If the parameters are not valid - */ - protected void validateParametersExist(Map parameters, String... propertyNames) - throws RequestFailedException { - boolean success = true; - StringBuilder msg = - new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE))); - msg.append(Constants.NL); - for (String propertyName : propertyNames) { - String value = parameters.get(propertyName); - if (value == null || value.trim().length() == 0) { - success = false; - msg.append(Constants.QUOTE); - msg.append(propertyName); - msg.append(Constants.QUOTE); - msg.append(Constants.SPACE); - } - } - - if (!success) { - logger.error(msg.toString()); - throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, - (Server) null); - } - } - - /** - * @param rc The request context that manages the state and recovery of the request for the life of its processing. - */ - protected void doFailure(RequestContext rc, HttpStatus code, String message) { - try { - doFailure(rc, code, message, null); - } catch (APPCException e) { - logger.error("An APPC exception caught. Should never happen", e); - } - } - - protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException { - SvcLogicContext svcLogic = rc.getSvcLogicContext(); - String msg = (message == null) ? code.getReasonPhrase() : message; - if (msg.contains("\n")) { - msg = msg.substring(0, msg.indexOf('\n')); - } - String status; - try { - status = Integer.toString(code.getStatusCode()); - } catch (Exception e) { - logger.error("Error when parsing status code", e); - status = "500"; - } - svcLogic.setStatus(Outcome.FAILURE.toString()); - svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE, status); - svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg); - - if (null != cause) { - throw new APPCException(cause); - } - } - - /** - * @param rc The request context that manages the state and recovery of the request for the life of its processing. - */ - @SuppressWarnings("static-method") - protected void doSuccess(RequestContext rc) { - SvcLogicContext svcLogic = rc.getSvcLogicContext(); - svcLogic.setStatus(Outcome.SUCCESS.toString()); - svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE, - Integer.toString(HttpStatus.OK_200.getStatusCode())); - } - - protected boolean validateVM(RequestContext rc, String appName, String vmUrl, VMURL vm) - throws RequestFailedException { - String msg; - if (vm == null) { - msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl); - logger.error(msg); - doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); - return true; - } - validateVMURL(vm); - return false; - } - - protected void validateVMURL(VMURL vm) throws RequestFailedException { - String name = "vm-id"; - if (vm == null) { - throw new RequestFailedException(String.format("The value %s cannot be null.", name)); - } - - // Check that its a good uri - // This will probably never get hit bc of an earlier check while parsing - // the string to a VMURL - try { - // noinspection ResultOfMethodCallIgnored - URI.create(vm.toString()); - } catch (Exception e) { - logger.error("An error occurred when validating vm url", e); - throw new RequestFailedException( - String.format("The value %s is not well formed [%s].", name, vm.toString())); - } - - // Check the tenant and vmid segments - String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})"; - Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE); - - if (!pattern.matcher(vm.getTenantId()).matches()) { - throw new RequestFailedException( - String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId())); - } - if (!pattern.matcher(vm.getServerId()).matches()) { - throw new RequestFailedException( - String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId())); - } - } - - private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) { - if (vm != null && ident != null) { - ProviderCache cache = new ProviderCache(); - - cache.setIdentityURL(ident.toString()); - cache.setProviderName(ident.toString()); - - TenantCache tenant = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain); - - // Make sure we could initialize the the cache otherwise return null - if (tenant != null && tenant.isInitialized()) { - return cache; - } - } - return null; - } - - /** - * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a - * supported provider, regardless of region(s), and to return an opened context that can be used to access that - * server. - * - * @param rc The request context that wraps and manages the state of the request - * @param selfLinkURL The fully-qualified self-link URL of the server - * @param providerName The name of the provider to be searched - * @return The context that can be used to access the server, or null if not found. - */ - @SuppressWarnings("nls") - protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) { - VMURL vm = VMURL.parseURL(selfLinkURL); - IdentityURL ident = IdentityURL.parseURL(providerName); - String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME); - - if (vm == null) { - String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL); - logger.error(msg); - doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); - return null; - } - - /* - * Get the cache of tenants and contexts for the named provider, if one exists - */ - ProviderCache cache = providerCache.get(providerName); - - /* - * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to - * the cache and continue, otherwise fail the request. - */ - if (cache == null) { - if (ident != null) { - cache = createProviderCache(vm, ident); - } - if (cache != null) { - providerCache.put(cache.getProviderName(), cache); - } else { - String msg = EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, - providerCache.keySet().toString()); - logger.error(msg); - doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); - return null; - } - } - - if (providerName == null) { - logger.debug( - String.format("Using the default provider cache [%s] since no valid identity url was passed in.", - cache.getIdentityURL())); - } - - // get the tenant cache for the vm - String identityURL = cache.getIdentityURL(); - TenantCache tenantCache = cache.getTenant(vm.getTenantId()); - - if (tenantCache == null) { - // no tenantCache matching tenant, add tenant to the provider cache - tenantCache = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain); - if (tenantCache == null) { - // tenant not found - String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL); - logger.error(msg); - doFailure(rc, HttpStatus.NOT_FOUND_404, msg); - return null; - } - } - - // reserve the context - String tenantName = tenantCache.getTenantName(); - String tenantId = tenantCache.getTenantId(); - String region = tenantCache.determineRegion(vm); - - if (region != null) { - Pool pool = tenantCache.getPools().get(region); - - while (rc.attempt()) { - try { - Context context = pool.reserve(); - /* - * Insert logic here to test the context for connectivity because we may have gotten one from the - * pool that was previously created. - */ - reloginIfNeeded(context); - return context; - } catch (PoolExtensionException e) { - String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL, - tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()), - Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit())); - logger.error(msg, e); - rc.delay(); - } catch (Exception e) { - String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e, - e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName()); - - logger.error(msg, e); - doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); - return null; - } - } - - String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL); - logger.error(msg); - doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg); - return null; - } - - String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL); - logger.error(msg); - doFailure(rc, HttpStatus.NOT_FOUND_404, msg); - return null; - } - - private void reloginIfNeeded(Context context) throws ZoneException { - if (context.isStale()) { - context.relogin(); - } - } - - protected Context resolveContext(RequestContext rc, Map params, String appName, String vmUrl) - throws RequestFailedException { - - VMURL vm = VMURL.parseURL(vmUrl); - if (vm == null) { - String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl); - doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); - logger.error(msg); - return null; - } - validateVMURL(vm); - IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); - String identStr = (ident == null) ? null : ident.toString(); - - return getContext(rc, vmUrl, identStr); - - } - - - protected abstract ModelObject executeProviderOperation(Map params, SvcLogicContext context) - throws APPCException; - - @Override - public ModelObject doOperation(Map params, SvcLogicContext context) throws APPCException { - - return executeProviderOperation(params, context); - } -} +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.onap.appc.adapter.iaas.provider.operation.impl.base; + +import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; +import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER; +import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE; + +import com.att.cdp.exceptions.ZoneException; +import com.att.cdp.zones.Context; +import com.att.cdp.zones.model.ModelObject; +import com.att.cdp.zones.model.Server; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.eelf.i18n.EELFResourceManager; +import java.net.URI; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.regex.Pattern; +import org.glassfish.grizzly.http.util.HttpStatus; +import org.onap.appc.adapter.iaas.ProviderAdapter; +import org.onap.appc.adapter.iaas.impl.IdentityURL; +import org.onap.appc.adapter.iaas.impl.ProviderCache; +import org.onap.appc.adapter.iaas.impl.RequestContext; +import org.onap.appc.adapter.iaas.impl.RequestFailedException; +import org.onap.appc.adapter.iaas.impl.TenantCache; +import org.onap.appc.adapter.iaas.impl.VMURL; +import org.onap.appc.adapter.iaas.provider.operation.api.IProviderOperation; +import org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants; +import org.onap.appc.adapter.iaas.provider.operation.common.enums.Outcome; +import org.onap.appc.configuration.Configuration; +import org.onap.appc.configuration.ConfigurationFactory; +import org.onap.appc.exceptions.APPCException; +import org.onap.appc.i18n.Msg; +import org.onap.appc.pool.Pool; +import org.onap.appc.pool.PoolExtensionException; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.slf4j.MDC; + +public abstract class ProviderOperation implements IProviderOperation { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class); + protected static final Configuration configuration = ConfigurationFactory.getConfiguration(); + + + /** + * A cache of providers that are predefined. + */ + private Map providerCache; + + /** + * The username and password to use for dynamically created connections + */ + private String defaultUser; + private String defaultPassword; + private String defaultDomain; + + @Override + public void setDefaultUser(String defaultUser) { + this.defaultUser = defaultUser; + } + + @Override + public void setDefaultPassword(String defaultPassword) { + this.defaultPassword = defaultPassword; + } + + @Override + public void setProviderCache(Map providerCache) { + this.providerCache = providerCache; + } + + @Override + public void setDefaultDomain(String defaultDomain) { + this.defaultDomain = defaultDomain; + } + + /** + * set MDC props + */ + protected void setMDC(String service, String serviceName, String adapterName) { + MDC.put(MDC_ADAPTER, adapterName); + MDC.put(MDC_SERVICE, service); + MDC.put(MDC_SERVICE_NAME, serviceName); + } + + /** + * initial log of the operation + */ + protected void logOperation(Msg msg, Map params, SvcLogicContext context) { + + String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME); + logger.info(msg, appName); + + debugParameters(params); + debugContext(context); + } + /** + * This method is used to dump the value of the parameters to the log for debugging purposes. + * + * @param parameters The parameters to be printed to the log + */ + private void debugParameters(Map parameters) { + for (Entry entry : parameters.entrySet()) { + logger.debug(Msg.PROPERTY_VALUE, entry.getKey(), entry.getValue()); + } + } + /** + * This method is used to create a diagnostic dump of the context for the log + * + * @param context The context to be dumped + */ + @SuppressWarnings({"nls", "static-method"}) + private void debugContext(SvcLogicContext context) { + Set keys = context.getAttributeKeySet(); + StringBuilder builder = new StringBuilder(); + builder.append("Service Logic Context: Status "); + builder.append(Constants.LPAREN); + builder.append(context.getStatus()); + builder.append(Constants.RPAREN); + builder.append(", Attribute count "); + builder.append(Constants.LPAREN); + builder.append(keys == null ? "none" : Integer.toString(keys.size())); + builder.append(Constants.RPAREN); + if (keys != null && !keys.isEmpty()) { + builder.append(Constants.NL); + for (String key : keys) { + String value = context.getAttribute(key); + builder.append("Attribute "); + builder.append(Constants.LPAREN); + builder.append(key); + builder.append(Constants.RPAREN); + builder.append(", value "); + builder.append(Constants.LPAREN); + builder.append(value == null ? "" : value); + builder.append(Constants.RPAREN); + builder.append(Constants.NL); + } + } + logger.debug(builder.toString()); + } + + + /** + * This method is used to validate that the parameters contain all required property names, and that the values are + * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists. + * + * @param parameters The parameters to be checked + * @param propertyNames The list of property names that are required to be present. + * @throws RequestFailedException If the parameters are not valid + */ + protected void validateParametersExist(Map parameters, String... propertyNames) + throws RequestFailedException { + boolean success = true; + StringBuilder msg = + new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE))); + msg.append(Constants.NL); + for (String propertyName : propertyNames) { + String value = parameters.get(propertyName); + if (value == null || value.trim().length() == 0) { + success = false; + msg.append(Constants.QUOTE); + msg.append(propertyName); + msg.append(Constants.QUOTE); + msg.append(Constants.SPACE); + } + } + + if (!success) { + logger.error(msg.toString()); + throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, + (Server) null); + } + } + + /** + * @param rc The request context that manages the state and recovery of the request for the life of its processing. + */ + protected void doFailure(RequestContext rc, HttpStatus code, String message) { + try { + doFailure(rc, code, message, null); + } catch (APPCException e) { + logger.error("An APPC exception caught. Should never happen", e); + } + } + + protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException { + SvcLogicContext svcLogic = rc.getSvcLogicContext(); + String msg = (message == null) ? code.getReasonPhrase() : message; + if ((msg.contains("PALOS"))) { + msg = msg.substring(msg.indexOf("PALOS"), msg.length()); + msg = msg.substring(msg.indexOf("PALOS"), msg.indexOf("\n")); + } else { + if (msg.contains("\n")) { + msg = msg.substring(0, msg.indexOf('\n')); + } + } + String status; + try { + status = Integer.toString(code.getStatusCode()); + } catch (Exception e) { + logger.error("Error when parsing status code", e); + status = "500"; + } + svcLogic.setStatus(Outcome.FAILURE.toString()); + svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE, status); + svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg); + if (null != cause) { + throw new APPCException(cause); + } + } + + /** + * @param rc The request context that manages the state and recovery of the request for the life of its processing. + */ + @SuppressWarnings("static-method") + protected void doSuccess(RequestContext rc) { + SvcLogicContext svcLogic = rc.getSvcLogicContext(); + svcLogic.setStatus(Outcome.SUCCESS.toString()); + svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE, + Integer.toString(HttpStatus.OK_200.getStatusCode())); + } + + protected boolean validateVM(RequestContext rc, String appName, String vmUrl, VMURL vm) + throws RequestFailedException { + String msg; + if (vm == null) { + msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl); + logger.error(msg); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return true; + } + validateVMURL(vm); + return false; + } + + protected void validateVMURL(VMURL vm) throws RequestFailedException { + String name = "vm-id"; + if (vm == null) { + throw new RequestFailedException(String.format("The value %s cannot be null.", name)); + } + // Check that its a good uri + // This will probably never get hit bc of an earlier check while parsing + // the string to a VMURL + try { + // noinspection ResultOfMethodCallIgnored + URI.create(vm.toString()); + } catch (Exception e) { + logger.error("An error occurred when validating vm url", e); + throw new RequestFailedException( + String.format("The value %s is not well formed [%s].", name, vm.toString())); + } + // Check the tenant and vmid segments + String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})"; + Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE); + if (!pattern.matcher(vm.getTenantId()).matches()) { + throw new RequestFailedException( + String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId())); + } + if (!pattern.matcher(vm.getServerId()).matches()) { + throw new RequestFailedException( + String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId())); + } + } + + private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) { + if (vm != null && ident != null) { + ProviderCache cache = new ProviderCache(); + cache.setIdentityURL(ident.toString()); + cache.setProviderName(ident.toString()); + TenantCache tenant = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain); + // Make sure we could initialize the the cache otherwise return null + if (tenant != null && tenant.isInitialized()) { + return cache; + } + } + return null; + } + /** + * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a + * supported provider, regardless of region(s), and to return an opened context that can be used to access that + * server. + * + * @param rc The request context that wraps and manages the state of the request + * @param selfLinkURL The fully-qualified self-link URL of the server + * @param providerName The name of the provider to be searched + * @return The context that can be used to access the server, or null if not found. + */ + @SuppressWarnings("nls") + protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) { + VMURL vm = VMURL.parseURL(selfLinkURL); + IdentityURL ident = IdentityURL.parseURL(providerName); + String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME); + if (vm == null) { + String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL); + logger.error(msg); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return null; + } + /* + * Get the cache of tenants and contexts for the named provider, if one exists + */ + ProviderCache cache = providerCache.get(providerName); + /* + * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to + * the cache and continue, otherwise fail the request. + */ + if (cache == null) { + if (ident != null) { + cache = createProviderCache(vm, ident); + } + if (cache != null) { + providerCache.put(cache.getProviderName(), cache); + } else { + String msg = EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, + providerCache.keySet().toString()); + logger.error(msg); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return null; + } + } + if (providerName == null) { + logger.debug( + String.format("Using the default provider cache [%s] since no valid identity url was passed in.", + cache.getIdentityURL())); + } + // get the tenant cache for the vm + String identityURL = cache.getIdentityURL(); + TenantCache tenantCache = cache.getTenant(vm.getTenantId()); + if (tenantCache == null) { + // no tenantCache matching tenant, add tenant to the provider cache + tenantCache = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain); + if (tenantCache == null) { + // tenant not found + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + return null; + } + } + // reserve the context + String tenantName = tenantCache.getTenantName(); + String tenantId = tenantCache.getTenantId(); + String region = tenantCache.determineRegion(vm); + + if (region != null) { + Pool pool = tenantCache.getPools().get(region); + while (rc.attempt()) { + try { + Context context = pool.reserve(); + /* + * Insert logic here to test the context for connectivity because we may have gotten one from the + * pool that was previously created. + */ + reloginIfNeeded(context); + return context; + } catch (PoolExtensionException e) { + String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL, + tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()), + Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit())); + logger.error(msg, e); + rc.delay(); + } catch (Exception e) { + String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e, + e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName()); + logger.error(msg, e); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + return null; + } + } + String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL); + logger.error(msg); + doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg); + return null; + } + String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL); + logger.error(msg); + doFailure(rc, HttpStatus.NOT_FOUND_404, msg); + return null; + } + + private void reloginIfNeeded(Context context) throws ZoneException { + if (context.isStale()) { + context.relogin(); + } + } + + protected Context resolveContext(RequestContext rc, Map params, String appName, String vmUrl) + throws RequestFailedException { + VMURL vm = VMURL.parseURL(vmUrl); + if (vm == null) { + String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl); + doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg); + logger.error(msg); + return null; + } + validateVMURL(vm); + IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL)); + String identStr = (ident == null) ? null : ident.toString(); + return getContext(rc, vmUrl, identStr); + } + + protected abstract ModelObject executeProviderOperation(Map params, SvcLogicContext context) + throws APPCException; + @Override + public ModelObject doOperation(Map params, SvcLogicContext context) throws APPCException { + return executeProviderOperation(params, context); + } +} -- cgit 1.2.3-korg