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
feat(AWS Deploy): Ensure existence of S3 bucket if possible #10317
Conversation
@@ -104,11 +107,6 @@ class AwsDeploy { | |||
'before:deploy:deploy': async () => { | |||
await this.serverless.pluginManager.spawn('aws:common:validate'); | |||
|
|||
const bucketName = this.serverless.service.provider.deploymentBucket; | |||
if (bucketName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is now fully handled in ensureValidBucketExists
// If bucket name is set, it means it's defined as a part of CloudFormation template (custom bucket case was handled by logic above) | ||
if (this.bucketName) { | ||
if (!(await this.checkIfBucketExists(this.bucketName))) { | ||
// It means that bucket was removed manually but is still a part of the CloudFormation stack, we cannot manually fix it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I double checked if we can force CloudFormation deploy with the original template, but as expected, the update is rejected because "nothing changed"
Codecov Report
@@ Coverage Diff @@
## master #10317 +/- ##
==========================================
- Coverage 85.43% 85.38% -0.06%
==========================================
Files 340 340
Lines 13936 13984 +48
==========================================
+ Hits 11906 11940 +34
- Misses 2030 2044 +14
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pgrzesik that looks really great! I have just a few minor suggestions
lib/plugins/aws/deploy/index.js
Outdated
@@ -55,6 +57,7 @@ class AwsDeploy { | |||
deploy: { | |||
lifecycleEvents: [ | |||
'createStack', | |||
'ensureValidBucketExists', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we need a new lifecycle event? Why not just do it at L130, before setBucketName
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started with it in checkForChanges
, but it didn't feel right to have logic that "modifies" something in step called check
, which suggests that we're only doing checking here. But I see a point of not adding extra lifecycle events - what do you think is better here - having a little bit "inconsistent" (mutating) operation as a part of "check" logic or having a separate lifecycle event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently logic that resolves bucketName
and crashes if there's no bucket is in context of checkForChanges
, so I think it's ok to add there recovery logic, which instead of crashing ensures the bucket
I'm also not sure about changing our current lifecycle events set, I'd rather treat it more as part of legacy design that's best if left untouched (and not further explored). To avoid unexpected issues I'd rather introduce new lifecycle events only if there's really hard to go without it. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point - let's treat lifecycle engine as "legacy" and not introduce new hooks unless there's a really good reason for it. I've changed the implementation.
lib/plugins/aws/deploy/index.js
Outdated
@@ -126,6 +124,10 @@ class AwsDeploy { | |||
mainProgress.notice('Retrieving CloudFormation stack', { isMainEvent: true }), | |||
'aws:deploy:deploy:createStack': async () => this.createStack(), | |||
|
|||
'before:aws:deploy:deploy:ensureValidBucketExists': () => | |||
mainProgress.notice('Ensuring that deployment bucket exists', { isMainEvent: true }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we need a new progress event here.
It feels to me as part of Retrieving CloudFormation stack part, and it's pretty fast, so unlikely to be noticeable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure how to capture that properly, but I like your suggestions around progress
👍
const templateBody = _.merge( | ||
JSON.parse(getTemplateResult.TemplateBody), | ||
this.serverless.service.provider.coreCloudFormationTemplate | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_.merge
doesn't feel safe and we overuse it. I'd do:
Object.assign(getTemplateResult.TemplateBody.Resources,
this.serverless.service.provider.coreCloudFormationTemplate.Resources);
// Same for Outputs
Object.assign(..Outputs, ...Outputs);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good 👍
); | ||
const stackName = this.provider.naming.getStackName(); | ||
|
||
// This is situation where the bucket is not defined in the template at all |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I would register another main progress
with title as: Ensure deployment bucket
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good 👍
f1a96db
to
8ac2439
Compare
lib/plugins/aws/deploy/index.js
Outdated
@@ -127,6 +124,7 @@ class AwsDeploy { | |||
'aws:deploy:deploy:createStack': async () => this.createStack(), | |||
|
|||
'aws:deploy:deploy:checkForChanges': async () => { | |||
await this.ensureValidBucketExists(); | |||
await this.setBucketName(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line I believe now can be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is still needed, but potentially could be moved inside ensureValidBucketExists
- after the logic of ensureValidBucketExists
, in scenario where we create a new bucket via CF update, we don't know the bucket name and we have to retrieve it via SDK and that call handles that. What do you think, would it be better to just call it at the end of processing in ensureValidBucketExists
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose to simplify it as:
- Remove
setBucketName()
entirely (I've checked and it's safe against plugins) - In
ensureValidBucketExists
,ensure following logic is run:
if (!this.bucketName) {
this.bucketName = await this.provider.getServerlessDeploymentBucketName();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we cannot remove setBucketName
entirely, because it's also used in rollback
and deployList
logic. as for the proposed syntax, we can definitely do that but adjust the logic in ensureValidBucketExists
a bit more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the additional setBucketName
in checkForChanges
hook and adjusted the implementation of ensureValidBucketExists
- at the end of the function we should unconditionally call that method because we know the bucketName is not set (because we just ran the update for missing bucket in CF template)
8ac2439
to
0b4e5ad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great 👍
Follow up to: #10306
Closes: #3964
On a best-effort basis tries to ensure that S3 bucket for deployment artifact exists. Handles the following scenarios: