Search in sources :

Example 1 with StackInfoMapper

use of org.onap.so.openstack.mappers.StackInfoMapper in project so by onap.

the class MsoHeatUtils method createStack.

/**
 * Create a new Stack in the specified cloud location and tenant. The Heat template and parameter map are passed in
 * as arguments, along with the cloud access credentials. It is expected that parameters have been validated and
 * contain at minimum the required parameters for the given template with no extra (undefined) parameters..
 *
 * The Stack name supplied by the caller must be unique in the scope of this tenant. However, it should also be
 * globally unique, as it will be the identifier for the resource going forward in Inventory. This latter is managed
 * by the higher levels invoking this function.
 *
 * The caller may choose to let this function poll Openstack for completion of the stack creation, or may handle
 * polling itself via separate calls to query the status. In either case, a StackInfo object will be returned
 * containing the current status. When polling is enabled, a status of CREATED is expected. When not polling, a
 * status of BUILDING is expected.
 *
 * An error will be thrown if the requested Stack already exists in the specified Tenant and Cloud.
 *
 * For 1510 - add "environment", "files" (nested templates), and "heatFiles" (get_files) as parameters for
 * createStack. If environment is non-null, it will be added to the stack. The nested templates and get_file entries
 * both end up being added to the "files" on the stack. We must combine them before we add them to the stack if
 * they're both non-null.
 *
 * @param cloudSiteId The cloud (may be a region) in which to create the stack.
 * @param cloudOwner the cloud owner of the cloud site in which to create the stack
 * @param tenantId The Openstack ID of the tenant in which to create the Stack
 * @param stackName The name of the stack to create
 * @param vduModel contains information about the vdu model (added for plugin adapter)
 * @param heatTemplate The Heat template
 * @param stackInputs A map of key/value inputs
 * @param pollForCompletion Indicator that polling should be handled in Java vs. in the client
 * @param environment An optional yaml-format string to specify environmental parameters
 * @param files a Map<String, Object> that lists the child template IDs (file is the string, object is an int of
 *        Template id)
 * @param heatFiles a Map<String, Object> that lists the get_file entries (fileName, fileBody)
 * @param backout Donot delete stack on create Failure - defaulted to True
 * @return A StackInfo object
 * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
 */
public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, VduModelInfo vduModel, String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, int timeoutMinutes, String environment, Map<String, Object> nestedTemplates, Map<String, Object> heatFiles, boolean backout, boolean failIfExists) throws MsoException {
    stripMultiCloudInputs(stackInputs);
    CreateStackParam createStack = createStackParam(stackName, heatTemplate, stackInputs, timeoutMinutes, environment, nestedTemplates, heatFiles);
    Stack currentStack = queryHeatStack(stackName, cloudSiteId, tenantId);
    boolean operationPerformed = false;
    if (currentStack != null) {
        logger.debug("Existing Stack found with Status: {} ", currentStack.getStackStatus());
        if (CREATE_COMPLETE.equals(currentStack.getStackStatus())) {
            new StackInfoMapper(currentStack).map();
        } else if (CREATE_IN_PROGRESS.equals(currentStack.getStackStatus())) {
            // TODO should check poll for completion right here
            currentStack = processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, createStack, true);
        } else if (CREATE_FAILED.equals(currentStack.getStackStatus()) || DELETE_FAILED.equals(currentStack.getStackStatus())) {
            try {
                if (pollForCompletion) {
                    processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, createStack, true);
                }
            } catch (MsoException e) {
                if (e instanceof StackCreationException) {
                    logger.warn("Error during Stack will attempt to recreate stack");
                    currentStack = createStack(createStack, cloudSiteId, tenantId);
                    currentStack.setStackName(stackName);
                    if (pollForCompletion) {
                        currentStack = processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, createStack, true);
                    }
                } else {
                    throw e;
                }
            }
        }
    } else {
        currentStack = createStack(createStack, cloudSiteId, tenantId);
        currentStack.setStackName(stackName);
        if (pollForCompletion) {
            currentStack = processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, createStack, true);
        }
        operationPerformed = true;
    }
    StackInfo stackInfo = new StackInfoMapper(currentStack).map();
    stackInfo.setOperationPerformed(operationPerformed);
    return stackInfo;
}
Also used : StackInfoMapper(org.onap.so.openstack.mappers.StackInfoMapper) MsoException(org.onap.so.openstack.exceptions.MsoException) CreateStackParam(com.woorea.openstack.heat.model.CreateStackParam) StackInfo(org.onap.so.openstack.beans.StackInfo) Stack(com.woorea.openstack.heat.model.Stack)

