Skip to content
This repository has been archived by the owner on Oct 9, 2020. It is now read-only.

Commit

Permalink
up can update an existing stack using CloudFormation Changeset
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof committed Jul 16, 2020
1 parent 2afe344 commit 6629d8e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 13 deletions.
29 changes: 19 additions & 10 deletions pkg/amazon/backend/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ func (b *Backend) Up(ctx context.Context, options cli.ProjectOptions) error {
return err
}

update, err := b.api.StackExists(ctx, project.Name)
if err != nil {
return err
}
if update {
return fmt.Errorf("we do not (yet) support updating an existing CloudFormation stack")
}

template, err := b.Convert(project)
if err != nil {
return err
Expand Down Expand Up @@ -62,17 +54,34 @@ func (b *Backend) Up(ctx context.Context, options cli.ProjectOptions) error {
ParameterLoadBalancerARN: lb,
}

err = b.api.CreateStack(ctx, project.Name, template, parameters)
update, err := b.api.StackExists(ctx, project.Name)
if err != nil {
return err
}
operation := compose.StackCreate
if update {
operation = compose.StackUpdate
changeset, err := b.api.CreateChangeSet(ctx, project.Name, template, parameters)
if err != nil {
return err
}
err = b.api.UpdateStack(ctx, changeset)
if err != nil {
return err
}
} else {
err = b.api.CreateStack(ctx, project.Name, template, parameters)
if err != nil {
return err
}
}

fmt.Println()
w := console.NewProgressWriter()
for k := range template.Resources {
w.ResourceEvent(k, "PENDING", "")
}
return b.WaitStackCompletion(ctx, project.Name, compose.StackCreate, w)
return b.WaitStackCompletion(ctx, project.Name, operation, w)
}

func (b Backend) GetVPC(ctx context.Context, project *types.Project) (string, error) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/amazon/sdk/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type API interface {
GetStackID(ctx context.Context, name string) (string, error)
WaitStackComplete(ctx context.Context, name string, operation int) error
DescribeStackEvents(ctx context.Context, stackID string) ([]*cf.StackEvent, error)
CreateChangeSet(ctx context.Context, name string, template *cloudformation.Template, parameters map[string]string) (string, error)
UpdateStack(ctx context.Context, changeset string) error

DescribeServices(ctx context.Context, cluster string, arns []string) ([]compose.ServiceStatus, error)

Expand Down
59 changes: 56 additions & 3 deletions pkg/amazon/sdk/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,8 @@ func (s sdk) CreateStack(ctx context.Context, name string, template *cf.Template
param := []*cloudformation.Parameter{}
for name, value := range parameters {
param = append(param, &cloudformation.Parameter{
ParameterKey: aws.String(name),
ParameterValue: aws.String(value),
UsePreviousValue: aws.Bool(true),
ParameterKey: aws.String(name),
ParameterValue: aws.String(value),
})
}

Expand All @@ -194,6 +193,60 @@ func (s sdk) CreateStack(ctx context.Context, name string, template *cf.Template
return err
}

func (s sdk) CreateChangeSet(ctx context.Context, name string, template *cf.Template, parameters map[string]string) (string, error) {
logrus.Debug("Create CloudFormation Changeset")
json, err := template.JSON()
if err != nil {
return "", err
}

param := []*cloudformation.Parameter{}
for name := range parameters {
param = append(param, &cloudformation.Parameter{
ParameterKey: aws.String(name),
UsePreviousValue: aws.Bool(true),
})
}

update := fmt.Sprintf("Update%s", time.Now().Format("2006-01-02-15-04-05"))
changeset, err := s.CF.CreateChangeSetWithContext(ctx, &cloudformation.CreateChangeSetInput{
ChangeSetName: aws.String(update),
ChangeSetType: aws.String(cloudformation.ChangeSetTypeUpdate),
StackName: aws.String(name),
TemplateBody: aws.String(string(json)),
Parameters: param,
Capabilities: []*string{
aws.String(cloudformation.CapabilityCapabilityIam),
},
})
if err != nil {
return "", err
}

err = s.CF.WaitUntilChangeSetCreateCompleteWithContext(ctx, &cloudformation.DescribeChangeSetInput{
ChangeSetName: changeset.Id,
})
return *changeset.Id, err
}

func (s sdk) UpdateStack(ctx context.Context, changeset string) error {
desc, err := s.CF.DescribeChangeSetWithContext(ctx, &cloudformation.DescribeChangeSetInput{
ChangeSetName: aws.String(changeset),
})
if err != nil {
return err
}

if strings.HasPrefix(aws.StringValue(desc.StatusReason), "The submitted information didn't contain changes.") {
return nil
}

_, err = s.CF.ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{
ChangeSetName: aws.String(changeset),
})
return err
}

func (s sdk) WaitStackComplete(ctx context.Context, name string, operation int) error {
input := &cloudformation.DescribeStacksInput{
StackName: aws.String(name),
Expand Down
1 change: 1 addition & 0 deletions pkg/compose/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ServiceStatus struct {

const (
StackCreate = iota
StackUpdate
StackDelete
)

Expand Down

0 comments on commit 6629d8e

Please sign in to comment.