Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(s3-deployment): updating memoryLimit or vpc results in stack update failure #17530

Merged
merged 11 commits into from
Nov 23, 2021
Merged

fix(s3-deployment): updating memoryLimit or vpc results in stack update failure #17530

merged 11 commits into from
Nov 23, 2021

Conversation

corymhall
Copy link
Contributor

This fixes the issue where updating the memoryLimit or vpc of the
BucketDeployment resource would result in a stack update failure. In
order to fix this the ID of the BucketDeployment CustomResource includes
info on the memoryLimit and vpc in the same way that the Lambda function
does. This means that when either of these values are updated, the
BucketDeployment CustomResource will be recreated along with the Lambda
function.

If anyone is setting retainOnDelete=false (default is true) then
this change would result in the data in the bucket being deleted. In
order to avoid this scenario, this PR introduces a bucket tag that
controls whether or not a BucketDeployment resource can delete data from
the bucket.

The BucketDeployment resource will now add a tag to the deployment
bucket with a format like aws-cdk:cr-owned:{keyPrefix}:{uniqueHash}.
For example:

{
  Key: 'aws-cdk:cr-owned:deploy/here/:240D17B3',
  Value: 'true',
}

Each bucket+keyPrefix can be "owned" by 1 or more BucketDeployment
resources. Since there are some scenarios where multiple BucketDeployment
resources can deploy to the same bucket and key prefix
(e.g. using include/exclude) we also append part of the id to
make the key unique.

As long as a bucket+keyPrefix is "owned" by a BucketDeployment
resource, another CR cannot delete data. There are a couple of
scenarios where this comes into play.

  1. If the LogicalResourceId of the CustomResource changes
    (e.g. memoryLimit is updated) CloudFormation will first issue a 'Create'
    to create the new CustomResource and will update the Tag on the bucket.
    CloudFormation will then issue a 'Delete' on the old CustomResource
    and since the new CR "owns" the Bucket+keyPrefix (indicated by the
    presence of the tag), the old CR will not delete the contents of the bucket

  2. If the BucketDeployment resource is deleted and it is the only CR
    for that bucket+keyPrefix then CloudFormation will first remove the tag
    from the bucket and then issue a "Delete" to the CR. Since there are no
    tags indicating that this bucket+keyPrefix is "owned" then it will delete
    the contents.

  3. If the BucketDeployment resource is deleted and it is not the only
    CR for that bucket:keyPrefix then CloudFormation will first remove the tag
    from the bucket and then issue a "Delete" to the CR.
    Since there are other CRs that also "own" that bucket+keyPrefix
    (indicated by the presence of tags), there will
    still be a tag on the bucket and the contents will not be removed. The
    contents will only be removed after all BucketDeployment resource that
    "own" the bucket+keyPrefix have been removed.

  4. If the BucketDeployment resource and the S3 Bucket are both removed,
    then CloudFormation will first issue a "Delete" to the CR and since there
    is a tag on the bucket the contents will not be removed. If you want the
    contents of the bucket to be removed on bucket deletion, then
    autoDeleteObjects property should be set to true on the Bucket.

Scenario 3 & 4 are changes to the existing functionality in that they
now do not delete data in some scenarios when they did previously.

fixes #7128


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Nov 16, 2021

@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Nov 16, 2021
@corymhall corymhall requested a review from a team November 16, 2021 21:59
Bucket=bucketName,
)
return any((x["Key"].startswith(tag)) for x in request["TagSet"])
except Exception:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably also log the error to make it easier to investigate issues in the future.

@@ -15,6 +15,8 @@ import { ISource, SourceConfig } from './source';
// eslint-disable-next-line no-duplicate-imports, import/order
import { Construct as CoreConstruct } from '@aws-cdk/core';

// tag value has a limit of 256 characters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is part of the key, which is limited to 128 characters. In any case, how do you enforce this limit, given that the destinationKeyPrefix property doesn't seem to have any length constraint?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I added some validation which will throw an error if the tag key is > 128 characters (destinationKeyPrefix can't be > 104 characters). That is a very long key prefix so I don't think we will ever hit that limit, but I also can't think of a better way of handling this.

…te failure

This fixes the issue where updating the memoryLimit or vpc of the
BucketDeployment resource would result in a stack update failure. In
order to fix this the ID of the BucketDeployment CustomResource includes
info on the memoryLimit and vpc in the same way that the Lambda function
does. This means that when either of these values are updated, the
BucketDeployment CustomResource will be recreated along with the Lambda
function.

