@Override
 public void updateAllowedSubnets(Stack stack, String gateWayUserData, String coreUserData) {
   LOGGER.debug("Assembling update subnet event for: {}", stack);
   CloudContext cloudContext = new CloudContext(stack);
   CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
   CloudStack cloudStack = cloudStackConverter.convert(stack, coreUserData, gateWayUserData);
   List<CloudResource> resources = cloudResourceConverter.convert(stack.getResources());
   UpdateStackRequest<UpdateStackResult> updateRequest =
       new UpdateStackRequest<>(cloudContext, cloudCredential, cloudStack, resources);
   eventBus.notify(updateRequest.selector(), Event.wrap(updateRequest));
   try {
     UpdateStackResult res = updateRequest.await();
     LOGGER.info("Update stack result: {}", res);
     if (res.isFailed()) {
       if (res.getException() != null) {
         LOGGER.error("Failed to update the stack", res.getException());
         throw new OperationException(res.getException());
       }
       throw new OperationException(
           format(
               "Failed to update the stack: %s due to: %s", cloudContext, res.getStatusReason()));
     }
   } catch (InterruptedException e) {
     LOGGER.error("Error while updating the stack: " + cloudContext, e);
     throw new OperationException(e);
   }
 }
 @Override
 public void deleteStack(Stack stack, Credential credential) {
   LOGGER.debug("Assembling terminate stack event for stack: {}", stack);
   CloudContext cloudContext = new CloudContext(stack);
   CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
   List<CloudResource> resources = cloudResourceConverter.convert(stack.getResources());
   CloudStack cloudStack = cloudStackConverter.convert(stack, "", "");
   TerminateStackRequest<TerminateStackResult> terminateRequest =
       new TerminateStackRequest<>(cloudContext, cloudStack, cloudCredential, resources);
   LOGGER.info("Triggering terminate stack event: {}", terminateRequest);
   eventBus.notify(terminateRequest.selector(), Event.wrap(terminateRequest));
   try {
     TerminateStackResult res = terminateRequest.await();
     LOGGER.info("Terminate stack result: {}", res);
     if (res.getStatus().equals(EventStatus.FAILED)) {
       if (res.getErrorDetails() != null) {
         LOGGER.error("Failed to terminate the stack", res.getErrorDetails());
         throw new OperationException(res.getErrorDetails());
       }
       throw new OperationException(
           format(
               "Failed to terminate the stack: %s due to %s",
               cloudContext, res.getStatusReason()));
     }
   } catch (InterruptedException e) {
     LOGGER.error("Error while terminating the stack", e);
     throw new OperationException(e);
   }
 }
 @Override
 public void stopAll(Stack stack) {
   LOGGER.info("Assembling stop request for stack: {}", stack);
   CloudContext cloudContext = new CloudContext(stack);
   CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
   List<CloudInstance> instances = metadataConverter.convert(stack.getInstanceMetaDataAsList());
   List<CloudResource> resources = cloudResourceConverter.convert(stack.getResources());
   StopInstancesRequest<StopInstancesResult> stopRequest =
       new StopInstancesRequest<>(cloudContext, cloudCredential, resources, instances);
   LOGGER.info("Triggering event: {}", stopRequest);
   eventBus.notify(stopRequest.selector(), Event.wrap(stopRequest));
   try {
     StopInstancesResult res = stopRequest.await();
     LOGGER.info("Result: {}", res);
     if (res.isFailed()) {
       Exception exception = res.getException();
       LOGGER.error("Failed to stop the stack", exception);
       throw new OperationException(exception);
     } else {
       for (CloudVmInstanceStatus instanceStatus : res.getResults().getResults()) {
         if (instanceStatus.getStatus().equals(InstanceStatus.FAILED)) {
           throw new OperationException(
               "Failed to stop the following instance: " + instanceStatus.getCloudInstance());
         }
       }
     }
   } catch (InterruptedException e) {
     LOGGER.error("Error while stopping the stack", e);
     throw new OperationException(e);
   }
 }
 @Override
 public Set<String> removeInstances(
     Stack stack,
     String gateWayUserData,
     String coreUserData,
     Set<String> instanceIds,
     String instanceGroup) {
   LOGGER.debug("Assembling downscale stack event for stack: {}", stack);
   CloudContext cloudContext = new CloudContext(stack);
   CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
   List<CloudResource> resources = cloudResourceConverter.convert(stack.getResources());
   List<CloudInstance> instances = new ArrayList<>();
   InstanceGroup group = stack.getInstanceGroupByInstanceGroupName(instanceGroup);
   for (InstanceMetaData metaData : group.getAllInstanceMetaData()) {
     if (instanceIds.contains(metaData.getInstanceId())) {
       CloudInstance cloudInstance = metadataConverter.convert(metaData);
       instances.add(cloudInstance);
     }
   }
   CloudStack cloudStack =
       cloudStackConverter.convert(stack, coreUserData, gateWayUserData, instanceIds);
   DownscaleStackRequest<DownscaleStackResult> downscaleRequest =
       new DownscaleStackRequest<>(
           cloudContext, cloudCredential, cloudStack, resources, instances);
   LOGGER.info("Triggering downscale stack event: {}", downscaleRequest);
   eventBus.notify(downscaleRequest.selector(), Event.wrap(downscaleRequest));
   try {
     DownscaleStackResult res = downscaleRequest.await();
     LOGGER.info("Downscale stack result: {}", res);
     if (res.getStatus().equals(EventStatus.FAILED)) {
       LOGGER.error("Failed to downscale the stack", res.getErrorDetails());
       throw new OperationException(res.getErrorDetails());
     }
     return instanceIds;
   } catch (InterruptedException e) {
     LOGGER.error("Error while downscaling the stack", e);
     throw new OperationException(e);
   }
 }
 @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);
   }
 }