/*************************************************************************
* 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.amazonaws.services.s3.model.AmazonS3Exception;
import com.eucalyptus.auth.Accounts;
import com.eucalyptus.auth.principal.User;
import com.eucalyptus.auth.tokens.SecurityTokenAWSCredentialsProvider;
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.AWSS3BucketPolicyResourceInfo;
import com.eucalyptus.cloudformation.resources.standard.propertytypes.AWSS3BucketPolicyProperties;
import com.eucalyptus.cloudformation.template.JsonHelper;
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.objectstorage.client.EucaS3Client;
import com.eucalyptus.objectstorage.client.EucaS3ClientFactory;
import com.fasterxml.jackson.databind.node.TextNode;
import javax.annotation.Nullable;
import java.util.Objects;
/**
* Created by ethomas on 2/3/14.
*/
public class AWSS3BucketPolicyResourceAction extends StepBasedResourceAction {
private AWSS3BucketPolicyProperties properties = new AWSS3BucketPolicyProperties();
private AWSS3BucketPolicyResourceInfo info = new AWSS3BucketPolicyResourceInfo();
public AWSS3BucketPolicyResourceAction() {
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;
AWSS3BucketPolicyResourceAction otherAction = (AWSS3BucketPolicyResourceAction) resourceAction;
if (!Objects.equals(properties.getBucket(), otherAction.properties.getBucket())) {
// TODO: AWS actually reports the error here as: Bucket property is not updatable .. consider how to do that
updateType = UpdateType.max(updateType, UpdateType.UNSUPPORTED);
}
if (!Objects.equals(properties.getPolicyDocument(), otherAction.properties.getPolicyDocument())) {
updateType = UpdateType.max(updateType, UpdateType.NO_INTERRUPTION);
}
return updateType;
}
private enum CreateSteps implements Step {
SET_POLICY {
@Override
public ResourceAction perform(ResourceAction resourceAction) throws Exception {
AWSS3BucketPolicyResourceAction action = (AWSS3BucketPolicyResourceAction) resourceAction;
User user = Accounts.lookupPrincipalByUserId(action.getResourceInfo().getEffectiveUserId());
try ( final EucaS3Client s3c = EucaS3ClientFactory.getEucaS3Client( new SecurityTokenAWSCredentialsProvider( user ) ) ) {
s3c.setBucketPolicy(action.properties.getBucket(), action.properties.getPolicyDocument().toString());
}
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 {
REMOVE_POLICY {
@Override
public ResourceAction perform(ResourceAction resourceAction) throws Exception {
AWSS3BucketPolicyResourceAction action = (AWSS3BucketPolicyResourceAction) resourceAction;
if (!Boolean.TRUE.equals(action.info.getCreatedEnoughToDelete())) return action;
User user = Accounts.lookupPrincipalByUserId(action.getResourceInfo().getEffectiveUserId());
try ( final EucaS3Client s3c = EucaS3ClientFactory.getEucaS3Client( new SecurityTokenAWSCredentialsProvider( user ) ) ) {
s3c.deleteBucketPolicy(action.properties.getBucket());
} catch (AmazonS3Exception ex) {
if ("NoSuchBucket".equalsIgnoreCase(ex.getErrorCode())) {
// do nothing. (We check existence this way rather than if -> delete due to possible race conditions
} else {
throw ex;
}
}
return action;
}
};
@Nullable
@Override
public Integer getTimeout() {
return null;
}
}
@Override
public ResourceProperties getResourceProperties() {
return properties;
}
@Override
public void setResourceProperties(ResourceProperties resourceProperties) {
properties = (AWSS3BucketPolicyProperties) resourceProperties;
}
@Override
public ResourceInfo getResourceInfo() {
return info;
}
@Override
public void setResourceInfo(ResourceInfo resourceInfo) {
info = (AWSS3BucketPolicyResourceInfo) resourceInfo;
}
private enum UpdateNoInterruptionSteps implements UpdateStep {
UPDATE_POLICY {
@Override
public ResourceAction perform(ResourceAction oldResourceAction, ResourceAction newResourceAction) throws Exception {
AWSS3BucketPolicyResourceAction oldAction = (AWSS3BucketPolicyResourceAction) oldResourceAction;
AWSS3BucketPolicyResourceAction newAction = (AWSS3BucketPolicyResourceAction) newResourceAction;
User user = Accounts.lookupPrincipalByUserId(newAction.getResourceInfo().getEffectiveUserId());
try ( final EucaS3Client s3c = EucaS3ClientFactory.getEucaS3Client( new SecurityTokenAWSCredentialsProvider( user ) ) ) {
s3c.setBucketPolicy(newAction.properties.getBucket(), newAction.properties.getPolicyDocument().toString());
}
return newAction;
}
@Nullable
@Override
public Integer getTimeout() {
return null;
}
}
}
}