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: Adopt new logicalId override logic across the constructs #400

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions src/constructs/autoscaling/asg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { ApplicationProtocol } from "@aws-cdk/aws-elasticloadbalancingv2";
import { Stack } from "@aws-cdk/core";
import { Stage } from "../../constants";
import { TrackingTag } from "../../constants/library-info";
import type { SynthedStack } from "../../utils/test";
import { alphabeticalTags, simpleGuStackForTesting } from "../../utils/test";
import type { Resource, SynthedStack } from "../../utils/test";
import { alphabeticalTags, findResourceByTypeAndLogicalId, simpleGuStackForTesting } from "../../utils/test";
import { GuSecurityGroup } from "../ec2";
import { GuApplicationTargetGroup } from "../loadbalancing";
import type { GuAutoScalingGroupProps } from "./asg";
Expand Down Expand Up @@ -139,12 +139,12 @@ describe("The GuAutoScalingGroup", () => {
});

test("adds any target groups passed through props", () => {
const stack = simpleGuStackForTesting();
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });

const targetGroup = new GuApplicationTargetGroup(stack, "TargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
overrideId: true,
existingLogicalId: "MyTargetGroup",
});

new GuAutoScalingGroup(stack, "AutoscalingGroup", {
Expand All @@ -155,7 +155,7 @@ describe("The GuAutoScalingGroup", () => {
expect(stack).toHaveResource("AWS::AutoScaling::AutoScalingGroup", {
TargetGroupARNs: [
{
Ref: "TargetGroup",
Ref: "MyTargetGroup",
},
],
});
Expand All @@ -165,9 +165,9 @@ describe("The GuAutoScalingGroup", () => {
const app = "Testing";
const stack = simpleGuStackForTesting();

const securityGroup = new GuSecurityGroup(stack, "SecurityGroup", { vpc, overrideId: true, app });
const securityGroup1 = new GuSecurityGroup(stack, "SecurityGroup1", { vpc, overrideId: true, app });
const securityGroup2 = new GuSecurityGroup(stack, "SecurityGroup2", { vpc, overrideId: true, app });
const securityGroup = new GuSecurityGroup(stack, "SecurityGroup", { vpc, app });
const securityGroup1 = new GuSecurityGroup(stack, "SecurityGroup1", { vpc, app });
const securityGroup2 = new GuSecurityGroup(stack, "SecurityGroup2", { vpc, app });

new GuAutoScalingGroup(stack, "AutoscalingGroup", {
...defaultProps,
Expand All @@ -180,33 +180,41 @@ describe("The GuAutoScalingGroup", () => {
"Fn::GetAtt": [`GuHttpsEgressSecurityGroup${app}89CDDA4B`, "GroupId"],
},
{
"Fn::GetAtt": [`SecurityGroup${app}`, "GroupId"],
"Fn::GetAtt": [`SecurityGroup${app}A32D34F9`, "GroupId"],
},
{
"Fn::GetAtt": [`SecurityGroup1${app}`, "GroupId"],
"Fn::GetAtt": [`SecurityGroup1${app}CA3A17A4`, "GroupId"],
},
{
"Fn::GetAtt": [`SecurityGroup2${app}`, "GroupId"],
"Fn::GetAtt": [`SecurityGroup2${app}6436C75B`, "GroupId"],
},
],
});
});

test("does not include the UpdatePolicy property", () => {
const stack = simpleGuStackForTesting();
new GuAutoScalingGroup(stack, "AutoscalingGroup", { ...defaultProps, overrideId: true });
new GuAutoScalingGroup(stack, "AutoscalingGroup", { ...defaultProps });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources.AutoscalingGroup)).not.toContain("UpdatePolicy");
});
expect(stack).toHaveResourceOfTypeAndLogicalId("AWS::AutoScaling::AutoScalingGroup", /AutoscalingGroup.+/);

test("overrides the id with the overrideId prop set to true", () => {
const stack = simpleGuStackForTesting();
new GuAutoScalingGroup(stack, "AutoscalingGroup", { ...defaultProps, overrideId: true });
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- the `toHaveResourceOfTypeAndLogicalId` line above confirms `asgResource` will not be `undefined`
const asgResource: Resource = findResourceByTypeAndLogicalId(
stack,
"AWS::AutoScaling::AutoScalingGroup",
/AutoscalingGroup.+/
)!;

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
// This is checking the properties of the ASG resource
// TODO improve the syntax
expect(Object.keys(Object.values(asgResource)[0])).not.toContain("UpdatePolicy");
Copy link
Member Author

Choose a reason for hiding this comment

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

😷 sorry!

});

test("overrides the logicalId when existingLogicalId is set in a migrating stack", () => {
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });
new GuAutoScalingGroup(stack, "AutoscalingGroup", { ...defaultProps, existingLogicalId: "MyASG" });

expect(Object.keys(json.Resources)).toContain("AutoscalingGroup");
expect(stack).toHaveResourceOfTypeAndLogicalId("AWS::AutoScaling::AutoScalingGroup", "MyASG");
});

