/*
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.classmethod.aws.gradle.cloudformation;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.stream.Collectors;
import org.apache.commons.io.FilenameUtils;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import com.amazonaws.services.cloudformation.model.Parameter;
import com.amazonaws.services.cloudformation.model.Tag;
import jp.classmethod.aws.gradle.AwsPlugin;
import jp.classmethod.aws.gradle.s3.AmazonS3FileUploadTask;
import jp.classmethod.aws.gradle.s3.AmazonS3Plugin;
public class AmazonCloudFormationPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPluginManager().apply(AwsPlugin.class);
project.getPluginManager().apply(AmazonS3Plugin.class);
project.getExtensions().create(AmazonCloudFormationPluginExtension.NAME,
AmazonCloudFormationPluginExtension.class,
project);
applyTasks(project);
}
private void applyTasks(Project project) { // NOPMD
AmazonCloudFormationPluginExtension cfnExt =
project.getExtensions().findByType(AmazonCloudFormationPluginExtension.class);
AmazonS3FileUploadTask awsCfnUploadTemplate =
project.getTasks().create("awsCfnUploadTemplate", AmazonS3FileUploadTask.class, task -> {
task.setDescription("Upload cfn template file to the Amazon S3 bucket.");
task.conventionMapping("file", () -> cfnExt.getTemplateFile());
task.conventionMapping("bucketName", () -> cfnExt.getTemplateBucket());
task.conventionMapping("key", () -> {
String name = cfnExt.getTemplateFile().getName();
return createKey(name, project.getVersion(), cfnExt.getTemplateKeyPrefix());
});
task.doLast(t -> {
cfnExt.setTemplateURL(((AmazonS3FileUploadTask) t).getResourceUrl());
});
});
AmazonS3FileUploadTask awsCfnUploadPolicy =
project.getTasks().create("awsCfnUploadStackPolicy", AmazonS3FileUploadTask.class, task -> {
task.setDescription("Upload cfn stack policy file to the Amazon S3 bucket.");
task.conventionMapping("file", () -> cfnExt.getStackPolicyFile());
task.conventionMapping("bucketName", () -> cfnExt.getStackPolicyBucket());
task.conventionMapping("key", () -> {
String name = cfnExt.getStackPolicyFile().getName();
return createKey(name, project.getVersion(), cfnExt.getStackPolicyKeyPrefix());
});
task.doLast(t -> {
cfnExt.setStackPolicyURL(((AmazonS3FileUploadTask) t).getResourceUrl());
});
});
AmazonCloudFormationMigrateStackTask awsCfnMigrateStack = project.getTasks()
.create("awsCfnMigrateStack", AmazonCloudFormationMigrateStackTask.class, task -> {
task.setDescription("Create/Migrate cfn stack.");
task.mustRunAfter(awsCfnUploadTemplate);
task.mustRunAfter(awsCfnUploadPolicy);
task.conventionMapping("stackName", () -> cfnExt.getStackName());
task.conventionMapping("capabilityIam", () -> cfnExt.isCapabilityIam());
task.conventionMapping("useCapabilityIam", () -> cfnExt.getUseCapabilityIam());
task.conventionMapping("cfnStackParams", () -> cfnExt.getStackParams().entrySet().stream()
.map(it -> new Parameter()
.withParameterKey(it.getKey().toString())
.withParameterValue(it.getValue().toString()))
.collect(Collectors.toList()));
task.conventionMapping("cfnStackTags", () -> cfnExt.getStackTags().entrySet().stream()
.map(it -> new Tag()
.withKey(it.getKey().toString())
.withValue(it.getValue().toString()))
.collect(Collectors.toList()));
task.conventionMapping("cfnTemplateUrl", () -> cfnExt.getTemplateURL());
task.conventionMapping("cfnTemplateFile", () -> cfnExt.getTemplateFile());
task.conventionMapping("cfnStackPolicyUrl", () -> cfnExt.getStackPolicyURL());
task.conventionMapping("cfnStackPolicyFile", () -> cfnExt.getStackPolicyFile());
task.conventionMapping("cfnOnFailure", () -> cfnExt.getOnFailure());
});
project.getTasks()
.create("awsCfnValidateTemplateUrl", AmazonCloudFormationValidateTemplateUrlTask.class,
task -> {
task.setDescription("Validate template URL.");
task.conventionMapping("cfnTemplateUrl", () -> cfnExt.getTemplateURL());
task.dependsOn(awsCfnUploadTemplate);
});
project.getTasks()
.create("awsCfnCreateChangeSet", AmazonCloudFormationCreateChangeSetTask.class, task -> {
task.setDescription("Create cfn change set.");
task.mustRunAfter(awsCfnUploadTemplate);
task.conventionMapping("stackName", () -> cfnExt.getStackName());
task.conventionMapping("capabilityIam", () -> cfnExt.isCapabilityIam());
task.conventionMapping("useCapabilityIam", () -> cfnExt.getUseCapabilityIam());
task.conventionMapping("cfnStackParams", () -> cfnExt.getStackParams().entrySet().stream()
.map(it -> new Parameter()
.withParameterKey(it.getKey().toString())
.withParameterValue(it.getValue().toString()))
.collect(Collectors.toList()));
task.conventionMapping("cfnStackTags", () -> cfnExt.getStackTags().entrySet().stream()
.map(it -> new Tag()
.withKey(it.getKey().toString())
.withValue(it.getValue().toString()))
.collect(Collectors.toList()));
task.conventionMapping("cfnTemplateUrl", () -> cfnExt.getTemplateURL());
task.conventionMapping("cfnTemplateFile", () -> cfnExt.getTemplateFile());
});
project.getTasks()
.create("awsCfnExecuteChangeSet", AmazonCloudFormationExecuteChangeSetTask.class, task -> {
task.setDescription("execute latest cfn change set.");
task.conventionMapping("stackName", () -> cfnExt.getStackName());
});
project.getTasks().create("awsCfnWaitStackReady", AmazonCloudFormationWaitStackStatusTask.class, task -> {
task.setDescription("Wait cfn stack for *_COMPLETE status.");
task.mustRunAfter(awsCfnMigrateStack);
task.conventionMapping("stackName", () -> cfnExt.getStackName());
});
AmazonCloudFormationWaitStackStatusTask awsCfnWaitStackComplete =
project.getTasks().create("awsCfnWaitStackComplete", AmazonCloudFormationWaitStackStatusTask.class,
task -> {
task.setDescription("Wait cfn stack for CREATE_COMPLETE or UPDATE_COMPLETE status.");
task.mustRunAfter(awsCfnMigrateStack);
task.setSuccessStatuses(Arrays.asList("CREATE_COMPLETE", "UPDATE_COMPLETE"));
task.conventionMapping("stackName", () -> cfnExt.getStackName());
});
project.getTasks().create("awsCfnMigrateStackAndWaitCompleted")
.dependsOn(awsCfnMigrateStack, awsCfnWaitStackComplete)
.setDescription("Create/Migrate cfn stack, and wait stack for CREATE_COMPLETE or UPDATE_COMPLETE status.");
AmazonCloudFormationDeleteStackTask awsCfnDeleteStack =
project.getTasks().create("awsCfnDeleteStack", AmazonCloudFormationDeleteStackTask.class, task -> {
task.setDescription("Delete cfn stack.");
task.conventionMapping("stackName", () -> cfnExt.getStackName());
});
AmazonCloudFormationWaitStackStatusTask awsCfnWaitStackDeleted =
project.getTasks().create("awsCfnWaitStackDeleted", AmazonCloudFormationWaitStackStatusTask.class,
task -> {
task.setDescription("Wait cfn stack for DELETE_COMPLETE status.");
task.mustRunAfter(awsCfnDeleteStack);
task.setSuccessStatuses(Arrays.asList("DELETE_COMPLETE"));
task.conventionMapping("stackName", () -> cfnExt.getStackName());
});
project.getTasks().create("awsCfnDeleteStackAndWaitCompleted")
.dependsOn(awsCfnDeleteStack, awsCfnWaitStackDeleted)
.setDescription("Delete cfn stack, and wait stack for DELETE_COMPLETE status.");
}
private String createKey(String name, Object version, String prefix) {
String path = name.substring(FilenameUtils.getPrefix(name).length());
String baseName = FilenameUtils.getBaseName(name);
String extension = FilenameUtils.getExtension(name);
return String.format(Locale.ENGLISH, "%s/%s/%s-%s-%s%s", new Object[] {
prefix,
path,
baseName,
version,
createTimestamp(),
extension.length() > 0 ? "." + extension : ""
});
}
private String createTimestamp() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'_'HHmmss", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(new Date());
}
}