/************************************************************************* * 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.cloudformation.ValidationErrorException; 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.AWSCloudWatchAlarmResourceInfo; import com.eucalyptus.cloudformation.resources.standard.propertytypes.AWSCloudWatchAlarmProperties; import com.eucalyptus.cloudformation.resources.standard.propertytypes.CloudWatchMetricDimension; 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.cloudwatch.common.CloudWatch; import com.eucalyptus.cloudwatch.common.msgs.AlarmNames; import com.eucalyptus.cloudwatch.common.msgs.DeleteAlarmsResponseType; import com.eucalyptus.cloudwatch.common.msgs.DeleteAlarmsType; import com.eucalyptus.cloudwatch.common.msgs.DescribeAlarmsResponseType; import com.eucalyptus.cloudwatch.common.msgs.DescribeAlarmsType; import com.eucalyptus.cloudwatch.common.msgs.Dimension; import com.eucalyptus.cloudwatch.common.msgs.Dimensions; import com.eucalyptus.cloudwatch.common.msgs.PutMetricAlarmResponseType; import com.eucalyptus.cloudwatch.common.msgs.PutMetricAlarmType; import com.eucalyptus.cloudwatch.common.msgs.ResourceList; import com.eucalyptus.component.ServiceConfiguration; import com.eucalyptus.component.Topology; 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.Objects; /** * Created by ethomas on 2/3/14. */ public class AWSCloudWatchAlarmResourceAction extends StepBasedResourceAction { private AWSCloudWatchAlarmProperties properties = new AWSCloudWatchAlarmProperties(); private AWSCloudWatchAlarmResourceInfo info = new AWSCloudWatchAlarmResourceInfo(); public AWSCloudWatchAlarmResourceAction() { super(fromEnum(CreateSteps.class), fromEnum(DeleteSteps.class), fromUpdateEnum(UpdateNoInterruptionSteps.class), null); } private enum CreateSteps implements Step { CREATE_ALARM { @Override public ResourceAction perform(ResourceAction resourceAction) throws Exception { AWSCloudWatchAlarmResourceAction action = (AWSCloudWatchAlarmResourceAction) resourceAction; ServiceConfiguration configuration = Topology.lookup(CloudWatch.class); if (action.properties.getAlarmName() == null) { action.properties.setAlarmName(action.getDefaultPhysicalResourceId()); } // check alarm exists (TODO: check aws does this...) DescribeAlarmsType describeAlarmsType = MessageHelper.createMessage(DescribeAlarmsType.class, action.info.getEffectiveUserId()); AlarmNames alarmNames = new AlarmNames(); alarmNames.setMember(Lists.newArrayList(action.properties.getAlarmName())); describeAlarmsType.setAlarmNames(alarmNames); DescribeAlarmsResponseType describeAlarmsResponseType = AsyncRequests.<DescribeAlarmsType,DescribeAlarmsResponseType> sendSync(configuration, describeAlarmsType); if (describeAlarmsResponseType.getDescribeAlarmsResult() != null && describeAlarmsResponseType.getDescribeAlarmsResult().getMetricAlarms() != null && describeAlarmsResponseType.getDescribeAlarmsResult().getMetricAlarms().getMember() != null && describeAlarmsResponseType.getDescribeAlarmsResult().getMetricAlarms().getMember().size() > 0) { throw new ValidationErrorException("Alarm " + action.properties.getAlarmName() + " already exists"); } PutMetricAlarmType putMetricAlarmType = MessageHelper.createMessage(PutMetricAlarmType.class, action.info.getEffectiveUserId()); putMetricAlarmType.setActionsEnabled(action.properties.getActionsEnabled() == null ? Boolean.TRUE : action.properties.getActionsEnabled()); if (action.properties.getAlarmActions() != null) { ResourceList alarmActions = new ResourceList(); ArrayList<String> alarmActionsMember = Lists.newArrayList(action.properties.getAlarmActions()); alarmActions.setMember(alarmActionsMember); putMetricAlarmType.setAlarmActions(alarmActions); } putMetricAlarmType.setAlarmDescription(action.properties.getAlarmDescription()); putMetricAlarmType.setAlarmName(action.properties.getAlarmName()); putMetricAlarmType.setComparisonOperator(action.properties.getComparisonOperator()); if (action.properties.getDimensions() != null) { Dimensions dimensions = new Dimensions(); ArrayList<Dimension> dimensionsMember = Lists.newArrayList(); for (CloudWatchMetricDimension cloudWatchMetricDimension: action.properties.getDimensions()) { Dimension dimension = new Dimension(); dimension.setName(cloudWatchMetricDimension.getName()); dimension.setValue(cloudWatchMetricDimension.getValue()); dimensionsMember.add(dimension); } dimensions.setMember(dimensionsMember); putMetricAlarmType.setDimensions(dimensions); } putMetricAlarmType.setEvaluationPeriods(action.properties.getEvaluationPeriods()); if (action.properties.getInsufficientDataActions() != null) { ResourceList insufficientDataActions = new ResourceList(); ArrayList<String> insufficientDataActionsMember = Lists.newArrayList(action.properties.getInsufficientDataActions()); insufficientDataActions.setMember(insufficientDataActionsMember); putMetricAlarmType.setInsufficientDataActions(insufficientDataActions); } putMetricAlarmType.setMetricName(action.properties.getMetricName()); putMetricAlarmType.setNamespace(action.properties.getNamespace()); if (action.properties.getOkActions() != null) { ResourceList okActions = new ResourceList(); ArrayList<String> okActionsMember = Lists.newArrayList(action.properties.getOkActions()); okActions.setMember(okActionsMember); putMetricAlarmType.setOkActions(okActions); } putMetricAlarmType.setPeriod(action.properties.getPeriod()); putMetricAlarmType.setStatistic(action.properties.getStatistic()); putMetricAlarmType.setThreshold(action.properties.getThreshold()); putMetricAlarmType.setUnit(action.properties.getUnit()); AsyncRequests.<PutMetricAlarmType, PutMetricAlarmResponseType> sendSync(configuration, putMetricAlarmType); action.info.setPhysicalResourceId(action.properties.getAlarmName()); 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_ALARM { @Override public ResourceAction perform(ResourceAction resourceAction) throws Exception { AWSCloudWatchAlarmResourceAction action = (AWSCloudWatchAlarmResourceAction) resourceAction; ServiceConfiguration configuration = Topology.lookup(CloudWatch.class); if (!Boolean.TRUE.equals(action.info.getCreatedEnoughToDelete())) return action; DescribeAlarmsType describeAlarmsType = MessageHelper.createMessage(DescribeAlarmsType.class, action.info.getEffectiveUserId()); AlarmNames alarmNames = new AlarmNames(); alarmNames.setMember(Lists.newArrayList(action.info.getPhysicalResourceId())); describeAlarmsType.setAlarmNames(alarmNames); DescribeAlarmsResponseType describeAlarmsResponseType = AsyncRequests.<DescribeAlarmsType,DescribeAlarmsResponseType> sendSync(configuration, describeAlarmsType); if (describeAlarmsResponseType.getDescribeAlarmsResult() != null && describeAlarmsResponseType.getDescribeAlarmsResult().getMetricAlarms() != null && describeAlarmsResponseType.getDescribeAlarmsResult().getMetricAlarms().getMember() != null && describeAlarmsResponseType.getDescribeAlarmsResult().getMetricAlarms().getMember().size() > 0) { DeleteAlarmsType deleteAlarmsType = MessageHelper.createMessage(DeleteAlarmsType.class, action.info.getEffectiveUserId()); deleteAlarmsType.setAlarmNames(alarmNames); AsyncRequests.<DeleteAlarmsType, DeleteAlarmsResponseType> sendSync(configuration, deleteAlarmsType); } return action; } }; @Nullable @Override public Integer getTimeout() { return null; } } private enum UpdateNoInterruptionSteps implements UpdateStep { UPDATE_ALARM { @Override public ResourceAction perform(ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception { AWSCloudWatchAlarmResourceAction oldAction = (AWSCloudWatchAlarmResourceAction) oldResourceAction; AWSCloudWatchAlarmResourceAction newAction = (AWSCloudWatchAlarmResourceAction) newResourceAction; // just update the alarm values. ServiceConfiguration configuration = Topology.lookup(CloudWatch.class); PutMetricAlarmType putMetricAlarmType = MessageHelper.createMessage(PutMetricAlarmType.class, oldAction.info.getEffectiveUserId()); putMetricAlarmType.setActionsEnabled(newAction.properties.getActionsEnabled() == null ? Boolean.TRUE : newAction.properties.getActionsEnabled()); if (newAction.properties.getAlarmActions() != null) { ResourceList alarmActions = new ResourceList(); ArrayList<String> alarmActionsMember = Lists.newArrayList(newAction.properties.getAlarmActions()); alarmActions.setMember(alarmActionsMember); putMetricAlarmType.setAlarmActions(alarmActions); } putMetricAlarmType.setAlarmDescription(newAction.properties.getAlarmDescription()); putMetricAlarmType.setAlarmName(oldAction.info.getPhysicalResourceId()); // alarm name is physical resource id putMetricAlarmType.setComparisonOperator(newAction.properties.getComparisonOperator()); if (newAction.properties.getDimensions() != null) { Dimensions dimensions = new Dimensions(); ArrayList<Dimension> dimensionsMember = Lists.newArrayList(); for (CloudWatchMetricDimension cloudWatchMetricDimension: newAction.properties.getDimensions()) { Dimension dimension = new Dimension(); dimension.setName(cloudWatchMetricDimension.getName()); dimension.setValue(cloudWatchMetricDimension.getValue()); dimensionsMember.add(dimension); } dimensions.setMember(dimensionsMember); putMetricAlarmType.setDimensions(dimensions); } putMetricAlarmType.setEvaluationPeriods(newAction.properties.getEvaluationPeriods()); if (newAction.properties.getInsufficientDataActions() != null) { ResourceList insufficientDataActions = new ResourceList(); ArrayList<String> insufficientDataActionsMember = Lists.newArrayList(newAction.properties.getInsufficientDataActions()); insufficientDataActions.setMember(insufficientDataActionsMember); putMetricAlarmType.setInsufficientDataActions(insufficientDataActions); } putMetricAlarmType.setMetricName(newAction.properties.getMetricName()); putMetricAlarmType.setNamespace(newAction.properties.getNamespace()); if (newAction.properties.getOkActions() != null) { ResourceList okActions = new ResourceList(); ArrayList<String> okActionsMember = Lists.newArrayList(newAction.properties.getOkActions()); okActions.setMember(okActionsMember); putMetricAlarmType.setOkActions(okActions); } putMetricAlarmType.setPeriod(newAction.properties.getPeriod()); putMetricAlarmType.setStatistic(newAction.properties.getStatistic()); putMetricAlarmType.setThreshold(newAction.properties.getThreshold()); putMetricAlarmType.setUnit(newAction.properties.getUnit()); AsyncRequests.<PutMetricAlarmType, PutMetricAlarmResponseType> sendSync(configuration, putMetricAlarmType); return newAction; } }; @Nullable @Override public Integer getTimeout() { return null; } } @Override public ResourceProperties getResourceProperties() { return properties; } @Override public void setResourceProperties(ResourceProperties resourceProperties) { properties = (AWSCloudWatchAlarmProperties) resourceProperties; } @Override public ResourceInfo getResourceInfo() { return info; } @Override public void setResourceInfo(ResourceInfo resourceInfo) { info = (AWSCloudWatchAlarmResourceInfo) resourceInfo; } @Override public UpdateType getUpdateType(ResourceAction resourceAction, boolean stackTagsChanged) { UpdateType updateType = info.supportsTags() && stackTagsChanged ? UpdateType.NO_INTERRUPTION : UpdateType.NONE; AWSCloudWatchAlarmResourceAction otherAction = (AWSCloudWatchAlarmResourceAction) resourceAction; if (!Objects.equals(properties.getActionsEnabled(), otherAction.properties.getActionsEnabled())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getAlarmActions(), otherAction.properties.getAlarmActions())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getAlarmDescription(), otherAction.properties.getAlarmDescription())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getAlarmName(), otherAction.properties.getAlarmName())) { updateType = UpdateType.max(updateType, UpdateType.NEEDS_REPLACEMENT); } if (!Objects.equals(properties.getComparisonOperator(), otherAction.properties.getComparisonOperator())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getDimensions(), otherAction.properties.getDimensions())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getEvaluationPeriods(), otherAction.properties.getEvaluationPeriods())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getInsufficientDataActions(), otherAction.properties.getInsufficientDataActions())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getMetricName(), otherAction.properties.getMetricName())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getNamespace(), otherAction.properties.getNamespace())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getOkActions(), otherAction.properties.getOkActions())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getPeriod(), otherAction.properties.getPeriod())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getStatistic(), otherAction.properties.getStatistic())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getThreshold(), otherAction.properties.getThreshold())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } if (!Objects.equals(properties.getUnit(), otherAction.properties.getUnit())) { updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION); } return updateType; } }