test("does not override the id by default", () => {
Expand Down
16 changes: 10 additions & 6 deletions src/constructs/autoscaling/asg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { Stage } from "../../constants";
import type { GuStack } from "../core";
import { GuAmiParameter, GuInstanceTypeParameter } from "../core";
import { AppIdentity } from "../core/identity";
import { GuMigratingResource } from "../core/migrating";
import type { GuStatefulConstruct } from "../core/migrating";
import { GuHttpsEgressSecurityGroup } from "../ec2";

// Since we want to override the types of what gets passed in for the below props,
Expand All @@ -25,15 +27,15 @@ export interface GuAutoScalingGroupProps
| "desiredCapacity"
| "securityGroup"
>,
AppIdentity {
AppIdentity,
GuMigratingResource {
stageDependentProps: GuStageDependentAsgProps;
instanceType?: InstanceType;
imageId?: GuAmiParameter;
machineImage?: MachineImage;
userData: UserData | string;
additionalSecurityGroups?: ISecurityGroup[];
targetGroup?: ApplicationTargetGroup;
overrideId?: boolean;
}

type GuStageDependentAsgProps = Record<Stage, GuAsgCapacityProps>;
Expand Down Expand Up @@ -77,7 +79,9 @@ function wireStageDependentProps(stack: GuStack, stageDependentProps: GuStageDep
};
}

export class GuAutoScalingGroup extends AutoScalingGroup {
export class GuAutoScalingGroup extends AutoScalingGroup implements GuStatefulConstruct {
public readonly isStatefulConstruct: true;

constructor(scope: GuStack, id: string, props: GuAutoScalingGroupProps) {
const userData = props.userData instanceof UserData ? props.userData : UserData.custom(props.userData);

Expand All @@ -101,10 +105,11 @@ export class GuAutoScalingGroup extends AutoScalingGroup {

// Do not use the default AWS security group which allows egress on any port.
// Favour HTTPS only egress rules by default.
securityGroup: GuHttpsEgressSecurityGroup.forVpc(scope, props),
securityGroup: GuHttpsEgressSecurityGroup.forVpc(scope, { app: props.app, vpc: props.vpc }),
akash1810 marked this conversation as resolved.
Show resolved Hide resolved
};

super(scope, AppIdentity.suffixText(props, id), mergedProps);
this.isStatefulConstruct = true;

mergedProps.targetGroup && this.attachToApplicationTargetGroup(mergedProps.targetGroup);

Expand All @@ -116,8 +121,7 @@ export class GuAutoScalingGroup extends AutoScalingGroup {
// { UpdatePolicy: { autoScalingScheduledAction: { IgnoreUnmodifiedGroupSizeProperties: true }}
cfnAsg.addDeletionOverride("UpdatePolicy");

if (mergedProps.overrideId) cfnAsg.overrideLogicalId(id);

GuMigratingResource.setLogicalId(this, scope, props);
AppIdentity.taggedConstruct(props, this);
}
}
11 changes: 5 additions & 6 deletions src/constructs/ec2/security-groups/base.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "@aws-cdk/assert/jest";
import "../../../utils/test/jest";
import { SynthUtils } from "@aws-cdk/assert";
import { Peer, Port, Vpc } from "@aws-cdk/aws-ec2";
import { Stack } from "@aws-cdk/core";
Expand All @@ -13,13 +14,11 @@ describe("The GuSecurityGroup class", () => {
publicSubnetIds: [""],
});

it("overrides the id if the prop is set to true", () => {
const stack = simpleGuStackForTesting();

new GuSecurityGroup(stack, "TestSecurityGroup", { vpc, overrideId: true, app: "testing" });
it("overrides the logicalId when existingLogicalId is set in a migrating stack", () => {
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });
new GuSecurityGroup(stack, "TestSecurityGroup", { vpc, existingLogicalId: "TestSG", app: "testing" });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources)).toContain("TestSecurityGroupTesting");
expect(stack).toHaveResourceOfTypeAndLogicalId("AWS::EC2::SecurityGroup", "TestSG");
});

it("does not overrides the id if the prop is set to false", () => {
Expand Down
11 changes: 4 additions & 7 deletions src/constructs/ec2/security-groups/base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { CfnSecurityGroup, IPeer, SecurityGroupProps } from "@aws-cdk/aws-ec2";
import type { IPeer, SecurityGroupProps } from "@aws-cdk/aws-ec2";
import { Peer, Port, SecurityGroup } from "@aws-cdk/aws-ec2";
import type { GuStack } from "../../core";
import { AppIdentity } from "../../core/identity";
import { GuMigratingResource } from "../../core/migrating";

/**
* A way to describe an ingress or egress rule for a security group.
Expand All @@ -28,8 +29,7 @@ export interface SecurityGroupAccessRule {
description: string;
}

export interface GuBaseSecurityGroupProps extends SecurityGroupProps {
overrideId?: boolean;
export interface GuBaseSecurityGroupProps extends SecurityGroupProps, GuMigratingResource {
ingresses?: SecurityGroupAccessRule[];
egresses?: SecurityGroupAccessRule[];
}
Expand All @@ -49,10 +49,7 @@ export interface GuSecurityGroupProps extends GuBaseSecurityGroupProps, AppIdent
export abstract class GuBaseSecurityGroup extends SecurityGroup {
protected constructor(scope: GuStack, id: string, props: GuBaseSecurityGroupProps) {
super(scope, id, props);

if (props.overrideId) {
(this.node.defaultChild as CfnSecurityGroup).overrideLogicalId(id);
}
GuMigratingResource.setLogicalId(this, scope, props);

props.ingresses?.forEach(({ range, port, description }) => {
const connection: Port = typeof port === "number" ? Port.tcp(port) : port;
Expand Down
13 changes: 4 additions & 9 deletions src/constructs/iam/policies/base-policy.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import type { CfnPolicy, PolicyProps } from "@aws-cdk/aws-iam";
import type { PolicyProps } from "@aws-cdk/aws-iam";
import { Effect, Policy, PolicyStatement } from "@aws-cdk/aws-iam";
import type { GuStack } from "../../core";
import { GuMigratingResource } from "../../core/migrating";

export interface GuPolicyProps extends PolicyProps {
overrideId?: boolean;
}
export interface GuPolicyProps extends PolicyProps, GuMigratingResource {}

export type GuNoStatementsPolicyProps = Omit<GuPolicyProps, "statements">;

export abstract class GuPolicy extends Policy {
protected constructor(scope: GuStack, id: string, props: GuPolicyProps) {
super(scope, id, props);

if (props.overrideId) {
const child = this.node.defaultChild as CfnPolicy;
child.overrideLogicalId(id);
}
GuMigratingResource.setLogicalId(this, scope, props);
}
}

Expand Down
Loading