Example 2 with StackInfoMapper

use of org.onap.so.openstack.mappers.StackInfoMapper in project so by onap.

the class MsoMulticloudUtils method queryStack.

/**
 * Query for a single stack (by ID) in a tenant. This call will always return a StackInfo object. If the stack does
 * not exist, an "empty" StackInfo will be returned - containing only the stack name and a status of NOTFOUND.
 *
 * @param tenantId The Openstack ID of the tenant in which to query
 * @param cloudSiteId The cloud identifier (may be a region) in which to query
 * @param cloudOwner cloud owner of the cloud site in which to query
 * @param stackId The ID of the stack to query
 * @return A StackInfo object
 * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
 */
@Override
public StackInfo queryStack(String cloudSiteId, String cloudOwner, String tenantId, String instanceId) throws MsoException {
    if (logger.isDebugEnabled()) {
        logger.debug(String.format("Query multicloud HEAT stack: %s in tenant %s", instanceId, tenantId));
    }
    String stackName = null;
    String stackId = null;
    boolean byName = false;
    int offset = instanceId.indexOf('/');
    if (offset > 0 && offset < (instanceId.length() - 1)) {
        stackName = instanceId.substring(0, offset);
        stackId = instanceId.substring(offset + 1);
    } else {
        stackName = instanceId;
        stackId = instanceId;
        byName = true;
    }
    StackInfo returnInfo = new StackInfo();
    returnInfo.setName(stackName);
    String multicloudEndpoint = getMulticloudEndpoint(cloudSiteId, cloudOwner, stackId, byName);
    RestClient multicloudClient = getMulticloudClient(multicloudEndpoint, tenantId);
    if (multicloudClient != null) {
        Response response = multicloudClient.get();
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Multicloud GET Response: %s", response.toString()));
        }
        MulticloudQueryResponse responseBody = null;
        if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) {
            returnInfo.setStatus(HeatStatus.NOTFOUND);
            returnInfo.setStatusMessage(response.getStatusInfo().getReasonPhrase());
        } else if (response.getStatus() == Response.Status.OK.getStatusCode() && response.hasEntity()) {
            responseBody = getQueryBody((java.io.InputStream) response.getEntity());
            if (responseBody != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Multicloud Create Response Body: {}", responseBody);
                }
                Stack workloadStack = getWorkloadStack(responseBody.getWorkloadStatusReason());
                if (workloadStack != null && !responseBody.getWorkloadStatus().equals("GET_FAILED") && !responseBody.getWorkloadStatus().contains("UPDATE")) {
                    returnInfo = new StackInfoMapper(workloadStack).map();
                } else {
                    returnInfo.setCanonicalName(stackName + "/" + responseBody.getWorkloadId());
                    returnInfo.setStatus(getHeatStatus(responseBody.getWorkloadStatus()));
                    returnInfo.setStatusMessage(responseBody.getWorkloadStatus());
                }
            } else {
                returnInfo.setName(stackName);
                if (!byName)
                    returnInfo.setCanonicalName(instanceId);
                returnInfo.setStatus(HeatStatus.FAILED);
                returnInfo.setStatusMessage(MULTICLOUD_QUERY_BODY_NULL);
            }
        } else {
            returnInfo.setName(stackName);
            if (!byName)
                returnInfo.setCanonicalName(instanceId);
            returnInfo.setStatus(HeatStatus.FAILED);
            returnInfo.setStatusMessage(response.getStatusInfo().getReasonPhrase());
        }
    }
    return returnInfo;
}
Also used : Response(javax.ws.rs.core.Response) StackInfoMapper(org.onap.so.openstack.mappers.StackInfoMapper) RestClient(org.onap.so.client.RestClient) StackInfo(org.onap.so.openstack.beans.StackInfo) Stack(com.woorea.openstack.heat.model.Stack)

Example 3 with StackInfoMapper

use of org.onap.so.openstack.mappers.StackInfoMapper in project so by onap.

the class MsoHeatUtilsWithUpdate method updateStack.

/**
 * Update a Stack in the specified cloud location and tenant. The Heat template and parameter map are passed in as
 * arguments, along with the cloud access credentials. It is expected that parameters have been validated and
 * contain at minimum the required parameters for the given template with no extra (undefined) parameters..
 *
 * The Stack name supplied by the caller must be unique in the scope of this tenant. However, it should also be
 * globally unique, as it will be the identifier for the resource going forward in Inventory. This latter is managed
 * by the higher levels invoking this function.
 *
 * The caller may choose to let this function poll Openstack for completion of the stack creation, or may handle
 * polling itself via separate calls to query the status. In either case, a StackInfo object will be returned
 * containing the current status. When polling is enabled, a status of CREATED is expected. When not polling, a
 * status of BUILDING is expected.
 *
 * An error will be thrown if the requested Stack already exists in the specified Tenant and Cloud.
 *
 * @param tenantId The Openstack ID of the tenant in which to create the Stack
 * @param cloudSiteId The cloud identifier (may be a region) in which to create the tenant.
 * @param stackName The name of the stack to update
 * @param heatTemplate The Heat template
 * @param stackInputs A map of key/value inputs
 * @param pollForCompletion Indicator that polling should be handled in Java vs. in the client
 * @param environment An optional yaml-format string to specify environmental parameters
 * @param files a Map<String, Object> for listing child template IDs
 * @param heatFiles a Map<String, Object> for listing get_file entries (fileName, fileBody)
 * @return A StackInfo object
 * @throws MsoException Thrown if the Openstack API call returns an exception.
 */
