Skip to content

Commit

Permalink
Merge pull request #187 from guardian/jl/asg-byo
Browse files Browse the repository at this point in the history
ASG adds instanceType and AMI parameters
  • Loading branch information
Jamie Lynch authored Jan 21, 2021
2 parents 7ffae66 + f31b430 commit dc7c899
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 15 deletions.
29 changes: 23 additions & 6 deletions src/constructs/autoscaling/asg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,45 @@ describe("The GuAutoScalingGroup", () => {
});
const defaultProps: GuAutoScalingGroupProps = {
vpc,
imageId: "123",
instanceType: "t3.macro", // Use a value that doesn't exist to ensure that we haven't matched a default
userData: "user data",
};

test("correctly sets the machine image using props and calling getImage", () => {
test("adds the AMI parameter", () => {
const stack = simpleGuStackForTesting();

new GuAutoScalingGroup(stack, "AutoscalingGroup", { ...defaultProps, osType: 1 });

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;

expect(json.Parameters.AMI).toEqual({
Description: "AMI ID",
Type: "String",
});

expect(stack).toHaveResource("AWS::AutoScaling::LaunchConfiguration", {
ImageId: "123",
ImageId: {
Ref: "AMI",
},
});
});

test("correctly sets instance type using prop", () => {
test("adds the instanceType parameter", () => {
const stack = simpleGuStackForTesting();

new GuAutoScalingGroup(stack, "AutoscalingGroup", defaultProps);

const json = SynthUtils.toCloudFormation(stack) as SynthedStack;

expect(json.Parameters.InstanceType).toEqual({
Type: "String",
Description: "EC2 Instance Type",
Default: "t3.small",
});

expect(stack).toHaveResource("AWS::AutoScaling::LaunchConfiguration", {
InstanceType: "t3.macro",
InstanceType: {
Ref: "InstanceType",
},
});
});

Expand Down
25 changes: 16 additions & 9 deletions src/constructs/autoscaling/asg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import type { ISecurityGroup, MachineImage, MachineImageConfig } from "@aws-cdk/
import { InstanceType, OperatingSystemType, UserData } from "@aws-cdk/aws-ec2";
import type { ApplicationTargetGroup } from "@aws-cdk/aws-elasticloadbalancingv2";
import type { GuStack } from "../core";
import { GuInstanceTypeParameter, GuStringParameter } from "../core";

// Since we want to override the types of what gets passed in for the below props,
// we need to use Omit<T, U> to remove them from the interface this extends
// https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys
export interface GuAutoScalingGroupProps
extends Omit<AutoScalingGroupProps, "imageId" | "osType" | "machineImage" | "instanceType" | "userData"> {
imageId: string;
osType?: OperatingSystemType;
machineImage?: MachineImage;
instanceType: string;
userData: string;
securityGroups?: ISecurityGroup[];
targetGroup?: ApplicationTargetGroup;
Expand All @@ -22,34 +21,42 @@ export interface GuAutoScalingGroupProps

export class GuAutoScalingGroup extends AutoScalingGroup {
constructor(scope: GuStack, id: string, props: GuAutoScalingGroupProps) {
const imageId = new GuStringParameter(scope, "AMI", {
description: "AMI ID",
});

const instanceType = new GuInstanceTypeParameter(scope);

// We need to override getImage() so that we can pass in the AMI as a parameter
// Otherwise, MachineImage.lookup({ name: 'some str' }) would work as long
// as the name is hard-coded
function getImage(): MachineImageConfig {
return {
osType: props.osType ?? OperatingSystemType.LINUX,
userData: UserData.custom(props.userData),
imageId: props.imageId,
imageId: imageId.valueAsString,
};
}

super(scope, id, {
const mergedProps = {
...props,
machineImage: { getImage: getImage },
instanceType: new InstanceType(props.instanceType),
instanceType: new InstanceType(instanceType.valueAsString),
userData: UserData.custom(props.userData),
});
};

super(scope, id, mergedProps);

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

props.securityGroups?.forEach((sg) => this.addSecurityGroup(sg));
mergedProps.securityGroups?.forEach((sg) => this.addSecurityGroup(sg));

const cfnAsg = this.node.defaultChild as CfnAutoScalingGroup;
// A CDK AutoScalingGroup comes with this update policy, whereas the CFN autscaling group
// leaves it to the default value, which is actually false.
// { UpdatePolicy: { autoScalingScheduledAction: { IgnoreUnmodifiedGroupSizeProperties: true }}
cfnAsg.addDeletionOverride("UpdatePolicy");

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

0 comments on commit dc7c899

Please sign in to comment.