Skip to content

Commit

Permalink
feat: env deploy --no-rollback flag (#4168)
Browse files Browse the repository at this point in the history
should help with some debugging.
- https://gitter.im/aws/copilot-cli?at=636cb648473cf96648dbcbb9
- https://gitter.im/aws/copilot-cli?at=636c024ca34b51121122d168

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the Apache 2.0 License.
  • Loading branch information
dannyrandall authored Nov 16, 2022
1 parent e7fadd1 commit 5781c53
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
10 changes: 9 additions & 1 deletion internal/pkg/cli/deploy/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

awscfn "github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/copilot-cli/internal/pkg/aws/cloudformation"
awscloudformation "github.com/aws/copilot-cli/internal/pkg/aws/cloudformation"
"github.com/aws/copilot-cli/internal/pkg/aws/ec2"
"github.com/aws/copilot-cli/internal/pkg/aws/elbv2"
"github.com/aws/copilot-cli/internal/pkg/aws/partitions"
Expand Down Expand Up @@ -321,6 +322,7 @@ type DeployEnvironmentInput struct {
ForceNewUpdate bool
RawManifest []byte
PermissionsBoundary string
DisableRollback bool
}

// GenerateCloudFormationTemplate returns the environment stack's template and parameter configuration.
Expand Down Expand Up @@ -366,8 +368,14 @@ func (d *envDeployer) DeployEnvironment(in *DeployEnvironmentInput) error {
if err != nil {
return fmt.Errorf("retrieve environment stack force update ID: %w", err)
}
opts := []awscloudformation.StackOption{
awscloudformation.WithRoleARN(d.env.ExecutionRoleARN),
}
if in.DisableRollback {
opts = append(opts, awscloudformation.WithDisableRollback())
}
conf := cfnstack.NewEnvConfigFromExistingStack(stackInput, lastForceUpdateID, oldParams)
return d.envDeployer.UpdateAndRenderEnvironment(conf, stackInput.ArtifactBucketARN, cloudformation.WithRoleARN(d.env.ExecutionRoleARN))
return d.envDeployer.UpdateAndRenderEnvironment(conf, stackInput.ArtifactBucketARN, opts...)
}

func (d *envDeployer) getAppRegionalResources() (*cfnstack.AppRegionalResources, error) {
Expand Down
22 changes: 18 additions & 4 deletions internal/pkg/cli/deploy/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,10 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) {
Name: mockAppName,
}
testCases := map[string]struct {
setUpMocks func(m *envDeployerMocks)
inManifest *manifest.Environment
wantedError error
setUpMocks func(m *envDeployerMocks)
inManifest *manifest.Environment
inDisableRollback bool
wantedError error
}{
"fail to get app resources by region": {
setUpMocks: func(m *envDeployerMocks) {
Expand Down Expand Up @@ -360,6 +361,18 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) {
m.envDeployer.EXPECT().UpdateAndRenderEnvironment(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
},
},
"successful environment deployment, no rollback": {
inDisableRollback: true,
setUpMocks: func(m *envDeployerMocks) {
m.appCFN.EXPECT().GetAppResourcesByRegion(mockApp, mockEnvRegion).Return(&cfnstack.AppRegionalResources{
S3Bucket: "mockS3Bucket",
}, nil)
m.prefixListGetter.EXPECT().CloudFrontManagedPrefixListID().Return("mockPrefixListID", nil).Times(0)
m.envDeployer.EXPECT().DeployedEnvironmentParameters(gomock.Any(), gomock.Any()).Return(nil, nil)
m.envDeployer.EXPECT().ForceUpdateOutputID(gomock.Any(), gomock.Any()).Return("", nil)
m.envDeployer.EXPECT().UpdateAndRenderEnvironment(gomock.Any(), gomock.Any(), gomock.Len(2)).Return(nil)
},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
Expand Down Expand Up @@ -388,7 +401,8 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) {
CustomResourcesURLs: map[string]string{
"mockResource": "mockURL",
},
Manifest: tc.inManifest,
Manifest: tc.inManifest,
DisableRollback: tc.inDisableRollback,
}
gotErr := d.DeployEnvironment(mockIn)
if tc.wantedError != nil {
Expand Down
20 changes: 17 additions & 3 deletions internal/pkg/cli/env_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/aws/copilot-cli/internal/pkg/aws/sessions"
"github.com/aws/copilot-cli/internal/pkg/cli/deploy"
"github.com/aws/copilot-cli/internal/pkg/config"
"github.com/aws/copilot-cli/internal/pkg/deploy/cloudformation/stack"
"github.com/aws/copilot-cli/internal/pkg/manifest"
"github.com/aws/copilot-cli/internal/pkg/term/color"
"github.com/aws/copilot-cli/internal/pkg/term/log"
Expand All @@ -27,9 +28,10 @@ import (
)

type deployEnvVars struct {
appName string
name string
forceNewUpdate bool
appName string
name string
forceNewUpdate bool
disableRollback bool
}

type deployEnvOpts struct {
Expand Down Expand Up @@ -147,6 +149,7 @@ func (o *deployEnvOpts) Execute() error {
ForceNewUpdate: o.forceNewUpdate,
RawManifest: rawMft,
PermissionsBoundary: o.targetApp.PermissionsBoundary,
DisableRollback: o.disableRollback,
}); err != nil {
var errEmptyChangeSet *awscfn.ErrChangeSetEmpty
if errors.As(err, &errEmptyChangeSet) {
Expand All @@ -156,6 +159,16 @@ necessary by a service deployment.
In this case, you can run %s to push a modified template, even if there are no immediate changes.
`, color.HighlightCode("copilot env deploy --force"))
}
if o.disableRollback {
stackName := stack.NameForEnv(o.targetApp.Name, o.targetEnv.Name)
rollbackCmd := fmt.Sprintf("aws cloudformation rollback-stack --stack-name %s --role-arn %s", stackName, o.targetEnv.ExecutionRoleARN)
log.Infof(`It seems like you have disabled automatic stack rollback for this deployment.
To debug, you can visit the AWS console to inspect the errors.
After fixing the deployment, you can:
1. Run %s to rollback the deployment.
2. Run %s to make a new deployment.
`, color.HighlightCode(rollbackCmd), color.HighlightCode("copilot env deploy"))
}
return fmt.Errorf("deploy environment %s: %w", o.name, err)
}
Expand Down Expand Up @@ -271,5 +284,6 @@ Deploy an environment named "test".
cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription)
cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", envFlagDescription)
cmd.Flags().BoolVar(&vars.forceNewUpdate, forceFlag, false, forceEnvDeployFlagDescription)
cmd.Flags().BoolVar(&vars.disableRollback, noRollbackFlag, false, noRollbackFlagDescription)
return cmd
}

0 comments on commit 5781c53

Please sign in to comment.