public StackInfo updateStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, String heatTemplate, Map<String, Object> stackInputs, boolean pollForCompletion, int timeoutMinutes, String environment, Map<String, Object> files, Map<String, Object> heatFiles) throws MsoException {
    boolean heatEnvtVariable = true;
    if (environment == null || "".equalsIgnoreCase(environment.trim())) {
        heatEnvtVariable = false;
    }
    boolean haveFiles = true;
    if (files == null || files.isEmpty()) {
        haveFiles = false;
    }
    boolean haveHeatFiles = true;
    if (heatFiles == null || heatFiles.isEmpty()) {
        haveHeatFiles = false;
    }
    Heat heatClient = getHeatClient(cloudSiteId, tenantId);
    // Perform a query first to get the current status
    Stack heatStack = queryHeatStack(heatClient, stackName);
    if (heatStack == null || "DELETE_COMPLETE".equals(heatStack.getStackStatus())) {
        // Not found. Return a StackInfo with status NOTFOUND
        throw new MsoStackNotFound(stackName, tenantId, cloudSiteId);
    }
    // Use canonical name "<stack name>/<stack-id>" to update the stack.
    // Otherwise, update by name returns a 302 redirect.
    // NOTE: This is specific to the v1 Orchestration API.
    String canonicalName = heatStack.getStackName() + "/" + heatStack.getId();
    logger.debug("Ready to Update Stack ({}) with input params: {}", canonicalName, stackInputs);
    // force entire stackInput object to generic Map<String, Object> for openstack compatibility
    ObjectMapper mapper = new ObjectMapper();
    Map<String, Object> normalized = new HashMap<>();
    try {
        normalized = mapper.readValue(mapper.writeValueAsString(stackInputs), new TypeReference<HashMap<String, Object>>() {
        });
    } catch (IOException e1) {
        logger.debug("could not map json", e1);
    }
    // Build up the stack update parameters
    // Disable auto-rollback, because error reason is lost. Always rollback in the code.
    UpdateStackParam stack = new UpdateStackParam();
    stack.setTimeoutMinutes(timeoutMinutes);
    stack.setParameters(normalized);
    stack.setTemplate(heatTemplate);
    stack.setDisableRollback(true);
    // TJM add envt to stack
    if (heatEnvtVariable) {
        stack.setEnvironment(environment);
    }
    // and then add to stack (both are part of "files:" being added to stack)
    if (haveFiles && haveHeatFiles) {
        // Let's do this here - not in the bean
        logger.debug("Found files AND heatFiles - combine and add!");
        Map<String, Object> combinedFiles = new HashMap<>();
        for (String keyString : files.keySet()) {
            combinedFiles.put(keyString, files.get(keyString));
        }
        for (String keyString : heatFiles.keySet()) {
            combinedFiles.put(keyString, heatFiles.get(keyString));
        }
        stack.setFiles(combinedFiles);
    } else {
        // Handle case where we have one or neither
        if (haveFiles) {
            stack.setFiles(files);
        }
        if (haveHeatFiles) {
            // setFiles method modified to handle adding a map.
            stack.setFiles(heatFiles);
        }
    }
    try {
        // Execute the actual Openstack command to update the Heat stack
        OpenStackRequest<Void> request = heatClient.getStacks().update(canonicalName, stack);
        executeAndRecordOpenstackRequest(request);
    } catch (OpenStackBaseException e) {
        // in the cloud. Rethrow the error as an MSO exception.
        throw heatExceptionToMsoException(e, UPDATE_STACK);
    } catch (RuntimeException e) {
        // Catch-all
        throw runtimeExceptionToMsoException(e, UPDATE_STACK);
    }
    // If client has requested a final response, poll for stack completion
    Stack updateStack = null;
    if (pollForCompletion) {
        // Set a time limit on overall polling.
        // Use the resource (template) timeout for Openstack (expressed in minutes)
        // and add one poll interval to give Openstack a chance to fail on its own.
        int createPollInterval = Integer.parseInt(this.environment.getProperty(createPollIntervalProp, CREATE_POLL_INTERVAL_DEFAULT));
        int pollTimeout = (timeoutMinutes * 60) + createPollInterval;
        boolean loopAgain = true;
        while (loopAgain) {
            try {
                updateStack = queryHeatStack(heatClient, canonicalName);
                logger.debug("{} ({}) ", updateStack.getStackStatus(), canonicalName);
                try {
                    logger.debug("Current stack {}" + this.getOutputsAsStringBuilderWithUpdate(heatStack).toString());
                } catch (Exception e) {
                    logger.debug("an error occurred trying to print out the current outputs of the stack", e);
                }
                if ("UPDATE_IN_PROGRESS".equals(updateStack.getStackStatus())) {
                    // Sleep and try again unless timeout has been reached
                    if (pollTimeout <= 0) {
                        // Note that this should not occur, since there is a timeout specified
                        // in the Openstack call.
                        logger.error("{} Cloud site: {} Tenant: {} Stack: {} Stack status: {} {} Update stack timeout", MessageEnum.RA_UPDATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName, updateStack.getStackStatus(), ErrorCode.AvailabilityError.getValue());
                        loopAgain = false;
                    } else {
                        try {
                            Thread.sleep(createPollInterval * 1000L);
                        } catch (InterruptedException e) {
                            // If we are interrupted, we should stop ASAP.
                            loopAgain = false;
                            // Set again the interrupted flag
                            Thread.currentThread().interrupt();
                        }
                    }
                    pollTimeout -= createPollInterval;
                    logger.debug("pollTimeout remaining: {}", pollTimeout);
                } else {
                    loopAgain = false;
                }
            } catch (MsoException e) {
                // Cannot query the stack. Something is wrong.
                // TODO: No way to roll back the stack at this point. What to do?
                e.addContext(UPDATE_STACK);
                throw e;
            }
        }
        if (!"UPDATE_COMPLETE".equals(updateStack.getStackStatus())) {
            logger.error("{} Stack status: {} Stack status reason: {} {} Update Stack error", MessageEnum.RA_UPDATE_STACK_ERR, updateStack.getStackStatus(), updateStack.getStackStatusReason(), ErrorCode.DataError.getValue());
            // TODO: No way to roll back the stack at this point. What to do?
            // Throw a 'special case' of MsoOpenstackException to report the Heat status
            MsoOpenstackException me = null;
            if ("UPDATE_IN_PROGRESS".equals(updateStack.getStackStatus())) {
                me = new MsoOpenstackException(0, "", "Stack Update Timeout");
            } else {
                String error = "Stack error (" + updateStack.getStackStatus() + "): " + updateStack.getStackStatusReason();
                me = new MsoOpenstackException(0, "", error);
            }
            me.addContext(UPDATE_STACK);
            throw me;
        }
    } else {
        // Return the current status.
        updateStack = queryHeatStack(heatClient, canonicalName);
        if (updateStack != null) {
            logger.debug("UpdateStack, status = {}", updateStack.getStackStatus());
        } else {
            logger.debug("UpdateStack, stack not found");
        }
    }
    return new StackInfoMapper(updateStack).map();
}
Also used : MsoStackNotFound(org.onap.so.openstack.exceptions.MsoStackNotFound) MsoException(org.onap.so.openstack.exceptions.MsoException) HashMap(java.util.HashMap) OpenStackBaseException(com.woorea.openstack.base.client.OpenStackBaseException) UpdateStackParam(com.woorea.openstack.heat.model.UpdateStackParam) IOException(java.io.IOException) OpenStackBaseException(com.woorea.openstack.base.client.OpenStackBaseException) MsoOpenstackException(org.onap.so.openstack.exceptions.MsoOpenstackException) IOException(java.io.IOException) MsoException(org.onap.so.openstack.exceptions.MsoException) Stack(com.woorea.openstack.heat.model.Stack) MsoOpenstackException(org.onap.so.openstack.exceptions.MsoOpenstackException) StackInfoMapper(org.onap.so.openstack.mappers.StackInfoMapper) Heat(com.woorea.openstack.heat.Heat) TypeReference(com.fasterxml.jackson.core.type.TypeReference) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 4 with StackInfoMapper

