Search in sources :

Example 6 with Stack

use of com.woorea.openstack.heat.model.Stack in project so by onap.

the class MsoHeatUtils method handleKeyPairConflict.

protected Stack handleKeyPairConflict(String cloudSiteId, String tenantId, CreateStackParam stackCreate, int timeoutMinutes, boolean backout, Stack stack) throws MsoException {
    logger.info("Keypair conflict found on stack, attempting to clean up");
    try {
        Matcher m = Pattern.compile("'([^']+?)'").matcher(stack.getStackStatusReason());
        if (m.find()) {
            novaClient.deleteKeyPair(cloudSiteId, tenantId, m.group(1));
        }
    } catch (NovaClientException e) {
        logger.warn("Could not delete keypair", e);
    }
    handleUnknownCreateStackFailure(stack, timeoutMinutes, cloudSiteId, tenantId);
    Stack newStack = createStack(stackCreate, cloudSiteId, tenantId);
    newStack.setStackName(stackCreate.getStackName());
    return processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, newStack, stackCreate, false);
}
Also used : Matcher(java.util.regex.Matcher) Stack(com.woorea.openstack.heat.model.Stack)

Example 7 with Stack

use of com.woorea.openstack.heat.model.Stack in project so by onap.

the class MsoHeatUtils method pollStackForStatus.

public Stack pollStackForStatus(int timeoutMinutes, Stack stack, String stackStatus, String cloudSiteId, String tenantId, boolean notFoundIsSuccess) throws MsoException {
    int pollingFrequency = Integer.parseInt(this.environment.getProperty(createPollIntervalProp, CREATE_POLL_INTERVAL_DEFAULT));
    LocalDateTime stopPolling = LocalDateTime.now().plusMinutes(timeoutMinutes);
    if (pollingFrequency > timeoutMinutes * 60) {
        logger.debug("Will not poll. Poll interval {} sec is greater then timeout {} sec", pollingFrequency, timeoutMinutes * 60);
        stopPolling = LocalDateTime.now().minusMinutes(1);
    }
    Heat heatClient = getHeatClient(cloudSiteId, tenantId);
    while (true) {
        String stackName = stack.getStackName() + "/" + stack.getId();
        if (stack.getId() == null) {
            stackName = stack.getStackName();
        }
        Stack latestStack = queryHeatStack(heatClient, stackName);
        if (latestStack == null && notFoundIsSuccess) {
            return null;
        } else if (latestStack != null) {
            String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID);
            statusHandler.updateStackStatus(latestStack, requestId);
            if (stackStatus.equals(latestStack.getStackStatus())) {
                if (LocalDateTime.now().isAfter(stopPolling)) {
                    logger.error("Polling of stack timed out with Status: {}", latestStack.getStackStatus());
                    return latestStack;
                }
                logger.debug("Will poll again until {}", stopPolling);
                sleep(pollingFrequency * 1000L);
            } else {
                return latestStack;
            }
        }
    }
}
Also used : LocalDateTime(java.time.LocalDateTime) Heat(com.woorea.openstack.heat.Heat) Stack(com.woorea.openstack.heat.model.Stack)

Example 8 with Stack

use of com.woorea.openstack.heat.model.Stack 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 9 with Stack

use of com.woorea.openstack.heat.model.Stack in project so by onap.

the class MsoMulticloudUtils method getWorkloadStack.

private Stack getWorkloadStack(JsonNode node) {
    if (node == null)
        return null;
    Stack workloadStack = null;
    if (node.has("stacks")) {
        try {
            if (!node.at("/stacks/0").isNull() && node.at("/stacks/0").has("stack_status")) {
                workloadStack = JSON_MAPPER.treeToValue(node.at("/stacks/0"), Stack.class);
            } else {
                workloadStack = new Stack();
                workloadStack.setStackStatus("NOT_FOUND");
            }
        } catch (Exception e) {
            logger.debug("Multicloud Get Exception mapping /stack/0: {} ", node.toString(), e);
        }
    } else if (node.has("stack")) {
        try {
            if (node.at("/stack").has("stack_status")) {
                workloadStack = JSON_MAPPER.treeToValue(node.at("/stack"), Stack.class);
            }
        } catch (Exception e) {
            logger.debug("Multicloud Get Exception mapping /stack: {} ", node.toString(), e);
        }
    }
    if (workloadStack != null)
        logger.debug("Multicloud getWorkloadStack() returning Stack Object: {} ", workloadStack);
    return workloadStack;
}
Also used : MsoAdapterException(org.onap.so.openstack.exceptions.MsoAdapterException) VduException(org.onap.so.adapters.vdu.VduException) MsoOpenstackException(org.onap.so.openstack.exceptions.MsoOpenstackException) MalformedURLException(java.net.MalformedURLException) UriBuilderException(javax.ws.rs.core.UriBuilderException) MsoException(org.onap.so.openstack.exceptions.MsoException) Stack(com.woorea.openstack.heat.model.Stack)

Example 10 with Stack

use of com.woorea.openstack.heat.model.Stack 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)

Aggregations

Stack (com.woorea.openstack.heat.model.Stack)41 Test (org.junit.Test)26 CreateStack (com.woorea.openstack.heat.StackResource.CreateStack)15 DeleteStack (com.woorea.openstack.heat.StackResource.DeleteStack)15 CreateStackParam (com.woorea.openstack.heat.model.CreateStackParam)10 Heat (com.woorea.openstack.heat.Heat)9 StackInfo (org.onap.so.openstack.beans.StackInfo)9 StackInfoMapper (org.onap.so.openstack.mappers.StackInfoMapper)7 MsoException (org.onap.so.openstack.exceptions.MsoException)5 OpenStackRequest (com.woorea.openstack.base.client.OpenStackRequest)3 File (java.io.File)3 HashMap (java.util.HashMap)3 CloudSite (org.onap.so.db.catalog.beans.CloudSite)3 MsoOpenstackException (org.onap.so.openstack.exceptions.MsoOpenstackException)3 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 RequestProcessingData (org.onap.so.db.request.beans.RequestProcessingData)2 TypeReference (com.fasterxml.jackson.core.type.TypeReference)1 OpenStackBaseException (com.woorea.openstack.base.client.OpenStackBaseException)1 OpenStackConnectException (com.woorea.openstack.base.client.OpenStackConnectException)1 OpenStackResponseException (com.woorea.openstack.base.client.OpenStackResponseException)1