diff --git a/cliparser/cliparser.go b/cliparser/cliparser.go index b974708..c8ccfac 100644 --- a/cliparser/cliparser.go +++ b/cliparser/cliparser.go @@ -32,6 +32,7 @@ var OfflineValidateMode = "validate_offline" var ConfigureMode = "configure" var CreateStackMode = "create-stack" var DestroyStackMode = "delete-stack" +var UpdateStackMode = "update-stack" var MfaMode = "mfa" type CliArguments struct { @@ -88,6 +89,13 @@ func ParseCliArguments(args []string) (cliArguments CliArguments, err error) { deleteStack = app.Command(DestroyStackMode, "Deletes a stack on aws") deleteStackName = deleteStack.Arg("stack", "An AWS stack name.").Required().String() + updateStack = app.Command(UpdateStackMode, "Updates a stack on aws") + updateStackName = updateStack.Arg("stack", "An AWS stack name").String() + updateStackTemplate = updateStack.Arg("template", "A path to the template file.").String() + updateStackImpName = updateStack.Flag("stack", "Sn AWS stack name.").String() + updateStackImpTemplate = updateStack.Flag("template", "A path to the template file.").String() + updateStackCapabilities = updateStack.Flag("capabilities", "Capabilities: CAPABILITY_IAM | CAPABILITY_NAMED_IAM").Enums("CAPABILITY_IAM", "CAPABILITY_NAMED_IAM") + mfaCommand = app.Command(MfaMode, "Create temporary secure credentials with MFA.") ) @@ -133,6 +141,23 @@ func ParseCliArguments(args []string) (cliArguments CliArguments, err error) { case mfaCommand.FullCommand(): cliArguments.Mode = &MfaMode + // update Stack + case updateStack.FullCommand(): + cliArguments.Mode = &UpdateStackMode + cliArguments.Capabilities = updateStackCapabilities + if len(*updateStackImpTemplate) > 0 && len(*updateStackImpName) > 0 { + cliArguments.Stack = updateStackImpName + cliArguments.TemplatePath = updateStackImpTemplate + } else if len(*updateStackName) > 0 && len(*updateStackTemplate) > 0 { + cliArguments.Stack = updateStackName + cliArguments.TemplatePath = updateStackTemplate + } else if len(*updateStackName) > 0 && len(*updateStackImpTemplate) > 0 { + cliArguments.Stack = updateStackName + cliArguments.TemplatePath = updateStackImpTemplate + } else { + err = errors.New("You have to specify stack name and template file, try --help") + return + } } // OTHER FLAGS diff --git a/main.go b/main.go index a9efd01..a1c2c79 100644 --- a/main.go +++ b/main.go @@ -89,4 +89,10 @@ func main() { os.Exit(1) } } + + if *context.CliArguments.Mode == cliparser.UpdateStackMode { + stack.UpdateStack(&context) + os.Exit(0) + } + } diff --git a/stack/stack.go b/stack/stack.go index fd8e52a..2bbd2bf 100644 --- a/stack/stack.go +++ b/stack/stack.go @@ -26,6 +26,21 @@ func createStackInput(context *context.Context, template *string, stackName *str return templateStruct } +// This function gets template and name of stack. It creates "CreateStackInput" structure. +func updateStackInput(context *context.Context, template *string, stackName *string) cloudformation.UpdateStackInput { + rawCapabilities := *context.CliArguments.Capabilities + capabilities := make([]*string, len(rawCapabilities)) + for i, capability := range rawCapabilities { + capabilities[i] = &capability + } + templateStruct := cloudformation.UpdateStackInput{ + TemplateBody: template, + StackName: stackName, + Capabilities: capabilities, + } + return templateStruct +} + // This function reads "StackName" from Stack in CliArguments and file from TemplatePath in CliArguments. It converts these to type string. func getTemplateFromFile(context *context.Context) (string, string) { @@ -70,6 +85,23 @@ func DestroyStack(context *context.Context) { } } +func UpdateStack(context *context.Context) { + template, stackName := getTemplateFromFile(context) + templateStruct := updateStackInput(context, &template, &stackName) + session := mysession.InitializeSession(context) + err := updateStack(templateStruct, session) + if err != nil { + context.Logger.Error(err.Error()) + os.Exit(1) + } +} + +func updateStack(updateStackInput cloudformation.UpdateStackInput, session *session.Session) error { + api := cloudformation.New(session) + _, err := api.UpdateStack(&updateStackInput) + return err +} + // This function gets "StackName" from Stack in CliArguments and creates "DeleteStackInput" structure. func deleteStackInput(context *context.Context) cloudformation.DeleteStackInput { name := *context.CliArguments.Stack