Replaced all tabs with spaces in java and pom.xml
[so.git] / adapters / mso-adapter-utils / src / main / java / org / onap / so / cloudify / utils / MsoCloudifyUtils.java
index 6b16194..0a0f278 100644 (file)
@@ -102,7 +102,7 @@ import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Component;
 
 @Component
-public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
+public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin {
 
     private static final String CLOUDIFY = "Cloudify";
     private static final String CREATE_DEPLOYMENT = "CreateDeployment";
@@ -132,24 +132,21 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
     private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
 
     /**
-     * Create a new Deployment from a specified blueprint, and install it in the specified
-     * cloud location and tenant. The blueprint identifier and parameter map are passed in
-     * as arguments, along with the cloud access credentials.  The blueprint should have been
-     * previously uploaded to Cloudify.
+     * Create a new Deployment from a specified blueprint, and install it in the specified cloud location and tenant.
+     * The blueprint identifier and parameter map are passed in as arguments, along with the cloud access credentials.
+     * The blueprint should have been previously uploaded to Cloudify.
      *
-     * It is expected that parameters have been validated and contain at minimum the required
-     * parameters for the given template with no extra (undefined) parameters..
+     * 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 deployment ID supplied by the caller must be unique in the scope of the Cloudify
-     * tenant (not the Openstack 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 deployment ID supplied by the caller must be unique in the scope of the Cloudify tenant (not the Openstack
+     * 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.
      *
-     * This function executes the "install" workflow on the newly created workflow.  Cloudify
-     * will be polled for completion unless the client requests otherwise.
+     * This function executes the "install" workflow on the newly created workflow. Cloudify will be polled for
+     * completion unless the client requests otherwise.
      *
-     * An error will be thrown if the requested Deployment already exists in the specified
-     * Cloudify instance.
+     * An error will be thrown if the requested Deployment already exists in the specified Cloudify instance.
      *
      * @param cloudSiteId The cloud (may be a region) in which to create the stack.
      * @param tenantId The Openstack ID of the tenant in which to create the Stack
@@ -164,22 +161,16 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
      * @throws MsoIOException Thrown on Cloudify connection errors.
      */
 
-    public DeploymentInfo createAndInstallDeployment (String cloudSiteId,
-                                  String tenantId,
-                                  String deploymentId,
-                                  String blueprintId,
-                                  Map <String, ? extends Object> inputs,
-                                  boolean pollForCompletion,
-                                  int timeoutMinutes,
-                                  boolean backout) throws MsoException
-    {
+    public DeploymentInfo createAndInstallDeployment(String cloudSiteId, String tenantId, String deploymentId,
+            String blueprintId, Map<String, ? extends Object> inputs, boolean pollForCompletion, int timeoutMinutes,
+            boolean backout) throws MsoException {
         // Obtain the cloud site information where we will create the stack
-        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite(cloudSiteId);
         if (!cloudSite.isPresent()) {
-            throw new MsoCloudSiteNotFound (cloudSiteId);
+            throw new MsoCloudSiteNotFound(cloudSiteId);
         }
 
-        Cloudify cloudify = getCloudifyClient (cloudSite.get());
+        Cloudify cloudify = getCloudifyClient(cloudSite.get());
 
         logger.debug("Ready to Create Deployment ({}) with input params: {}", deploymentId, inputs);
 
@@ -187,159 +178,150 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
         // - from provided "environment" file
         // - passed in by caller
         // - special input for cloud-specific Credentials
-        Map<String,Object> expandedInputs = new HashMap<> (inputs);
+        Map<String, Object> expandedInputs = new HashMap<>(inputs);
 
         String platform = cloudSite.get().getPlatform();
         if (platform == null || platform.equals("") || platform.equalsIgnoreCase("OPENSTACK")) {
-               // Create the Cloudify OpenstackConfig with the credentials
-               OpenstackConfig openstackConfig = getOpenstackConfig (cloudSite.get(), tenantId);
-               expandedInputs.put("openstack_config", openstackConfig);
+            // Create the Cloudify OpenstackConfig with the credentials
+            OpenstackConfig openstackConfig = getOpenstackConfig(cloudSite.get(), tenantId);
+            expandedInputs.put("openstack_config", openstackConfig);
         } else if (platform.equalsIgnoreCase("AZURE")) {
-               // Create Cloudify AzureConfig with the credentials
-               AzureConfig azureConfig = getAzureConfig (cloudSite.get(), tenantId);
-               expandedInputs.put("azure_config",  azureConfig);
+            // Create Cloudify AzureConfig with the credentials
+            AzureConfig azureConfig = getAzureConfig(cloudSite.get(), tenantId);
+            expandedInputs.put("azure_config", azureConfig);
         }
 
         // Build up the parameters to create a new deployment
-       CreateDeploymentParams deploymentParams = new CreateDeploymentParams();
-       deploymentParams.setBlueprintId(blueprintId);
-       deploymentParams.setInputs(expandedInputs);
-
-       Deployment deployment = null;
-       try {
-               CreateDeployment createDeploymentRequest = cloudify.deployments().create(deploymentId, deploymentParams);
-          logger.debug(createDeploymentRequest.toString());
-
-               deployment = executeAndRecordCloudifyRequest (createDeploymentRequest);
-       }
-       catch (CloudifyResponseException e) {
+        CreateDeploymentParams deploymentParams = new CreateDeploymentParams();
+        deploymentParams.setBlueprintId(blueprintId);
+        deploymentParams.setInputs(expandedInputs);
+
+        Deployment deployment = null;
+        try {
+            CreateDeployment createDeploymentRequest = cloudify.deployments().create(deploymentId, deploymentParams);
+            logger.debug(createDeploymentRequest.toString());
+
+            deployment = executeAndRecordCloudifyRequest(createDeploymentRequest);
+        } catch (CloudifyResponseException e) {
             // Since this came on the 'Create Deployment' command, nothing was changed
             // in the cloud. Return the error as an exception.
-            if (e.getStatus () == 409) {
+            if (e.getStatus() == 409) {
                 // Deployment already exists. Return a specific error for this case
-                MsoException me = new MsoDeploymentAlreadyExists (deploymentId, cloudSiteId);
-                me.addContext (CREATE_DEPLOYMENT);
+                MsoException me = new MsoDeploymentAlreadyExists(deploymentId, cloudSiteId);
+                me.addContext(CREATE_DEPLOYMENT);
                 throw me;
             } else {
                 // Convert the CloudifyResponseException to an MsoException
                 logger.debug("ERROR STATUS = {},\n{}\n{}", e.getStatus(), e.getMessage(), e.getLocalizedMessage());
-                MsoException me = cloudifyExceptionToMsoException (e, CREATE_DEPLOYMENT);
-                me.setCategory (MsoExceptionCategory.OPENSTACK);
+                MsoException me = cloudifyExceptionToMsoException(e, CREATE_DEPLOYMENT);
+                me.setCategory(MsoExceptionCategory.OPENSTACK);
                 throw me;
             }
         } catch (CloudifyConnectException e) {
             // Error connecting to Cloudify instance. Convert to an MsoException
-            throw cloudifyExceptionToMsoException (e, CREATE_DEPLOYMENT);
+            throw cloudifyExceptionToMsoException(e, CREATE_DEPLOYMENT);
         } catch (RuntimeException e) {
             // Catch-all
-            throw runtimeExceptionToMsoException (e, CREATE_DEPLOYMENT);
+            throw runtimeExceptionToMsoException(e, CREATE_DEPLOYMENT);
         }
 
-       /*
-        * It can take some time for Cloudify to be ready to execute a workflow
-        * on the deployment.  Sleep 30 seconds based on observation of behavior
-        * in a Cloudify VM instance (delay due to "create_deployment_environment").
-        */
-       sleep(30000);
-       
-       /*
-        * Next execute the "install" workflow.
-        * Note - this assumes there are no additional parameters required for the workflow.
-        */
-        int createPollInterval = Integer.parseInt(this.environment.getProperty(createPollIntervalProp, createPollIntervalDefault));
+        /*
+         * It can take some time for Cloudify to be ready to execute a workflow on the deployment. Sleep 30 seconds
+         * based on observation of behavior in a Cloudify VM instance (delay due to "create_deployment_environment").
+         */
+        sleep(30000);
+
+        /*
+         * Next execute the "install" workflow. Note - this assumes there are no additional parameters required for the
+         * workflow.
+         */
+        int createPollInterval =
+                Integer.parseInt(this.environment.getProperty(createPollIntervalProp, createPollIntervalDefault));
         int pollTimeout = (timeoutMinutes * 60) + createPollInterval;
 
         Execution installWorkflow = null;
 
         try {
-               installWorkflow = executeWorkflow (cloudify, deploymentId, "install", null, pollForCompletion, pollTimeout, createPollInterval);
-
-               if (installWorkflow.getStatus().equals(TERMINATED)) {
-                       //  Success!
-                       //  Create and return a DeploymentInfo structure.  Include the Runtime outputs
-                               return new DeploymentInfoBuilder()
-                                       .withId(deployment.getId())
-                                       .withDeploymentInputs(deployment.getInputs())
-                                       .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
-                                       .fromExecution(installWorkflow)
-                                       .build();
-               }
-               else {
-                       // The workflow completed with errors.  Must try to back it out.
-               if (!backout)
-               {
-                  logger.warn("{} Deployment installation failed, backout deletion suppressed {} {}",
-                      MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(),
-                      "Exception in Deployment Installation, backout suppressed");
-              }
-               else {
-                       // Poll on delete if we rollback - use same values for now
-                   int deletePollInterval = createPollInterval;
-                   int deletePollTimeout = pollTimeout;
-
-                   try {
-                       // Run the uninstall to undo the install
-                       Execution uninstallWorkflow = executeWorkflow (cloudify, deploymentId, "uninstall", null, pollForCompletion, deletePollTimeout, deletePollInterval);
-
-                       if (uninstallWorkflow.getStatus().equals(TERMINATED))
-                       {
-                               //  The uninstall completed.  Delete the deployment itself
-                               DeleteDeployment deleteRequest = cloudify.deployments().deleteByName(deploymentId);
-                               executeAndRecordCloudifyRequest (deleteRequest);
-                       }
-                       else {
-                               // Didn't uninstall successfully.  Log this error
-                        logger.error("{} Create Deployment: Cloudify error rolling back deployment install: {} {}",
-                            MessageEnum.RA_CREATE_STACK_ERR, installWorkflow.getError(),
-                            ErrorCode.BusinessProcesssError.getValue());
+            installWorkflow = executeWorkflow(cloudify, deploymentId, "install", null, pollForCompletion, pollTimeout,
+                    createPollInterval);
+
+            if (installWorkflow.getStatus().equals(TERMINATED)) {
+                // Success!
+                // Create and return a DeploymentInfo structure. Include the Runtime outputs
+                return new DeploymentInfoBuilder().withId(deployment.getId())
+                        .withDeploymentInputs(deployment.getInputs())
+                        .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
+                        .fromExecution(installWorkflow).build();
+            } else {
+                // The workflow completed with errors. Must try to back it out.
+                if (!backout) {
+                    logger.warn("{} Deployment installation failed, backout deletion suppressed {} {}",
+                            MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(),
+                            "Exception in Deployment Installation, backout suppressed");
+                } else {
+                    // Poll on delete if we rollback - use same values for now
+                    int deletePollInterval = createPollInterval;
+                    int deletePollTimeout = pollTimeout;
+
+                    try {
+                        // Run the uninstall to undo the install
+                        Execution uninstallWorkflow = executeWorkflow(cloudify, deploymentId, "uninstall", null,
+                                pollForCompletion, deletePollTimeout, deletePollInterval);
+
+                        if (uninstallWorkflow.getStatus().equals(TERMINATED)) {
+                            // The uninstall completed. Delete the deployment itself
+                            DeleteDeployment deleteRequest = cloudify.deployments().deleteByName(deploymentId);
+                            executeAndRecordCloudifyRequest(deleteRequest);
+                        } else {
+                            // Didn't uninstall successfully. Log this error
+                            logger.error("{} Create Deployment: Cloudify error rolling back deployment install: {} {}",
+                                    MessageEnum.RA_CREATE_STACK_ERR, installWorkflow.getError(),
+                                    ErrorCode.BusinessProcesssError.getValue());
+                        }
+                    } catch (Exception e) {
+                        // Catch-all for backout errors trying to uninstall/delete
+                        // Log this error, and return the original exception
+                        logger.error("{} Create Stack: Nested exception rolling back deployment install: {}",
+                                MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), e);
                     }
-                   }
-                   catch (Exception e) {
-                       // Catch-all for backout errors trying to uninstall/delete
-                       // Log this error, and return the original exception
-                      logger.error("{} Create Stack: Nested exception rolling back deployment install: {}",
-                          MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), e);
-                  }
-               }
-
-               MsoCloudifyException me = new MsoCloudifyException (0, "Workflow Execution Failed", installWorkflow.getError());
-                me.addContext (CREATE_DEPLOYMENT);
+                }
+
+                MsoCloudifyException me =
+                        new MsoCloudifyException(0, "Workflow Execution Failed", installWorkflow.getError());
+                me.addContext(CREATE_DEPLOYMENT);
 
                 throw me;
-               }
-        }
-        catch (MsoException me) {
-               // Install failed.  Unless requested otherwise, back out the deployment 
-               
-               if (!backout)
-               {
-              logger.warn("{} Deployment installation failed, backout deletion suppressed {}",
-                  MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue());
-          }
-               else {
-                       // Poll on delete if we rollback - use same values for now
-                   int deletePollInterval = createPollInterval;
-                   int deletePollTimeout = pollTimeout;
-
-                   try {
-                       // Run the uninstall to undo the install.
-                       // Always try to run it, as it should be idempotent
-                       executeWorkflow (cloudify, deploymentId, "uninstall", null, pollForCompletion, deletePollTimeout, deletePollInterval);
-
-                       // Delete the deployment itself
-                       DeleteDeployment deleteRequest = cloudify.deployments().deleteByName(deploymentId);
-                       executeAndRecordCloudifyRequest (deleteRequest);
-                   }
-                   catch (Exception e) {
-                       // Catch-all for backout errors trying to uninstall/delete
-                       // Log this error, and return the original exception
-                  logger.error("{} Create Stack: Nested exception rolling back deployment install: {} ",
-                      MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), e);
-              }
-               }
+            }
+        } catch (MsoException me) {
+            // Install failed. Unless requested otherwise, back out the deployment
+
+            if (!backout) {
+                logger.warn("{} Deployment installation failed, backout deletion suppressed {}",
+                        MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue());
+            } else {
+                // Poll on delete if we rollback - use same values for now
+                int deletePollInterval = createPollInterval;
+                int deletePollTimeout = pollTimeout;
+
+                try {
+                    // Run the uninstall to undo the install.
+                    // Always try to run it, as it should be idempotent
+                    executeWorkflow(cloudify, deploymentId, "uninstall", null, pollForCompletion, deletePollTimeout,
+                            deletePollInterval);
+
+                    // Delete the deployment itself
+                    DeleteDeployment deleteRequest = cloudify.deployments().deleteByName(deploymentId);
+                    executeAndRecordCloudifyRequest(deleteRequest);
+                } catch (Exception e) {
+                    // Catch-all for backout errors trying to uninstall/delete
+                    // Log this error, and return the original exception
+                    logger.error("{} Create Stack: Nested exception rolling back deployment install: {} ",
+                            MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), e);
+                }
+            }
 
             // Propagate the original exception from Stack Query.
-            me.addContext (CREATE_DEPLOYMENT);
+            me.addContext(CREATE_DEPLOYMENT);
 
             throw me;
         }
@@ -347,302 +329,275 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
 
 
     /*
-     * Get the runtime Outputs of a deployment.
-     * Return the Map of tag/value outputs.
+     * Get the runtime Outputs of a deployment. Return the Map of tag/value outputs.
      */
-    private Optional<Map<String, Object>> getDeploymentOutputs (Cloudify cloudify, String deploymentId)
-        throws MsoException
-    {
-       // Build and send the Cloudify request
-               DeploymentOutputs deploymentOutputs;
-       try {
-               GetDeploymentOutputs queryDeploymentOutputs = cloudify.deployments().outputsById(deploymentId);
-          logger.debug(queryDeploymentOutputs.toString());
-
-               deploymentOutputs = executeAndRecordCloudifyRequest(queryDeploymentOutputs);
-                       if (deploymentOutputs != null) {
-                               return Optional.ofNullable(deploymentOutputs.getOutputs());
-                       } else {
-                               return Optional.empty();
-                       }
-       }
-       catch (CloudifyConnectException ce) {
-               // Couldn't connect to Cloudify
-          logger.error("{} QueryDeploymentOutputs: Cloudify connection failure: {} ",
-              MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), ce);
-          throw new MsoIOException (ce.getMessage(), ce);
-       }
-       catch (CloudifyResponseException re) {
-            if (re.getStatus () == 404) {
-               // No Outputs
-               return Optional.empty();
+    private Optional<Map<String, Object>> getDeploymentOutputs(Cloudify cloudify, String deploymentId)
+            throws MsoException {
+        // Build and send the Cloudify request
+        DeploymentOutputs deploymentOutputs;
+        try {
+            GetDeploymentOutputs queryDeploymentOutputs = cloudify.deployments().outputsById(deploymentId);
+            logger.debug(queryDeploymentOutputs.toString());
+
+            deploymentOutputs = executeAndRecordCloudifyRequest(queryDeploymentOutputs);
+            if (deploymentOutputs != null) {
+                return Optional.ofNullable(deploymentOutputs.getOutputs());
+            } else {
+                return Optional.empty();
+            }
+        } catch (CloudifyConnectException ce) {
+            // Couldn't connect to Cloudify
+            logger.error("{} QueryDeploymentOutputs: Cloudify connection failure: {} ", MessageEnum.RA_CREATE_STACK_ERR,
+                    ErrorCode.BusinessProcesssError.getValue(), ce);
+            throw new MsoIOException(ce.getMessage(), ce);
+        } catch (CloudifyResponseException re) {
+            if (re.getStatus() == 404) {
+                // No Outputs
+                return Optional.empty();
             }
-            throw new MsoCloudifyException (re.getStatus(), re.getMessage(), re.getLocalizedMessage(), re);
-       }
-       catch (Exception e) {
-               // Catch-all
-               throw new MsoAdapterException (e.getMessage(), e);
-       }
+            throw new MsoCloudifyException(re.getStatus(), re.getMessage(), re.getLocalizedMessage(), re);
+        } catch (Exception e) {
+            // Catch-all
+            throw new MsoAdapterException(e.getMessage(), e);
+        }
     }
 
     /*
-     * Execute a workflow on a deployment.  Handle polling for completion with timeout.
-     * Return the final Execution object with status.
-     * Throw an exception on Errors.
-     * Question - how does the client know whether rollback needs to be done?
+     * Execute a workflow on a deployment. Handle polling for completion with timeout. Return the final Execution object
+     * with status. Throw an exception on Errors. Question - how does the client know whether rollback needs to be done?
      */
-    private Execution executeWorkflow (Cloudify cloudify, String deploymentId, String workflowId, Map<String,Object> workflowParams, boolean pollForCompletion, int timeout, int pollInterval)
-       throws MsoCloudifyException
-    {
+    private Execution executeWorkflow(Cloudify cloudify, String deploymentId, String workflowId,
+            Map<String, Object> workflowParams, boolean pollForCompletion, int timeout, int pollInterval)
+            throws MsoCloudifyException {
         logger.debug("Executing '{}' workflow on deployment '{}'", workflowId, deploymentId);
 
-               StartExecutionParams executeParams = new StartExecutionParams();
-               executeParams.setWorkflowId(workflowId);
-               executeParams.setDeploymentId(deploymentId);
-               executeParams.setParameters(workflowParams);
-
-               Execution execution = null;
-               String executionId = null;
-               String command = "start";
-               Exception savedException = null;
-
-               try {
-                       StartExecution executionRequest = cloudify.executions().start(executeParams);
-        logger.debug(executionRequest.toString());
-        execution = executeAndRecordCloudifyRequest (executionRequest);
-                       executionId = execution.getId();
-
-                       if (!pollForCompletion) {
-                               // Client did not request polling, so just return the Execution object
-                               return execution;
-                       }
-
-                       // Enter polling loop
-                       boolean timedOut = false;
-                       int pollTimeout = timeout;
-
-                       String status = execution.getStatus();
-
-                       // Create a reusable cloudify query request
-                       GetExecution queryExecution = cloudify.executions().byId(executionId);
-                       command = "query";
-
-                       while (!timedOut && !(status.equals(TERMINATED) || status.equals("failed") || status.equals(CANCELLED)))
-                       {
-                               // workflow is still running; check for timeout
-                               if (pollTimeout <= 0) {
-            logger.debug("workflow {} timed out on deployment {}", execution.getWorkflowId(),
-                execution.getDeploymentId());
-            timedOut = true;
-                                       continue;
-                               }
-
-                               sleep(pollInterval * 1000L);
-
-                               pollTimeout -= pollInterval;
-          logger.debug("pollTimeout remaining: " + pollTimeout);
-
-                               execution = queryExecution.execute();
-                               status = execution.getStatus();
-                       }
-
-                       // Broke the loop.  Check again for a terminal state
-                       if (status.equals(TERMINATED)){
-                               // Success!
-          logger.debug("Workflow '{}' completed successfully on deployment '{}'", workflowId, deploymentId);
-          return execution;
-                       }
-                       else if (status.equals("failed")){
-                               // Workflow failed.  Log it and return the execution object (don't throw exception here)
-          logger.error("{} Cloudify workflow failure: {} {} Execute Workflow: Failed: {}",
-              MessageEnum.RA_CREATE_STACK_ERR, execution.getError(),
-              ErrorCode.BusinessProcesssError.getValue(), execution.getError());
-          return execution;
-                       }
-                       else if (status.equals(CANCELLED)){
-                               // Workflow was cancelled, leaving the deployment in an indeterminate state.  Log it and return the execution object (don't throw exception here)
-          logger.error("{} Cloudify workflow cancelled. Deployment is in an indeterminate state {} {} {}",
-              MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(),
-              "Execute Workflow cancelled: ", workflowId);
-          return execution;
-                       }
-                       else {
-                               // Can only get here after a timeout
-          logger.error("{} Cloudify workflow timeout {} Execute Workflow: Timed Out", MessageEnum.RA_CREATE_STACK_ERR,
-              ErrorCode.BusinessProcesssError.getValue());
-      }
-               }
-               catch (CloudifyConnectException ce) {
-        logger.error("{} {} Execute Workflow ({} {}): Cloudify connection failure {} ", MessageEnum.RA_CREATE_STACK_ERR,
-            ErrorCode.BusinessProcesssError.getValue(), command, ce);
-        savedException = ce;
-               }
-               catch (CloudifyResponseException re) {
-        logger.error("{} {} Execute Workflow ({}): Cloudify response error {} ", MessageEnum.RA_CREATE_STACK_ERR,
-            ErrorCode.BusinessProcesssError.getValue(), command, re.getMessage(), re);
-        savedException = re;
-               }
-               catch (RuntimeException e) {
-                       // Catch-all
-        logger.error("{} {} Execute Workflow ({}): Internal error {}", MessageEnum.RA_CREATE_STACK_ERR,
-            ErrorCode.BusinessProcesssError.getValue(), command, e.getMessage(), e);
-        savedException = e;
-               }
-
-               //  Get to this point ONLY on an error or timeout
-               //  The cloudify execution is still running (we've not received a terminal status),
-               //  so try to Cancel it.
-               CancelExecutionParams cancelParams = new CancelExecutionParams();
-               cancelParams.setAction("cancel");
-               // TODO:  Use force_cancel?
-
-               Execution cancelExecution = null;
-
-               try {
-                       CancelExecution cancelRequest = cloudify.executions().cancel(executionId, cancelParams);
-        logger.debug(cancelRequest.toString());
-        cancelExecution = cancelRequest.execute();
-
-                       // Enter polling loop
-                       boolean timedOut = false;
-                       int cancelTimeout = timeout;    // TODO: For now, just use same timeout
-
-                       String status = cancelExecution.getStatus();
-
-                       // Poll for completion.  Create a reusable cloudify query request
-                       GetExecution queryExecution = cloudify.executions().byId(executionId);
-
-                       while (!timedOut && !status.equals(CANCELLED))
-                       {
-                               // workflow is still running; check for timeout
-                               if (cancelTimeout <= 0) {
-            logger.debug("Cancel timeout for workflow {} on deployment {}", workflowId, deploymentId);
-            timedOut = true;
-                                       continue;
-                               }
-
-                               sleep(pollInterval * 1000L);
-
-                               cancelTimeout -= pollInterval;
-          logger.debug("pollTimeout remaining: {}", cancelTimeout);
-
-          execution = queryExecution.execute();
-                               status = execution.getStatus();
-                       }
-
-                       // Broke the loop.  Check again for a terminal state
-                       if (status.equals(CANCELLED)){
-                               // Finished cancelling.  Return the original exception
-          logger.debug("Cancel workflow {} completed on deployment {}", workflowId, deploymentId);
-          throw new MsoCloudifyException (-1, "", "", savedException);
-                       }
-                       else {
-                               // Can only get here after a timeout
-          logger.debug("Cancel workflow {} timeout out on deployment {}", workflowId, deploymentId);
-          MsoCloudifyException exception = new MsoCloudifyException (-1, "", "", savedException);
-                               exception.setPendingWorkflow(true);
-                               throw exception;
-                       }
-               }
-               catch (Exception e) {
-                       // Catch-all.  Log the message and throw the original exception
-        logger.debug("Cancel workflow {} failed for deployment {} :", workflowId, deploymentId, e);
-        MsoCloudifyException exception = new MsoCloudifyException (-1, "", "", savedException);
-                       exception.setPendingWorkflow(true);
-                       throw exception;
-               }
+        StartExecutionParams executeParams = new StartExecutionParams();
+        executeParams.setWorkflowId(workflowId);
+        executeParams.setDeploymentId(deploymentId);
+        executeParams.setParameters(workflowParams);
+
+        Execution execution = null;
+        String executionId = null;
+        String command = "start";
+        Exception savedException = null;
+
+        try {
+            StartExecution executionRequest = cloudify.executions().start(executeParams);
+            logger.debug(executionRequest.toString());
+            execution = executeAndRecordCloudifyRequest(executionRequest);
+            executionId = execution.getId();
+
+            if (!pollForCompletion) {
+                // Client did not request polling, so just return the Execution object
+                return execution;
+            }
+
+            // Enter polling loop
+            boolean timedOut = false;
+            int pollTimeout = timeout;
+
+            String status = execution.getStatus();
+
+            // Create a reusable cloudify query request
+            GetExecution queryExecution = cloudify.executions().byId(executionId);
+            command = "query";
+
+            while (!timedOut && !(status.equals(TERMINATED) || status.equals("failed") || status.equals(CANCELLED))) {
+                // workflow is still running; check for timeout
+                if (pollTimeout <= 0) {
+                    logger.debug("workflow {} timed out on deployment {}", execution.getWorkflowId(),
+                            execution.getDeploymentId());
+                    timedOut = true;
+                    continue;
+                }
+
+                sleep(pollInterval * 1000L);
+
+                pollTimeout -= pollInterval;
+                logger.debug("pollTimeout remaining: " + pollTimeout);
+
+                execution = queryExecution.execute();
+                status = execution.getStatus();
+            }
+
+            // Broke the loop. Check again for a terminal state
+            if (status.equals(TERMINATED)) {
+                // Success!
+                logger.debug("Workflow '{}' completed successfully on deployment '{}'", workflowId, deploymentId);
+                return execution;
+            } else if (status.equals("failed")) {
+                // Workflow failed. Log it and return the execution object (don't throw exception here)
+                logger.error("{} Cloudify workflow failure: {} {} Execute Workflow: Failed: {}",
+                        MessageEnum.RA_CREATE_STACK_ERR, execution.getError(),
+                        ErrorCode.BusinessProcesssError.getValue(), execution.getError());
+                return execution;
+            } else if (status.equals(CANCELLED)) {
+                // Workflow was cancelled, leaving the deployment in an indeterminate state. Log it and return the
+                // execution object (don't throw exception here)
+                logger.error("{} Cloudify workflow cancelled. Deployment is in an indeterminate state {} {} {}",
+                        MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(),
+                        "Execute Workflow cancelled: ", workflowId);
+                return execution;
+            } else {
+                // Can only get here after a timeout
+                logger.error("{} Cloudify workflow timeout {} Execute Workflow: Timed Out",
+                        MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue());
+            }
+        } catch (CloudifyConnectException ce) {
+            logger.error("{} {} Execute Workflow ({} {}): Cloudify connection failure {} ",
+                    MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), command, ce);
+            savedException = ce;
+        } catch (CloudifyResponseException re) {
+            logger.error("{} {} Execute Workflow ({}): Cloudify response error {} ", MessageEnum.RA_CREATE_STACK_ERR,
+                    ErrorCode.BusinessProcesssError.getValue(), command, re.getMessage(), re);
+            savedException = re;
+        } catch (RuntimeException e) {
+            // Catch-all
+            logger.error("{} {} Execute Workflow ({}): Internal error {}", MessageEnum.RA_CREATE_STACK_ERR,
+                    ErrorCode.BusinessProcesssError.getValue(), command, e.getMessage(), e);
+            savedException = e;
+        }
+
+        // Get to this point ONLY on an error or timeout
+        // The cloudify execution is still running (we've not received a terminal status),
+        // so try to Cancel it.
+        CancelExecutionParams cancelParams = new CancelExecutionParams();
+        cancelParams.setAction("cancel");
+        // TODO: Use force_cancel?
+
+        Execution cancelExecution = null;
+
+        try {
+            CancelExecution cancelRequest = cloudify.executions().cancel(executionId, cancelParams);
+            logger.debug(cancelRequest.toString());
+            cancelExecution = cancelRequest.execute();
+
+            // Enter polling loop
+            boolean timedOut = false;
+            int cancelTimeout = timeout; // TODO: For now, just use same timeout
+
+            String status = cancelExecution.getStatus();
+
+            // Poll for completion. Create a reusable cloudify query request
+            GetExecution queryExecution = cloudify.executions().byId(executionId);
+
+            while (!timedOut && !status.equals(CANCELLED)) {
+                // workflow is still running; check for timeout
+                if (cancelTimeout <= 0) {
+                    logger.debug("Cancel timeout for workflow {} on deployment {}", workflowId, deploymentId);
+                    timedOut = true;
+                    continue;
+                }
+
+                sleep(pollInterval * 1000L);
+
+                cancelTimeout -= pollInterval;
+                logger.debug("pollTimeout remaining: {}", cancelTimeout);
+
+                execution = queryExecution.execute();
+                status = execution.getStatus();
+            }
+
+            // Broke the loop. Check again for a terminal state
+            if (status.equals(CANCELLED)) {
+                // Finished cancelling. Return the original exception
+                logger.debug("Cancel workflow {} completed on deployment {}", workflowId, deploymentId);
+                throw new MsoCloudifyException(-1, "", "", savedException);
+            } else {
+                // Can only get here after a timeout
+                logger.debug("Cancel workflow {} timeout out on deployment {}", workflowId, deploymentId);
+                MsoCloudifyException exception = new MsoCloudifyException(-1, "", "", savedException);
+                exception.setPendingWorkflow(true);
+                throw exception;
+            }
+        } catch (Exception e) {
+            // Catch-all. Log the message and throw the original exception
+            logger.debug("Cancel workflow {} failed for deployment {} :", workflowId, deploymentId, e);
+            MsoCloudifyException exception = new MsoCloudifyException(-1, "", "", savedException);
+            exception.setPendingWorkflow(true);
+            throw exception;
+        }
     }
 
 
 
     /**
-     * Query for a Cloudify Deployment (by Name). This call will always return a
-     * DeploymentInfo object. If the deployment does not exist, an "empty" DeploymentInfo will be
-     * returned - containing only the deployment ID and a special status of NOTFOUND.
+     * Query for a Cloudify Deployment (by Name). This call will always return a DeploymentInfo object. If the
+     * deployment does not exist, an "empty" DeploymentInfo will be returned - containing only the deployment ID and a
+     * special 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
      * @return A StackInfo object
      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
      */
-    public DeploymentInfo queryDeployment (String cloudSiteId, String tenantId, String deploymentId)
-       throws MsoException
-    {
-        logger.debug ("Query Cloudify Deployment: {} in tenant {}", deploymentId, tenantId);
+    public DeploymentInfo queryDeployment(String cloudSiteId, String tenantId, String deploymentId)
+            throws MsoException {
+        logger.debug("Query Cloudify Deployment: {} in tenant {}", deploymentId, tenantId);
 
         // Obtain the cloud site information where we will create the stack
-        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite(cloudSiteId);
         if (!cloudSite.isPresent()) {
-            throw new MsoCloudSiteNotFound (cloudSiteId);
+            throw new MsoCloudSiteNotFound(cloudSiteId);
         }
 
-        Cloudify cloudify = getCloudifyClient (cloudSite.get());
-
-       // Build and send the Cloudify request
-               Deployment deployment = new Deployment();
-       try {
-               GetDeployment queryDeployment = cloudify.deployments().byId(deploymentId);
-          logger.debug(queryDeployment.toString());
-               deployment = executeAndRecordCloudifyRequest(queryDeployment);
-
-               //  Next look for the latest execution
-               ListExecutions listExecutions = cloudify.executions().listFiltered ("deployment_id=" + deploymentId, "-created_at");
-               Executions executions = listExecutions.execute();
-
-               //  If no executions, does this give NOT_FOUND or empty set?
-               if (executions.getItems().isEmpty()) {
-                       return new DeploymentInfoBuilder()
-                                       .withId(deployment.getId())
-                                       .withDeploymentInputs(deployment.getInputs())
-                                       .build();
-               }
-               else {
-                               return new DeploymentInfoBuilder()
-                                       .withId(deployment.getId())
-                                       .withDeploymentInputs(deployment.getInputs())
-                                       .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
-                                       .fromExecution(executions.getItems().get(0))
-                                       .build();
-               }
-       }
-       catch (CloudifyConnectException ce) {
-               // Couldn't connect to Cloudify
-          logger.error("{} QueryDeployment: Cloudify connection failure: {} ", MessageEnum.RA_CREATE_STACK_ERR,
-              ErrorCode.BusinessProcesssError.getValue(), ce);
-          throw new MsoIOException (ce.getMessage(), ce);
-       }
-       catch (CloudifyResponseException re) {
-            if (re.getStatus () == 404) {
-               // Got a NOT FOUND error.  React differently based on deployment vs. execution
-               if (deployment != null) {
-                       // Got NOT_FOUND on the executions.  Assume this is a valid "empty" set
-                                       return new DeploymentInfoBuilder()
-                                               .withId(deployment.getId())
-                                               .withDeploymentInputs(deployment.getInputs())
-                                               .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
-                                               .build();
-               } else {
-                       // Deployment not found.  Default status of a DeploymentInfo object is NOTFOUND
-                       return new DeploymentInfoBuilder().withId(deploymentId).build();
-               }
+        Cloudify cloudify = getCloudifyClient(cloudSite.get());
+
+        // Build and send the Cloudify request
+        Deployment deployment = new Deployment();
+        try {
+            GetDeployment queryDeployment = cloudify.deployments().byId(deploymentId);
+            logger.debug(queryDeployment.toString());
+            deployment = executeAndRecordCloudifyRequest(queryDeployment);
+
+            // Next look for the latest execution
+            ListExecutions listExecutions =
+                    cloudify.executions().listFiltered("deployment_id=" + deploymentId, "-created_at");
+            Executions executions = listExecutions.execute();
+
+            // If no executions, does this give NOT_FOUND or empty set?
+            if (executions.getItems().isEmpty()) {
+                return new DeploymentInfoBuilder().withId(deployment.getId())
+                        .withDeploymentInputs(deployment.getInputs()).build();
+            } else {
+                return new DeploymentInfoBuilder().withId(deployment.getId())
+                        .withDeploymentInputs(deployment.getInputs())
+                        .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
+                        .fromExecution(executions.getItems().get(0)).build();
             }
-            throw new MsoCloudifyException (re.getStatus(), re.getMessage(), re.getLocalizedMessage(), re);
-       }
-       catch (Exception e) {
-               // Catch-all
-               throw new MsoAdapterException (e.getMessage(), e);
-       }
+        } catch (CloudifyConnectException ce) {
+            // Couldn't connect to Cloudify
+            logger.error("{} QueryDeployment: Cloudify connection failure: {} ", MessageEnum.RA_CREATE_STACK_ERR,
+                    ErrorCode.BusinessProcesssError.getValue(), ce);
+            throw new MsoIOException(ce.getMessage(), ce);
+        } catch (CloudifyResponseException re) {
+            if (re.getStatus() == 404) {
+                // Got a NOT FOUND error. React differently based on deployment vs. execution
+                if (deployment != null) {
+                    // Got NOT_FOUND on the executions. Assume this is a valid "empty" set
+                    return new DeploymentInfoBuilder().withId(deployment.getId())
+                            .withDeploymentInputs(deployment.getInputs())
+                            .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get()).build();
+                } else {
+                    // Deployment not found. Default status of a DeploymentInfo object is NOTFOUND
+                    return new DeploymentInfoBuilder().withId(deploymentId).build();
+                }
+            }
+            throw new MsoCloudifyException(re.getStatus(), re.getMessage(), re.getLocalizedMessage(), re);
+        } catch (Exception e) {
+            // Catch-all
+            throw new MsoAdapterException(e.getMessage(), e);
+        }
     }
 
 
     /**
-     * Delete a Cloudify deployment (by ID). If the deployment is not found, it will be
-     * considered a successful deletion. The return value is a DeploymentInfo object which
-     * contains the last deployment status.
+     * Delete a Cloudify deployment (by ID). If the deployment is not found, it will be considered a successful
+     * deletion. The return value is a DeploymentInfo object which contains the last deployment status.
      *
-     * There is no rollback from a successful deletion. A deletion failure will
-     * also result in an undefined deployment state - the components may or may not have been
-     * all or partially deleted, so the resulting deployment must be considered invalid.
+     * There is no rollback from a successful deletion. A deletion failure will also result in an undefined deployment
+     * state - the components may or may not have been all or partially deleted, so the resulting deployment must be
+     * considered invalid.
      *
      * @param tenantId The Openstack ID of the tenant in which to perform the delete
      * @param cloudSiteId The cloud identifier (may be a region) from which to delete the stack.
@@ -650,274 +605,247 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
      * @throws MsoCloudSiteNotFound
      */
-    public DeploymentInfo uninstallAndDeleteDeployment (String cloudSiteId,
-                                  String tenantId,
-                                  String deploymentId,
-                                  int timeoutMinutes) throws MsoException
-    {
+    public DeploymentInfo uninstallAndDeleteDeployment(String cloudSiteId, String tenantId, String deploymentId,
+            int timeoutMinutes) throws MsoException {
         // Obtain the cloud site information where we will create the stack
-        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite(cloudSiteId);
         if (!cloudSite.isPresent()) {
-            throw new MsoCloudSiteNotFound (cloudSiteId);
+            throw new MsoCloudSiteNotFound(cloudSiteId);
         }
 
-        Cloudify cloudify = getCloudifyClient (cloudSite.get());
+        Cloudify cloudify = getCloudifyClient(cloudSite.get());
 
-        logger.debug ("Ready to Uninstall/Delete Deployment ({})", deploymentId);
+        logger.debug("Ready to Uninstall/Delete Deployment ({})", deploymentId);
 
         // Query first to save the trouble if deployment not found
-               try {
-               GetDeployment queryDeploymentRequest = cloudify.deployments().byId(deploymentId);
-          logger.debug(queryDeploymentRequest.toString());
+        try {
+            GetDeployment queryDeploymentRequest = cloudify.deployments().byId(deploymentId);
+            logger.debug(queryDeploymentRequest.toString());
 
-       //      deployment = executeAndRecordCloudifyRequest (queryDeploymentRequest);
-       }
-       catch (CloudifyResponseException e) {
+            // deployment = executeAndRecordCloudifyRequest (queryDeploymentRequest);
+        } catch (CloudifyResponseException e) {
             // Since this came on the 'Create Deployment' command, nothing was changed
             // in the cloud. Return the error as an exception.
-            if (e.getStatus () == 404) {
-                // Deployment doesn't exist.  Return a "NOTFOUND" DeploymentInfo object
-               // TODO:  Should return NULL?
+            if (e.getStatus() == 404) {
+                // Deployment doesn't exist. Return a "NOTFOUND" DeploymentInfo object
+                // TODO: Should return NULL?
                 logger.debug("Deployment requested for deletion does not exist: {}", deploymentId);
-                return new DeploymentInfoBuilder()
-                                       .withId(deploymentId)
-                                       .withStatus(DeploymentStatus.NOTFOUND)
-                                       .build();
-           } else {
+                return new DeploymentInfoBuilder().withId(deploymentId).withStatus(DeploymentStatus.NOTFOUND).build();
+            } else {
                 // Convert the CloudifyResponseException to an MsoOpenstackException
                 logger.debug("ERROR STATUS = {}, \n {}\n {}\n {}", e.getStatus(), e.getMessage(),
-                    e.getLocalizedMessage(), e);
-                MsoException me = cloudifyExceptionToMsoException (e, DELETE_DEPLOYMENT);
-                me.setCategory (MsoExceptionCategory.INTERNAL);
+                        e.getLocalizedMessage(), e);
+                MsoException me = cloudifyExceptionToMsoException(e, DELETE_DEPLOYMENT);
+                me.setCategory(MsoExceptionCategory.INTERNAL);
                 throw me;
             }
         } catch (CloudifyConnectException e) {
             // Error connecting to Cloudify instance. Convert to an MsoException
-               throw cloudifyExceptionToMsoException (e, DELETE_DEPLOYMENT);
+            throw cloudifyExceptionToMsoException(e, DELETE_DEPLOYMENT);
         } catch (RuntimeException e) {
             // Catch-all
-            throw runtimeExceptionToMsoException (e, DELETE_DEPLOYMENT);
+            throw runtimeExceptionToMsoException(e, DELETE_DEPLOYMENT);
         }
 
-       /*
-        *  Query the outputs before deleting so they can be returned as well
-        */
-       //DeploymentOutputs outputs = getDeploymentOutputs (cloudify, deploymentId);
-       
-       /*
-        * Next execute the "uninstall" workflow.
-        * Note - this assumes there are no additional parameters required for the workflow.
-        */
-       // TODO: No deletePollInterval that I'm aware of.  Use the create interval
-        int deletePollInterval = Integer.parseInt(this.environment.getProperty (deletePollIntervalProp, deletePollIntervalDefault));
+        /*
+         * Query the outputs before deleting so they can be returned as well
+         */
+        // DeploymentOutputs outputs = getDeploymentOutputs (cloudify, deploymentId);
+
+        /*
+         * Next execute the "uninstall" workflow. Note - this assumes there are no additional parameters required for
+         * the workflow.
+         */
+        // TODO: No deletePollInterval that I'm aware of. Use the create interval
+        int deletePollInterval =
+                Integer.parseInt(this.environment.getProperty(deletePollIntervalProp, deletePollIntervalDefault));
         int pollTimeout = (timeoutMinutes * 60) + deletePollInterval;
 
         Execution uninstallWorkflow = null;
 
         try {
-               uninstallWorkflow = executeWorkflow (cloudify, deploymentId, "uninstall", null, true, pollTimeout, deletePollInterval);
-
-               if (uninstallWorkflow.getStatus().equals(TERMINATED)) {
-                       //  Successful uninstall.
-              logger.debug("Uninstall successful for deployment {}", deploymentId);
-          }
-               else {
-                       // The uninstall workflow completed with an error.  Must fail the request, but will
-                       // leave the deployment in an indeterminate state, as cloud resources may still exist.
-               MsoCloudifyException me = new MsoCloudifyException (0, "Uninstall Workflow Failed", uninstallWorkflow.getError());
-                me.addContext (DELETE_DEPLOYMENT);
+            uninstallWorkflow =
+                    executeWorkflow(cloudify, deploymentId, "uninstall", null, true, pollTimeout, deletePollInterval);
+
+            if (uninstallWorkflow.getStatus().equals(TERMINATED)) {
+                // Successful uninstall.
+                logger.debug("Uninstall successful for deployment {}", deploymentId);
+            } else {
+                // The uninstall workflow completed with an error. Must fail the request, but will
+                // leave the deployment in an indeterminate state, as cloud resources may still exist.
+                MsoCloudifyException me =
+                        new MsoCloudifyException(0, "Uninstall Workflow Failed", uninstallWorkflow.getError());
+                me.addContext(DELETE_DEPLOYMENT);
 
                 throw me;
-               }
-        }
-        catch (MsoException me) {
-               // Uninstall workflow has failed.
-               // Must fail the deletion... may leave the deployment in an inconclusive state 
-            me.addContext (DELETE_DEPLOYMENT);
+            }
+        } catch (MsoException me) {
+            // Uninstall workflow has failed.
+            // Must fail the deletion... may leave the deployment in an inconclusive state
+            me.addContext(DELETE_DEPLOYMENT);
 
             throw me;
         }
-        
+
         // At this point, the deployment has been successfully uninstalled.
         // Next step is to delete the deployment itself
-               Deployment deployment;
+        Deployment deployment;
         try {
-               DeleteDeployment deleteRequest = cloudify.deployments().deleteByName(deploymentId);
+            DeleteDeployment deleteRequest = cloudify.deployments().deleteByName(deploymentId);
             logger.debug(deleteRequest.toString());
 
-               // The delete request returns the deleted deployment
-               deployment = deleteRequest.execute();
+            // The delete request returns the deleted deployment
+            deployment = deleteRequest.execute();
 
-        }
-        catch (CloudifyConnectException ce) {
-               // Failed to delete.  Must fail the request, but will leave the (uninstalled)
-               // deployment in Cloudify DB.
-               MsoCloudifyException me = new MsoCloudifyException (0, "Deployment Delete Failed", ce.getMessage(), ce);
-            me.addContext (DELETE_DEPLOYMENT);
+        } catch (CloudifyConnectException ce) {
+            // Failed to delete. Must fail the request, but will leave the (uninstalled)
+            // deployment in Cloudify DB.
+            MsoCloudifyException me = new MsoCloudifyException(0, "Deployment Delete Failed", ce.getMessage(), ce);
+            me.addContext(DELETE_DEPLOYMENT);
 
             throw me;
-        }
-        catch (CloudifyResponseException re) {
-               // Failed to delete.  Must fail the request, but will leave the (uninstalled)
-               // deployment in the Cloudify DB.
-               MsoCloudifyException me = new MsoCloudifyException (re.getStatus(), re.getMessage(), re.getMessage(), re);
-            me.addContext (DELETE_DEPLOYMENT);
+        } catch (CloudifyResponseException re) {
+            // Failed to delete. Must fail the request, but will leave the (uninstalled)
+            // deployment in the Cloudify DB.
+            MsoCloudifyException me = new MsoCloudifyException(re.getStatus(), re.getMessage(), re.getMessage(), re);
+            me.addContext(DELETE_DEPLOYMENT);
 
             throw me;
-        }
-        catch (Exception e) {
-               // Catch-all
-               MsoAdapterException ae = new MsoAdapterException (e.getMessage(), e);
-            ae.addContext (DELETE_DEPLOYMENT);
+        } catch (Exception e) {
+            // Catch-all
+            MsoAdapterException ae = new MsoAdapterException(e.getMessage(), e);
+            ae.addContext(DELETE_DEPLOYMENT);
 
             throw ae;
         }
 
-       // Return the deleted deployment info (with runtime outputs) along with the completed uninstall workflow status
-               return new DeploymentInfoBuilder()
-                       .withId(deployment.getId())
-                       .withDeploymentInputs(deployment.getInputs())
-                       .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
-                       .fromExecution(uninstallWorkflow)
-                       .build();
+        // Return the deleted deployment info (with runtime outputs) along with the completed uninstall workflow status
+        return new DeploymentInfoBuilder().withId(deployment.getId()).withDeploymentInputs(deployment.getInputs())
+                .withDeploymentOutputs(getDeploymentOutputs(cloudify, deploymentId).get())
+                .fromExecution(uninstallWorkflow).build();
     }
 
 
     /**
-     * Check if a blueprint is available for use at a targeted cloud site.
-     * This requires checking the Cloudify Manager which is servicing that
-     * cloud site to see if the specified blueprint has been loaded.
+     * Check if a blueprint is available for use at a targeted cloud site. This requires checking the Cloudify Manager
+     * which is servicing that cloud site to see if the specified blueprint has been loaded.
      *
      * @param cloudSiteId The cloud site where the blueprint is needed
      * @param blueprintId The ID for the blueprint in Cloudify
      */
-    public boolean isBlueprintLoaded (String cloudSiteId, String blueprintId)
-       throws MsoException
-    {
+    public boolean isBlueprintLoaded(String cloudSiteId, String blueprintId) throws MsoException {
         // Obtain the cloud site information where we will load the blueprint
-        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite(cloudSiteId);
         if (!cloudSite.isPresent()) {
-            throw new MsoCloudSiteNotFound (cloudSiteId);
+            throw new MsoCloudSiteNotFound(cloudSiteId);
         }
 
-        Cloudify cloudify = getCloudifyClient (cloudSite.get());
-
-       GetBlueprint getRequest = cloudify.blueprints().getMetadataById(blueprintId);
-       try {
-               Blueprint bp = getRequest.execute();
-          logger.debug("Blueprint exists: {}", bp.getId());
-          return true;
-       }
-       catch (CloudifyResponseException ce) {
-               if (ce.getStatus() == 404) {
-                       return false;
-               } else {
-                       throw ce;
-               }
-       } catch (Exception e) {
-               throw e;
-       } 
+        Cloudify cloudify = getCloudifyClient(cloudSite.get());
+
+        GetBlueprint getRequest = cloudify.blueprints().getMetadataById(blueprintId);
+        try {
+            Blueprint bp = getRequest.execute();
+            logger.debug("Blueprint exists: {}", bp.getId());
+            return true;
+        } catch (CloudifyResponseException ce) {
+            if (ce.getStatus() == 404) {
+                return false;
+            } else {
+                throw ce;
+            }
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * Upload a blueprint to the Cloudify Manager that is servicing a Cloud Site.
-     * The blueprint currently must be structured as a single directory with all
-     * of the required files.  One of those files is designated the "main file"
-     * for the blueprint.  Files are provided as byte arrays, though expect only
-     * text files will be distributed from ASDC and stored by MSO.
+     * Upload a blueprint to the Cloudify Manager that is servicing a Cloud Site. The blueprint currently must be
+     * structured as a single directory with all of the required files. One of those files is designated the "main file"
+     * for the blueprint. Files are provided as byte arrays, though expect only text files will be distributed from ASDC
+     * and stored by MSO.
      *
-     * Cloudify requires a single root directory in its blueprint zip files.
-     * The requested blueprint ID will also be used as the directory.
-     * All of the files will be added to this directory in the zip file.
+     * Cloudify requires a single root directory in its blueprint zip files. The requested blueprint ID will also be
+     * used as the directory. All of the files will be added to this directory in the zip file.
      */
-    public void uploadBlueprint (String cloudSiteId,
-                                                       String blueprintId,
-                                                       String mainFileName,
-                                                       Map<String,byte[]> blueprintFiles,
-                                                       boolean failIfExists)
-       throws MsoException
-    {
+    public void uploadBlueprint(String cloudSiteId, String blueprintId, String mainFileName,
+            Map<String, byte[]> blueprintFiles, boolean failIfExists) throws MsoException {
         // Obtain the cloud site information where we will load the blueprint
-        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        Optional<CloudSite> cloudSite = cloudConfig.getCloudSite(cloudSiteId);
         if (!cloudSite.isPresent()) {
-            throw new MsoCloudSiteNotFound (cloudSiteId);
+            throw new MsoCloudSiteNotFound(cloudSiteId);
         }
 
-        Cloudify cloudify = getCloudifyClient (cloudSite.get());
+        Cloudify cloudify = getCloudifyClient(cloudSite.get());
 
-        boolean blueprintUploaded = uploadBlueprint (cloudify, blueprintId, mainFileName, blueprintFiles);
+        boolean blueprintUploaded = uploadBlueprint(cloudify, blueprintId, mainFileName, blueprintFiles);
 
         if (!blueprintUploaded && failIfExists) {
-               throw new MsoAdapterException ("Blueprint already exists");
+            throw new MsoAdapterException("Blueprint already exists");
         }
     }
 
     /*
-     * Common method to load a blueprint.  May be called from 
+     * Common method to load a blueprint. May be called from
      */
-    protected boolean uploadBlueprint (Cloudify cloudify, String blueprintId, String mainFileName, Map<String,byte[]> blueprintFiles)
-       throws MsoException
-    {
-       // Check if it already exists.  If so, return false.
-       GetBlueprint getRequest = cloudify.blueprints().getMetadataById(blueprintId);
-       try {
-               Blueprint bp = getRequest.execute();
-          logger.debug("Blueprint {} already exists.", bp.getId());
-          return false;
-       }
-       catch (CloudifyResponseException ce) {
-               if (ce.getStatus() == 404) {
-                       // This is the expected result.
-            logger.debug("Verified that Blueprint doesn't exist yet");
-        } else {
-                       throw ce;
-               }
-       } catch (Exception e) {
-               throw e;
-       }
-
-       // Create a blueprint ZIP file in memory
-               ByteArrayOutputStream zipBuffer = new ByteArrayOutputStream();
-               ZipOutputStream zipOut = new ZipOutputStream(zipBuffer);
-
-               try {
-                       // Put the root directory
-                       String rootDir = blueprintId + ((blueprintId.endsWith("/") ? "" : "/"));
-                       zipOut.putNextEntry(new ZipEntry (rootDir));
-                       zipOut.closeEntry();
-
-                       for (String fileName : blueprintFiles.keySet()) {
-                               ZipEntry ze = new ZipEntry (rootDir + fileName);
-                               zipOut.putNextEntry (ze);
-                               zipOut.write (blueprintFiles.get(fileName));
-                               zipOut.closeEntry();
-                       }
-                       zipOut.close();
-               }
-               catch (IOException e) {
-                       // Since we're writing to a byte array, this should never happen
-               }
+    protected boolean uploadBlueprint(Cloudify cloudify, String blueprintId, String mainFileName,
+            Map<String, byte[]> blueprintFiles) throws MsoException {
+        // Check if it already exists. If so, return false.
+        GetBlueprint getRequest = cloudify.blueprints().getMetadataById(blueprintId);
+        try {
+            Blueprint bp = getRequest.execute();
+            logger.debug("Blueprint {} already exists.", bp.getId());
+            return false;
+        } catch (CloudifyResponseException ce) {
+            if (ce.getStatus() == 404) {
+                // This is the expected result.
+                logger.debug("Verified that Blueprint doesn't exist yet");
+            } else {
+                throw ce;
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+
+        // Create a blueprint ZIP file in memory
+        ByteArrayOutputStream zipBuffer = new ByteArrayOutputStream();
+        ZipOutputStream zipOut = new ZipOutputStream(zipBuffer);
+
+        try {
+            // Put the root directory
+            String rootDir = blueprintId + ((blueprintId.endsWith("/") ? "" : "/"));
+            zipOut.putNextEntry(new ZipEntry(rootDir));
+            zipOut.closeEntry();
+
+            for (String fileName : blueprintFiles.keySet()) {
+                ZipEntry ze = new ZipEntry(rootDir + fileName);
+                zipOut.putNextEntry(ze);
+                zipOut.write(blueprintFiles.get(fileName));
+                zipOut.closeEntry();
+            }
+            zipOut.close();
+        } catch (IOException e) {
+            // Since we're writing to a byte array, this should never happen
+        }
         logger.debug("Blueprint zip file size: {}", zipBuffer.size());
 
         // Ready to upload the blueprint zip
 
-       try (InputStream blueprintStream = new ByteArrayInputStream (zipBuffer.toByteArray())) {
-               UploadBlueprint uploadRequest = cloudify.blueprints().uploadFromStream(blueprintId,  mainFileName,  blueprintStream);
-               Blueprint blueprint = uploadRequest.execute();
-          logger.debug("Successfully uploaded blueprint {}", blueprint.getId());
-      }
-       catch (CloudifyResponseException | CloudifyConnectException e) {
-               throw cloudifyExceptionToMsoException (e, "UPLOAD_BLUEPRINT");
-       }
-       catch (RuntimeException e) {
-               // Catch-all
-               throw runtimeExceptionToMsoException (e, "UPLOAD_BLUEPRINT");
-       } catch (IOException e) {
-               // for try-with-resources
-                       throw ioExceptionToMsoException(e, "UPLOAD_BLUEPRINT");
-               }
-
-       return true;
+        try (InputStream blueprintStream = new ByteArrayInputStream(zipBuffer.toByteArray())) {
+            UploadBlueprint uploadRequest =
+                    cloudify.blueprints().uploadFromStream(blueprintId, mainFileName, blueprintStream);
+            Blueprint blueprint = uploadRequest.execute();
+            logger.debug("Successfully uploaded blueprint {}", blueprint.getId());
+        } catch (CloudifyResponseException | CloudifyConnectException e) {
+            throw cloudifyExceptionToMsoException(e, "UPLOAD_BLUEPRINT");
+        } catch (RuntimeException e) {
+            // Catch-all
+            throw runtimeExceptionToMsoException(e, "UPLOAD_BLUEPRINT");
+        } catch (IOException e) {
+            // for try-with-resources
+            throw ioExceptionToMsoException(e, "UPLOAD_BLUEPRINT");
+        }
+
+        return true;
     }
 
 
@@ -926,35 +854,33 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
     // PRIVATE FUNCTIONS FOR USE WITHIN THIS CLASS
 
     /**
-     * Get a Cloudify client for the specified cloud site.
-     * Everything that is required can be found in the Cloud Config.
+     * Get a Cloudify client for the specified cloud site. Everything that is required can be found in the Cloud Config.
      *
      * @param cloudSite
      * @return a Cloudify object
      */
-    public Cloudify getCloudifyClient (CloudSite cloudSite) throws MsoException
-    {
+    public Cloudify getCloudifyClient(CloudSite cloudSite) throws MsoException {
         CloudifyManager cloudifyConfig = cloudConfig.getCloudifyManager(cloudSite.getCloudifyId());
         if (cloudifyConfig == null) {
-               throw new MsoCloudifyManagerNotFound (cloudSite.getId());
+            throw new MsoCloudifyManagerNotFound(cloudSite.getId());
         }
 
         // Get a Cloudify client
-       // Set a Token Provider to fetch tokens from Cloudify itself.
+        // Set a Token Provider to fetch tokens from Cloudify itself.
         String cloudifyUrl = cloudifyConfig.getCloudifyUrl();
-        Cloudify cloudify = new Cloudify (cloudifyUrl);
-       cloudify.setTokenProvider(new CloudifyClientTokenProvider(cloudifyUrl, cloudifyConfig.getUsername(), CryptoUtils.decryptCloudConfigPassword(cloudifyConfig.getPassword())));
+        Cloudify cloudify = new Cloudify(cloudifyUrl);
+        cloudify.setTokenProvider(new CloudifyClientTokenProvider(cloudifyUrl, cloudifyConfig.getUsername(),
+                CryptoUtils.decryptCloudConfigPassword(cloudifyConfig.getPassword())));
 
-       return cloudify;
+        return cloudify;
     }
 
 
     /*
-     * Query for a Cloudify Deployment. This function is needed in several places, so
-     * a common method is useful. This method takes an authenticated CloudifyClient
-     * (which internally identifies the cloud & tenant to search), and returns
-     * a Deployment object if found, Null if not found, or an MsoCloudifyException
-     * if the Cloudify API call fails.
+     * Query for a Cloudify Deployment. This function is needed in several places, so a common method is useful. This
+     * method takes an authenticated CloudifyClient (which internally identifies the cloud & tenant to search), and
+     * returns a Deployment object if found, Null if not found, or an MsoCloudifyException if the Cloudify API call
+     * fails.
      *
      * @param cloudifyClient an authenticated Cloudify client
      *
@@ -964,234 +890,223 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
      *
      * @throws MsoCloudifyException Thrown if the Cloudify API call returns an exception
      */
-    protected Deployment queryDeployment (Cloudify cloudify, String deploymentId) throws MsoException {
+    protected Deployment queryDeployment(Cloudify cloudify, String deploymentId) throws MsoException {
         if (deploymentId == null) {
             return null;
         }
         try {
-            GetDeployment request = cloudify.deployments().byId (deploymentId);
-            return executeAndRecordCloudifyRequest (request);
+            GetDeployment request = cloudify.deployments().byId(deploymentId);
+            return executeAndRecordCloudifyRequest(request);
         } catch (CloudifyResponseException e) {
-            if (e.getStatus () == 404) {
-                logger.debug ("queryDeployment - not found: {}", deploymentId);
+            if (e.getStatus() == 404) {
+                logger.debug("queryDeployment - not found: {}", deploymentId);
                 return null;
             } else {
                 // Convert the CloudifyResponseException to an MsoCloudifyException
-                throw cloudifyExceptionToMsoException (e, "QueryDeployment");
+                throw cloudifyExceptionToMsoException(e, "QueryDeployment");
             }
         } catch (CloudifyConnectException e) {
             // Connection to Openstack failed
-            throw cloudifyExceptionToMsoException (e, "QueryDeployment");
+            throw cloudifyExceptionToMsoException(e, "QueryDeployment");
         }
     }
 
 
-       public void copyStringOutputsToInputs(Map<String, String> inputs,
-                       Map<String, Object> otherStackOutputs, boolean overWrite) {
-               if (inputs == null || otherStackOutputs == null)
-                       return;
-
-               for (Map.Entry<String, Object> entry : otherStackOutputs.entrySet()) {
-                       String key = entry.getKey();
-                       Object value = entry.getValue();
-
-                       if (value instanceof JsonNode) {
-                               // This is a bit of mess - but I think it's the least impacting
-                               // let's convert it BACK to a string - then it will get converted back later
-                               try {
-                                       inputs.put(key, this.convertNode((JsonNode) value));
-                               } catch (Exception e) {
-            logger.debug("WARNING: unable to convert JsonNode output value for {}", key);
-            //effect here is this value will not have been copied to the inputs - and therefore will error out downstream
-                               }
-                       } else if (value instanceof java.util.LinkedHashMap) {
-          logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
-          try {
-                                       inputs.put(key, JSON_MAPPER.writeValueAsString(value));
-                               } catch (Exception e) {
-            logger.debug("WARNING: unable to convert LinkedHashMap output value for {}", key);
+    public void copyStringOutputsToInputs(Map<String, String> inputs, Map<String, Object> otherStackOutputs,
+            boolean overWrite) {
+        if (inputs == null || otherStackOutputs == null)
+            return;
+
+        for (Map.Entry<String, Object> entry : otherStackOutputs.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+
+            if (value instanceof JsonNode) {
+                // This is a bit of mess - but I think it's the least impacting
+                // let's convert it BACK to a string - then it will get converted back later
+                try {
+                    inputs.put(key, this.convertNode((JsonNode) value));
+                } catch (Exception e) {
+                    logger.debug("WARNING: unable to convert JsonNode output value for {}", key);
+                    // effect here is this value will not have been copied to the inputs - and therefore will error out
+                    // downstream
+                }
+            } else if (value instanceof java.util.LinkedHashMap) {
+                logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
+                try {
+                    inputs.put(key, JSON_MAPPER.writeValueAsString(value));
+                } catch (Exception e) {
+                    logger.debug("WARNING: unable to convert LinkedHashMap output value for {}", key);
+                }
+            } else {
+                // just try to cast it - could be an integer or some such
+                try {
+                    inputs.put(key, (String) value);
+                } catch (Exception e) {
+                    logger.debug("WARNING: unable to convert output value for {}", key);
+                    // effect here is this value will not have been copied to the inputs - and therefore will error out
+                    // downstream
+                }
+            }
         }
-                       } else {
-                               // just try to cast it - could be an integer or some such
-                               try {
-                                       inputs.put(key, (String) value);
-                               } catch (Exception e) {
-            logger.debug("WARNING: unable to convert output value for {}", key);
-            //effect here is this value will not have been copied to the inputs - and therefore will error out downstream
-                               }
-                       }
-               }
-               return;
-       }
-
-       /*
-        * Normalize an input value to an Object, based on the target parameter type.
-        * If the type is not recognized, it will just be returned unchanged (as a string).
-        */
-       public Object convertInputValue (Object inputValue, HeatTemplateParam templateParam)
-       {
-               String type = templateParam.getParamType();
-      logger.debug("Parameter: {} is of type {}", templateParam.getParamName(), type);
-
-      if (type.equalsIgnoreCase("number")) {
-                       try {
-                               return Integer.valueOf(inputValue.toString());
-                       }
-                       catch (Exception e) {
-          logger.debug("Unable to convert {} to an integer!", inputValue);
-          return null;
-                       }
-               } else if (type.equalsIgnoreCase("json")) {
-                       try {
-                               if (inputValue instanceof String) {
-                                       return JSON_MAPPER.readTree(inputValue.toString());
-                               }
-                               //will already marshal to json without intervention
-                               return inputValue;
-                       }
-                       catch (Exception e) {
-          logger.debug("Unable to convert {} to a JsonNode!", inputValue);
-          return null;
-                       }
-               } else if (type.equalsIgnoreCase("boolean")) {
-                       return new Boolean(inputValue.toString());
-               }
-
-               // Nothing else matched.  Return the original string
-               return inputValue;
-       }
-
-
-       private String convertNode(final JsonNode node) {
-               try {
-                       final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
-                       return JSON_MAPPER.writeValueAsString(obj);
-               } catch (JsonParseException jpe) {
-        logger.debug("Error converting json to string {}", jpe);
-    } catch (Exception e) {
-        logger.debug("Error converting json to string {}", e);
+        return;
     }
-               return "[Error converting json to string]";
-       }
-       
-       
+
     /*
-     * Method to execute a Cloudify command and track its execution time.
-     * For the metrics log, a category of "Cloudify" is used along with a
-     * sub-category that identifies the specific call (using the real
-     * cloudify-client classname of the CloudifyRequest<T> parameter).
+     * Normalize an input value to an Object, based on the target parameter type. If the type is not recognized, it will
+     * just be returned unchanged (as a string).
      */
+    public Object convertInputValue(Object inputValue, HeatTemplateParam templateParam) {
+        String type = templateParam.getParamType();
+        logger.debug("Parameter: {} is of type {}", templateParam.getParamName(), type);
 
+        if (type.equalsIgnoreCase("number")) {
+            try {
+                return Integer.valueOf(inputValue.toString());
+            } catch (Exception e) {
+                logger.debug("Unable to convert {} to an integer!", inputValue);
+                return null;
+            }
+        } else if (type.equalsIgnoreCase("json")) {
+            try {
+                if (inputValue instanceof String) {
+                    return JSON_MAPPER.readTree(inputValue.toString());
+                }
+                // will already marshal to json without intervention
+                return inputValue;
+            } catch (Exception e) {
+                logger.debug("Unable to convert {} to a JsonNode!", inputValue);
+                return null;
+            }
+        } else if (type.equalsIgnoreCase("boolean")) {
+            return new Boolean(inputValue.toString());
+        }
+
+        // Nothing else matched. Return the original string
+        return inputValue;
+    }
+
+
+    private String convertNode(final JsonNode node) {
+        try {
+            final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
+            return JSON_MAPPER.writeValueAsString(obj);
+        } catch (JsonParseException jpe) {
+            logger.debug("Error converting json to string {}", jpe);
+        } catch (Exception e) {
+            logger.debug("Error converting json to string {}", e);
+        }
+        return "[Error converting json to string]";
+    }
 
-    protected <T> T executeAndRecordCloudifyRequest (CloudifyRequest <T> request) {
 
-       String requestType;
-        if (request.getClass ().getEnclosingClass () != null) {
-            requestType = request.getClass ().getEnclosingClass ().getSimpleName () + "."
-                          + request.getClass ().getSimpleName ();
+    /*
+     * Method to execute a Cloudify command and track its execution time. For the metrics log, a category of "Cloudify"
+     * is used along with a sub-category that identifies the specific call (using the real cloudify-client classname of
+     * the CloudifyRequest<T> parameter).
+     */
+
+
+    protected <T> T executeAndRecordCloudifyRequest(CloudifyRequest<T> request) {
+
+        String requestType;
+        if (request.getClass().getEnclosingClass() != null) {
+            requestType =
+                    request.getClass().getEnclosingClass().getSimpleName() + "." + request.getClass().getSimpleName();
         } else {
-            requestType = request.getClass ().getSimpleName ();
+            requestType = request.getClass().getSimpleName();
         }
 
         int retryDelay = poConfig.getRetryDelay();
         int retryCount = poConfig.getRetryCount();
-        String retryCodes  = poConfig.getRetryCodes();
+        String retryCodes = poConfig.getRetryCodes();
 
         // Run the actual command. All exceptions will be propagated
-        while (true)
-        {
-               try {
-                return request.execute ();
-               } 
-               catch (CloudifyResponseException e) {
-                       boolean retry = false;
-                       if (retryCodes != null ) {
-                               int code = e.getStatus();
-                logger.debug("Config values RetryDelay: {} RetryCount:{} RetryCodes:{} ResponseCode:{}", retryDelay,
-                    retryCount, retryCodes, code);
-                for (String rCode : retryCodes.split (",")) {
-                                       try {
-                                               if (retryCount > 0 && code == Integer.parseInt (rCode))
-                                               {
-                                                       retryCount--;
-                                                       retry = true;
-                      logger.debug(
-                          "CloudifyResponseException ResponseCode:{} request:{} Retry indicated. Attempts remaining:{}",
-                          code, requestType, retryCount);
-                      break;
-                                               }
-                                       } catch (NumberFormatException e1) {
-                    logger.error("{} No retries. Exception in parsing retry code in config:{} {}",
-                        MessageEnum.RA_CONFIG_EXC, rCode, ErrorCode.SchemaError.getValue());
+        while (true) {
+            try {
+                return request.execute();
+            } catch (CloudifyResponseException e) {
+                boolean retry = false;
+                if (retryCodes != null) {
+                    int code = e.getStatus();
+                    logger.debug("Config values RetryDelay: {} RetryCount:{} RetryCodes:{} ResponseCode:{}", retryDelay,
+                            retryCount, retryCodes, code);
+                    for (String rCode : retryCodes.split(",")) {
+                        try {
+                            if (retryCount > 0 && code == Integer.parseInt(rCode)) {
+                                retryCount--;
+                                retry = true;
+                                logger.debug(
+                                        "CloudifyResponseException ResponseCode:{} request:{} Retry indicated. Attempts remaining:{}",
+                                        code, requestType, retryCount);
+                                break;
+                            }
+                        } catch (NumberFormatException e1) {
+                            logger.error("{} No retries. Exception in parsing retry code in config:{} {}",
+                                    MessageEnum.RA_CONFIG_EXC, rCode, ErrorCode.SchemaError.getValue());
+                            throw e;
+                        }
+                    }
+                }
+                if (retry) {
+                    sleep(retryDelay * 1000L);
+                } else
+                    throw e; // exceeded retryCount or code is not retryable
+            } catch (CloudifyConnectException e) {
+                // Connection to Cloudify failed
+                if (retryCount > 0) {
+                    retryCount--;
+                    logger.debug(" request: {} Retry indicated. Attempts remaining:{}", requestType, retryCount);
+                    sleep(retryDelay * 1000L);
+                } else
                     throw e;
-                                       }
-                               }
-                       }
-                       if (retry)
-                       {
-                               sleep(retryDelay * 1000L);
-                       }
-                       else
-                               throw e; // exceeded retryCount or code is not retryable
-               }
-               catch (CloudifyConnectException e) {
-                       // Connection to Cloudify failed
-                       if (retryCount > 0)
-                       {
-                               retryCount--;
-                logger.debug(" request: {} Retry indicated. Attempts remaining:{}", requestType, retryCount);
-                sleep(retryDelay * 1000L);
-                       }
-                       else
-                               throw e;
-
-               }
+
+            }
         }
     }
+
     /*
-     * Convert an Exception on a Cloudify call to an MsoCloudifyException.
-     * This method supports CloudifyResponseException and CloudifyConnectException.
+     * Convert an Exception on a Cloudify call to an MsoCloudifyException. This method supports
+     * CloudifyResponseException and CloudifyConnectException.
      */
-    protected MsoException cloudifyExceptionToMsoException (CloudifyBaseException e, String context) {
+    protected MsoException cloudifyExceptionToMsoException(CloudifyBaseException e, String context) {
         MsoException me = null;
 
         if (e instanceof CloudifyResponseException) {
-               CloudifyResponseException re = (CloudifyResponseException) e;
+            CloudifyResponseException re = (CloudifyResponseException) e;
 
             try {
                 // Failed Cloudify calls return an error entity body.
-                CloudifyError error = re.getResponse ().getErrorEntity (CloudifyError.class);
+                CloudifyError error = re.getResponse().getErrorEntity(CloudifyError.class);
                 logger.error("{} {} {} Exception - Cloudify Error on {}: {}", MessageEnum.RA_CONNECTION_EXCEPTION,
-                    CLOUDIFY, ErrorCode.DataError.getValue(), context, error.getErrorCode());
+                        CLOUDIFY, ErrorCode.DataError.getValue(), context, error.getErrorCode());
                 String fullError = error.getErrorCode() + ": " + error.getMessage();
                 logger.debug(fullError);
-                               me = new MsoCloudifyException (re.getStatus(),
-                                                re.getMessage(),
-                                                fullError);
+                me = new MsoCloudifyException(re.getStatus(), re.getMessage(), fullError);
             } catch (Exception e2) {
                 // Couldn't parse the body as a "CloudifyError". Report the original HTTP error.
                 logger.error("{} {} {} Exception - HTTP Error on {}: {}, {} ", MessageEnum.RA_CONNECTION_EXCEPTION,
-                    CLOUDIFY, ErrorCode.DataError.getValue(), context, re.getStatus(), e.getMessage(), e2);
-                me = new MsoCloudifyException (re.getStatus (), re.getMessage (), "");
+                        CLOUDIFY, ErrorCode.DataError.getValue(), context, re.getStatus(), e.getMessage(), e2);
+                me = new MsoCloudifyException(re.getStatus(), re.getMessage(), "");
             }
 
             // Add the context of the error
-            me.addContext (context);
+            me.addContext(context);
 
             // Generate an alarm for 5XX and higher errors.
-            if (re.getStatus () >= 500) {
+            if (re.getStatus() >= 500) {
 
             }
         } else if (e instanceof CloudifyConnectException) {
-               CloudifyConnectException ce = (CloudifyConnectException) e;
+            CloudifyConnectException ce = (CloudifyConnectException) e;
 
-            me = new MsoIOException (ce.getMessage ());
-            me.addContext (context);
+            me = new MsoIOException(ce.getMessage());
+            me.addContext(context);
 
             // Generate an alarm for all connection errors.
 
             logger.error("{} {} {} Cloudify connection error on {}: ", MessageEnum.RA_CONNECTION_EXCEPTION, CLOUDIFY,
-                ErrorCode.DataError.getValue(), context, e);
+                    ErrorCode.DataError.getValue(), context, e);
         }
 
         return me;
@@ -1208,88 +1123,75 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
     /**
      * VduPlugin interface for instantiate function.
      *
-     * This one is a bit more complex, in that it will first upload the blueprint if needed,
-     * then create the Cloudify deployment and execute the install workflow.
+     * This one is a bit more complex, in that it will first upload the blueprint if needed, then create the Cloudify
+     * deployment and execute the install workflow.
      *
-     * This implementation also merges any parameters defined in the ENV file with the other
-     * other input parameters for any undefined parameters).
-     * The basic MsoCloudifyUtils separates blueprint management from deploument actions,
-     * but the VduPlugin does not declare blueprint management operations.
+     * This implementation also merges any parameters defined in the ENV file with the other other input parameters for
+     * any undefined parameters). The basic MsoCloudifyUtils separates blueprint management from deploument actions, but
+     * the VduPlugin does not declare blueprint management operations.
      */
     @Override
-       public VduInstance instantiateVdu (
-                       CloudInfo cloudInfo,
-                       String instanceName,
-                       Map<String,Object> inputs,
-                       VduModelInfo vduModel,
-                       boolean rollbackOnFailure)
-       throws VduException
-    {
-       String cloudSiteId = cloudInfo.getCloudSiteId();
-       String tenantId = cloudInfo.getTenantId();
-
-       // Translate the VDU ModelInformation structure to that which is needed for
-       // creating and uploading a blueprint.  Use the model customization UUID as
-       // the blueprint identifier.
-
-       String blueprintId = vduModel.getModelCustomizationUUID();
-
-               try {
-
-               if (! isBlueprintLoaded (cloudSiteId, blueprintId)) {
-            logger.debug("Blueprint {} is not loaded.  Will upload it now.", blueprintId);
-
-                               // Prepare the blueprint inputs.  Need the set of blueprint templates and files,
-                               // plus the main blueprint name.
-                               Map<String,byte[]> blueprintFiles = new HashMap<>();
-                               String mainTemplate = "";
-
-                               // Add all of the blueprint artifacts from the VDU model
-                               List<VduArtifact> vduArtifacts = vduModel.getArtifacts();
-                               for (VduArtifact vduArtifact: vduArtifacts)
-                               {
-                                       // Add all artifacts to the blueprint, with one exception.
-                                       // ENVIRONMENT files will be processed later as additional parameters.
-
-                                       ArtifactType artifactType = vduArtifact.getType();
-                                       if (artifactType != ArtifactType.ENVIRONMENT) {
-                                               blueprintFiles.put(vduArtifact.getName(), vduArtifact.getContent());
-
-                                               if (artifactType == ArtifactType.MAIN_TEMPLATE) {
-                                                       mainTemplate = vduArtifact.getName();
-                                               }
-                                       }
-                               }
-
-                   // Upload the blueprint package
-                               uploadBlueprint(cloudSiteId, blueprintId, mainTemplate, blueprintFiles, false);
-                       }
-       }
-       catch (Exception e) {
-               throw new VduException ("CloudifyUtils (instantiateVDU): blueprint Exception", e);
-       }
-
-
-       // Next, create and install a new deployment based on the blueprint.
-       // For Cloudify, the deploymentId is specified by the client.  Just use the instance name
-       // as the ID.
-
-       try {
-               // Query the Cloudify Deployment object and  populate a VduInstance
-               DeploymentInfo deployment = createAndInstallDeployment (cloudSiteId,
-                    tenantId,
-                    instanceName,
-                    blueprintId,
-                    inputs,
-                    true,  // (poll for completion)
-                    vduModel.getTimeoutMinutes(),
-                    rollbackOnFailure);
-
-               return deploymentInfoToVduInstance(deployment);
-       }
-       catch (Exception e) {
-               throw new VduException ("CloudifyUtils (instantiateVDU): Create-and-install-deployment Exception", e);
-       }
+    public VduInstance instantiateVdu(CloudInfo cloudInfo, String instanceName, Map<String, Object> inputs,
+            VduModelInfo vduModel, boolean rollbackOnFailure) throws VduException {
+        String cloudSiteId = cloudInfo.getCloudSiteId();
+        String tenantId = cloudInfo.getTenantId();
+
+        // Translate the VDU ModelInformation structure to that which is needed for
+        // creating and uploading a blueprint. Use the model customization UUID as
+        // the blueprint identifier.
+
+        String blueprintId = vduModel.getModelCustomizationUUID();
+
+        try {
+
+            if (!isBlueprintLoaded(cloudSiteId, blueprintId)) {
+                logger.debug("Blueprint {} is not loaded.  Will upload it now.", blueprintId);
+
+                // Prepare the blueprint inputs. Need the set of blueprint templates and files,
+                // plus the main blueprint name.
+                Map<String, byte[]> blueprintFiles = new HashMap<>();
+                String mainTemplate = "";
+
+                // Add all of the blueprint artifacts from the VDU model
+                List<VduArtifact> vduArtifacts = vduModel.getArtifacts();
+                for (VduArtifact vduArtifact : vduArtifacts) {
+                    // Add all artifacts to the blueprint, with one exception.
+                    // ENVIRONMENT files will be processed later as additional parameters.
+
+                    ArtifactType artifactType = vduArtifact.getType();
+                    if (artifactType != ArtifactType.ENVIRONMENT) {
+                        blueprintFiles.put(vduArtifact.getName(), vduArtifact.getContent());
+
+                        if (artifactType == ArtifactType.MAIN_TEMPLATE) {
+                            mainTemplate = vduArtifact.getName();
+                        }
+                    }
+                }
+
+                // Upload the blueprint package
+                uploadBlueprint(cloudSiteId, blueprintId, mainTemplate, blueprintFiles, false);
+            }
+        } catch (Exception e) {
+            throw new VduException("CloudifyUtils (instantiateVDU): blueprint Exception", e);
+        }
+
+
+        // Next, create and install a new deployment based on the blueprint.
+        // For Cloudify, the deploymentId is specified by the client. Just use the instance name
+        // as the ID.
+
+        try {
+            // Query the Cloudify Deployment object and populate a VduInstance
+            DeploymentInfo deployment =
+                    createAndInstallDeployment(cloudSiteId, tenantId, instanceName, blueprintId, inputs, true, // (poll
+                                                                                                               // for
+                                                                                                               // completion)
+                            vduModel.getTimeoutMinutes(), rollbackOnFailure);
+
+            return deploymentInfoToVduInstance(deployment);
+        } catch (Exception e) {
+            throw new VduException("CloudifyUtils (instantiateVDU): Create-and-install-deployment Exception", e);
+        }
     }
 
 
@@ -1297,21 +1199,18 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
      * VduPlugin interface for query function.
      */
     @Override
-       public VduInstance queryVdu (CloudInfo cloudInfo, String instanceId)
-       throws VduException
-    {
-       String cloudSiteId = cloudInfo.getCloudSiteId();
-       String tenantId = cloudInfo.getTenantId();
-
-       try {
-               // Query the Cloudify Deployment object and  populate a VduInstance
-               DeploymentInfo deployment = queryDeployment (cloudSiteId, tenantId, instanceId);
-
-               return deploymentInfoToVduInstance(deployment);
-       }
-       catch (Exception e) {
-               throw new VduException ("Query VDU Exception", e);
-       }
+    public VduInstance queryVdu(CloudInfo cloudInfo, String instanceId) throws VduException {
+        String cloudSiteId = cloudInfo.getCloudSiteId();
+        String tenantId = cloudInfo.getTenantId();
+
+        try {
+            // Query the Cloudify Deployment object and populate a VduInstance
+            DeploymentInfo deployment = queryDeployment(cloudSiteId, tenantId, instanceId);
+
+            return deploymentInfoToVduInstance(deployment);
+        } catch (Exception e) {
+            throw new VduException("Query VDU Exception", e);
+        }
     }
 
 
@@ -1319,139 +1218,124 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin{
      * VduPlugin interface for delete function.
      */
     @Override
-       public VduInstance deleteVdu (CloudInfo cloudInfo, String instanceId, int timeoutMinutes)
-       throws VduException
-    {
-       String cloudSiteId = cloudInfo.getCloudSiteId();
-       String tenantId = cloudInfo.getTenantId();
-
-       try {
-               // Uninstall and delete the Cloudify Deployment
-               DeploymentInfo deployment = uninstallAndDeleteDeployment (cloudSiteId, tenantId, instanceId, timeoutMinutes);
-
-               // Populate a VduInstance based on the deleted Cloudify Deployment object
-               return deploymentInfoToVduInstance(deployment);
-       }
-       catch (Exception e) {
-               throw new VduException ("Delete VDU Exception", e);
-       }
+    public VduInstance deleteVdu(CloudInfo cloudInfo, String instanceId, int timeoutMinutes) throws VduException {
+        String cloudSiteId = cloudInfo.getCloudSiteId();
+        String tenantId = cloudInfo.getTenantId();
+
+        try {
+            // Uninstall and delete the Cloudify Deployment
+            DeploymentInfo deployment = uninstallAndDeleteDeployment(cloudSiteId, tenantId, instanceId, timeoutMinutes);
+
+            // Populate a VduInstance based on the deleted Cloudify Deployment object
+            return deploymentInfoToVduInstance(deployment);
+        } catch (Exception e) {
+            throw new VduException("Delete VDU Exception", e);
+        }
     }
 
 
     /**
      * VduPlugin interface for update function.
      *
-     * Update is currently not supported in the MsoCloudifyUtils implementation.
-     * Just return a VduException.
+     * Update is currently not supported in the MsoCloudifyUtils implementation. Just return a VduException.
      *
      */
     @Override
-       public VduInstance updateVdu (
-                       CloudInfo cloudInfo,
-                       String instanceId,
-                       Map<String,Object> inputs,
-                       VduModelInfo vduModel,
-                       boolean rollbackOnFailure)
-       throws VduException
-    {
-       throw new VduException ("CloudifyUtils: updateVDU interface not supported");
+    public VduInstance updateVdu(CloudInfo cloudInfo, String instanceId, Map<String, Object> inputs,
+            VduModelInfo vduModel, boolean rollbackOnFailure) throws VduException {
+        throw new VduException("CloudifyUtils: updateVDU interface not supported");
     }
 
 
     /*
      * Convert the local DeploymentInfo object (Cloudify-specific) to a generic VduInstance object
      */
-    protected VduInstance deploymentInfoToVduInstance (DeploymentInfo deployment)
-    {
-       VduInstance vduInstance = new VduInstance();
+    protected VduInstance deploymentInfoToVduInstance(DeploymentInfo deployment) {
+        VduInstance vduInstance = new VduInstance();
 
-       // only one ID in Cloudify, use for both VDU name and ID
-       vduInstance.setVduInstanceId(deployment.getId());
-       vduInstance.setVduInstanceName(deployment.getId());
+        // only one ID in Cloudify, use for both VDU name and ID
+        vduInstance.setVduInstanceId(deployment.getId());
+        vduInstance.setVduInstanceName(deployment.getId());
 
-       // Copy inputs and outputs
-       vduInstance.setInputs(deployment.getInputs());
-       vduInstance.setOutputs(deployment.getOutputs());
+        // Copy inputs and outputs
+        vduInstance.setInputs(deployment.getInputs());
+        vduInstance.setOutputs(deployment.getOutputs());
 
-       // Translate the status elements
-       vduInstance.setStatus(deploymentStatusToVduStatus (deployment));
+        // Translate the status elements
+        vduInstance.setStatus(deploymentStatusToVduStatus(deployment));
 
-       return vduInstance;
+        return vduInstance;
     }
 
-    protected VduStatus deploymentStatusToVduStatus (DeploymentInfo deployment)
-    {
-       VduStatus vduStatus = new VduStatus();
-
-       // Determine the status based on last action & status
-       // DeploymentInfo object should be enhanced to report a better status internally.
-       DeploymentStatus status = deployment.getStatus();
-
-       if (status == null) {
-               vduStatus.setState(VduStateType.UNKNOWN);
-       }
-       else if (status == DeploymentStatus.NOTFOUND) {
-               vduStatus.setState(VduStateType.NOTFOUND);
-       }
-       else if (status == DeploymentStatus.INSTALLED) {
-               vduStatus.setState(VduStateType.INSTANTIATED);
-       }
-       else if (status == DeploymentStatus.CREATED) {
-               // Deployment exists but is not installed.  This shouldn't really happen,
-               // since create + install or uninstall + delete are always done together.
-               // But account for it anyway, assuming the operation is still in progress.
-               String lastAction = deployment.getLastAction();
-               if (lastAction == null)
-                       vduStatus.setState(VduStateType.INSTANTIATING);
-               else
-                       vduStatus.setState(VduStateType.DELETING);
-       }
-       else if (status == DeploymentStatus.FAILED) {
-               vduStatus.setState(VduStateType.FAILED);
-       } else {
-               vduStatus.setState(VduStateType.UNKNOWN);
-       }
-
-       vduStatus.setErrorMessage(deployment.getErrorMessage());
-       vduStatus.setLastAction(new PluginAction(deployment.getLastAction(), deployment.getActionStatus(), deployment.getErrorMessage()));
-
-       return vduStatus;
+    protected VduStatus deploymentStatusToVduStatus(DeploymentInfo deployment) {
+        VduStatus vduStatus = new VduStatus();
+
+        // Determine the status based on last action & status
+        // DeploymentInfo object should be enhanced to report a better status internally.
+        DeploymentStatus status = deployment.getStatus();
+
+        if (status == null) {
+            vduStatus.setState(VduStateType.UNKNOWN);
+        } else if (status == DeploymentStatus.NOTFOUND) {
+            vduStatus.setState(VduStateType.NOTFOUND);
+        } else if (status == DeploymentStatus.INSTALLED) {
+            vduStatus.setState(VduStateType.INSTANTIATED);
+        } else if (status == DeploymentStatus.CREATED) {
+            // Deployment exists but is not installed. This shouldn't really happen,
+            // since create + install or uninstall + delete are always done together.
+            // But account for it anyway, assuming the operation is still in progress.
+            String lastAction = deployment.getLastAction();
+            if (lastAction == null)
+                vduStatus.setState(VduStateType.INSTANTIATING);
+            else
+                vduStatus.setState(VduStateType.DELETING);
+        } else if (status == DeploymentStatus.FAILED) {
+            vduStatus.setState(VduStateType.FAILED);
+        } else {
+            vduStatus.setState(VduStateType.UNKNOWN);
+        }
+
+        vduStatus.setErrorMessage(deployment.getErrorMessage());
+        vduStatus.setLastAction(new PluginAction(deployment.getLastAction(), deployment.getActionStatus(),
+                deployment.getErrorMessage()));
+
+        return vduStatus;
     }
 
     /*
-     * Return an OpenstackConfig object as expected by Cloudify Openstack Plug-in.
-     * Base the values on the CloudSite definition.
+     * Return an OpenstackConfig object as expected by Cloudify Openstack Plug-in. Base the values on the CloudSite
+     * definition.
      */
-    protected OpenstackConfig getOpenstackConfig (CloudSite cloudSite, String tenantId) {
+    protected OpenstackConfig getOpenstackConfig(CloudSite cloudSite, String tenantId) {
         OpenstackConfig openstackConfig = new OpenstackConfig();
-        openstackConfig.setRegion (cloudSite.getRegionId());
-        openstackConfig.setAuthUrl (cloudSite.getIdentityService().getIdentityUrl());
-        openstackConfig.setUsername (cloudSite.getIdentityService().getMsoId());
-        openstackConfig.setPassword (CryptoUtils.decryptCloudConfigPassword(cloudSite.getIdentityService().getMsoPass()));
-        openstackConfig.setTenantName (tenantId);
+        openstackConfig.setRegion(cloudSite.getRegionId());
+        openstackConfig.setAuthUrl(cloudSite.getIdentityService().getIdentityUrl());
+        openstackConfig.setUsername(cloudSite.getIdentityService().getMsoId());
+        openstackConfig
+                .setPassword(CryptoUtils.decryptCloudConfigPassword(cloudSite.getIdentityService().getMsoPass()));
+        openstackConfig.setTenantName(tenantId);
         return openstackConfig;
     }
 
     /*
-     * Return an Azure object as expected by Cloudify Azure Plug-in.
-     * Base the values on the CloudSite definition.
+     * Return an Azure object as expected by Cloudify Azure Plug-in. Base the values on the CloudSite definition.
      */
-    protected AzureConfig getAzureConfig (CloudSite cloudSite, String tenantId) {
+    protected AzureConfig getAzureConfig(CloudSite cloudSite, String tenantId) {
         AzureConfig azureConfig = new AzureConfig();
         // TODO: Use adminTenant for now, instead of adding another element
-        azureConfig.setSubscriptionId (cloudSite.getIdentityService().getAdminTenant());
-        azureConfig.setTenantId (tenantId);
-        azureConfig.setClientId (cloudSite.getIdentityService().getMsoId());
-        azureConfig.setClientSecret (cloudSite.getIdentityService().getMsoPass());
+        azureConfig.setSubscriptionId(cloudSite.getIdentityService().getAdminTenant());
+        azureConfig.setTenantId(tenantId);
+        azureConfig.setClientId(cloudSite.getIdentityService().getMsoId());
+        azureConfig.setClientSecret(cloudSite.getIdentityService().getMsoPass());
         return azureConfig;
     }
 
     private void sleep(long time) {
-               try {
-                       Thread.sleep(time);
-               } catch (InterruptedException e) {
-        logger.debug("Thread interrupted while sleeping!", e);
-        Thread.currentThread().interrupt();
-               }
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            logger.debug("Thread interrupted while sleeping!", e);
+            Thread.currentThread().interrupt();
+        }
     }
 }