diff --git a/awsapi/cloudformation.go b/awsapi/cloudformation.go index c293b7c..4fec2ab 100644 --- a/awsapi/cloudformation.go +++ b/awsapi/cloudformation.go @@ -17,6 +17,7 @@ type CloudFormationAPI interface { CreateChangeSet(input *cloudformation.CreateChangeSetInput) (*cloudformation.CreateChangeSetOutput, error) DescribeChangeSet(input *cloudformation.DescribeChangeSetInput) (*cloudformation.DescribeChangeSetOutput, error) WaitUntilChangeSetCreateComplete(input *cloudformation.DescribeChangeSetInput) error + DeleteChangeSet(input *cloudformation.DeleteChangeSetInput) (*cloudformation.DeleteChangeSetOutput, error) } type AWSCloudFormationAPI struct { @@ -63,3 +64,7 @@ func (cf *AWSCloudFormationAPI) DescribeChangeSet(input *cloudformation.Describe func (cf *AWSCloudFormationAPI) WaitUntilChangeSetCreateComplete(input *cloudformation.DescribeChangeSetInput) error { return cf.api.WaitUntilChangeSetCreateComplete(input) } + +func (cf *AWSCloudFormationAPI) DeleteChangeSet(input *cloudformation.DeleteChangeSetInput) (*cloudformation.DeleteChangeSetOutput, error) { + return cf.api.DeleteChangeSet(input) +} diff --git a/cliparser/cliparser.go b/cliparser/cliparser.go index ff65ae7..3923df4 100644 --- a/cliparser/cliparser.go +++ b/cliparser/cliparser.go @@ -38,6 +38,7 @@ var DestroySinkMode = "destroy-remote-sink" var CreateParametersMode = "create-parameters" var SetStackPolicyMode = "set-stack-policy" var CreateChangeSetMode = "create-change-set" +var DeleteChangeSetMode = "delete-change-set" var LintMode = "lint" var ChangeSetDefaultName string @@ -126,6 +127,10 @@ func ParseCliArguments(args []string) (cliArguments CliArguments, err error) { createChangeSetLintConfiguration = createChangeSet.Flag("lint-configuration", "A path to the configuration file").String() createChangeSetEstimateCost = createChangeSet.Flag("estimate-cost", "Enable cost estimation during validation").Bool() + deleteChangeSet = app.Command(DeleteChangeSetMode, "Deletes a changeSet on aws") + deleteChangeSetStackName = deleteChangeSet.Arg("stack", "An AWS stack Name").Required().String() + deleteChangeSetName = deleteChangeSet.Arg("change-set", "An AWS Change Set name").Required().String() + deleteStack = app.Command(DestroyStackMode, "Deletes a stack on aws") deleteStackName = deleteStack.Arg("stack", "An AWS stack name.").Required().String() @@ -251,6 +256,11 @@ func ParseCliArguments(args []string) (cliArguments CliArguments, err error) { cliArguments.LinterConfiguration = createChangeSetLintConfiguration cliArguments.EstimateCost = createChangeSetEstimateCost + case deleteChangeSet.FullCommand(): + cliArguments.Mode = &DeleteChangeSetMode + cliArguments.Stack = deleteChangeSetStackName + cliArguments.ChangeSet = deleteChangeSetName + // set up remote sink case setupSink.FullCommand(): cliArguments.Mode = &SetupSinkMode diff --git a/main.go b/main.go index 63a2a8a..d785df1 100644 --- a/main.go +++ b/main.go @@ -101,6 +101,11 @@ func main() { } } + if *ctx.CliArguments.Mode == cliparser.DeleteChangeSetMode { + ctx.InitializeAwsAPI() + utilities.CheckErrorCodeAndExit(stack.DeleteChangeSet(&ctx)) + } + if *ctx.CliArguments.Mode == cliparser.UpdateStackMode { ctx.InitializeAwsAPI() if *ctx.CliArguments.SkipValidation || validator.ValidateAndEstimateCost(&ctx) { diff --git a/stack/changeset.go b/stack/changeset.go index 11f762d..d637011 100644 --- a/stack/changeset.go +++ b/stack/changeset.go @@ -21,6 +21,23 @@ func createChangeSetInput(template *string, stackName *string, params []*cloudfo return templateStruct, nil } +func createDeleteChangeSetInput(ctx *context.Context) cloudformation.DeleteChangeSetInput { + return cloudformation.DeleteChangeSetInput{ + ChangeSetName: ctx.CliArguments.ChangeSet, + StackName: ctx.CliArguments.Stack, + } +} +func DeleteChangeSet(ctx *context.Context) (err error) { + templateStruct := createDeleteChangeSetInput(ctx) + _, err = ctx.CloudFormation.DeleteChangeSet(&templateStruct) + if err != nil { + ctx.Logger.Error(err.Error()) + return + } + ctx.Logger.Info("Deletion of Change Set " + *ctx.CliArguments.ChangeSet + " request successful") + return +} + func NewChangeSet(context *context.Context) (err error) { template, stackName, err := getTemplateFromFile(context) if err != nil { @@ -72,23 +89,23 @@ func shouldExecuteChangeSet() bool { return false } -func describeChangeSet(context *context.Context) (err error) { +func describeChangeSet(context *context.Context) error { context.Logger.Info("Waiting for change set creation...") describeChangeSetInput := cloudformation.DescribeChangeSetInput{ ChangeSetName: context.CliArguments.ChangeSet, StackName: context.CliArguments.Stack, } - err = context.CloudFormation.WaitUntilChangeSetCreateComplete(&describeChangeSetInput) + err := context.CloudFormation.WaitUntilChangeSetCreateComplete(&describeChangeSetInput) if err != nil { context.Logger.Error(err.Error()) - return + return err } describeChangeSetOutput, err := context.CloudFormation.DescribeChangeSet(&describeChangeSetInput) if err != nil { context.Logger.Error(err.Error()) - return + return err } _, table := initStackTableWriter() @@ -111,7 +128,7 @@ func describeChangeSet(context *context.Context) (err error) { }) } table.Render() - return + return nil } func initStackTableWriter() (*progress.ParseWriter, *tablewriter.Table) { diff --git a/stack/mocks/mock_aws_api.go b/stack/mocks/mock_aws_api.go index 015f354..6760040 100644 --- a/stack/mocks/mock_aws_api.go +++ b/stack/mocks/mock_aws_api.go @@ -161,3 +161,16 @@ func (m *MockCloudFormationAPI) WaitUntilChangeSetCreateComplete(input *cloudfor func (mr *MockCloudFormationAPIMockRecorder) WaitUntilChangeSetCreateComplete(input interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilChangeSetCreateComplete", reflect.TypeOf((*MockCloudFormationAPI)(nil).WaitUntilChangeSetCreateComplete), input) } + +// DeleteChangeSet mocks base method +func (m *MockCloudFormationAPI) DeleteChangeSet(input *cloudformation.DeleteChangeSetInput) (*cloudformation.DeleteChangeSetOutput, error) { + ret := m.ctrl.Call(m, "DeleteChangeSet", input) + ret0, _ := ret[0].(*cloudformation.DeleteChangeSetOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteChangeSet indicates an expected call of DeleteChangeSet +func (mr *MockCloudFormationAPIMockRecorder) DeleteChangeSet(input interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeSet", reflect.TypeOf((*MockCloudFormationAPI)(nil).DeleteChangeSet), input) +}