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.openecomp.appc.adapter.iaas.provider.operation.impl.base;
 
  27 import org.openecomp.appc.adapter.iaas.ProviderAdapter;
 
  28 import org.openecomp.appc.adapter.iaas.impl.*;
 
  29 import org.openecomp.appc.adapter.iaas.provider.operation.api.IProviderOperation;
 
  30 import org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants;
 
  31 import org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Outcome;
 
  32 import org.openecomp.appc.configuration.Configuration;
 
  33 import org.openecomp.appc.configuration.ConfigurationFactory;
 
  34 import org.openecomp.appc.exceptions.APPCException;
 
  35 import org.openecomp.appc.i18n.Msg;
 
  36 import org.openecomp.appc.pool.Pool;
 
  37 import org.openecomp.appc.pool.PoolExtensionException;
 
  38 import com.att.cdp.zones.Context;
 
  39 import com.att.cdp.zones.model.ModelObject;
 
  40 import com.att.cdp.zones.model.Server;
 
  41 import com.att.eelf.configuration.EELFLogger;
 
  42 import com.att.eelf.configuration.EELFManager;
 
  43 import com.att.eelf.i18n.EELFResourceManager;
 
  44 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 
  45 import org.glassfish.grizzly.http.util.HttpStatus;
 
  51 import java.util.regex.Pattern;
 
  53 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER;
 
  54 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;
 
  55 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
 
  58  * @since September 26, 2016
 
  60 public abstract class ProviderOperation implements IProviderOperation {
 
  62     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);
 
  63     protected static final Configuration configuration = ConfigurationFactory.getConfiguration();
 
  65     public void setProviderCache(Map<String, ProviderCache> providerCache) {
 
  66         this.providerCache = providerCache;
 
  70      * A cache of providers that are predefined.
 
  72     private Map<String /* provider name */, ProviderCache> providerCache;
 
  75     public void setDefaultUser(String defaultUser) {
 
  76         DEFAULT_USER = defaultUser;
 
  79     public void setDefaultPass(String defaultPass) {
 
  80         DEFAULT_PASS = defaultPass;
 
  84      * The username and password to use for dynamically created connections
 
  86     private static String DEFAULT_USER;
 
  87     private static String DEFAULT_PASS;
 
  96     protected void setMDC(String service, String serviceName, String adapterName){
 
  97         MDC.put(MDC_ADAPTER, adapterName);
 
  98         MDC.put(MDC_SERVICE, service);
 
  99         MDC.put(MDC_SERVICE_NAME, serviceName);
 
 103      * initial log of the operation
 
 108     protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context){
 
 110         String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
 
 111         logger.info(msg, appName);
 
 113         debugParameters(params);
 
 114         debugContext(context);
 
 118      * This method is used to dump the value of the parameters to the log for debugging purposes.
 
 121      *            The parameters to be printed to the log
 
 123     private void debugParameters(Map<String, String> parameters) {
 
 124         for (String key : parameters.keySet()) {
 
 125             logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key));
 
 130      * This method is used to create a diagnostic dump of the context for the log
 
 133      *            The context to be dumped
 
 136             "nls", "static-method"
 
 138     private void debugContext(SvcLogicContext context) {
 
 139         Set<String> keys = context.getAttributeKeySet();
 
 140         StringBuilder builder = new StringBuilder();
 
 142         builder.append("Service Logic Context: Status ");
 
 143         builder.append(Constants.LPAREN);
 
 144         builder.append(context.getStatus());
 
 145         builder.append(Constants.RPAREN);
 
 146         builder.append(", Attribute count ");
 
 147         builder.append(Constants.LPAREN);
 
 148         builder.append(keys == null ? "none" : Integer.toString(keys.size()));
 
 149         builder.append(Constants.RPAREN);
 
 150         if (keys != null && !keys.isEmpty()) {
 
 151             builder.append(Constants.NL);
 
 152             for (String key : keys) {
 
 153                 String value = context.getAttribute(key);
 
 154                 builder.append("Attribute ");
 
 155                 builder.append(Constants.LPAREN);
 
 157                 builder.append(Constants.RPAREN);
 
 158                 builder.append(", value ");
 
 159                 builder.append(Constants.LPAREN);
 
 160                 builder.append(value == null ? "" : value);
 
 161                 builder.append(Constants.RPAREN);
 
 162                 builder.append(Constants.NL);
 
 166         logger.debug(builder.toString());
 
 171      * This method is used to validate that the parameters contain all required property names, and that the values are
 
 172      * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.
 
 175      *            The parameters to be checked
 
 176      * @param propertyNames
 
 177      *            The list of property names that are required to be present.
 
 178      * @throws RequestFailedException
 
 179      *             If the parameters are not valid
 
 181     protected void validateParametersExist(Map<String, String> parameters, String... propertyNames)
 
 182             throws RequestFailedException {
 
 183         boolean success = true;
 
 184         StringBuilder msg = new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));
 
 185         msg.append(Constants.NL);
 
 186         for (String propertyName : propertyNames) {
 
 187             String value = parameters.get(propertyName);
 
 188             if (value == null || value.trim().length() == 0) {
 
 190                 msg.append(Constants.QUOTE);
 
 191                 msg.append(propertyName);
 
 192                 msg.append(Constants.QUOTE);
 
 193                 msg.append(Constants.SPACE);
 
 198             logger.error(msg.toString());
 
 199             throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null);
 
 205      *            The request context that manages the state and recovery of the request for the life of its processing.
 
 209     protected void doFailure(RequestContext rc, HttpStatus code, String message) {
 
 211             doFailure(rc, code, message, null);
 
 212         } catch (APPCException ignored) {/* never happens */}
 
 215     protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {
 
 216         SvcLogicContext svcLogic = rc.getSvcLogicContext();
 
 217         String msg = (message == null) ? code.getReasonPhrase() : message;
 
 218         if (msg.contains("\n")) {
 
 219             msg = msg.substring(0, msg.indexOf("\n"));
 
 223             status = Integer.toString(code.getStatusCode());
 
 224         } catch (Exception e) {
 
 227         svcLogic.setStatus(Outcome.FAILURE.toString());
 
 228         svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, status);
 
 229         svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg);
 
 231         if (null != cause) throw new APPCException(cause);
 
 236      *            The request context that manages the state and recovery of the request for the life of its processing.
 
 238     @SuppressWarnings("static-method")
 
 239     protected void doSuccess(RequestContext rc) {
 
 240         SvcLogicContext svcLogic = rc.getSvcLogicContext();
 
 241         svcLogic.setStatus(Outcome.SUCCESS.toString());
 
 242         svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode()));
 
 245     protected boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm)
 
 246             throws RequestFailedException {
 
 249             msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
 
 251             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
 
 258     protected void validateVMURL(VMURL vm) throws RequestFailedException {
 
 259         String name = "vm-id";
 
 261             throw new RequestFailedException(String.format("The value %s cannot be null.", name));
 
 264         // Check that its a good uri
 
 265         // This will probably never get hit bc of an earlier check while parsing
 
 266         // the string to a VMURL
 
 268             //noinspection ResultOfMethodCallIgnored
 
 269             URI.create(vm.toString());
 
 270         } catch (Exception e) {
 
 271             throw new RequestFailedException(
 
 272                     String.format("The value %s is not well formed [%s].", name, vm.toString()));
 
 275         // Check the tenant and vmid segments
 
 276         String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";
 
 277         Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);
 
 279         if (!pattern.matcher(vm.getTenantId()).matches()) {
 
 280             throw new RequestFailedException(
 
 281                     String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));
 
 283         if (!pattern.matcher(vm.getServerId()).matches()) {
 
 284             throw new RequestFailedException(
 
 285                     String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));
 
 289     private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
 
 290         if (vm != null && ident != null) {
 
 291             ProviderCache cache = new ProviderCache();
 
 293             cache.setIdentityURL(ident.toString());
 
 294             cache.setProviderName(ident.toString());
 
 295             // cache.setProviderType("OpenStack");
 
 297             TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS);
 
 299             // Make sure we could initialize the the cache otherwise return null
 
 300             if (tenant != null && tenant.isInitialized()) {
 
 308      * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a
 
 309      * supported provider, regardless of region(s), and to return an opened context that can be used to access that
 
 313      *            The request context that wraps and manages the state of the request
 
 315      *            The fully-qualified self-link URL of the server
 
 316      * @param providerName
 
 317      *            The name of the provider to be searched
 
 318      * @return The context that can be used to access the server, or null if not found.
 
 320     @SuppressWarnings("nls")
 
 321     protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) {
 
 322         VMURL vm = VMURL.parseURL(selfLinkURL);
 
 323         IdentityURL ident = IdentityURL.parseURL(providerName);
 
 324         String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
 
 327             String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
 
 329             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
 
 334          * Get the cache of tenants and contexts for the named provider, if one exists
 
 336         ProviderCache cache = providerCache.get(providerName);
 
 339          * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to
 
 340          * the cache and continue, otherwise fail the request.
 
 344                 cache = createProviderCache(vm, ident);
 
 347                 providerCache.put(cache.getProviderName(), cache);
 
 350                         EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString());
 
 352                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
 
 357         if (providerName == null) {
 
 359                     .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
 
 360                             cache.getIdentityURL()));
 
 363         // get the tenant cache for the vm
 
 364         String identityURL = cache.getIdentityURL();
 
 365         TenantCache tenantCache = cache.getTenant(vm.getTenantId());
 
 367         if(tenantCache == null){
 
 368             //no tenantCache matching tenant, add tenant to the provider cache
 
 369             tenantCache = cache.addTenant(vm.getTenantId(),null,DEFAULT_USER, DEFAULT_PASS);
 
 371             if(tenantCache == null){
 
 373                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
 
 375                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
 
 380         //reserve the context
 
 381         String tenantName = tenantCache.getTenantName();
 
 382         String tenantId = tenantCache.getTenantId();
 
 383         String region = tenantCache.determineRegion(vm);
 
 385         if (region != null) {
 
 386             Pool<Context> pool = tenantCache.getPools().get(region);
 
 388             while (rc.attempt()) {
 
 390                     Context context = pool.reserve();
 
 393                      * Insert logic here to test the context for connectivity because we may have gotten one from
 
 394                      * the pool that was previously created.
 
 396                     if (context.isStale()) {
 
 400                 } catch (PoolExtensionException e) {
 
 401                     String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,
 
 402                             tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),
 
 403                             Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
 
 404                     logger.error(msg, e);
 
 406                 } catch (Exception e) {
 
 407                     String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
 
 408                             e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
 
 410                     logger.error(msg, e);
 
 411                     doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
 
 416             String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
 
 418             doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
 
 423         String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
 
 425         doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
 
 429     protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url)
 
 430             throws RequestFailedException {
 
 432         VMURL vm = VMURL.parseURL(vm_url);
 
 434             String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
 
 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, vm_url, identStr);
 
 453     protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context) throws APPCException;
 
 456     public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
 
 458         return executeProviderOperation(params,context);