@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> 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);
  }
  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> 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;
  }