/************************************************************************* * Copyright 2009-2013 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.cloudformation.resources.standard.actions; import com.eucalyptus.autoscaling.common.AutoScaling; import com.eucalyptus.autoscaling.common.msgs.AutoScalingGroupNames; import com.eucalyptus.autoscaling.common.msgs.DeletePolicyResponseType; import com.eucalyptus.autoscaling.common.msgs.DeletePolicyType; import com.eucalyptus.autoscaling.common.msgs.DescribeAutoScalingGroupsResponseType; import com.eucalyptus.autoscaling.common.msgs.DescribeAutoScalingGroupsType; import com.eucalyptus.autoscaling.common.msgs.PutScalingPolicyResponseType; import com.eucalyptus.autoscaling.common.msgs.PutScalingPolicyType; import com.eucalyptus.cloudformation.ValidationErrorException; import com.eucalyptus.cloudformation.resources.EC2Helper; import com.eucalyptus.cloudformation.resources.ResourceAction; import com.eucalyptus.cloudformation.resources.ResourceInfo; import com.eucalyptus.cloudformation.resources.ResourceProperties; import com.eucalyptus.cloudformation.resources.standard.info.AWSAutoScalingScalingPolicyResourceInfo; import com.eucalyptus.cloudformation.resources.standard.propertytypes.AWSAutoScalingScalingPolicyProperties; import com.eucalyptus.cloudformation.template.JsonHelper; import com.eucalyptus.cloudformation.util.MessageHelper; import com.eucalyptus.cloudformation.workflow.steps.Step; import com.eucalyptus.cloudformation.workflow.steps.StepBasedResourceAction; import com.eucalyptus.cloudformation.workflow.steps.UpdateStep; import com.eucalyptus.cloudformation.workflow.updateinfo.UpdateType; import com.eucalyptus.component.ServiceConfiguration; import com.eucalyptus.component.Topology; import com.eucalyptus.compute.common.AddressInfoType; import com.eucalyptus.compute.common.AssociateAddressResponseType; import com.eucalyptus.compute.common.AssociateAddressType; import com.eucalyptus.compute.common.Compute; import com.eucalyptus.compute.common.DescribeInstancesResponseType; import com.eucalyptus.compute.common.DescribeInstancesType; import com.eucalyptus.compute.common.DisassociateAddressResponseType; import com.eucalyptus.compute.common.DisassociateAddressType; import com.eucalyptus.compute.common.Filter; import com.eucalyptus.util.async.AsyncRequests; import com.fasterxml.jackson.databind.node.TextNode; import com.google.common.collect.Lists; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * Created by ethomas on 2/3/14. */ public class AWSAutoScalingScalingPolicyResourceAction extends StepBasedResourceAction { private AWSAutoScalingScalingPolicyProperties properties = new AWSAutoScalingScalingPolicyProperties(); private AWSAutoScalingScalingPolicyResourceInfo info = new AWSAutoScalingScalingPolicyResourceInfo(); public AWSAutoScalingScalingPolicyResourceAction() { super(fromEnum(CreateSteps.class), fromEnum(DeleteSteps.class), fromUpdateEnum(UpdateNoInterruptionSteps.class), null); } @Override public UpdateType getUpdateType(ResourceAction resourceAction, boolean stackTagsChanged) { UpdateType updateType = info.supportsTags() && stackTagsChanged ? UpdateType.NO_INTERRUPTION : UpdateType.NONE; AWSAutoScalingScalingPolicyResourceAction otherAction = (AWSAutoScalingScalingPolicyResourceAction) resourceAction; if (!Objects.equals(properties.getAdjustmentType(), otherAction.properties.getAdjustmentType())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getAutoScalingGroupName(), otherAction.properties.getAutoScalingGroupName())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getCooldown(), otherAction.properties.getCooldown())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getScalingAdjustment(), otherAction.properties.getScalingAdjustment())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } return updateType; } private enum CreateSteps implements Step { CREATE_SCALING_POLICY { @Override public ResourceAction perform(ResourceAction resourceAction) throws Exception { AWSAutoScalingScalingPolicyResourceAction action = (AWSAutoScalingScalingPolicyResourceAction) resourceAction; ServiceConfiguration configuration = Topology.lookup(AutoScaling.class); DescribeAutoScalingGroupsType describeAutoScalingGroupsType = MessageHelper.createMessage(DescribeAutoScalingGroupsType.class, action.info.getEffectiveUserId()); AutoScalingGroupNames autoScalingGroupNames = new AutoScalingGroupNames(); ArrayList<String> member = Lists.newArrayList(action.properties.getAutoScalingGroupName()); autoScalingGroupNames.setMember(member); describeAutoScalingGroupsType.setAutoScalingGroupNames(autoScalingGroupNames); DescribeAutoScalingGroupsResponseType describeAutoScalingGroupsResponseType = AsyncRequests.<DescribeAutoScalingGroupsType,DescribeAutoScalingGroupsResponseType> sendSync(configuration, describeAutoScalingGroupsType); if (action.doesGroupNotExist(describeAutoScalingGroupsResponseType)) { throw new Exception("Autoscaling group " + action.properties.getAutoScalingGroupName() + " does not exist"); } String scalingPolicyName = action.getDefaultPhysicalResourceId(); PutScalingPolicyType putScalingPolicyType = MessageHelper.createMessage(PutScalingPolicyType.class, action.info.getEffectiveUserId()); putScalingPolicyType.setAutoScalingGroupName(action.properties.getAutoScalingGroupName()); putScalingPolicyType.setAdjustmentType(action.properties.getAdjustmentType()); putScalingPolicyType.setCooldown(action.properties.getCooldown()); putScalingPolicyType.setPolicyName(scalingPolicyName); putScalingPolicyType.setScalingAdjustment(action.properties.getScalingAdjustment()); PutScalingPolicyResponseType putScalingPolicyResponseType = AsyncRequests.<PutScalingPolicyType,PutScalingPolicyResponseType> sendSync(configuration, putScalingPolicyType); action.info.setPhysicalResourceId(putScalingPolicyResponseType.getPutScalingPolicyResult().getPolicyARN()); // Docs are wrong, need ARN for alarms (and it is what AWS does action.info.setCreatedEnoughToDelete(true); action.info.setReferenceValueJson(JsonHelper.getStringFromJsonNode(new TextNode(action.info.getPhysicalResourceId()))); return action; } }; @Nullable @Override public Integer getTimeout() { return null; } } private enum DeleteSteps implements Step { DELETE_SCALING_POLICY { @Override public ResourceAction perform(ResourceAction resourceAction) throws Exception { AWSAutoScalingScalingPolicyResourceAction action = (AWSAutoScalingScalingPolicyResourceAction) resourceAction; ServiceConfiguration configuration = Topology.lookup(AutoScaling.class); if (!Boolean.TRUE.equals(action.info.getCreatedEnoughToDelete())) return action; // no group, bye... DescribeAutoScalingGroupsType describeAutoScalingGroupsType = MessageHelper.createMessage(DescribeAutoScalingGroupsType.class, action.info.getEffectiveUserId()); AutoScalingGroupNames autoScalingGroupNames = new AutoScalingGroupNames(); ArrayList<String> member = Lists.newArrayList(action.properties.getAutoScalingGroupName()); autoScalingGroupNames.setMember(member); describeAutoScalingGroupsType.setAutoScalingGroupNames(autoScalingGroupNames); DescribeAutoScalingGroupsResponseType describeAutoScalingGroupsResponseType = AsyncRequests.<DescribeAutoScalingGroupsType,DescribeAutoScalingGroupsResponseType> sendSync(configuration, describeAutoScalingGroupsType); if (action.doesGroupNotExist(describeAutoScalingGroupsResponseType)) { return action; } // Can delete with no consequence if not gone DeletePolicyType deletePolicyType = MessageHelper.createMessage(DeletePolicyType.class, action.info.getEffectiveUserId()); deletePolicyType.setPolicyName(action.info.getPhysicalResourceId()); deletePolicyType.setAutoScalingGroupName(action.properties.getAutoScalingGroupName()); AsyncRequests.<DeletePolicyType,DeletePolicyResponseType> sendSync(configuration, deletePolicyType); return action; } }; @Nullable @Override public Integer getTimeout() { return null; } } private enum UpdateNoInterruptionSteps implements UpdateStep { UPDATE_SCALING_POLICY { @Override public ResourceAction perform(ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception { AWSAutoScalingScalingPolicyResourceAction oldAction = (AWSAutoScalingScalingPolicyResourceAction) oldResourceAction; AWSAutoScalingScalingPolicyResourceAction newAction = (AWSAutoScalingScalingPolicyResourceAction) newResourceAction; ServiceConfiguration configuration = Topology.lookup(AutoScaling.class); if (!Objects.equals(oldAction.properties.getAutoScalingGroupName(), newAction.properties.getAutoScalingGroupName())) { DeletePolicyType deletePolicyType = MessageHelper.createMessage(DeletePolicyType.class, newAction.info.getEffectiveUserId()); deletePolicyType.setPolicyName(oldAction.info.getPhysicalResourceId()); deletePolicyType.setAutoScalingGroupName(oldAction.properties.getAutoScalingGroupName()); AsyncRequests.<DeletePolicyType, DeletePolicyResponseType>sendSync(configuration, deletePolicyType); } String policyName = getPolicyNameFromArn(oldAction.info.getPhysicalResourceId()); PutScalingPolicyType putScalingPolicyType = MessageHelper.createMessage(PutScalingPolicyType.class, newAction.info.getEffectiveUserId()); putScalingPolicyType.setAutoScalingGroupName(newAction.properties.getAutoScalingGroupName()); putScalingPolicyType.setAdjustmentType(newAction.properties.getAdjustmentType()); putScalingPolicyType.setCooldown(newAction.properties.getCooldown()); putScalingPolicyType.setPolicyName(policyName); putScalingPolicyType.setScalingAdjustment(newAction.properties.getScalingAdjustment()); PutScalingPolicyResponseType putScalingPolicyResponseType = AsyncRequests.<PutScalingPolicyType,PutScalingPolicyResponseType> sendSync(configuration, putScalingPolicyType); newAction.info.setPhysicalResourceId(putScalingPolicyResponseType.getPutScalingPolicyResult().getPolicyARN()); // Docs are wrong, need ARN for alarms (and it is what AWS does newAction.info.setCreatedEnoughToDelete(true); newAction.info.setReferenceValueJson(JsonHelper.getStringFromJsonNode(new TextNode(newAction.info.getPhysicalResourceId()))); return newAction; } @Nullable @Override public Integer getTimeout() { return null; } }; } private static String getPolicyNameFromArn(String arn) throws ValidationErrorException { if (arn == null) return null; // Hack. Policy ARN looks like: //arn:aws:autoscaling:<region>:<account-id>:scalingPolicy:<some-uuid>:autoScalingGroupName/<groupName>:policyName/<policyName> if (!arn.contains("policyName/")) { throw new ValidationErrorException("Invalid policy arn " + arn); } else { return arn.substring(arn.lastIndexOf("policyName/") + "policyName/".length()); } } @Override public ResourceProperties getResourceProperties() { return properties; } @Override public void setResourceProperties(ResourceProperties resourceProperties) { properties = (AWSAutoScalingScalingPolicyProperties) resourceProperties; } @Override public ResourceInfo getResourceInfo() { return info; } @Override public void setResourceInfo(ResourceInfo resourceInfo) { info = (AWSAutoScalingScalingPolicyResourceInfo) resourceInfo; } private boolean doesGroupNotExist(DescribeAutoScalingGroupsResponseType describeAutoScalingGroupsResponseType) { return describeAutoScalingGroupsResponseType == null || describeAutoScalingGroupsResponseType.getDescribeAutoScalingGroupsResult() == null || describeAutoScalingGroupsResponseType.getDescribeAutoScalingGroupsResult().getAutoScalingGroups() == null || describeAutoScalingGroupsResponseType.getDescribeAutoScalingGroupsResult().getAutoScalingGroups().getMember() == null || describeAutoScalingGroupsResponseType.getDescribeAutoScalingGroupsResult().getAutoScalingGroups().getMember().isEmpty(); } }