use of org.onap.so.openstack.mappers.StackInfoMapper in project so by onap.

the class PollService method pollDeleteResource.

private StackInfo pollDeleteResource(int pollingTimeout, String cloudSiteId, String tenantId, String stackId, MutableBoolean success) throws MsoException {
    Stack currentStack = createCurrentStack(stackId);
    Stack stack = msoHeatUtils.pollStackForStatus(pollingTimeout, currentStack, "DELETE_IN_PROGRESS", cloudSiteId, tenantId, true);
    if (stack != null) {
        // if stack is null it was not found and no need to do post process
        msoHeatUtils.postProcessStackDelete(stack);
    }
    success.setTrue();
    return new StackInfoMapper(stack).map();
}
Also used : StackInfoMapper(org.onap.so.openstack.mappers.StackInfoMapper) Stack(com.woorea.openstack.heat.model.Stack)

Example 5 with StackInfoMapper

use of org.onap.so.openstack.mappers.StackInfoMapper in project so by onap.

the class MsoHeatUtils method queryStack.

/**
 * Query for a single stack (by Name) in a tenant. This call will always return a StackInfo object. If the stack
 * does not exist, an "empty" StackInfo will be returned - containing only the stack name and a status of NOTFOUND.
 *
 * @param tenantId The Openstack ID of the tenant in which to query
 * @param cloudSiteId The cloud identifier (may be a region) in which to query
 * @param cloudOwner the cloud owner of the cloud site in which to query
 * @param stackName The name of the stack to query (may be simple or canonical)
 * @return A StackInfo object
 * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
 */
public StackInfo queryStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName) throws MsoException {
    logger.debug("Query HEAT stack: {} in tenant {}", stackName, tenantId);
    Heat heatClient = null;
    try {
        heatClient = getHeatClient(cloudSiteId, tenantId);
    } catch (MsoTenantNotFound e) {
        // Tenant doesn't exist, so stack doesn't either
        logger.debug("Tenant with id " + tenantId + "not found.", e);
        return new StackInfo(stackName, HeatStatus.NOTFOUND);
    } catch (MsoException me) {
        // Got an Openstack error. Propagate it
        logger.error("{} {} Openstack Exception on Token request: ", MessageEnum.RA_CONNECTION_EXCEPTION, ErrorCode.AvailabilityError.getValue(), me);
        me.addContext("QueryStack");
        throw me;
    }
    // Query the Stack.
    // An MsoException will propagate transparently to the caller.
    Stack heatStack = queryHeatStack(heatClient, stackName);
    if (heatStack == null) {
        // Stack does not exist. Return a StackInfo with status NOTFOUND
        return new StackInfo(stackName, HeatStatus.NOTFOUND);
    }
    return new StackInfoMapper(heatStack).map();
}
Also used : StackInfoMapper(org.onap.so.openstack.mappers.StackInfoMapper) Heat(com.woorea.openstack.heat.Heat) MsoException(org.onap.so.openstack.exceptions.MsoException) MsoTenantNotFound(org.onap.so.openstack.exceptions.MsoTenantNotFound) StackInfo(org.onap.so.openstack.beans.StackInfo) Stack(com.woorea.openstack.heat.model.Stack)

Aggregations

Stack (com.woorea.openstack.heat.model.Stack)7 StackInfoMapper (org.onap.so.openstack.mappers.StackInfoMapper)7 StackInfo (org.onap.so.openstack.beans.StackInfo)4 MsoException (org.onap.so.openstack.exceptions.MsoException)3 Heat (com.woorea.openstack.heat.Heat)2 TypeReference (com.fasterxml.jackson.core.type.TypeReference)1 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)1 OpenStackBaseException (com.woorea.openstack.base.client.OpenStackBaseException)1 CreateStackParam (com.woorea.openstack.heat.model.CreateStackParam)1 UpdateStackParam (com.woorea.openstack.heat.model.UpdateStackParam)1 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 Response (javax.ws.rs.core.Response)1 RestClient (org.onap.so.client.RestClient)1 MsoOpenstackException (org.onap.so.openstack.exceptions.MsoOpenstackException)1 MsoStackNotFound (org.onap.so.openstack.exceptions.MsoStackNotFound)1 MsoTenantNotFound (org.onap.so.openstack.exceptions.MsoTenantNotFound)1