diff --git a/src/constructs/autoscaling/user-data.ts b/src/constructs/autoscaling/user-data.ts index 1a4f706664..1ffcdaa303 100644 --- a/src/constructs/autoscaling/user-data.ts +++ b/src/constructs/autoscaling/user-data.ts @@ -30,7 +30,7 @@ export class GuUserData { private downloadDistributable(scope: GuStack, app: AppIdentity, props: GuDistributableForEc2) { const bucketKey = GuDistributable.getObjectKey(scope, app, props); - const bucket = Bucket.fromBucketAttributes(scope, "DistributionBucket", { + const bucket = Bucket.fromBucketAttributes(scope, `DistributionBucket-${app.app}`, { bucketName: GuDistributionBucketParameter.getInstance(scope).valueAsString, }); diff --git a/src/experimental/riff-raff-yaml-file/deployments/cloudformation.ts b/src/experimental/riff-raff-yaml-file/deployments/cloudformation.ts index 456cbee7d3..e8308e870b 100644 --- a/src/experimental/riff-raff-yaml-file/deployments/cloudformation.ts +++ b/src/experimental/riff-raff-yaml-file/deployments/cloudformation.ts @@ -49,24 +49,32 @@ export function cloudFormationDeployment( export function addAmiParametersToCloudFormationDeployment( cfnDeployment: RiffRaffDeployment, - asg: GuAutoScalingGroup + autoScalingGroups: GuAutoScalingGroup[] ): RiffRaffDeploymentProps { - const { imageRecipe, app, amiParameter } = asg; + const amiParametersToTags = autoScalingGroups.reduce((acc, asg) => { + const { imageRecipe, app, amiParameter } = asg; - if (!imageRecipe) { - throw new Error(`Unable to produce a working riff-raff.yaml file; imageRecipe missing from ASG ${app}`); - } + if (!imageRecipe) { + throw new Error(`Unable to produce a working riff-raff.yaml file; imageRecipe missing from ASG ${app}`); + } - return { - ...cfnDeployment.props, - parameters: { - ...cfnDeployment.props.parameters, - amiParameter: amiParameter.node.id, - amiTags: { + return { + ...acc, + [amiParameter.node.id]: { BuiltBy: "amigo", Recipe: imageRecipe, AmigoStage: "PROD", }, + }; + }, {}); + + return { + ...cfnDeployment.props, + parameters: { + ...cfnDeployment.props.parameters, + + // only add the `amiParametersToTags` property if there are some + ...(autoScalingGroups.length > 0 && { amiParametersToTags }), }, }; } diff --git a/src/experimental/riff-raff-yaml-file/index.test.ts b/src/experimental/riff-raff-yaml-file/index.test.ts index 62b5345931..7e3d3b1e55 100644 --- a/src/experimental/riff-raff-yaml-file/index.test.ts +++ b/src/experimental/riff-raff-yaml-file/index.test.ts @@ -5,7 +5,7 @@ import { Runtime } from "aws-cdk-lib/aws-lambda"; import { AccessScope } from "../../constants"; import type { GuStackProps } from "../../constructs/core"; import { GuStack } from "../../constructs/core"; -import { GuEc2App, GuScheduledLambda } from "../../patterns"; +import { GuEc2App, GuNodeApp, GuPlayApp, GuScheduledLambda } from "../../patterns"; import { RiffRaffYamlFileExperimental } from "./index"; describe("The RiffRaffYamlFileExperimental class", () => { @@ -445,11 +445,11 @@ describe("The RiffRaffYamlFileExperimental class", () => { parameters: templateStagePaths: TEST: test-stack.template.json - amiParameter: AMIMyapp - amiTags: - BuiltBy: amigo - Recipe: arm64-bionic-java11-deploy-infrastructure - AmigoStage: PROD + amiParametersToTags: + AMIMyapp: + BuiltBy: amigo + Recipe: arm64-bionic-java11-deploy-infrastructure + AmigoStage: PROD dependencies: - asg-upload-eu-west-1-test-my-app asg-update-eu-west-1-test-my-app: @@ -563,11 +563,11 @@ describe("The RiffRaffYamlFileExperimental class", () => { templateStagePaths: CODE: test-stack-eu-CODE.template.json PROD: test-stack-eu-PROD.template.json - amiParameter: AMIMyec2app - amiTags: - BuiltBy: amigo - Recipe: arm64-bionic-java11-deploy-infrastructure - AmigoStage: PROD + amiParametersToTags: + AMIMyec2app: + BuiltBy: amigo + Recipe: arm64-bionic-java11-deploy-infrastructure + AmigoStage: PROD dependencies: - lambda-upload-eu-west-1-test-my-lambda-app - asg-upload-eu-west-1-test-my-ec2-app @@ -641,11 +641,11 @@ describe("The RiffRaffYamlFileExperimental class", () => { templateStagePaths: CODE: test-stack-us-CODE.template.json PROD: test-stack-us-PROD.template.json - amiParameter: AMIMyec2app - amiTags: - BuiltBy: amigo - Recipe: arm64-bionic-java11-deploy-infrastructure - AmigoStage: PROD + amiParametersToTags: + AMIMyec2app: + BuiltBy: amigo + Recipe: arm64-bionic-java11-deploy-infrastructure + AmigoStage: PROD dependencies: - lambda-upload-us-east-1-test-my-lambda-app - asg-upload-us-east-1-test-my-ec2-app @@ -683,4 +683,145 @@ describe("The RiffRaffYamlFileExperimental class", () => { " `); }); + + it("Should support multiple ASGs using a variety of AMIs recipes", () => { + const app = new App({ outdir: "/tmp/cdk.out" }); + + class MyApplicationStack extends GuStack { + // eslint-disable-next-line custom-rules/valid-constructors -- unit testing + constructor(app: App, id: string, props: GuStackProps) { + super(app, id, props); + + new GuPlayApp(this, { + app: "my-api", + instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MICRO), + access: { scope: AccessScope.PUBLIC }, + userData: { + distributable: { + fileName: `my-api.deb`, + executionStatement: `dpkg -i /my-api/my-api.deb`, + }, + }, + certificateProps: { + domainName: "api.devx.gutools.co.uk", + }, + monitoringConfiguration: { noMonitoring: true }, + scaling: { + minimumInstances: 1, + }, + imageRecipe: "arm64-bionic-java11-deploy-infrastructure", + }); + + new GuNodeApp(this, { + app: "my-data-collector", + instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MICRO), + access: { scope: AccessScope.PUBLIC }, + userData: { + distributable: { + fileName: `my-data-collector.deb`, + executionStatement: `dpkg -i /my-data-collector/my-data-collector.deb`, + }, + }, + certificateProps: { + domainName: "data-collector.devx.gutools.co.uk", + }, + monitoringConfiguration: { noMonitoring: true }, + scaling: { + minimumInstances: 1, + }, + imageRecipe: "arm64-bionic-node18-deploy-infrastructure", + }); + } + } + + new MyApplicationStack(app, "test-stack", { stack: "test", stage: "CODE", env: { region: "eu-west-1" } }); + + const actual = new RiffRaffYamlFileExperimental(app).toYAML(); + + expect(actual).toMatchInlineSnapshot(` + "allowedStages: + - CODE + deployments: + asg-upload-eu-west-1-test-my-api: + type: autoscaling + actions: + - uploadArtifacts + regions: + - eu-west-1 + stacks: + - test + app: my-api + parameters: + bucketSsmLookup: true + prefixApp: true + contentDirectory: my-api + asg-upload-eu-west-1-test-my-data-collector: + type: autoscaling + actions: + - uploadArtifacts + regions: + - eu-west-1 + stacks: + - test + app: my-data-collector + parameters: + bucketSsmLookup: true + prefixApp: true + contentDirectory: my-data-collector + cfn-eu-west-1-test-my-application-stack: + type: cloud-formation + regions: + - eu-west-1 + stacks: + - test + app: my-application-stack + contentDirectory: /tmp/cdk.out + parameters: + templateStagePaths: + CODE: test-stack.template.json + amiParametersToTags: + AMIMyapi: + BuiltBy: amigo + Recipe: arm64-bionic-java11-deploy-infrastructure + AmigoStage: PROD + AMIMydatacollector: + BuiltBy: amigo + Recipe: arm64-bionic-node18-deploy-infrastructure + AmigoStage: PROD + dependencies: + - asg-upload-eu-west-1-test-my-api + - asg-upload-eu-west-1-test-my-data-collector + asg-update-eu-west-1-test-my-api: + type: autoscaling + actions: + - deploy + regions: + - eu-west-1 + stacks: + - test + app: my-api + parameters: + bucketSsmLookup: true + prefixApp: true + dependencies: + - cfn-eu-west-1-test-my-application-stack + contentDirectory: my-api + asg-update-eu-west-1-test-my-data-collector: + type: autoscaling + actions: + - deploy + regions: + - eu-west-1 + stacks: + - test + app: my-data-collector + parameters: + bucketSsmLookup: true + prefixApp: true + dependencies: + - cfn-eu-west-1-test-my-application-stack + contentDirectory: my-data-collector + " + `); + }); }); diff --git a/src/experimental/riff-raff-yaml-file/index.ts b/src/experimental/riff-raff-yaml-file/index.ts index 06506a1308..2aeda60849 100644 --- a/src/experimental/riff-raff-yaml-file/index.ts +++ b/src/experimental/riff-raff-yaml-file/index.ts @@ -235,9 +235,12 @@ export class RiffRaffYamlFileExperimental { autoscalingGroups.forEach((asg) => { const asgDeployment = autoscalingDeployment(asg, cfnDeployment); deployments.set(asgDeployment.name, asgDeployment.props); - - deployments.set(cfnDeployment.name, addAmiParametersToCloudFormationDeployment(cfnDeployment, asg)); }); + + deployments.set( + cfnDeployment.name, + addAmiParametersToCloudFormationDeployment(cfnDeployment, autoscalingGroups) + ); }); }); });