-
Notifications
You must be signed in to change notification settings - Fork 5
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: add first draft of EC2 App Pattern #399
Conversation
} from "../constructs/loadbalancing"; | ||
|
||
interface GuEc2AppProps extends AppIdentity { | ||
userData: GuUserData | string; |
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.
If the user needs to download private config then we still need to wire up these permissions (for more details on that, see: #312)
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.
}, | ||
role: new GuInstanceRole(scope, { app: props.app }), | ||
healthCheck: HealthCheck.elb({ grace: Duration.minutes(2) }), // should this be defaulted at pattern or construct level? | ||
userData: props.userData instanceof GuUserData ? props.userData.userData : props.userData, |
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.
Might be nicer for userData
in GuAutoScalingGroup
's props to be of type GuUserData | string
.
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 it is already, what would look better here do you think?
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 looks fantastic, great work!
Should we add a test for a single GuStack
with multiple GuEc2App
s too?
fdb284f
to
756cf9b
Compare
I made a change to how the IDs of VPC constructs are declared, as we ran into issues with declaring multiple |
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.
Added a couple of comments, mainly on code reuse.
src/patterns/ec2-app.test.ts
Outdated
{ | ||
Key: "gu:cdk:version", | ||
PropagateAtLaunch: true, | ||
Value: "TEST", | ||
}, |
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.
Better to use the mock here.
This would become:
import { TrackingTag } from "../../constants/library-info";
...
Tags: alphabeticalTags([
TrackingTag,
{ Key: "App", ... },
...
]);
That is, this can be replaced:
{
Key: "gu:cdk:version",
PropagateAtLaunch: true,
Value: "TEST",
},
With:
TrackingTag
Using the constant means we can update the naming of the tag in one place (should we want to).
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.
Good shout. This doesn't currently work due to the missing PropagateAtLaunch
keypair, but I've created a new constant that handles this called TrackingTagWithPropagate
.
src/patterns/ec2-app.ts
Outdated
constructor(scope: GuStack, props: GuEc2AppProps) { | ||
const id = (id: string) => `${props.app}${id}`; | ||
|
||
scope.tags.setTag(id("App"), props.app); |
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.
The AppIdentity.taggedConstruct
helper should be used here for consistency.
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.
Good shout, done.
src/patterns/ec2-app.ts
Outdated
*/ | ||
export class GuEc2App { | ||
constructor(scope: GuStack, props: GuEc2AppProps) { | ||
const id = (id: string) => `${props.app}${id}`; |
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.
AppIdentity.suffixText
in other places that are app aware, can this be reused here for consistency?
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.
Yep, done!
src/patterns/ec2-app.ts
Outdated
|
||
const asg = new GuAutoScalingGroup(scope, id("AutoScalingGroup"), { | ||
vpc, | ||
app: props.app, |
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.
minor: we've destructured app
above, so this can become:
app: props.app, | |
app, |
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.
Good catch, done.
src/patterns/ec2-app.ts
Outdated
*/ | ||
export class GuPlayApp extends GuEc2App { | ||
constructor(scope: GuStack, props: GuMaybePortProps) { | ||
super(scope, { ...props, applicationPort: props.applicationPort ?? GuApplicationPorts.Play }); |
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'd favour being strongly opinionated here and say Play always runs on 9000
. That is, don't accept applicationPort
in the props.
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.
Good shout, done.
src/patterns/ec2-app.ts
Outdated
*/ | ||
export class GuNodeApp extends GuEc2App { | ||
constructor(scope: GuStack, props: GuMaybePortProps) { | ||
super(scope, { ...props, applicationPort: props.applicationPort ?? GuApplicationPorts.Node }); |
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.
Similar to above, I'd favour being strongly opinionated here and say Node always runs on 3000. That is, don't accept applicationPort in the props.
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.
Good shout, done.
expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); | ||
}); | ||
|
||
it("can handle multiple EC2 apps in a single stack", function () { |
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.
🎉 lovely!
The commit history on this PR is 👌🏽 . |
b06fcf3
to
7ab36ad
Compare
7ab36ad
to
78cf237
Compare
This should now be ready for review again @akash1810 @jacobwinch ! |
src/constants/library-info.ts
Outdated
@@ -10,3 +10,8 @@ export const TrackingTag = { | |||
Key: "gu:cdk:version", | |||
Value: LibraryInfo.VERSION, | |||
}; | |||
|
|||
export const TrackingTagWithPropagate = { |
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 don't think this is correct, as I'm not sure we want to publicly export this variant as it's specifically for the tests and not for "daily use"? In the past we've done something like this.
I think there's an opportunity to add a custom matcher here (similar to toHaveResourceOfTypeAndLogicalId) as it looks like we want to assert a construct has the identity tags. That is, a "toHaveAnIdentityTaggedResource" matcher that'll take a stack, a resource type string and assert that it's tags contain all the identity keys?
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.
After discussing this via Chat, we decided to go with the simpler option for now, in order to get this merged. We'll look at implementing the custom matcher when everyone is around to work on it together.
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!
👍🏽 to this too.
🎉 This PR is included in version 8.3.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
What does this change?
This PR adds a first attempt at our EC2 App pattern. It's still a work in progress, but we have confirmed that this minimal version of the pattern can be deployed successfully so it feels like a good time to get something merged.
Does this change require changes to existing projects or CDK CLI?
No.
How to test
We've added a basic unit test for this. More unit tests (and proper docs) will be added as the pattern develops.
We've also manually tested deploying a stack with the following code:
This just allows us to serve a static file via
/healthcheck
, so that we can ensure that requests can be served correctly.How can we measure success?
It should be much faster/easier to create a new EC2 app from scratch using this pattern.
Have we considered potential risks?
Although this pattern is now functional, we don't want 'real' users to start experimenting with it at this stage. To mitigate against this: