@Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   // Create 'system' tags as admin user
   String effectiveAdminUserId =
       Accounts.lookupPrincipalByAccountNumber(
               Accounts.lookupPrincipalByUserId(action.info.getEffectiveUserId())
                   .getAccountNumber())
           .getUserId();
   CreateTagsType createSystemTagsType =
       MessageHelper.createPrivilegedMessage(CreateTagsType.class, effectiveAdminUserId);
   createSystemTagsType.setResourcesSet(
       Lists.newArrayList(action.info.getPhysicalResourceId()));
   createSystemTagsType.setTagSet(
       EC2Helper.createTagSet(
           TagHelper.getEC2SystemTags(action.info, action.getStackEntity())));
   AsyncRequests.<CreateTagsType, CreateTagsResponseType>sendSync(
       configuration, createSystemTagsType);
   // Create non-system tags as regular user
   List<EC2Tag> tags = TagHelper.getEC2StackTags(action.getStackEntity());
   if (action.properties.getTags() != null && !action.properties.getTags().isEmpty()) {
     TagHelper.checkReservedEC2TemplateTags(action.properties.getTags());
     tags.addAll(action.properties.getTags());
   }
   if (!tags.isEmpty()) {
     CreateTagsType createTagsType =
         MessageHelper.createMessage(CreateTagsType.class, action.info.getEffectiveUserId());
     createTagsType.setResourcesSet(Lists.newArrayList(action.info.getPhysicalResourceId()));
     createTagsType.setTagSet(EC2Helper.createTagSet(tags));
     AsyncRequests.<CreateTagsType, CreateTagsResponseType>sendSync(
         configuration, createTagsType);
   }
   return action;
 }
 @Override
 public ResourceAction perform(
     ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception {
   AWSEC2VolumeResourceAction oldAction = (AWSEC2VolumeResourceAction) oldResourceAction;
   AWSEC2VolumeResourceAction newAction = (AWSEC2VolumeResourceAction) newResourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   DescribeVolumeAttributeType describeVolumeAttributeType =
       MessageHelper.createMessage(
           DescribeVolumeAttributeType.class, newAction.info.getEffectiveUserId());
   describeVolumeAttributeType.setVolumeId(newAction.info.getPhysicalResourceId());
   describeVolumeAttributeType.setAttribute("autoEnableIO");
   DescribeVolumeAttributeResponseType describeVolumeAttributeResponseType =
       AsyncRequests.sendSync(configuration, describeVolumeAttributeType);
   Boolean originalValue = null;
   if (describeVolumeAttributeResponseType != null) {
     originalValue = describeVolumeAttributeResponseType.getAutoEnableIO();
   }
   if (!Objects.equals(originalValue, newAction.properties.getAutoEnableIO())) {
     ModifyVolumeAttributeType modifyVolumeAttributeTypeType =
         MessageHelper.createMessage(
             ModifyVolumeAttributeType.class, newAction.info.getEffectiveUserId());
     modifyVolumeAttributeTypeType.setVolumeId(newAction.info.getPhysicalResourceId());
     modifyVolumeAttributeTypeType.setAutoEnableIO(newAction.properties.getAutoEnableIO());
     AsyncRequests.sendSync(configuration, modifyVolumeAttributeTypeType);
   }
   return newAction;
 }
 @Override
 public ResourceAction perform(
     ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception {
   AWSIAMInstanceProfileResourceAction oldAction =
       (AWSIAMInstanceProfileResourceAction) oldResourceAction;
   AWSIAMInstanceProfileResourceAction newAction =
       (AWSIAMInstanceProfileResourceAction) newResourceAction;
   ServiceConfiguration configuration = Topology.lookup(Euare.class);
   // This is a weird case.  There can be only 1 role per instance profile, but the API might
   // allow more.
   // As such, we delete the current role if it exists.
   GetInstanceProfileType getInstanceProfileType =
       MessageHelper.createMessage(
           GetInstanceProfileType.class, newAction.info.getEffectiveUserId());
   getInstanceProfileType.setInstanceProfileName(newAction.info.getPhysicalResourceId());
   GetInstanceProfileResponseType getInstanceProfileResponseType =
       AsyncRequests.<GetInstanceProfileType, GetInstanceProfileResponseType>sendSync(
           configuration, getInstanceProfileType);
   for (String roleName : getRoleNames(getInstanceProfileResponseType)) {
     RemoveRoleFromInstanceProfileType removeRoleFromInstanceProfileType =
         MessageHelper.createMessage(
             RemoveRoleFromInstanceProfileType.class, newAction.info.getEffectiveUserId());
     removeRoleFromInstanceProfileType.setInstanceProfileName(
         newAction.info.getPhysicalResourceId());
     removeRoleFromInstanceProfileType.setRoleName(roleName);
     AsyncRequests
         .<RemoveRoleFromInstanceProfileType, RemoveRoleFromInstanceProfileResponseType>
             sendSync(configuration, removeRoleFromInstanceProfileType);
   }
   if (newAction.properties.getRoles() != null) {
     if (newAction.properties.getRoles().size() == 0)
       throw new ValidationErrorException("Property Roles can not be empty.");
     if (newAction.properties.getRoles().size() > 1)
       throw new ValidationErrorException("Roles has too many elements. The limit is 1.");
     for (String roleName : newAction.properties.getRoles()) {
       AddRoleToInstanceProfileType addRoleToInstanceProfileType =
           MessageHelper.createMessage(
               AddRoleToInstanceProfileType.class, newAction.info.getEffectiveUserId());
       addRoleToInstanceProfileType.setInstanceProfileName(
           newAction.info.getPhysicalResourceId());
       addRoleToInstanceProfileType.setRoleName(roleName);
       AsyncRequests
           .<AddRoleToInstanceProfileType, AddRoleToInstanceProfileResponseType>sendSync(
               configuration, addRoleToInstanceProfileType);
     }
   }
   return newAction;
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   DescribeVolumesType describeVolumesType =
       MessageHelper.createMessage(
           DescribeVolumesType.class, action.info.getEffectiveUserId());
   describeVolumesType
       .getFilterSet()
       .add(Filter.filter("volume-id", action.info.getPhysicalResourceId()));
   DescribeVolumesResponseType describeVolumesResponseType;
   try {
     describeVolumesResponseType = AsyncRequests.sendSync(configuration, describeVolumesType);
   } catch (final Exception e) {
     throw new ValidationErrorException(
         "Error describing volume "
             + action.info.getPhysicalResourceId()
             + ":"
             + asWebServiceErrorMessage(e, e.getMessage()));
   }
   if (describeVolumesResponseType.getVolumeSet().size() == 0) {
     throw new RetryAfterConditionCheckFailedException(
         "Volume " + action.info.getPhysicalResourceId() + " not yet available");
   }
   if (!"available".equals(describeVolumesResponseType.getVolumeSet().get(0).getStatus())) {
     throw new RetryAfterConditionCheckFailedException(
         "Volume " + action.info.getPhysicalResourceId() + " not yet available");
   }
   return action;
 }
      @Override
      public ResourceAction perform(ResourceAction resourceAction) throws Exception {
        AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
        ServiceConfiguration configuration = Topology.lookup(Compute.class);
        CreateVolumeType createVolumeType =
            MessageHelper.createMessage(CreateVolumeType.class, action.info.getEffectiveUserId());
        createVolumeType.setAvailabilityZone(action.properties.getAvailabilityZone());
        if (action.properties.getEncrypted() != null) {
          createVolumeType.setEncrypted(action.properties.getEncrypted());
        }
        // KmsKeyId not supported
        if (action.properties.getIops() != null) {
          createVolumeType.setIops(action.properties.getIops());
        }
        if (action.properties.getSize() != null) {
          createVolumeType.setSize(action.properties.getSize());
        }
        if (action.properties.getSnapshotId() != null) {
          createVolumeType.setSnapshotId(action.properties.getSnapshotId());
        }
        if (action.properties.getVolumeType() != null) {
          createVolumeType.setVolumeType(action.properties.getVolumeType());
        } else {
          createVolumeType.setVolumeType("standard");
        }

        CreateVolumeResponseType createVolumeResponseType =
            AsyncRequests.<CreateVolumeType, CreateVolumeResponseType>sendSync(
                configuration, createVolumeType);
        action.info.setPhysicalResourceId(createVolumeResponseType.getVolume().getVolumeId());
        action.info.setCreatedEnoughToDelete(true);
        action.info.setReferenceValueJson(
            JsonHelper.getStringFromJsonNode(new TextNode(action.info.getPhysicalResourceId())));
        return action;
      }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   if (volumeDeleted(action, configuration)) return action;
   if (!("Snapshot".equals(action.info.getDeletionPolicy()))) return action;
   DescribeSnapshotsType describeSnapshotsType =
       MessageHelper.createMessage(
           DescribeSnapshotsType.class, action.info.getEffectiveUserId());
   String snapshotId =
       JsonHelper.getJsonNodeFromString(action.info.getSnapshotIdForDelete()).asText();
   describeSnapshotsType.getFilterSet().add(Filter.filter("snapshot-id", snapshotId));
   DescribeSnapshotsResponseType describeSnapshotsResponseType =
       AsyncRequests.sendSync(configuration, describeSnapshotsType);
   if (describeSnapshotsResponseType.getSnapshotSet() == null
       || describeSnapshotsResponseType.getSnapshotSet().isEmpty()) {
     throw new RetryAfterConditionCheckFailedException(
         "Snapshot " + snapshotId + " not yet complete");
   }
   if ("error".equals(describeSnapshotsResponseType.getSnapshotSet().get(0).getStatus())) {
     throw new ResourceFailureException(
         "Error creating snapshot "
             + snapshotId
             + ", while deleting volume "
             + action.info.getPhysicalResourceId());
   } else if (!"completed"
       .equals(describeSnapshotsResponseType.getSnapshotSet().get(0).getStatus())) {
     throw new RetryAfterConditionCheckFailedException(
         "Snapshot " + snapshotId + " not yet complete");
   }
   return action;
 }
 private static boolean volumeDeleted(
     AWSEC2VolumeResourceAction action, ServiceConfiguration configuration) throws Exception {
   if (!Boolean.TRUE.equals(action.info.getCreatedEnoughToDelete())) return true;
   DescribeVolumesType describeVolumesType =
       MessageHelper.createMessage(DescribeVolumesType.class, action.info.getEffectiveUserId());
   describeVolumesType
       .getFilterSet()
       .add(Filter.filter("volume-id", action.info.getPhysicalResourceId()));
   DescribeVolumesResponseType describeVolumesResponseType;
   try {
     describeVolumesResponseType = AsyncRequests.sendSync(configuration, describeVolumesType);
   } catch (final Exception e) {
     throw new ValidationErrorException(
         "Error describing volume "
             + action.info.getPhysicalResourceId()
             + ":"
             + asWebServiceErrorMessage(e, e.getMessage()));
   }
   if (describeVolumesResponseType.getVolumeSet().size() == 0) {
     return true; // already deleted
   }
   if ("deleted".equals(describeVolumesResponseType.getVolumeSet().get(0).getStatus())) {
     return true;
   }
   return false;
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSIAMInstanceProfileResourceAction action =
       (AWSIAMInstanceProfileResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Euare.class);
   String instanceProfileName = action.getDefaultPhysicalResourceId();
   CreateInstanceProfileType createInstanceProfileType =
       MessageHelper.createMessage(
           CreateInstanceProfileType.class, action.info.getEffectiveUserId());
   createInstanceProfileType.setPath(action.properties.getPath());
   createInstanceProfileType.setInstanceProfileName(instanceProfileName);
   CreateInstanceProfileResponseType createInstanceProfileResponseType =
       AsyncRequests.<CreateInstanceProfileType, CreateInstanceProfileResponseType>sendSync(
           configuration, createInstanceProfileType);
   String arn =
       createInstanceProfileResponseType
           .getCreateInstanceProfileResult()
           .getInstanceProfile()
           .getArn();
   action.info.setPhysicalResourceId(instanceProfileName);
   action.info.setCreatedEnoughToDelete(true);
   action.info.setArn(JsonHelper.getStringFromJsonNode(new TextNode(arn)));
   action.info.setReferenceValueJson(
       JsonHelper.getStringFromJsonNode(new TextNode(action.info.getPhysicalResourceId())));
   return action;
 }
 private void disassociateRouteTable(ServiceConfiguration configuration, String associationId)
     throws Exception {
   DisassociateRouteTableType disassociateRouteTableType =
       MessageHelper.createMessage(DisassociateRouteTableType.class, info.getEffectiveUserId());
   disassociateRouteTableType.setAssociationId(associationId);
   AsyncRequests.<DisassociateRouteTableType, DisassociateRouteTableResponseType>sendSync(
       configuration, disassociateRouteTableType);
 }
 private String associateRouteTable(
     ServiceConfiguration configuration, String subnetId, String routeTableId) throws Exception {
   AssociateRouteTableType associateRouteTableType =
       MessageHelper.createMessage(AssociateRouteTableType.class, info.getEffectiveUserId());
   associateRouteTableType.setRouteTableId(routeTableId);
   associateRouteTableType.setSubnetId(subnetId);
   AssociateRouteTableResponseType associateRouteTableResponseType =
       AsyncRequests.<AssociateRouteTableType, AssociateRouteTableResponseType>sendSync(
           configuration, associateRouteTableType);
   return associateRouteTableResponseType.getAssociationId();
 }
 private void checkSubnetExists(ServiceConfiguration configuration) throws Exception {
   DescribeSubnetsType describeSubnetsType =
       MessageHelper.createMessage(DescribeSubnetsType.class, info.getEffectiveUserId());
   describeSubnetsType.getFilterSet().add(Filter.filter("subnet-id", properties.getSubnetId()));
   DescribeSubnetsResponseType describeSubnetsResponseType =
       AsyncRequests.sendSync(configuration, describeSubnetsType);
   if (describeSubnetsResponseType.getSubnetSet() == null
       || describeSubnetsResponseType.getSubnetSet().getItem() == null
       || describeSubnetsResponseType.getSubnetSet().getItem().isEmpty()) {
     throw new ValidationErrorException("No such subnet with id '" + properties.getSubnetId());
   }
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   if (volumeDeleted(action, configuration)) return action;
   DeleteVolumeType deleteVolumeType =
       MessageHelper.createMessage(DeleteVolumeType.class, action.info.getEffectiveUserId());
   deleteVolumeType.setVolumeId(action.info.getPhysicalResourceId());
   AsyncRequests.<DeleteVolumeType, DeleteVolumeResponseType>sendSync(
       configuration, deleteVolumeType);
   return action;
 }
 private boolean subnetExistsForDelete(ServiceConfiguration configuration) throws Exception {
   DescribeSubnetsType describeSubnetsType =
       MessageHelper.createMessage(DescribeSubnetsType.class, info.getEffectiveUserId());
   describeSubnetsType.getFilterSet().add(Filter.filter("subnet-id", properties.getSubnetId()));
   DescribeSubnetsResponseType describeSubnetsResponseType =
       AsyncRequests.sendSync(configuration, describeSubnetsType);
   if (describeSubnetsResponseType.getSubnetSet() == null
       || describeSubnetsResponseType.getSubnetSet().getItem() == null
       || describeSubnetsResponseType.getSubnetSet().getItem().isEmpty()) {
     return false;
   }
   return true;
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   if (action.properties.getAutoEnableIO() != null) {
     ModifyVolumeAttributeType modifyVolumeAttributeTypeType =
         MessageHelper.createMessage(
             ModifyVolumeAttributeType.class, action.info.getEffectiveUserId());
     modifyVolumeAttributeTypeType.setVolumeId(action.info.getPhysicalResourceId());
     modifyVolumeAttributeTypeType.setAutoEnableIO(action.properties.getAutoEnableIO());
     AsyncRequests.sendSync(configuration, modifyVolumeAttributeTypeType);
   }
   return action;
 }
 private String replaceAssociation(
     ServiceConfiguration configuration, String oldAssociationId, String routeTableId)
     throws Exception {
   ReplaceRouteTableAssociationType replaceRouteTableAssociationType =
       MessageHelper.createMessage(
           ReplaceRouteTableAssociationType.class, info.getEffectiveUserId());
   replaceRouteTableAssociationType.setRouteTableId(routeTableId);
   replaceRouteTableAssociationType.setAssociationId(oldAssociationId);
   ReplaceRouteTableAssociationResponseType replaceRouteTableAssociationResponseType =
       AsyncRequests
           .<ReplaceRouteTableAssociationType, ReplaceRouteTableAssociationResponseType>sendSync(
               configuration, replaceRouteTableAssociationType);
   return replaceRouteTableAssociationResponseType.getNewAssociationId();
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSIAMPolicyResourceAction action = (AWSIAMPolicyResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Euare.class);
   if (action.properties.getGroups() != null) {
     for (String groupName : action.properties.getGroups()) {
       PutGroupPolicyType putGroupPolicyType =
           MessageHelper.createMessage(
               PutGroupPolicyType.class, action.info.getEffectiveUserId());
       putGroupPolicyType.setGroupName(groupName);
       putGroupPolicyType.setPolicyName(action.properties.getPolicyName());
       putGroupPolicyType.setPolicyDocument(action.properties.getPolicyDocument().toString());
       AsyncRequests.<PutGroupPolicyType, PutGroupPolicyResponseType>sendSync(
           configuration, putGroupPolicyType);
     }
   }
   return action;
 }
      @Override
      public ResourceAction perform(ResourceAction resourceAction) throws Exception {
        AWSIAMInstanceProfileResourceAction action =
            (AWSIAMInstanceProfileResourceAction) resourceAction;
        ServiceConfiguration configuration = Topology.lookup(Euare.class);
        if (!Boolean.TRUE.equals(action.info.getCreatedEnoughToDelete())) return action;

        if (!IAMHelper.instanceProfileExists(
            configuration, action.info.getPhysicalResourceId(), action.info.getEffectiveUserId()))
          return action;

        // we can delete the instance profile without detaching the role
        DeleteInstanceProfileType deleteInstanceProfileType =
            MessageHelper.createMessage(
                DeleteInstanceProfileType.class, action.info.getEffectiveUserId());
        deleteInstanceProfileType.setInstanceProfileName(action.info.getPhysicalResourceId());
        AsyncRequests.<DeleteInstanceProfileType, DeleteInstanceProfileResponseType>sendSync(
            configuration, deleteInstanceProfileType);
        return action;
      }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSIAMInstanceProfileResourceAction action =
       (AWSIAMInstanceProfileResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Euare.class);
   if (action.properties.getRoles() != null) {
     for (String roleName : action.properties.getRoles()) {
       AddRoleToInstanceProfileType addRoleToInstanceProfileType =
           MessageHelper.createMessage(
               AddRoleToInstanceProfileType.class, action.info.getEffectiveUserId());
       addRoleToInstanceProfileType.setInstanceProfileName(
           action.info.getPhysicalResourceId());
       addRoleToInstanceProfileType.setRoleName(roleName);
       AsyncRequests
           .<AddRoleToInstanceProfileType, AddRoleToInstanceProfileResponseType>sendSync(
               configuration, addRoleToInstanceProfileType);
     }
   }
   return action;
 }
 private boolean associationIdExistsForDelete(ServiceConfiguration configuration)
     throws Exception {
   DescribeRouteTablesType describeRouteTablesType =
       MessageHelper.createMessage(DescribeRouteTablesType.class, info.getEffectiveUserId());
   ArrayList<Filter> filterSet = Lists.newArrayList();
   ;
   Filter filter = new Filter();
   filter.setName("association.route-table-association-id");
   filter.setValueSet(Lists.<String>newArrayList(info.getPhysicalResourceId()));
   filterSet.add(filter);
   describeRouteTablesType.setFilterSet(filterSet);
   DescribeRouteTablesResponseType describeRouteTablesResponseType =
       AsyncRequests.<DescribeRouteTablesType, DescribeRouteTablesResponseType>sendSync(
           configuration, describeRouteTablesType);
   if (describeRouteTablesResponseType.getRouteTableSet() == null
       || describeRouteTablesResponseType.getRouteTableSet().getItem() == null
       || describeRouteTablesResponseType.getRouteTableSet().getItem().isEmpty()) {
     return false;
   }
   return true;
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSEC2VolumeResourceAction action = (AWSEC2VolumeResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Compute.class);
   if (volumeDeleted(action, configuration)) return action;
   if (!("Snapshot".equals(action.info.getDeletionPolicy()))) return action;
   CreateSnapshotType createSnapshotType =
       MessageHelper.createMessage(CreateSnapshotType.class, action.info.getEffectiveUserId());
   createSnapshotType.setVolumeId(action.info.getPhysicalResourceId());
   CreateSnapshotResponseType createSnapshotResponseType =
       AsyncRequests.<CreateSnapshotType, CreateSnapshotResponseType>sendSync(
           configuration, createSnapshotType);
   if (createSnapshotResponseType.getSnapshot() == null
       || createSnapshotResponseType.getSnapshot().getSnapshotId() == null) {
     throw new ResourceFailureException(
         "Unable to create snapshot on delete for volume "
             + action.info.getPhysicalResourceId());
   } else {
     action.info.setSnapshotIdForDelete(
         JsonHelper.getStringFromJsonNode(
             new TextNode(createSnapshotResponseType.getSnapshot().getSnapshotId())));
   }
   return action;
 }
 @Override
 public ResourceAction perform(ResourceAction resourceAction) throws Exception {
   AWSIAMInstanceProfileResourceAction action =
       (AWSIAMInstanceProfileResourceAction) resourceAction;
   ServiceConfiguration configuration = Topology.lookup(Euare.class);
   if (action.properties.getRoles() != null) {
     if (action.properties.getRoles().size() > 1)
       throw new ValidationErrorException("Roles has too many elements. The limit is 1.");
     if (action.properties.getRoles().size() == 0)
       throw new ValidationErrorException("Property Roles can not be empty.");
     for (String roleName : action.properties.getRoles()) {
       AddRoleToInstanceProfileType addRoleToInstanceProfileType =
           MessageHelper.createMessage(
               AddRoleToInstanceProfileType.class, action.info.getEffectiveUserId());
       addRoleToInstanceProfileType.setInstanceProfileName(
           action.info.getPhysicalResourceId());
       addRoleToInstanceProfileType.setRoleName(roleName);
       AsyncRequests
           .<AddRoleToInstanceProfileType, AddRoleToInstanceProfileResponseType>sendSync(
               configuration, addRoleToInstanceProfileType);
     }
   }
   return action;
 }
      @Override
      public ResourceAction perform(
          ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception {
        AWSEC2VolumeResourceAction oldAction = (AWSEC2VolumeResourceAction) oldResourceAction;
        AWSEC2VolumeResourceAction newAction = (AWSEC2VolumeResourceAction) newResourceAction;
        ServiceConfiguration configuration = Topology.lookup(Compute.class);
        DescribeTagsType describeTagsType =
            MessageHelper.createMessage(
                DescribeTagsType.class, newAction.info.getEffectiveUserId());
        describeTagsType.setFilterSet(
            Lists.newArrayList(
                Filter.filter("resource-id", newAction.info.getPhysicalResourceId())));
        DescribeTagsResponseType describeTagsResponseType =
            AsyncRequests.sendSync(configuration, describeTagsType);
        Set<EC2Tag> existingTags = Sets.newLinkedHashSet();
        if (describeTagsResponseType != null && describeTagsResponseType.getTagSet() != null) {
          for (TagInfo tagInfo : describeTagsResponseType.getTagSet()) {
            EC2Tag tag = new EC2Tag();
            tag.setKey(tagInfo.getKey());
            tag.setValue(tagInfo.getValue());
            existingTags.add(tag);
          }
        }
        Set<EC2Tag> newTags = Sets.newLinkedHashSet();
        if (newAction.properties.getTags() != null) {
          newTags.addAll(newAction.properties.getTags());
        }
        List<EC2Tag> newStackTags = TagHelper.getEC2StackTags(newAction.getStackEntity());
        if (newStackTags != null) {
          newTags.addAll(newStackTags);
        }
        TagHelper.checkReservedEC2TemplateTags(newTags);
        // add only 'new' tags
        Set<EC2Tag> onlyNewTags = Sets.difference(newTags, existingTags);
        if (!onlyNewTags.isEmpty()) {
          CreateTagsType createTagsType =
              MessageHelper.createMessage(
                  CreateTagsType.class, newAction.info.getEffectiveUserId());
          createTagsType.setResourcesSet(
              Lists.newArrayList(newAction.info.getPhysicalResourceId()));
          createTagsType.setTagSet(EC2Helper.createTagSet(onlyNewTags));
          AsyncRequests.<CreateTagsType, CreateTagsResponseType>sendSync(
              configuration, createTagsType);
        }
        //  Get old tags...
        Set<EC2Tag> oldTags = Sets.newLinkedHashSet();
        if (oldAction.properties.getTags() != null) {
          oldTags.addAll(oldAction.properties.getTags());
        }
        List<EC2Tag> oldStackTags = TagHelper.getEC2StackTags(oldAction.getStackEntity());
        if (oldStackTags != null) {
          oldTags.addAll(oldStackTags);
        }

        // remove only the old tags that are not new and that exist
        Set<EC2Tag> tagsToRemove =
            Sets.intersection(oldTags, Sets.difference(existingTags, newTags));
        if (!tagsToRemove.isEmpty()) {
          DeleteTagsType deleteTagsType =
              MessageHelper.createMessage(
                  DeleteTagsType.class, newAction.info.getEffectiveUserId());
          deleteTagsType.setResourcesSet(
              Lists.newArrayList(newAction.info.getPhysicalResourceId()));
          deleteTagsType.setTagSet(EC2Helper.deleteTagSet(tagsToRemove));
          AsyncRequests.<DeleteTagsType, DeleteTagsResponseType>sendSync(
              configuration, deleteTagsType);
        }
        return newAction;
      }
      @Override
      public ResourceAction perform(ResourceAction resourceAction) throws Exception {
        AWSIAMInstanceProfileResourceAction action =
            (AWSIAMInstanceProfileResourceAction) resourceAction;
        ServiceConfiguration configuration = Topology.lookup(Euare.class);
        if (action.info.getPhysicalResourceId() == null) return action;

        // if no instance profile, bye...
        boolean seenAllInstanceProfiles = false;
        boolean foundInstanceProfile = false;
        String instanceProfileMarker = null;
        while (!seenAllInstanceProfiles && !foundInstanceProfile) {
          ListInstanceProfilesType listInstanceProfilesType =
              MessageHelper.createMessage(
                  ListInstanceProfilesType.class, action.info.getEffectiveUserId());
          if (instanceProfileMarker != null) {
            listInstanceProfilesType.setMarker(instanceProfileMarker);
          }
          ListInstanceProfilesResponseType listInstanceProfilesResponseType =
              AsyncRequests.<ListInstanceProfilesType, ListInstanceProfilesResponseType>sendSync(
                  configuration, listInstanceProfilesType);
          if (listInstanceProfilesResponseType.getListInstanceProfilesResult().getIsTruncated()
              == Boolean.TRUE) {
            instanceProfileMarker =
                listInstanceProfilesResponseType.getListInstanceProfilesResult().getMarker();
          } else {
            seenAllInstanceProfiles = true;
          }
          if (listInstanceProfilesResponseType.getListInstanceProfilesResult().getInstanceProfiles()
                  != null
              && listInstanceProfilesResponseType
                      .getListInstanceProfilesResult()
                      .getInstanceProfiles()
                      .getMember()
                  != null) {
            for (InstanceProfileType instanceProfileType :
                listInstanceProfilesResponseType
                    .getListInstanceProfilesResult()
                    .getInstanceProfiles()
                    .getMember()) {
              if (instanceProfileType
                  .getInstanceProfileName()
                  .equals(action.info.getPhysicalResourceId())) {
                foundInstanceProfile = true;
                break;
              }
            }
          }
        }
        // we can delete the instance profile without detaching the role

        if (!foundInstanceProfile) return action;

        DeleteInstanceProfileType deleteInstanceProfileType =
            MessageHelper.createMessage(
                DeleteInstanceProfileType.class, action.info.getEffectiveUserId());
        deleteInstanceProfileType.setInstanceProfileName(action.info.getPhysicalResourceId());
        AsyncRequests.<DeleteInstanceProfileType, DeleteInstanceProfileResponseType>sendSync(
            configuration, deleteInstanceProfileType);
        return action;
      }
      @Override
      public ResourceAction perform(ResourceAction resourceAction) throws Exception {
        AWSIAMPolicyResourceAction action = (AWSIAMPolicyResourceAction) resourceAction;
        ServiceConfiguration configuration = Topology.lookup(Euare.class);
        if (action.info.getPhysicalResourceId() == null) return action;

        // find all roles that still exist from the list and remove the policy
        if (action.properties.getRoles() != null && action.properties.getRoles().size() > 0) {
          List<String> realRolesToRemovePolicyFrom = Lists.newArrayList();
          Set<String> passedInRoles =
              action.properties.getRoles() == null
                  ? new HashSet<String>()
                  : Sets.newHashSet(action.properties.getRoles());
          boolean seenAllRoles = false;
          String roleMarker = null;
          while (!seenAllRoles) {
            ListRolesType listRolesType =
                MessageHelper.createMessage(ListRolesType.class, action.info.getEffectiveUserId());
            if (roleMarker != null) {
              listRolesType.setMarker(roleMarker);
            }
            ListRolesResponseType listRolesResponseType =
                AsyncRequests.<ListRolesType, ListRolesResponseType>sendSync(
                    configuration, listRolesType);
            if (listRolesResponseType.getListRolesResult().getIsTruncated() == Boolean.TRUE) {
              roleMarker = listRolesResponseType.getListRolesResult().getMarker();
            } else {
              seenAllRoles = true;
            }
            if (listRolesResponseType.getListRolesResult().getRoles() != null
                && listRolesResponseType.getListRolesResult().getRoles().getMember() != null) {
              for (RoleType roleType :
                  listRolesResponseType.getListRolesResult().getRoles().getMember()) {
                if (passedInRoles.contains(roleType.getRoleName())) {
                  realRolesToRemovePolicyFrom.add(roleType.getRoleName());
                }
              }
            }
          }
          for (String role : realRolesToRemovePolicyFrom) {
            DeleteRolePolicyType deleteRolePolicyType =
                MessageHelper.createMessage(
                    DeleteRolePolicyType.class, action.info.getEffectiveUserId());
            deleteRolePolicyType.setRoleName(role);
            deleteRolePolicyType.setPolicyName(action.properties.getPolicyName());
            AsyncRequests.<DeleteRolePolicyType, DeleteRolePolicyResponseType>sendSync(
                configuration, deleteRolePolicyType);
          }
        }

        // find all users that still exist from the list and remove the policy
        if (action.properties.getUsers() != null && action.properties.getUsers().size() > 0) {
          List<String> realUsersToRemovePolicyFrom = Lists.newArrayList();
          Set<String> passedInUsers =
              action.properties.getUsers() == null
                  ? new HashSet<String>()
                  : Sets.newHashSet(action.properties.getUsers());
          boolean seenAllUsers = false;
          String userMarker = null;
          while (!seenAllUsers) {
            ListUsersType listUsersType =
                MessageHelper.createMessage(ListUsersType.class, action.info.getEffectiveUserId());
            ;
            if (userMarker != null) {
              listUsersType.setMarker(userMarker);
            }
            ListUsersResponseType listUsersResponseType =
                AsyncRequests.<ListUsersType, ListUsersResponseType>sendSync(
                    configuration, listUsersType);
            if (listUsersResponseType.getListUsersResult().getIsTruncated() == Boolean.TRUE) {
              userMarker = listUsersResponseType.getListUsersResult().getMarker();
            } else {
              seenAllUsers = true;
            }
            if (listUsersResponseType.getListUsersResult().getUsers() != null
                && listUsersResponseType.getListUsersResult().getUsers().getMemberList() != null) {
              for (UserType userType :
                  listUsersResponseType.getListUsersResult().getUsers().getMemberList()) {
                if (passedInUsers.contains(userType.getUserName())) {
                  realUsersToRemovePolicyFrom.add(userType.getUserName());
                }
              }
            }
          }
          for (String user : realUsersToRemovePolicyFrom) {
            DeleteUserPolicyType deleteUserPolicyType =
                MessageHelper.createMessage(
                    DeleteUserPolicyType.class, action.info.getEffectiveUserId());
            deleteUserPolicyType.setUserName(user);
            deleteUserPolicyType.setPolicyName(action.properties.getPolicyName());
            AsyncRequests.<DeleteUserPolicyType, DeleteUserPolicyResponseType>sendSync(
                configuration, deleteUserPolicyType);
          }
        }

        // find all groups that still exist from the list and remove the policy
        if (action.properties.getGroups() != null && action.properties.getGroups().size() > 0) {
          List<String> realGroupsToRemovePolicyFrom = Lists.newArrayList();
          Set<String> passedInGroups =
              action.properties.getGroups() == null
                  ? new HashSet<String>()
                  : Sets.newHashSet(action.properties.getGroups());
          boolean seenAllGroups = false;
          String groupMarker = null;
          while (!seenAllGroups) {
            ListGroupsType listGroupsType =
                MessageHelper.createMessage(ListGroupsType.class, action.info.getEffectiveUserId());
            if (groupMarker != null) {
              listGroupsType.setMarker(groupMarker);
            }
            ListGroupsResponseType listGroupsResponseType =
                AsyncRequests.<ListGroupsType, ListGroupsResponseType>sendSync(
                    configuration, listGroupsType);
            if (listGroupsResponseType.getListGroupsResult().getIsTruncated() == Boolean.TRUE) {
              groupMarker = listGroupsResponseType.getListGroupsResult().getMarker();
            } else {
              seenAllGroups = true;
            }
            if (listGroupsResponseType.getListGroupsResult().getGroups() != null
                && listGroupsResponseType.getListGroupsResult().getGroups().getMemberList()
                    != null) {
              for (GroupType groupType :
                  listGroupsResponseType.getListGroupsResult().getGroups().getMemberList()) {
                if (passedInGroups.contains(groupType.getGroupName())) {
                  realGroupsToRemovePolicyFrom.add(groupType.getGroupName());
                }
              }
            }
          }
          for (String group : realGroupsToRemovePolicyFrom) {
            DeleteGroupPolicyType deleteGroupPolicyType =
                MessageHelper.createMessage(
                    DeleteGroupPolicyType.class, action.info.getEffectiveUserId());
            deleteGroupPolicyType.setGroupName(group);
            deleteGroupPolicyType.setPolicyName(action.properties.getPolicyName());
            AsyncRequests.<DeleteGroupPolicyType, DeleteGroupPolicyResponseType>sendSync(
                configuration, deleteGroupPolicyType);
          }
        }
        return action;
      }