If anyone is setting `retainOnDelete=false` (default is `true`) then
this change would result in the data in the bucket being deleted. In
order to avoid this scenario, this PR introduces a bucket tag that
controls whether or not a BucketDeployment resource can delete data from
the bucket.

The BucketDeployment resource will now add a tag to the deployment
bucket with a format like `aws-cdk:cr-owned:{keyPrefix}:{uniqueHash}`.
For example:

{
  Key: 'aws-cdk:cr-owned:deploy/here/:240D17B3',
  Value: 'true',
}

Each bucket+keyPrefix can be "owned" by 1 or more BucketDeployment
resources. Since there are some scenarios where multiple BucketDeployment
resources can deploy to the same bucket and key prefix
(e.g. using include/exclude) we also append part of the id to
make the key unique.

As long as a bucket+keyPrefix is "owned" by a BucketDeployment
resource, another CR cannot delete data. There are a couple of
scenarios where this comes into play.

1. If the LogicalResourceId of the CustomResource changes
(e.g. memoryLimit is updated) CloudFormation will first issue a 'Create'
to create the new CustomResource and will update the Tag on the bucket.
CloudFormation will then issue a 'Delete' on the old CustomResource
and since the new CR "owns" the Bucket+keyPrefix (indicated by the
presence of the tag), the old CR will not delete the contents of the bucket

2. If the BucketDeployment resource is deleted _and_ it is the only CR
for that bucket+keyPrefix then CloudFormation will first remove the tag
from the bucket and then issue a "Delete" to the CR. Since there are no
tags indicating that this bucket+keyPrefix is "owned" then it will delete
the contents.

3. If the BucketDeployment resource is deleted _and_ it is *not* the only
CR for that bucket:keyPrefix then CloudFormation will first remove the tag
from the bucket and then issue a "Delete" to the CR.
Since there are other CRs that also "own" that bucket+keyPrefix
(indicated by the presence of tags), there will
still be a tag on the bucket and the contents will not be removed. The
contents will only be removed after _all_ BucketDeployment resource that
"own" the bucket+keyPrefix have been removed.

4. If the BucketDeployment resource _and_ the S3 Bucket are both removed,
then CloudFormation will first issue a "Delete" to the CR and since there
is a tag on the bucket the contents will not be removed. If you want the
contents of the bucket to be removed on bucket deletion, then
`autoDeleteObjects` property should be set to true on the Bucket.

Scenario 3 & 4 are changes to the existing functionality in that they
now do *not* delete data in some scenarios when they did previously.

fixes #7128

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
@mergify
Copy link
Contributor

mergify bot commented Nov 22, 2021

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

mergify bot and others added 2 commits November 22, 2021 15:34

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
@mergify
Copy link
Contributor

mergify bot commented Nov 23, 2021

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: b761d3b
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify mergify bot merged commit 2ba40d1 into aws:master Nov 23, 2021
@mergify
Copy link
Contributor

mergify bot commented Nov 23, 2021

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

