@Override
  public List<CloudVmInstanceStatus> check(AuthenticatedContext ac, List<CloudInstance> vms) {
    List<CloudVmInstanceStatus> statuses = new ArrayList<>();
    AzureRMClient azureRMClient = armClient.getClient(ac.getCloudCredential());
    String stackName = armTemplateUtils.getStackName(ac.getCloudContext());

    for (CloudInstance vm : vms) {
      try {
        Map<String, Object> virtualMachine =
            azureRMClient.getVirtualMachineInstanceView(stackName, vm.getInstanceId());
        List<Map<String, Object>> vmStatuses = (List) virtualMachine.get("statuses");
        for (Map<String, Object> vmStatuse : vmStatuses) {
          String statusCode = vmStatuse.get("code").toString();
          if (statusCode.startsWith("PowerState")) {
            statusCode = statusCode.replace("PowerState/", "");
            statuses.add(new CloudVmInstanceStatus(vm, ArmInstanceStatus.get(statusCode)));
            break;
          }
        }
      } catch (Exception e) {
        statuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.TERMINATED));
      }
    }
    return statuses;
  }
  @SuppressWarnings("unchecked")
  @Override
  public List<CloudResourceStatus> launch(
      AuthenticatedContext authenticatedContext,
      CloudStack stack,
      PersistenceNotifier notifier,
      AdjustmentType adjustmentType,
      Long threshold) {
    String stackName = authenticatedContext.getCloudContext().getName();
    boolean existingNetwork = isExistingNetwork(stack);
    boolean assignFloatingIp = assignFloatingIp(stack);
    String existingSubnetCidr = getExistingSubnetCidr(authenticatedContext, stack);
    String heatTemplate =
        heatTemplateBuilder.build(
            stackName,
            stack.getGroups(),
            stack.getSecurity(),
            stack.getImage(),
            existingNetwork,
            existingSubnetCidr != null,
            assignFloatingIp);
    Map<String, String> parameters =
        heatTemplateBuilder.buildParameters(
            authenticatedContext,
            stack.getNetwork(),
            stack.getImage(),
            existingNetwork,
            existingSubnetCidr);

    OSClient client = openStackClient.createOSClient(authenticatedContext);

    Stack heatStack =
        client
            .heat()
            .stacks()
            .create(
                Builders.stack()
                    .name(stackName)
                    .template(heatTemplate)
                    .disableRollback(false)
                    .parameters(parameters)
                    .timeoutMins(OPERATION_TIMEOUT)
                    .build());

    CloudResource cloudResource =
        new CloudResource.Builder().type(ResourceType.HEAT_STACK).name(heatStack.getId()).build();
    try {
      notifier.notifyAllocation(cloudResource, authenticatedContext.getCloudContext());
    } catch (Exception e) {
      // Rollback
      terminate(authenticatedContext, stack, Lists.newArrayList(cloudResource));
    }
    List<CloudResourceStatus> resources =
        check(authenticatedContext, Lists.newArrayList(cloudResource));
    LOGGER.debug("Launched resources: {}", resources);
    return resources;
  }
 @Override
 public List<CloudResourceStatus> update(
     AuthenticatedContext authenticatedContext, CloudStack stack, List<CloudResource> resources) {
   String stackName = authenticatedContext.getCloudContext().getName();
   boolean existingNetwork = isExistingNetwork(stack);
   boolean assignFloatingIp = assignFloatingIp(stack);
   String existingSubnetCidr = getExistingSubnetCidr(authenticatedContext, stack);
   String heatTemplate =
       heatTemplateBuilder.build(
           stackName,
           stack.getGroups(),
           stack.getSecurity(),
           stack.getImage(),
           existingNetwork,
           existingSubnetCidr != null,
           assignFloatingIp);
   Map<String, String> parameters =
       heatTemplateBuilder.buildParameters(
           authenticatedContext,
           stack.getNetwork(),
           stack.getImage(),
           existingNetwork,
           existingSubnetCidr);
   return updateHeatStack(authenticatedContext, resources, heatTemplate, parameters);
 }
  @Override
  public List<CloudVmInstanceStatus> stop(
      AuthenticatedContext ac, List<CloudResource> resources, List<CloudInstance> vms) {
    AzureRMClient azureRMClient = armClient.getClient(ac.getCloudCredential());
    String stackName = armTemplateUtils.getStackName(ac.getCloudContext());
    List<CloudVmInstanceStatus> statuses = new ArrayList<>();

    for (CloudInstance vm : vms) {
      try {
        azureRMClient.stopVirtualMachine(stackName, vm.getInstanceId());
        statuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.IN_PROGRESS));
      } catch (HttpResponseException e) {
        statuses.add(
            new CloudVmInstanceStatus(
                vm, InstanceStatus.FAILED, e.getResponse().getData().toString()));
      } catch (Exception e) {
        statuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.FAILED, e.getMessage()));
      }
    }
    return statuses;
  }
 private void doRollbackAndDecreaseNodeCount(
     AuthenticatedContext auth,
     List<CloudResourceStatus> statuses,
     Set<Long> ids,
     Group group,
     ResourceBuilderContext ctx,
     ResourceBuilders resourceBuilders,
     Boolean upscale) {
   List<ComputeResourceBuilder> compute =
       resourceBuilders.compute(auth.getCloudContext().getPlatform());
   List<Future<ResourceRequestResult<List<CloudResourceStatus>>>> futures = new ArrayList<>();
   LOGGER.info(
       String.format(
           "InstanceGroup %s node count decreased with one so the new node size is: %s",
           group.getName(), group.getInstances().size()));
   if (getRemovableInstanceTemplates(group, ids).size() <= 0 && !upscale) {
     LOGGER.info("InstanceGroup node count lower than 1 which is incorrect so error will throw");
     throwError(statuses);
   } else {
     for (int i = compute.size() - 1; i >= 0; i--) {
       for (CloudResourceStatus cloudResourceStatus : statuses) {
         try {
           if (compute
               .get(i)
               .resourceType()
               .equals(cloudResourceStatus.getCloudResource().getType())) {
             ResourceDeleteThread thread =
                 createThread(
                     ResourceDeleteThread.NAME,
                     ctx,
                     auth,
                     cloudResourceStatus.getCloudResource(),
                     compute.get(i),
                     false);
             Future<ResourceRequestResult<List<CloudResourceStatus>>> future =
                 resourceBuilderExecutor.submit(thread);
             futures.add(future);
             for (Future<ResourceRequestResult<List<CloudResourceStatus>>> future1 : futures) {
               future1.get();
             }
             futures.clear();
           }
         } catch (Exception e) {
           LOGGER.info("Resource can not be deleted. Reason: {} ", e.getMessage());
         }
       }
     }
   }
 }
 private void doRollback(
     AuthenticatedContext auth,
     List<CloudResourceStatus> failuresList,
     Group group,
     Integer fullNodeCount,
     ResourceBuilderContext ctx,
     ResourceBuilders resourceBuilders,
     ScaleContext stx) {
   CloudContext localStack = auth.getCloudContext();
   Set<Long> failures = failureCount(failuresList);
   if (stx.getAdjustmentType() == null && failures.size() > 0) {
     LOGGER.info("Failure policy is null so error will throw");
     throwError(failuresList);
   }
   switch (stx.getAdjustmentType()) {
     case EXACT:
       if (stx.getThreshold() > fullNodeCount - failures.size()) {
         LOGGER.info("Number of failures is more than the threshold so error will throw");
         throwError(failuresList);
       } else if (failures.size() != 0) {
         LOGGER.info("Decrease node counts because threshold was higher");
         handleExceptions(
             auth, failuresList, group, ctx, resourceBuilders, failures, stx.getUpscale());
       }
       break;
     case PERCENTAGE:
       if (Double.valueOf(stx.getThreshold())
           > calculatePercentage(failures.size(), fullNodeCount)) {
         LOGGER.info("Number of failures is more than the threshold so error will throw");
         throwError(failuresList);
       } else if (failures.size() != 0) {
         LOGGER.info("Decrease node counts because threshold was higher");
         handleExceptions(
             auth, failuresList, group, ctx, resourceBuilders, failures, stx.getUpscale());
       }
       break;
     case BEST_EFFORT:
       LOGGER.info("Decrease node counts because threshold was higher");
       handleExceptions(
           auth, failuresList, group, ctx, resourceBuilders, failures, stx.getUpscale());
       break;
     default:
       LOGGER.info("Unsupported adjustment type so error will throw");
       throwError(failuresList);
       break;
   }
 }
  private List<CloudResourceStatus> updateHeatStack(
      AuthenticatedContext authenticatedContext,
      List<CloudResource> resources,
      String heatTemplate,
      Map<String, String> parameters) {
    CloudResource resource = utils.getHeatResource(resources);
    String stackName = authenticatedContext.getCloudContext().getName();
    String heatStackId = resource.getName();

    OSClient client = openStackClient.createOSClient(authenticatedContext);
    StackUpdate updateRequest =
        Builders.stackUpdate()
            .template(heatTemplate)
            .parameters(parameters)
            .timeoutMins(OPERATION_TIMEOUT)
            .build();
    client.heat().stacks().update(stackName, heatStackId, updateRequest);
    LOGGER.info(
        "Heat stack update request sent with stack name: '{}' for Heat stack: '{}'",
        stackName,
        heatStackId);
    return check(authenticatedContext, resources);
  }
  @Override
  public List<CloudResourceStatus> terminate(
      AuthenticatedContext authenticatedContext,
      CloudStack cloudStack,
      List<CloudResource> resources) {

    for (CloudResource resource : resources) {
      switch (resource.getType()) {
        case HEAT_STACK:
          String heatStackId = resource.getName();
          String stackName = authenticatedContext.getCloudContext().getName();
          LOGGER.info("Terminate stack: {}", stackName);
          OSClient client = openStackClient.createOSClient(authenticatedContext);
          client.heat().stacks().delete(stackName, heatStackId);
          break;
        default:
          throw new CloudConnectorException(
              String.format("Invalid resource type: %s", resource.getType()));
      }
    }

    return check(authenticatedContext, resources);
  }
  @Override
  public List<CloudResourceStatus> check(
      AuthenticatedContext authenticatedContext, List<CloudResource> resources) {
    List<CloudResourceStatus> result = new ArrayList<>();
    OSClient client = openStackClient.createOSClient(authenticatedContext);

    for (CloudResource resource : resources) {
      switch (resource.getType()) {
        case HEAT_STACK:
          String heatStackId = resource.getName();
          String stackName = authenticatedContext.getCloudContext().getName();
          LOGGER.info("Checking OpenStack Heat stack status of: {}", stackName);
          Stack heatStack = client.heat().stacks().getDetails(stackName, heatStackId);
          CloudResourceStatus heatResourceStatus = utils.heatStatus(resource, heatStack);
          result.add(heatResourceStatus);
          break;
        default:
          throw new CloudConnectorException(
              String.format("Invalid resource type: %s", resource.getType()));
      }
    }

    return result;
  }