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<String, String> params, SvcLogicContext context)
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<Volume> 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 {
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<String, String> map = ser.getAttachments(vm);
+ if (map != null && !(map.isEmpty())) {
+ Iterator<Entry<String, String>> 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<Volume> 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<String, String> map = ser.getAttachments(vm);
+ if (map != null && !(map.isEmpty())) {
+ Iterator<Entry<String, String>> 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;
}
+
}
-/*-
- * ============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<String /* provider name */, ProviderCache> 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<String, ProviderCache> 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<String, String> 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<String, String> parameters) {
- for (Entry<String, String> 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<String> 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<String, String> 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<Context> 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<String, String> 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<String, String> params, SvcLogicContext context)
- throws APPCException;
-
- @Override
- public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
-
- return executeProviderOperation(params, context);
- }
-}
+/*-\r
+ * ============LICENSE_START=======================================================\r
+ * ONAP : APPC\r
+ * ================================================================================\r
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
+ * ================================================================================\r
+ * Copyright (C) 2017 Amdocs\r
+ * =============================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * \r
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * ============LICENSE_END=========================================================\r
+ */\r
+\r
+package org.onap.appc.adapter.iaas.provider.operation.impl.base;\r
+\r
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;\r
+import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER;\r
+import static org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;\r
+\r
+import com.att.cdp.exceptions.ZoneException;\r
+import com.att.cdp.zones.Context;\r
+import com.att.cdp.zones.model.ModelObject;\r
+import com.att.cdp.zones.model.Server;\r
+import com.att.eelf.configuration.EELFLogger;\r
+import com.att.eelf.configuration.EELFManager;\r
+import com.att.eelf.i18n.EELFResourceManager;\r
+import java.net.URI;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.regex.Pattern;\r
+import org.glassfish.grizzly.http.util.HttpStatus;\r
+import org.onap.appc.adapter.iaas.ProviderAdapter;\r
+import org.onap.appc.adapter.iaas.impl.IdentityURL;\r
+import org.onap.appc.adapter.iaas.impl.ProviderCache;\r
+import org.onap.appc.adapter.iaas.impl.RequestContext;\r
+import org.onap.appc.adapter.iaas.impl.RequestFailedException;\r
+import org.onap.appc.adapter.iaas.impl.TenantCache;\r
+import org.onap.appc.adapter.iaas.impl.VMURL;\r
+import org.onap.appc.adapter.iaas.provider.operation.api.IProviderOperation;\r
+import org.onap.appc.adapter.iaas.provider.operation.common.constants.Constants;\r
+import org.onap.appc.adapter.iaas.provider.operation.common.enums.Outcome;\r
+import org.onap.appc.configuration.Configuration;\r
+import org.onap.appc.configuration.ConfigurationFactory;\r
+import org.onap.appc.exceptions.APPCException;\r
+import org.onap.appc.i18n.Msg;\r
+import org.onap.appc.pool.Pool;\r
+import org.onap.appc.pool.PoolExtensionException;\r
+import org.onap.ccsdk.sli.core.sli.SvcLogicContext;\r
+import org.slf4j.MDC;\r
+\r
+public abstract class ProviderOperation implements IProviderOperation {\r
+\r
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);\r
+ protected static final Configuration configuration = ConfigurationFactory.getConfiguration();\r
+\r
+\r
+ /**\r
+ * A cache of providers that are predefined.\r
+ */\r
+ private Map<String /* provider name */, ProviderCache> providerCache;\r
+\r
+ /**\r
+ * The username and password to use for dynamically created connections\r
+ */\r
+ private String defaultUser;\r
+ private String defaultPassword;\r
+ private String defaultDomain;\r
+\r
+ @Override\r
+ public void setDefaultUser(String defaultUser) {\r
+ this.defaultUser = defaultUser;\r
+ }\r
+\r
+ @Override\r
+ public void setDefaultPassword(String defaultPassword) {\r
+ this.defaultPassword = defaultPassword;\r
+ }\r
+\r
+ @Override\r
+ public void setProviderCache(Map<String, ProviderCache> providerCache) {\r
+ this.providerCache = providerCache;\r
+ }\r
+\r
+ @Override\r
+ public void setDefaultDomain(String defaultDomain) {\r
+ this.defaultDomain = defaultDomain;\r
+ }\r
+\r
+ /**\r
+ * set MDC props\r
+ */\r
+ protected void setMDC(String service, String serviceName, String adapterName) {\r
+ MDC.put(MDC_ADAPTER, adapterName);\r
+ MDC.put(MDC_SERVICE, service);\r
+ MDC.put(MDC_SERVICE_NAME, serviceName);\r
+ }\r
+\r
+ /**\r
+ * initial log of the operation\r
+ */\r
+ protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context) {\r
+\r
+ String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME);\r
+ logger.info(msg, appName);\r
+\r
+ debugParameters(params);\r
+ debugContext(context);\r
+ }\r
+ /**\r
+ * This method is used to dump the value of the parameters to the log for debugging purposes.\r
+ *\r
+ * @param parameters The parameters to be printed to the log\r
+ */\r
+ private void debugParameters(Map<String, String> parameters) {\r
+ for (Entry<String, String> entry : parameters.entrySet()) {\r
+ logger.debug(Msg.PROPERTY_VALUE, entry.getKey(), entry.getValue());\r
+ }\r
+ }\r
+ /**\r
+ * This method is used to create a diagnostic dump of the context for the log\r
+ *\r
+ * @param context The context to be dumped\r
+ */\r
+ @SuppressWarnings({"nls", "static-method"})\r
+ private void debugContext(SvcLogicContext context) {\r
+ Set<String> keys = context.getAttributeKeySet();\r
+ StringBuilder builder = new StringBuilder();\r
+ builder.append("Service Logic Context: Status ");\r
+ builder.append(Constants.LPAREN);\r
+ builder.append(context.getStatus());\r
+ builder.append(Constants.RPAREN);\r
+ builder.append(", Attribute count ");\r
+ builder.append(Constants.LPAREN);\r
+ builder.append(keys == null ? "none" : Integer.toString(keys.size()));\r
+ builder.append(Constants.RPAREN);\r
+ if (keys != null && !keys.isEmpty()) {\r
+ builder.append(Constants.NL);\r
+ for (String key : keys) {\r
+ String value = context.getAttribute(key);\r
+ builder.append("Attribute ");\r
+ builder.append(Constants.LPAREN);\r
+ builder.append(key);\r
+ builder.append(Constants.RPAREN);\r
+ builder.append(", value ");\r
+ builder.append(Constants.LPAREN);\r
+ builder.append(value == null ? "" : value);\r
+ builder.append(Constants.RPAREN);\r
+ builder.append(Constants.NL);\r
+ }\r
+ }\r
+ logger.debug(builder.toString());\r
+ }\r
+\r
+\r
+ /**\r
+ * This method is used to validate that the parameters contain all required property names, and that the values are\r
+ * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.\r
+ *\r
+ * @param parameters The parameters to be checked\r
+ * @param propertyNames The list of property names that are required to be present.\r
+ * @throws RequestFailedException If the parameters are not valid\r
+ */\r
+ protected void validateParametersExist(Map<String, String> parameters, String... propertyNames)\r
+ throws RequestFailedException {\r
+ boolean success = true;\r
+ StringBuilder msg =\r
+ new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));\r
+ msg.append(Constants.NL);\r
+ for (String propertyName : propertyNames) {\r
+ String value = parameters.get(propertyName);\r
+ if (value == null || value.trim().length() == 0) {\r
+ success = false;\r
+ msg.append(Constants.QUOTE);\r
+ msg.append(propertyName);\r
+ msg.append(Constants.QUOTE);\r
+ msg.append(Constants.SPACE);\r
+ }\r
+ }\r
+\r
+ if (!success) {\r
+ logger.error(msg.toString());\r
+ throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400,\r
+ (Server) null);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param rc The request context that manages the state and recovery of the request for the life of its processing.\r
+ */\r
+ protected void doFailure(RequestContext rc, HttpStatus code, String message) {\r
+ try {\r
+ doFailure(rc, code, message, null);\r
+ } catch (APPCException e) {\r
+ logger.error("An APPC exception caught. Should never happen", e);\r
+ }\r
+ }\r
+\r
+ protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {\r
+ SvcLogicContext svcLogic = rc.getSvcLogicContext();\r
+ String msg = (message == null) ? code.getReasonPhrase() : message;\r
+ if ((msg.contains("PALOS"))) {\r
+ msg = msg.substring(msg.indexOf("PALOS"), msg.length());\r
+ msg = msg.substring(msg.indexOf("PALOS"), msg.indexOf("\n"));\r
+ } else {\r
+ if (msg.contains("\n")) {\r
+ msg = msg.substring(0, msg.indexOf('\n'));\r
+ }\r
+ }\r
+ String status;\r
+ try {\r
+ status = Integer.toString(code.getStatusCode());\r
+ } catch (Exception e) {\r
+ logger.error("Error when parsing status code", e);\r
+ status = "500";\r
+ }\r
+ svcLogic.setStatus(Outcome.FAILURE.toString());\r
+ svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE, status);\r
+ svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg);\r
+ if (null != cause) {\r
+ throw new APPCException(cause);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param rc The request context that manages the state and recovery of the request for the life of its processing.\r
+ */\r
+ @SuppressWarnings("static-method")\r
+ protected void doSuccess(RequestContext rc) {\r
+ SvcLogicContext svcLogic = rc.getSvcLogicContext();\r
+ svcLogic.setStatus(Outcome.SUCCESS.toString());\r
+ svcLogic.setAttribute(org.onap.appc.Constants.ATTRIBUTE_ERROR_CODE,\r
+ Integer.toString(HttpStatus.OK_200.getStatusCode()));\r
+ }\r
+\r
+ protected boolean validateVM(RequestContext rc, String appName, String vmUrl, VMURL vm)\r
+ throws RequestFailedException {\r
+ String msg;\r
+ if (vm == null) {\r
+ msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl);\r
+ logger.error(msg);\r
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);\r
+ return true;\r
+ }\r
+ validateVMURL(vm);\r
+ return false;\r
+ }\r
+\r
+ protected void validateVMURL(VMURL vm) throws RequestFailedException {\r
+ String name = "vm-id";\r
+ if (vm == null) {\r
+ throw new RequestFailedException(String.format("The value %s cannot be null.", name));\r
+ }\r
+ // Check that its a good uri\r
+ // This will probably never get hit bc of an earlier check while parsing\r
+ // the string to a VMURL\r
+ try {\r
+ // noinspection ResultOfMethodCallIgnored\r
+ URI.create(vm.toString());\r
+ } catch (Exception e) {\r
+ logger.error("An error occurred when validating vm url", e);\r
+ throw new RequestFailedException(\r
+ String.format("The value %s is not well formed [%s].", name, vm.toString()));\r
+ }\r
+ // Check the tenant and vmid segments\r
+ String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";\r
+ Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);\r
+ if (!pattern.matcher(vm.getTenantId()).matches()) {\r
+ throw new RequestFailedException(\r
+ String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));\r
+ }\r
+ if (!pattern.matcher(vm.getServerId()).matches()) {\r
+ throw new RequestFailedException(\r
+ String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));\r
+ }\r
+ }\r
+\r
+ private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {\r
+ if (vm != null && ident != null) {\r
+ ProviderCache cache = new ProviderCache();\r
+ cache.setIdentityURL(ident.toString());\r
+ cache.setProviderName(ident.toString());\r
+ TenantCache tenant = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain);\r
+ // Make sure we could initialize the the cache otherwise return null\r
+ if (tenant != null && tenant.isInitialized()) {\r
+ return cache;\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ /**\r
+ * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a\r
+ * supported provider, regardless of region(s), and to return an opened context that can be used to access that\r
+ * server.\r
+ *\r
+ * @param rc The request context that wraps and manages the state of the request\r
+ * @param selfLinkURL The fully-qualified self-link URL of the server\r
+ * @param providerName The name of the provider to be searched\r
+ * @return The context that can be used to access the server, or null if not found.\r
+ */\r
+ @SuppressWarnings("nls")\r
+ protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) {\r
+ VMURL vm = VMURL.parseURL(selfLinkURL);\r
+ IdentityURL ident = IdentityURL.parseURL(providerName);\r
+ String appName = configuration.getProperty(org.onap.appc.Constants.PROPERTY_APPLICATION_NAME);\r
+ if (vm == null) {\r
+ String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);\r
+ logger.error(msg);\r
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);\r
+ return null;\r
+ }\r
+ /*\r
+ * Get the cache of tenants and contexts for the named provider, if one exists\r
+ */\r
+ ProviderCache cache = providerCache.get(providerName);\r
+ /*\r
+ * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to\r
+ * the cache and continue, otherwise fail the request.\r
+ */\r
+ if (cache == null) {\r
+ if (ident != null) {\r
+ cache = createProviderCache(vm, ident);\r
+ }\r
+ if (cache != null) {\r
+ providerCache.put(cache.getProviderName(), cache);\r
+ } else {\r
+ String msg = EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName,\r
+ providerCache.keySet().toString());\r
+ logger.error(msg);\r
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);\r
+ return null;\r
+ }\r
+ }\r
+ if (providerName == null) {\r
+ logger.debug(\r
+ String.format("Using the default provider cache [%s] since no valid identity url was passed in.",\r
+ cache.getIdentityURL()));\r
+ }\r
+ // get the tenant cache for the vm\r
+ String identityURL = cache.getIdentityURL();\r
+ TenantCache tenantCache = cache.getTenant(vm.getTenantId());\r
+ if (tenantCache == null) {\r
+ // no tenantCache matching tenant, add tenant to the provider cache\r
+ tenantCache = cache.addTenant(vm.getTenantId(), null, defaultUser, defaultPassword, defaultDomain);\r
+ if (tenantCache == null) {\r
+ // tenant not found\r
+ String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);\r
+ logger.error(msg);\r
+ doFailure(rc, HttpStatus.NOT_FOUND_404, msg);\r
+ return null;\r
+ }\r
+ }\r
+ // reserve the context\r
+ String tenantName = tenantCache.getTenantName();\r
+ String tenantId = tenantCache.getTenantId();\r
+ String region = tenantCache.determineRegion(vm);\r
+\r
+ if (region != null) {\r
+ Pool<Context> pool = tenantCache.getPools().get(region);\r
+ while (rc.attempt()) {\r
+ try {\r
+ Context context = pool.reserve();\r
+ /*\r
+ * Insert logic here to test the context for connectivity because we may have gotten one from the\r
+ * pool that was previously created.\r
+ */\r
+ reloginIfNeeded(context);\r
+ return context;\r
+ } catch (PoolExtensionException e) {\r
+ String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,\r
+ tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),\r
+ Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));\r
+ logger.error(msg, e);\r
+ rc.delay();\r
+ } catch (Exception e) {\r
+ String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,\r
+ e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());\r
+ logger.error(msg, e);\r
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);\r
+ return null;\r
+ }\r
+ }\r
+ String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);\r
+ logger.error(msg);\r
+ doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);\r
+ return null;\r
+ }\r
+ String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);\r
+ logger.error(msg);\r
+ doFailure(rc, HttpStatus.NOT_FOUND_404, msg);\r
+ return null;\r
+ }\r
+\r
+ private void reloginIfNeeded(Context context) throws ZoneException {\r
+ if (context.isStale()) {\r
+ context.relogin();\r
+ }\r
+ }\r
+\r
+ protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vmUrl)\r
+ throws RequestFailedException {\r
+ VMURL vm = VMURL.parseURL(vmUrl);\r
+ if (vm == null) {\r
+ String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vmUrl);\r
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);\r
+ logger.error(msg);\r
+ return null;\r
+ }\r
+ validateVMURL(vm);\r
+ IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));\r
+ String identStr = (ident == null) ? null : ident.toString();\r
+ return getContext(rc, vmUrl, identStr);\r
+ }\r
+\r
+ protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context)\r
+ throws APPCException;\r
+ @Override\r
+ public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {\r
+ return executeProviderOperation(params, context);\r
+ }\r
+}\r