/*************************************************************************
* Copyright 2009-2015 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.AWSEC2VPCGatewayAttachmentResourceInfo;
import com.eucalyptus.cloudformation.resources.standard.propertytypes.AWSEC2VPCGatewayAttachmentProperties;
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.AttachInternetGatewayResponseType;
import com.eucalyptus.compute.common.AttachInternetGatewayType;
import com.eucalyptus.compute.common.AttachVpnGatewayResponseType;
import com.eucalyptus.compute.common.AttachVpnGatewayType;
import com.eucalyptus.compute.common.Compute;
import com.eucalyptus.compute.common.DescribeInternetGatewaysResponseType;
import com.eucalyptus.compute.common.DescribeInternetGatewaysType;
import com.eucalyptus.compute.common.DescribeVpcsResponseType;
import com.eucalyptus.compute.common.DescribeVpcsType;
import com.eucalyptus.compute.common.DescribeVpnGatewaysResponseType;
import com.eucalyptus.compute.common.DescribeVpnGatewaysType;
import com.eucalyptus.compute.common.DetachInternetGatewayResponseType;
import com.eucalyptus.compute.common.DetachInternetGatewayType;
import com.eucalyptus.compute.common.DetachVpnGatewayResponseType;
import com.eucalyptus.compute.common.DetachVpnGatewayType;
import com.eucalyptus.compute.common.Filter;
import com.eucalyptus.compute.common.VpnGatewayIdSetItemType;
import com.eucalyptus.compute.common.VpnGatewayIdSetType;
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 AWSEC2VPCGatewayAttachmentResourceAction extends StepBasedResourceAction {
private AWSEC2VPCGatewayAttachmentProperties properties = new AWSEC2VPCGatewayAttachmentProperties();
private AWSEC2VPCGatewayAttachmentResourceInfo info = new AWSEC2VPCGatewayAttachmentResourceInfo();
public AWSEC2VPCGatewayAttachmentResourceAction() {
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;
AWSEC2VPCGatewayAttachmentResourceAction otherAction = (AWSEC2VPCGatewayAttachmentResourceAction) resourceAction;
if (!Objects.equals(properties.getInternetGatewayId(), otherAction.properties.getInternetGatewayId())) {
updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION);
}
if (!Objects.equals(properties.getVpnGatewayId(), otherAction.properties.getVpnGatewayId())) {
updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION);
}
if (!Objects.equals(properties.getVpcId(), otherAction.properties.getVpcId())) {
updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION);
}
return updateType;
}
private enum CreateSteps implements Step {
CREATE_ATTACHMENT {
@Override
public ResourceAction perform(ResourceAction resourceAction) throws Exception {
AWSEC2VPCGatewayAttachmentResourceAction action = (AWSEC2VPCGatewayAttachmentResourceAction) resourceAction;
ServiceConfiguration configuration = Topology.lookup(Compute.class);
if (action.properties.getInternetGatewayId() != null && action.properties.getVpnGatewayId() != null) {
throw new ValidationErrorException("Both InternetGatewayId and VpnGatewayId can not be set.");
}
if (action.properties.getInternetGatewayId() == null && action.properties.getVpnGatewayId() == null) {
throw new ValidationErrorException("One of InternetGatewayId or VpnGatewayId must be set.");
}
if (action.properties.getInternetGatewayId() != null) {
AttachInternetGatewayType attachInternetGatewayType = MessageHelper.createMessage(AttachInternetGatewayType.class, action.info.getEffectiveUserId());
attachInternetGatewayType.setInternetGatewayId(action.properties.getInternetGatewayId());
attachInternetGatewayType.setVpcId(action.properties.getVpcId());
AsyncRequests.<AttachInternetGatewayType,AttachInternetGatewayResponseType> sendSync(configuration, attachInternetGatewayType);
} else {
// TODO: we don't support this right now so maybe log an error if they try to go this way.
AttachVpnGatewayType attachVpnGatewayType = MessageHelper.createMessage(AttachVpnGatewayType.class, action.info.getEffectiveUserId());
attachVpnGatewayType.setVpnGatewayId(action.properties.getVpnGatewayId());
attachVpnGatewayType.setVpcId(action.properties.getVpcId());
AsyncRequests.<AttachVpnGatewayType,AttachVpnGatewayResponseType> sendSync(configuration, attachVpnGatewayType);
}
action.info.setPhysicalResourceId(action.getDefaultPhysicalResourceId());
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_ATTACHMENT {
@Override
public ResourceAction perform(ResourceAction resourceAction) throws Exception {
AWSEC2VPCGatewayAttachmentResourceAction action = (AWSEC2VPCGatewayAttachmentResourceAction) resourceAction;
ServiceConfiguration configuration = Topology.lookup(Compute.class);
if (!Boolean.TRUE.equals(action.info.getCreatedEnoughToDelete())) return action;
// Check vpc (return if gone)
DescribeVpcsType describeVpcsType = MessageHelper.createMessage(DescribeVpcsType.class, action.info.getEffectiveUserId());
describeVpcsType.getFilterSet( ).add( Filter.filter( "vpc-id", action.properties.getVpcId( ) ) );
DescribeVpcsResponseType describeVpcsResponseType = AsyncRequests.sendSync(configuration, describeVpcsType);
if (describeVpcsResponseType.getVpcSet() == null ||
describeVpcsResponseType.getVpcSet().getItem() == null ||
describeVpcsResponseType.getVpcSet().getItem().isEmpty()) {
return action; // already deleted
}
if (action.properties.getInternetGatewayId() != null) {
// Check gateway (return if gone)
DescribeInternetGatewaysType describeInternetGatewaysType = MessageHelper.createMessage(DescribeInternetGatewaysType.class, action.info.getEffectiveUserId());
describeInternetGatewaysType.getFilterSet( ).add( Filter.filter( "internet-gateway-id", action.properties.getInternetGatewayId( ) ) );
DescribeInternetGatewaysResponseType describeInternetGatewaysResponseType = AsyncRequests.sendSync(configuration, describeInternetGatewaysType);
if (describeInternetGatewaysResponseType.getInternetGatewaySet() == null || describeInternetGatewaysResponseType.getInternetGatewaySet().getItem() == null || describeInternetGatewaysResponseType.getInternetGatewaySet().getItem().isEmpty()) {
return action; // already deleted
}
DetachInternetGatewayType detachInternetGatewayType = MessageHelper.createMessage(DetachInternetGatewayType.class, action.info.getEffectiveUserId());
detachInternetGatewayType.setVpcId(action.properties.getVpcId());
detachInternetGatewayType.setInternetGatewayId(action.properties.getInternetGatewayId());
AsyncRequests.<DetachInternetGatewayType, DetachInternetGatewayResponseType>sendSync(configuration, detachInternetGatewayType);
} else {
// Check vpn gateway (return if gone)
DescribeVpnGatewaysType describeVpnGatewaysType = MessageHelper.createMessage(DescribeVpnGatewaysType.class, action.info.getEffectiveUserId());
action.setVpnGatewayId(describeVpnGatewaysType, action.properties.getVpnGatewayId());
DescribeVpnGatewaysResponseType describeVpnGatewaysResponseType = AsyncRequests.<DescribeVpnGatewaysType, DescribeVpnGatewaysResponseType>sendSync(configuration, describeVpnGatewaysType);
if (describeVpnGatewaysResponseType.getVpnGatewaySet() == null || describeVpnGatewaysResponseType.getVpnGatewaySet().getItem() == null || describeVpnGatewaysResponseType.getVpnGatewaySet().getItem().isEmpty()) {
return action; // already deleted
}
DetachVpnGatewayType detachVpnGatewayType = MessageHelper.createMessage(DetachVpnGatewayType.class, action.info.getEffectiveUserId());
detachVpnGatewayType.setVpcId(action.properties.getVpcId());
detachVpnGatewayType.setVpnGatewayId(action.properties.getVpnGatewayId());
AsyncRequests.<DetachVpnGatewayType, DetachVpnGatewayResponseType>sendSync(configuration, detachVpnGatewayType);
}
return action;
}
};
@Nullable
@Override
public Integer getTimeout() {
return null;
}
}
private enum UpdateNoInterruptionSteps implements UpdateStep {
UPDATE_ATTACHMENT {
@Override
public ResourceAction perform(ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception {
AWSEC2VPCGatewayAttachmentResourceAction oldAction = (AWSEC2VPCGatewayAttachmentResourceAction) oldResourceAction;
AWSEC2VPCGatewayAttachmentResourceAction newAction = (AWSEC2VPCGatewayAttachmentResourceAction) newResourceAction;
ServiceConfiguration configuration = Topology.lookup(Compute.class);
if (newAction.properties.getInternetGatewayId() != null && newAction.properties.getVpnGatewayId() != null) {
throw new ValidationErrorException("Both InternetGatewayId and VpnGatewayId can not be set.");
}
if (newAction.properties.getInternetGatewayId() == null && newAction.properties.getVpnGatewayId() == null) {
throw new ValidationErrorException("One of InternetGatewayId or VpnGatewayId must be set.");
}
// detach old items (TODO: error checking if not there)
if (oldAction.properties.getInternetGatewayId() != null) {
DetachInternetGatewayType detachInternetGatewayType = MessageHelper.createMessage(DetachInternetGatewayType.class, oldAction.info.getEffectiveUserId());
detachInternetGatewayType.setVpcId(oldAction.properties.getVpcId());
detachInternetGatewayType.setInternetGatewayId(oldAction.properties.getInternetGatewayId());
AsyncRequests.<DetachInternetGatewayType, DetachInternetGatewayResponseType>sendSync(configuration, detachInternetGatewayType);
} else {
DetachVpnGatewayType detachVpnGatewayType = MessageHelper.createMessage(DetachVpnGatewayType.class, oldAction.info.getEffectiveUserId());
detachVpnGatewayType.setVpcId(oldAction.properties.getVpcId());
detachVpnGatewayType.setVpnGatewayId(oldAction.properties.getVpnGatewayId());
AsyncRequests.<DetachVpnGatewayType, DetachVpnGatewayResponseType>sendSync(configuration, detachVpnGatewayType);
}
if (newAction.properties.getInternetGatewayId() != null) {
AttachInternetGatewayType attachInternetGatewayType = MessageHelper.createMessage(AttachInternetGatewayType.class, newAction.info.getEffectiveUserId());
attachInternetGatewayType.setInternetGatewayId(newAction.properties.getInternetGatewayId());
attachInternetGatewayType.setVpcId(newAction.properties.getVpcId());
AsyncRequests.<AttachInternetGatewayType,AttachInternetGatewayResponseType> sendSync(configuration, attachInternetGatewayType);
} else {
// TODO: we don't support this right now so maybe log an error if they try to go this way.
AttachVpnGatewayType attachVpnGatewayType = MessageHelper.createMessage(AttachVpnGatewayType.class, newAction.info.getEffectiveUserId());
attachVpnGatewayType.setVpnGatewayId(newAction.properties.getVpnGatewayId());
attachVpnGatewayType.setVpcId(newAction.properties.getVpcId());
AsyncRequests.<AttachVpnGatewayType,AttachVpnGatewayResponseType> sendSync(configuration, attachVpnGatewayType);
}
return newAction;
}
};
@Nullable
@Override
public Integer getTimeout() {
return null;
}
}
@Override
public ResourceProperties getResourceProperties() {
return properties;
}
@Override
public void setResourceProperties(ResourceProperties resourceProperties) {
properties = (AWSEC2VPCGatewayAttachmentProperties) resourceProperties;
}
@Override
public ResourceInfo getResourceInfo() {
return info;
}
@Override
public void setResourceInfo(ResourceInfo resourceInfo) {
info = (AWSEC2VPCGatewayAttachmentResourceInfo) resourceInfo;
}
private void setVpnGatewayId(DescribeVpnGatewaysType describeVpnGatewaysType, String vpnGatewayId) {
VpnGatewayIdSetType vpnGatewaySet = new VpnGatewayIdSetType();
describeVpnGatewaysType.setVpnGatewaySet(vpnGatewaySet);
ArrayList<VpnGatewayIdSetItemType> item = Lists.newArrayList();
vpnGatewaySet.setItem(item);
VpnGatewayIdSetItemType vpnGatewayIdSetItem = new VpnGatewayIdSetItemType();
item.add(vpnGatewayIdSetItem);
vpnGatewayIdSetItem.setVpnGatewayId(vpnGatewayId);
}
}