Skip to content

Commit

Permalink
fix: Add multi app support to GuApplicationLoadBalancer
Browse files Browse the repository at this point in the history
Make `GuApplicationLoadBalancer` consistent with other constructs by adding `AppIdentity` to its props and adding a suffix to its logicalId.
  • Loading branch information
akash1810 committed Apr 9, 2021
1 parent 1db9be7 commit 1f52b37
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 36 deletions.
41 changes: 17 additions & 24 deletions src/constructs/loadbalancing/alb/application-listener.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Stack } from "@aws-cdk/core";
import { RegexPattern } from "../../../constants";
import type { SynthedStack } from "../../../utils/test";
import { simpleGuStackForTesting } from "../../../utils/test";
import type { GuStack } from "../../core";
import type { AppIdentity } from "../../core/identity";
import { GuApplicationListener, GuHttpsApplicationListener } from "./application-listener";
import { GuApplicationLoadBalancer } from "./application-load-balancer";
Expand All @@ -20,19 +21,22 @@ const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", {

const app: AppIdentity = { app: "testing" };

const getLoadBalancer = (stack: GuStack): GuApplicationLoadBalancer => {
return new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc, ...app });
};

describe("The GuApplicationListener class", () => {
it("should use the AppIdentity to form its auto-generated logicalId", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "TargetGroup", {
vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
});
Expand All @@ -46,15 +50,14 @@ describe("The GuApplicationListener class", () => {
test("overrides the id if the prop is true", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
overrideId: true,
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
Expand All @@ -67,15 +70,14 @@ describe("The GuApplicationListener class", () => {
test("does not override the id if the prop is false", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
});
Expand All @@ -87,15 +89,14 @@ describe("The GuApplicationListener class", () => {
test("overrides the id if the stack migrated value is true", () => {
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
});
Expand All @@ -107,15 +108,14 @@ describe("The GuApplicationListener class", () => {
test("does not override the id if the stack migrated value is true but the override id value is false", () => {
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
overrideId: false,
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
Expand All @@ -128,15 +128,14 @@ describe("The GuApplicationListener class", () => {
test("sets default props", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
});
Expand All @@ -150,15 +149,14 @@ describe("The GuApplicationListener class", () => {
test("merges default and passed in props", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuApplicationListener(stack, "ApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
defaultAction: ListenerAction.forward([targetGroup]),
certificates: [{ certificateArn: "" }],
port: 80,
Expand All @@ -175,15 +173,14 @@ describe("The GuHttpsApplicationListener class", () => {
it("should use the AppIdentity to form its auto-generated logicalId", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "TargetGroup", {
vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuHttpsApplicationListener(stack, "HttpsApplicationListener", {
...app,
loadBalancer,
loadBalancer: getLoadBalancer(stack),
targetGroup,
});

Expand All @@ -196,14 +193,13 @@ describe("The GuHttpsApplicationListener class", () => {
test("sets default props", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuHttpsApplicationListener(stack, "ApplicationListener", {
loadBalancer,
loadBalancer: getLoadBalancer(stack),
targetGroup,
...app,
});
Expand All @@ -225,14 +221,13 @@ describe("The GuHttpsApplicationListener class", () => {
test("creates certificate prop if no value passed in", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuHttpsApplicationListener(stack, "ApplicationListener", {
loadBalancer,
loadBalancer: getLoadBalancer(stack),
targetGroup,
...app,
});
Expand Down Expand Up @@ -260,7 +255,6 @@ describe("The GuHttpsApplicationListener class", () => {
test("passing in an invalid ACM ARN", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
Expand All @@ -269,7 +263,7 @@ describe("The GuHttpsApplicationListener class", () => {
expect(
() =>
new GuHttpsApplicationListener(stack, "ApplicationListener", {
loadBalancer,
loadBalancer: getLoadBalancer(stack),
targetGroup,
certificate: "test",
...app,
Expand All @@ -280,14 +274,13 @@ describe("The GuHttpsApplicationListener class", () => {
test("does not create certificate prop if a value passed in", () => {
const stack = simpleGuStackForTesting();

const loadBalancer = new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
const targetGroup = new GuApplicationTargetGroup(stack, "GrafanaInternalTargetGroup", {
vpc: vpc,
protocol: ApplicationProtocol.HTTP,
});

new GuHttpsApplicationListener(stack, "ApplicationListener", {
loadBalancer,
loadBalancer: getLoadBalancer(stack),
targetGroup,
certificate: "arn:aws:acm:eu-west-1:000000000000:certificate/123abc-0000-0000-0000-123abc",
...app,
Expand Down
36 changes: 26 additions & 10 deletions src/constructs/loadbalancing/alb/application-load-balancer.test.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,77 @@
import "@aws-cdk/assert/jest";
import "../../../utils/test/jest";
import { SynthUtils } from "@aws-cdk/assert";
import { Vpc } from "@aws-cdk/aws-ec2";
import { Stack } from "@aws-cdk/core";
import type { SynthedStack } from "../../../utils/test";
import { simpleGuStackForTesting } from "../../../utils/test";
import type { AppIdentity } from "../../core/identity";
import { GuApplicationLoadBalancer } from "./application-load-balancer";

const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", {
vpcId: "test",
availabilityZones: [""],
publicSubnetIds: [""],
});

const app: AppIdentity = {
app: "testing",
};

describe("The GuApplicationLoadBalancer class", () => {
const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", {
vpcId: "test",
availabilityZones: [""],
publicSubnetIds: [""],
it("should use the AppIdentity to form its auto-generated logicalId", () => {
const stack = simpleGuStackForTesting();
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc });

expect(stack).toHaveResourceOfTypeAndLogicalId(
"AWS::ElasticLoadBalancingV2::LoadBalancer",
/^ApplicationLoadBalancerTesting.+/
);
});

test("overrides the id with the overrideId prop", () => {
const stack = simpleGuStackForTesting();
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc, overrideId: true });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc, overrideId: true });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources)).toContain("ApplicationLoadBalancer");
});

test("has an auto-generated ID by default", () => {
const stack = simpleGuStackForTesting();
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources)).not.toContain("ApplicationLoadBalancer");
});

test("overrides the id if the stack migrated value is true", () => {
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources)).toContain("ApplicationLoadBalancer");
});

test("does not override the id if the stack migrated value is true but the override id value is false", () => {
const stack = simpleGuStackForTesting({ migratedFromCloudFormation: true });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc, overrideId: false });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc, overrideId: false });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources)).not.toContain("ApplicationLoadBalancer");
});

test("deletes the Type property", () => {
const stack = simpleGuStackForTesting();
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc, overrideId: true });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc, overrideId: true });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;
expect(Object.keys(json.Resources.ApplicationLoadBalancer.Properties)).not.toContain("Type");
});

test("sets the deletion protection value to true by default", () => {
const stack = simpleGuStackForTesting();
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { vpc });
new GuApplicationLoadBalancer(stack, "ApplicationLoadBalancer", { ...app, vpc });

expect(stack).toHaveResource("AWS::ElasticLoadBalancingV2::LoadBalancer", {
LoadBalancerAttributes: [
Expand Down
7 changes: 5 additions & 2 deletions src/constructs/loadbalancing/alb/application-load-balancer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { ApplicationLoadBalancerProps, CfnLoadBalancer } from "@aws-cdk/aws-elasticloadbalancingv2";
import { ApplicationLoadBalancer } from "@aws-cdk/aws-elasticloadbalancingv2";
import type { GuStack } from "../../core";
import { AppIdentity } from "../../core/identity";

interface GuApplicationLoadBalancerProps extends ApplicationLoadBalancerProps {
interface GuApplicationLoadBalancerProps extends ApplicationLoadBalancerProps, AppIdentity {
overrideId?: boolean;
}

export class GuApplicationLoadBalancer extends ApplicationLoadBalancer {
constructor(scope: GuStack, id: string, props: GuApplicationLoadBalancerProps) {
super(scope, id, { deletionProtection: true, ...props });
const { app } = props;

super(scope, AppIdentity.suffixText({ app }, id), { deletionProtection: true, ...props });

const cfnLb = this.node.defaultChild as CfnLoadBalancer;

Expand Down

0 comments on commit 1f52b37

Please sign in to comment.