beezly pushed a commit to beezly/aws-cdk that referenced this pull request Nov 29, 2021
…te failure (aws#17530)

This fixes the issue where updating the memoryLimit or vpc of the
BucketDeployment resource would result in a stack update failure. In
order to fix this the ID of the BucketDeployment CustomResource includes
info on the memoryLimit and vpc in the same way that the Lambda function
does. This means that when either of these values are updated, the
BucketDeployment CustomResource will be recreated along with the Lambda
function.

If anyone is setting `retainOnDelete=false` (default is `true`) then
this change would result in the data in the bucket being deleted. In
order to avoid this scenario, this PR introduces a bucket tag that
controls whether or not a BucketDeployment resource can delete data from
the bucket.

The BucketDeployment resource will now add a tag to the deployment
bucket with a format like `aws-cdk:cr-owned:{keyPrefix}:{uniqueHash}`.
For example:

```
{
  Key: 'aws-cdk:cr-owned:deploy/here/:240D17B3',
  Value: 'true',
}
```

Each bucket+keyPrefix can be "owned" by 1 or more BucketDeployment
resources. Since there are some scenarios where multiple BucketDeployment
resources can deploy to the same bucket and key prefix
(e.g. using include/exclude) we also append part of the id to
make the key unique.

As long as a bucket+keyPrefix is "owned" by a BucketDeployment
resource, another CR cannot delete data. There are a couple of
scenarios where this comes into play.

1. If the LogicalResourceId of the CustomResource changes
(e.g. memoryLimit is updated) CloudFormation will first issue a 'Create'
to create the new CustomResource and will update the Tag on the bucket.
CloudFormation will then issue a 'Delete' on the old CustomResource
and since the new CR "owns" the Bucket+keyPrefix (indicated by the
presence of the tag), the old CR will not delete the contents of the bucket

2. If the BucketDeployment resource is deleted _and_ it is the only CR
for that bucket+keyPrefix then CloudFormation will first remove the tag
from the bucket and then issue a "Delete" to the CR. Since there are no
tags indicating that this bucket+keyPrefix is "owned" then it will delete
the contents.

3. If the BucketDeployment resource is deleted _and_ it is *not* the only
CR for that bucket:keyPrefix then CloudFormation will first remove the tag
from the bucket and then issue a "Delete" to the CR.
Since there are other CRs that also "own" that bucket+keyPrefix
(indicated by the presence of tags), there will
still be a tag on the bucket and the contents will not be removed. The
contents will only be removed after _all_ BucketDeployment resource that
"own" the bucket+keyPrefix have been removed.

4. If the BucketDeployment resource _and_ the S3 Bucket are both removed,
then CloudFormation will first issue a "Delete" to the CR and since there
is a tag on the bucket the contents will not be removed. If you want the
contents of the bucket to be removed on bucket deletion, then
`autoDeleteObjects` property should be set to true on the Bucket.

Scenario 3 & 4 are changes to the existing functionality in that they
now do *not* delete data in some scenarios when they did previously.

fixes aws#7128


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
TikiTDO pushed a commit to TikiTDO/aws-cdk that referenced this pull request Feb 21, 2022
…te failure (aws#17530)

This fixes the issue where updating the memoryLimit or vpc of the
BucketDeployment resource would result in a stack update failure. In
order to fix this the ID of the BucketDeployment CustomResource includes
info on the memoryLimit and vpc in the same way that the Lambda function
does. This means that when either of these values are updated, the
BucketDeployment CustomResource will be recreated along with the Lambda
function.

If anyone is setting `retainOnDelete=false` (default is `true`) then
this change would result in the data in the bucket being deleted. In
order to avoid this scenario, this PR introduces a bucket tag that
controls whether or not a BucketDeployment resource can delete data from
the bucket.

The BucketDeployment resource will now add a tag to the deployment
bucket with a format like `aws-cdk:cr-owned:{keyPrefix}:{uniqueHash}`.
For example:

```
{
  Key: 'aws-cdk:cr-owned:deploy/here/:240D17B3',
  Value: 'true',
}
```

Each bucket+keyPrefix can be "owned" by 1 or more BucketDeployment
resources. Since there are some scenarios where multiple BucketDeployment
resources can deploy to the same bucket and key prefix
(e.g. using include/exclude) we also append part of the id to
make the key unique.

As long as a bucket+keyPrefix is "owned" by a BucketDeployment
resource, another CR cannot delete data. There are a couple of
scenarios where this comes into play.

1. If the LogicalResourceId of the CustomResource changes
(e.g. memoryLimit is updated) CloudFormation will first issue a 'Create'
to create the new CustomResource and will update the Tag on the bucket.
CloudFormation will then issue a 'Delete' on the old CustomResource
and since the new CR "owns" the Bucket+keyPrefix (indicated by the
presence of the tag), the old CR will not delete the contents of the bucket

2. If the BucketDeployment resource is deleted _and_ it is the only CR
for that bucket+keyPrefix then CloudFormation will first remove the tag
from the bucket and then issue a "Delete" to the CR. Since there are no
tags indicating that this bucket+keyPrefix is "owned" then it will delete
the contents.

3. If the BucketDeployment resource is deleted _and_ it is *not* the only
CR for that bucket:keyPrefix then CloudFormation will first remove the tag
from the bucket and then issue a "Delete" to the CR.
Since there are other CRs that also "own" that bucket+keyPrefix
(indicated by the presence of tags), there will
still be a tag on the bucket and the contents will not be removed. The
contents will only be removed after _all_ BucketDeployment resource that
"own" the bucket+keyPrefix have been removed.

4. If the BucketDeployment resource _and_ the S3 Bucket are both removed,
then CloudFormation will first issue a "Delete" to the CR and since there
is a tag on the bucket the contents will not be removed. If you want the
contents of the bucket to be removed on bucket deletion, then
`autoDeleteObjects` property should be set to true on the Bucket.

Scenario 3 & 4 are changes to the existing functionality in that they
now do *not* delete data in some scenarios when they did previously.

fixes aws#7128


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-s3-deployment contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Updating a BucketDeployment's memoryLimit causes stack update failure
3 participants