@Override
 public Set<Resource> buildStack(
     Stack stack,
     String gateWayUserData,
     String coreUserData,
     Map<String, Object> setupProperties) {
   LOGGER.info("Assembling launch request for stack: {}", stack);
   CloudContext cloudContext = new CloudContext(stack);
   CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
   CloudStack cloudStack = cloudStackConverter.convert(stack, coreUserData, gateWayUserData);
   instanceMetadataService.saveInstanceRequests(stack, cloudStack.getGroups());
   LaunchStackRequest launchRequest =
       new LaunchStackRequest(cloudContext, cloudCredential, cloudStack);
   LOGGER.info("Triggering event: {}", launchRequest);
   eventBus.notify(launchRequest.selector(), Event.wrap(launchRequest));
   try {
     LaunchStackResult res = launchRequest.await();
     LOGGER.info("Result: {}", res);
     validateResourceResults(cloudContext, res);
     List<CloudResourceStatus> results = res.getResults();
     updateNodeCount(stack.getId(), cloudStack.getGroups(), results, true);
     return transformResults(results, stack);
   } catch (InterruptedException e) {
     LOGGER.error("Error while launching stack", e);
     throw new OperationException(
         "Unexpected exception occurred during build stack: " + e.getMessage());
   }
 }
 @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<CloudResourceStatus> upscale(
      AuthenticatedContext authenticatedContext, CloudStack stack, List<CloudResource> resources) {
    AzureRMClient azureRMClient = armClient.createAccess(authenticatedContext.getCloudCredential());

    String stackName = armUtils.getStackName(authenticatedContext.getCloudContext());
    String template =
        armTemplateBuilder.build(
            stackName,
            authenticatedContext.getCloudCredential(),
            authenticatedContext.getCloudContext(),
            stack);
    String parameters =
        armTemplateBuilder.buildParameters(
            authenticatedContext.getCloudCredential(), stack.getNetwork(), stack.getImage());

    try {
      azureRMClient.createTemplateDeployment(stackName, stackName, template, parameters);
      List<CloudResourceStatus> check = new ArrayList<>();
      check.add(new CloudResourceStatus(resources.get(0), ResourceStatus.IN_PROGRESS));
      return check;
    } catch (HttpResponseException e) {
      throw new CloudConnectorException(e.getResponse().getData().toString(), e);
    } catch (Exception e) {
      throw new CloudConnectorException(String.format("Could not upscale: %s", stackName), e);
    }
  }
  @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;
  }
 private CloudStack removeDeleteRequestedInstances(CloudStack stack) {
   List<Group> groups = new ArrayList<>();
   for (Group group : stack.getGroups()) {
     List<CloudInstance> instances = new ArrayList<>(group.getInstances());
     for (CloudInstance instance : group.getInstances()) {
       if (InstanceStatus.DELETE_REQUESTED == instance.getTemplate().getStatus()) {
         instances.remove(instance);
       }
     }
     groups.add(new Group(group.getName(), group.getType(), instances));
   }
   return new CloudStack(
       groups, stack.getNetwork(), stack.getSecurity(), stack.getImage(), stack.getParameters());
 }
 private String getExistingSubnetCidr(
     AuthenticatedContext authenticatedContext, CloudStack stack) {
   Network network = stack.getNetwork();
   return utils.isExistingSubnet(network)
       ? utils.getExistingSubnetCidr(authenticatedContext, network)
       : null;
 }
 @Override
 public Set<Resource> addInstances(
     Stack stack,
     String gateWayUserData,
     String coreUserData,
     Integer adjustment,
     String instanceGroup) {
   LOGGER.debug("Assembling upscale stack event for stack: {}", stack);
   CloudContext cloudContext = new CloudContext(stack);
   CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
   InstanceGroup group = stack.getInstanceGroupByInstanceGroupName(instanceGroup);
   group.setNodeCount(group.getNodeCount() + adjustment);
   CloudStack cloudStack = cloudStackConverter.convert(stack, coreUserData, gateWayUserData);
   instanceMetadataService.saveInstanceRequests(stack, cloudStack.getGroups());
   List<CloudResource> resources = cloudResourceConverter.convert(stack.getResources());
   UpscaleStackRequest<UpscaleStackResult> upscaleRequest =
       new UpscaleStackRequest<>(cloudContext, cloudCredential, cloudStack, resources);
   LOGGER.info("Triggering upscale stack event: {}", upscaleRequest);
   eventBus.notify(upscaleRequest.selector(), Event.wrap(upscaleRequest));
   try {
     UpscaleStackResult res = upscaleRequest.await();
     LOGGER.info("Upscale stack result: {}", res);
     List<CloudResourceStatus> results = res.getResults();
     updateNodeCount(stack.getId(), cloudStack.getGroups(), results, false);
     validateResourceResults(cloudContext, res);
     Set<Resource> resourceSet = transformResults(results, stack);
     if (resourceSet.isEmpty()) {
       throw new OperationException(
           "Failed to upscale the cluster since all create request failed: "
               + results.get(0).getStatusReason());
     }
     return resourceSet;
   } catch (InterruptedException e) {
     LOGGER.error("Error while upscaling the stack", e);
     throw new OperationException(e);
   }
 }
  @Override
  public List<CloudResourceStatus> launch(
      AuthenticatedContext authenticatedContext,
      CloudStack stack,
      PersistenceNotifier notifier,
      AdjustmentType adjustmentType,
      Long threshold) {
    String stackName = armUtils.getStackName(authenticatedContext.getCloudContext());
    String resourceGroupName =
        armUtils.getResourceGroupName(authenticatedContext.getCloudContext());
    String template =
        armTemplateBuilder.build(
            stackName,
            authenticatedContext.getCloudCredential(),
            authenticatedContext.getCloudContext(),
            stack);
    String parameters =
        armTemplateBuilder.buildParameters(
            authenticatedContext.getCloudCredential(), stack.getNetwork(), stack.getImage());

    AzureRMClient access = armClient.createAccess(authenticatedContext.getCloudCredential());
    try {
      access.createTemplateDeployment(resourceGroupName, stackName, template, parameters);
    } catch (HttpResponseException e) {
      throw new CloudConnectorException(
          String.format(
              "Error occured when creating stack: %s", e.getResponse().getData().toString()));
    } catch (Exception e) {
      throw new CloudConnectorException(String.format("Invalid provisiong type: %s", stackName));
    }

    CloudResource cloudResource =
        new CloudResource.Builder().type(ResourceType.ARM_TEMPLATE).name(stackName).build();
    List<CloudResourceStatus> resources = check(authenticatedContext, Arrays.asList(cloudResource));
    LOGGER.debug("Launched resources: {}", resources);
    return resources;
  }
 @Override
 public List<CloudResourceStatus> terminate(
     AuthenticatedContext authenticatedContext, CloudStack stack, List<CloudResource> resources) {
   AzureRMClient azureRMClient = armClient.createAccess(authenticatedContext.getCloudCredential());
   for (CloudResource resource : resources) {
     try {
       azureRMClient.deleteResourceGroup(resource.getName());
       PollTask<Boolean> task =
           armPollTaskFactory.newResourceGroupDeleteStatusCheckerTask(
               authenticatedContext,
               armClient,
               new ResourceGroupCheckerContext(
                   new ArmCredentialView(authenticatedContext.getCloudCredential()),
                   resource.getName()));
       Boolean statePollerResult = task.call();
       if (!task.completed(statePollerResult)) {
         syncPollingScheduler.schedule(task);
       }
       if (armUtils.isPersistentStorage()) {
         CloudContext cloudCtx = authenticatedContext.getCloudContext();
         String storageName =
             armUtils.getStorageName(
                 authenticatedContext.getCloudCredential(), cloudCtx, stack.getRegion());
         String imageStorageGroup = armUtils.getImageResourceGroupName(cloudCtx);
         String diskContainer = armUtils.getDiskContainerName(cloudCtx);
         deleteContainer(azureRMClient, imageStorageGroup, storageName, diskContainer);
       }
     } catch (HttpResponseException e) {
       if (e.getStatusCode() != NOT_FOUND) {
         throw new CloudConnectorException(e.getResponse().getData().toString(), e);
       } else {
         return check(authenticatedContext, new ArrayList<CloudResource>());
       }
     } catch (Exception e) {
       throw new CloudConnectorException(
           String.format("Could not delete resource group: %s", resource.getName()), e);
     }
   }
   return check(authenticatedContext, resources);
 }
 private boolean assignFloatingIp(CloudStack stack) {
   return utils.assignFloatingIp(stack.getNetwork());
 }
 private boolean isExistingNetwork(CloudStack stack) {
   return utils.isExistingNetwork(stack.getNetwork());
 }
  @Override
  public List<CloudResourceStatus> downscale(
      AuthenticatedContext auth,
      CloudStack stack,
      List<CloudResource> resources,
      List<CloudInstance> vms) {
    AzureRMClient client = armClient.createAccess(auth.getCloudCredential());
    String stackName = armUtils.getStackName(auth.getCloudContext());
    String storageName =
        armUtils.getStorageName(
            auth.getCloudCredential(), auth.getCloudContext(), stack.getRegion());
    String imageStorageGroup = armUtils.getImageResourceGroupName(auth.getCloudContext());
    String diskContainer = armUtils.getDiskContainerName(auth.getCloudContext());

    for (CloudInstance instance : vms) {
      List<String> networkInterfacesNames = new ArrayList<>();
      List<String> storageProfileDiskNames = new ArrayList<>();
      String instanceId = instance.getInstanceId();

      try {
        Map<String, Object> virtualMachine = client.getVirtualMachine(stackName, instanceId);

        Map properties = (Map) virtualMachine.get("properties");

        Map networkProfile = (Map) properties.get("networkProfile");

        List<Map> networkInterfaces = (List<Map>) networkProfile.get("networkInterfaces");
        for (Map networkInterface : networkInterfaces) {
          networkInterfacesNames.add(
              getNameFromConnectionString(networkInterface.get("id").toString()));
        }

        Map storageProfile = (Map) properties.get("storageProfile");

        Map osDisk = (Map) storageProfile.get("osDisk");
        List<Map> dataDisks = (List<Map>) storageProfile.get("dataDisks");

        for (Map datadisk : dataDisks) {
          Map vhds = (Map) datadisk.get("vhd");
          storageProfileDiskNames.add(getNameFromConnectionString(vhds.get("uri").toString()));
        }
        Map vhds = (Map) osDisk.get("vhd");
        storageProfileDiskNames.add(getNameFromConnectionString(vhds.get("uri").toString()));
      } catch (HttpResponseException e) {
        if (e.getStatusCode() != NOT_FOUND) {
          throw new CloudConnectorException(e.getResponse().getData().toString(), e);
        }
      } catch (Exception e) {
        throw new CloudConnectorException(String.format("Could not downscale: %s", stackName), e);
      }
      try {
        deallocateVirtualMachine(auth, client, stackName, instanceId);
        deleteVirtualMachine(auth, client, stackName, instanceId);
        deleteNetworkInterfaces(auth, client, stackName, networkInterfacesNames);
        deleteDisk(storageProfileDiskNames, client, imageStorageGroup, storageName, diskContainer);
      } catch (CloudConnectorException e) {
        throw e;
      }
    }
    return check(auth, resources);
  }