@guardian/cdk 50.8.2 → 50.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/lib/constructs/autoscaling/asg.d.ts +1 -0
  2. package/lib/constructs/autoscaling/asg.d.ts.map +1 -1
  3. package/lib/constructs/autoscaling/asg.js +2 -1
  4. package/lib/constructs/autoscaling/asg.js.map +1 -1
  5. package/lib/constructs/lambda/lambda.d.ts +10 -1
  6. package/lib/constructs/lambda/lambda.d.ts.map +1 -1
  7. package/lib/constructs/lambda/lambda.js +6 -0
  8. package/lib/constructs/lambda/lambda.js.map +1 -1
  9. package/lib/experimental/patterns/kinesis-lambda.d.ts.map +1 -1
  10. package/lib/experimental/patterns/kinesis-lambda.js +4 -1
  11. package/lib/experimental/patterns/kinesis-lambda.js.map +1 -1
  12. package/lib/experimental/patterns/sns-lambda.d.ts.map +1 -1
  13. package/lib/experimental/patterns/sns-lambda.js +4 -1
  14. package/lib/experimental/patterns/sns-lambda.js.map +1 -1
  15. package/lib/experimental/riff-raff-yaml-file/index.d.ts.map +1 -1
  16. package/lib/experimental/riff-raff-yaml-file/index.js +4 -1
  17. package/lib/experimental/riff-raff-yaml-file/index.js.map +1 -1
  18. package/lib/patterns/api-lambda.d.ts.map +1 -1
  19. package/lib/patterns/api-lambda.js +4 -1
  20. package/lib/patterns/api-lambda.js.map +1 -1
  21. package/lib/patterns/api-multiple-lambdas.d.ts.map +1 -1
  22. package/lib/patterns/api-multiple-lambdas.js +4 -1
  23. package/lib/patterns/api-multiple-lambdas.js.map +1 -1
  24. package/lib/patterns/ec2-app/base.d.ts +6 -0
  25. package/lib/patterns/ec2-app/base.d.ts.map +1 -1
  26. package/lib/patterns/ec2-app/base.js +2 -1
  27. package/lib/patterns/ec2-app/base.js.map +1 -1
  28. package/lib/patterns/scheduled-lambda.d.ts.map +1 -1
  29. package/lib/patterns/scheduled-lambda.js +4 -2
  30. package/lib/patterns/scheduled-lambda.js.map +1 -1
  31. package/package.json +1 -1
@@ -15,6 +15,7 @@ export interface GuAutoScalingGroupProps extends Omit<AutoScalingGroupProps, "im
15
15
  additionalSecurityGroups?: ISecurityGroup[];
16
16
  targetGroup?: ApplicationTargetGroup;
17
17
  withoutImdsv2?: boolean;
18
+ httpPutResponseHopLimit?: number;
18
19
  }
19
20
  declare const GuAutoScalingGroup_base: {
20
21
  new (...args: any[]): {
@@ -1 +1 @@
1
- {"version":3,"file":"asg.d.ts","sourceRoot":"","sources":["../../../src/constructs/autoscaling/asg.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,qBAAqB,EAAuB,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EAAuC,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAC;AAC5F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQpD,MAAM,WAAW,uBACf,SAAQ,IAAI,CACR,qBAAqB,EACnB,SAAS,GACT,QAAQ,GACR,cAAc,GACd,UAAU,GACV,aAAa,GACb,aAAa,GACb,iBAAiB,GACjB,eAAe,GACf,eAAe,CAClB,EACD,WAAW,EACX,aAAa;IACf,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5C,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;;;;;;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,kBAAmB,SAAQ,uBAAqC;IAC3E,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,YAAY,EAAE,cAAc,CAAC;IAC7C,SAAgB,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;gBAEtC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB;CAoFvE"}
1
+ {"version":3,"file":"asg.d.ts","sourceRoot":"","sources":["../../../src/constructs/autoscaling/asg.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,qBAAqB,EAAuB,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EAAuC,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAC;AAC5F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQpD,MAAM,WAAW,uBACf,SAAQ,IAAI,CACR,qBAAqB,EACnB,SAAS,GACT,QAAQ,GACR,cAAc,GACd,UAAU,GACV,aAAa,GACb,aAAa,GACb,iBAAiB,GACjB,eAAe,GACf,eAAe,CAClB,EACD,WAAW,EACX,aAAa;IACf,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5C,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;;;;;;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,kBAAmB,SAAQ,uBAAqC;IAC3E,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,YAAY,EAAE,cAAc,CAAC;IAC7C,SAAgB,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;gBAEtC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB;CAsFvE"}
@@ -30,7 +30,7 @@ const iam_1 = require("../iam");
30
30
  */
31
31
  class GuAutoScalingGroup extends (0, app_aware_construct_1.GuAppAwareConstruct)(aws_autoscaling_1.AutoScalingGroup) {
32
32
  constructor(scope, id, props) {
33
- const { app, additionalSecurityGroups = [], blockDevices, imageId = new core_1.GuAmiParameter(scope, { app }), imageRecipe, instanceType, minimumInstances, maximumInstances, role = new iam_1.GuInstanceRole(scope, { app }), targetGroup, userData: userDataLike, vpc, withoutImdsv2 = false, } = props;
33
+ const { app, additionalSecurityGroups = [], blockDevices, imageId = new core_1.GuAmiParameter(scope, { app }), imageRecipe, instanceType, minimumInstances, maximumInstances, role = new iam_1.GuInstanceRole(scope, { app }), targetGroup, userData: userDataLike, vpc, withoutImdsv2 = false, httpPutResponseHopLimit, } = props;
34
34
  // Ensure min and max are defined in the same way. Throwing an `Error` when necessary. For example when min is defined via a Mapping, but max is not.
35
35
  if (aws_cdk_lib_1.Token.isUnresolved(minimumInstances) && !aws_cdk_lib_1.Token.isUnresolved(maximumInstances)) {
36
36
  throw new Error("minimumInstances is defined via a Mapping, but maximumInstances is not. Create maximumInstances via a Mapping too.");
@@ -56,6 +56,7 @@ class GuAutoScalingGroup extends (0, app_aware_construct_1.GuAppAwareConstruct)(
56
56
  requireImdsv2: !withoutImdsv2,
57
57
  userData,
58
58
  role,
59
+ httpPutResponseHopLimit,
59
60
  });
60
61
  // Add Wazuh & additional consumer specified Security Groups
61
62
  // Note: Launch templates via CDK allow specifying only one SG, so use connections
@@ -1 +1 @@
1
- {"version":3,"file":"asg.js","sourceRoot":"","sources":["../../../src/constructs/autoscaling/asg.ts"],"names":[],"mappings":"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","sourcesContent":["import { Token } from \"aws-cdk-lib\";\nimport { AutoScalingGroup } from \"aws-cdk-lib/aws-autoscaling\";\nimport type { AutoScalingGroupProps, CfnAutoScalingGroup } from \"aws-cdk-lib/aws-autoscaling\";\nimport { LaunchTemplate, OperatingSystemType, UserData } from \"aws-cdk-lib/aws-ec2\";\nimport type { InstanceType, ISecurityGroup, MachineImageConfig } from \"aws-cdk-lib/aws-ec2\";\nimport type { ApplicationTargetGroup } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport type { GuAsgCapacity } from \"../../types\";\nimport type { AmigoProps } from \"../../types/amigo\";\nimport { GuAppAwareConstruct } from \"../../utils/mixin/app-aware-construct\";\nimport { GuAmiParameter } from \"../core\";\nimport type { AppIdentity, GuStack } from \"../core\";\nimport { GuHttpsEgressSecurityGroup, GuWazuhAccess } from \"../ec2\";\nimport { GuInstanceRole } from \"../iam\";\n\n// Since we want to override the types of what gets passed in for the below props,\n// we need to use Omit<T, U> to remove them from the interface this extends\n// https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys\n// TODO avoid prop nesting to improve discoverability. See https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md#flat.\nexport interface GuAutoScalingGroupProps\n extends Omit<\n AutoScalingGroupProps,\n | \"imageId\"\n | \"osType\"\n | \"machineImage\"\n | \"userData\"\n | \"minCapacity\"\n | \"maxCapacity\"\n | \"desiredCapacity\"\n | \"requireImdsv2\"\n | \"securityGroup\"\n >,\n AppIdentity,\n GuAsgCapacity {\n imageId?: GuAmiParameter;\n imageRecipe?: string | AmigoProps;\n instanceType: InstanceType;\n userData: UserData | string;\n additionalSecurityGroups?: ISecurityGroup[];\n targetGroup?: ApplicationTargetGroup;\n withoutImdsv2?: boolean;\n}\n\n/**\n * Construct which creates an Auto Scaling group.\n *\n * By default, all EC2 instances in this group will use [[`GuInstanceRole`]],\n * which provides common permissions (e.g. the ability to download an artifact and write logs to the account's logging Kinesis stream).\n *\n * If additional IAM permissions are required, a custom role can be provided via the `role` prop.\n * You may wish to instantiate [[`GuInstanceRole`]] yourself as a basis for this custom role, as it allows custom permissions\n * to be passed in.\n *\n * All EC2 instances in this group will be automatically associated with two security groups:\n * 1. [[`GuHttpsEgressSecurityGroup`]], which allows outbound traffic over HTTPS.\n * 2. [[`GuWazuhAccess`]], which allows instances to communicate with Wazuh (for security monitoring).\n *\n * If additional ingress or egress rules are required, define custom security groups and pass them in via the\n * `additionalSecurityGroups` prop.\n *\n * All EC2 instances provisioned via this construct will use\n * [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html).\n */\nexport class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) {\n public readonly app: string;\n public readonly amiParameter: GuAmiParameter;\n public readonly imageRecipe?: string | AmigoProps;\n\n constructor(scope: GuStack, id: string, props: GuAutoScalingGroupProps) {\n const {\n app,\n additionalSecurityGroups = [],\n blockDevices,\n imageId = new GuAmiParameter(scope, { app }),\n imageRecipe,\n instanceType,\n minimumInstances,\n maximumInstances,\n role = new GuInstanceRole(scope, { app }),\n targetGroup,\n userData: userDataLike,\n vpc,\n withoutImdsv2 = false,\n } = props;\n\n // Ensure min and max are defined in the same way. Throwing an `Error` when necessary. For example when min is defined via a Mapping, but max is not.\n if (Token.isUnresolved(minimumInstances) && !Token.isUnresolved(maximumInstances)) {\n throw new Error(\n \"minimumInstances is defined via a Mapping, but maximumInstances is not. Create maximumInstances via a Mapping too.\"\n );\n }\n\n const userData = userDataLike instanceof UserData ? userDataLike : UserData.custom(userDataLike);\n\n // Generate an ID unique to this app\n const launchTemplateId = `${scope.stack}-${scope.stage}-${app}`;\n const launchTemplate = new LaunchTemplate(scope, launchTemplateId, {\n blockDevices,\n instanceType,\n machineImage: {\n getImage: (): MachineImageConfig => {\n return {\n osType: OperatingSystemType.LINUX,\n userData,\n imageId: imageId.valueAsString,\n };\n },\n },\n // Do not use the default AWS security group which allows egress on any port.\n // Favour HTTPS only egress rules by default.\n securityGroup: GuHttpsEgressSecurityGroup.forVpc(scope, { app, vpc }),\n requireImdsv2: !withoutImdsv2,\n userData,\n role,\n });\n\n // Add Wazuh & additional consumer specified Security Groups\n // Note: Launch templates via CDK allow specifying only one SG, so use connections\n // https://github.com/aws/aws-cdk/issues/18712\n [GuWazuhAccess.getInstance(scope, vpc), ...additionalSecurityGroups].forEach((sg) =>\n launchTemplate.connections.addSecurityGroup(sg)\n );\n\n const asgProps = {\n ...props,\n launchTemplate,\n maxCapacity: maximumInstances ?? minimumInstances * 2,\n minCapacity: minimumInstances,\n\n // Omit userData, instanceType, blockDevices & role from asgProps\n // As this are specified by the LaunchTemplate and must not be duplicated\n blockDevices: undefined,\n instanceType: undefined,\n role: undefined,\n userData: undefined,\n };\n\n super(scope, id, asgProps);\n\n this.app = app;\n this.amiParameter = imageId;\n this.imageRecipe = imageRecipe;\n\n targetGroup && this.attachToApplicationTargetGroup(targetGroup);\n\n const cfnAsg = this.node.defaultChild as CfnAutoScalingGroup;\n\n // A CDK AutoScalingGroup comes with this update policy, whereas the CFN autscaling group\n // leaves it to the default value, which is actually false.\n // { UpdatePolicy: { autoScalingScheduledAction: { IgnoreUnmodifiedGroupSizeProperties: true }}\n cfnAsg.addDeletionOverride(\"UpdatePolicy\");\n }\n}\n"]}
1
+ {"version":3,"file":"asg.js","sourceRoot":"","sources":["../../../src/constructs/autoscaling/asg.ts"],"names":[],"mappings":";;;AAAA,6CAAoC;AACpC,iEAA+D;AAE/D,iDAAoF;AAKpF,+EAA4E;AAC5E,kCAAyC;AAEzC,gCAAmE;AACnE,gCAAwC;AA+BxC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAa,kBAAmB,SAAQ,IAAA,yCAAmB,EAAC,kCAAgB,CAAC;IAK3E,YAAY,KAAc,EAAE,EAAU,EAAE,KAA8B;QACpE,MAAM,EACJ,GAAG,EACH,wBAAwB,GAAG,EAAE,EAC7B,YAAY,EACZ,OAAO,GAAG,IAAI,qBAAc,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAC5C,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,IAAI,GAAG,IAAI,oBAAc,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EACzC,WAAW,EACX,QAAQ,EAAE,YAAY,EACtB,GAAG,EACH,aAAa,GAAG,KAAK,EACrB,uBAAuB,GACxB,GAAG,KAAK,CAAC;QAEV,qJAAqJ;QACrJ,IAAI,mBAAK,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,mBAAK,CAAC,YAAY,CAAC,gBAAgB,CAAC,EAAE;YACjF,MAAM,IAAI,KAAK,CACb,oHAAoH,CACrH,CAAC;SACH;QAED,MAAM,QAAQ,GAAG,YAAY,YAAY,kBAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,kBAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEjG,oCAAoC;QACpC,MAAM,gBAAgB,GAAG,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC;QAChE,MAAM,cAAc,GAAG,IAAI,wBAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE;YACjE,YAAY;YACZ,YAAY;YACZ,YAAY,EAAE;gBACZ,QAAQ,EAAE,GAAuB,EAAE;oBACjC,OAAO;wBACL,MAAM,EAAE,6BAAmB,CAAC,KAAK;wBACjC,QAAQ;wBACR,OAAO,EAAE,OAAO,CAAC,aAAa;qBAC/B,CAAC;gBACJ,CAAC;aACF;YACD,6EAA6E;YAC7E,6CAA6C;YAC7C,aAAa,EAAE,gCAA0B,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YACrE,aAAa,EAAE,CAAC,aAAa;YAC7B,QAAQ;YACR,IAAI;YACJ,uBAAuB;SACxB,CAAC,CAAC;QAEH,4DAA4D;QAC5D,kFAAkF;QAClF,8CAA8C;QAC9C,CAAC,mBAAa,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,GAAG,wBAAwB,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAClF,cAAc,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAChD,CAAC;QAEF,MAAM,QAAQ,GAAG;YACf,GAAG,KAAK;YACR,cAAc;YACd,WAAW,EAAE,gBAAgB,IAAI,gBAAgB,GAAG,CAAC;YACrD,WAAW,EAAE,gBAAgB;YAE7B,iEAAiE;YACjE,yEAAyE;YACzE,YAAY,EAAE,SAAS;YACvB,YAAY,EAAE,SAAS;YACvB,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,SAAS;SACpB,CAAC;QAEF,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;QAE3B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAE/B,WAAW,IAAI,IAAI,CAAC,8BAA8B,CAAC,WAAW,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,YAAmC,CAAC;QAE7D,yFAAyF;QACzF,2DAA2D;QAC3D,+FAA+F;QAC/F,MAAM,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC;CACF;AA3FD,gDA2FC","sourcesContent":["import { Token } from \"aws-cdk-lib\";\nimport { AutoScalingGroup } from \"aws-cdk-lib/aws-autoscaling\";\nimport type { AutoScalingGroupProps, CfnAutoScalingGroup } from \"aws-cdk-lib/aws-autoscaling\";\nimport { LaunchTemplate, OperatingSystemType, UserData } from \"aws-cdk-lib/aws-ec2\";\nimport type { InstanceType, ISecurityGroup, MachineImageConfig } from \"aws-cdk-lib/aws-ec2\";\nimport type { ApplicationTargetGroup } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport type { GuAsgCapacity } from \"../../types\";\nimport type { AmigoProps } from \"../../types/amigo\";\nimport { GuAppAwareConstruct } from \"../../utils/mixin/app-aware-construct\";\nimport { GuAmiParameter } from \"../core\";\nimport type { AppIdentity, GuStack } from \"../core\";\nimport { GuHttpsEgressSecurityGroup, GuWazuhAccess } from \"../ec2\";\nimport { GuInstanceRole } from \"../iam\";\n\n// Since we want to override the types of what gets passed in for the below props,\n// we need to use Omit<T, U> to remove them from the interface this extends\n// https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys\n// TODO avoid prop nesting to improve discoverability. See https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md#flat.\nexport interface GuAutoScalingGroupProps\n extends Omit<\n AutoScalingGroupProps,\n | \"imageId\"\n | \"osType\"\n | \"machineImage\"\n | \"userData\"\n | \"minCapacity\"\n | \"maxCapacity\"\n | \"desiredCapacity\"\n | \"requireImdsv2\"\n | \"securityGroup\"\n >,\n AppIdentity,\n GuAsgCapacity {\n imageId?: GuAmiParameter;\n imageRecipe?: string | AmigoProps;\n instanceType: InstanceType;\n userData: UserData | string;\n additionalSecurityGroups?: ISecurityGroup[];\n targetGroup?: ApplicationTargetGroup;\n withoutImdsv2?: boolean;\n httpPutResponseHopLimit?: number;\n}\n\n/**\n * Construct which creates an Auto Scaling group.\n *\n * By default, all EC2 instances in this group will use [[`GuInstanceRole`]],\n * which provides common permissions (e.g. the ability to download an artifact and write logs to the account's logging Kinesis stream).\n *\n * If additional IAM permissions are required, a custom role can be provided via the `role` prop.\n * You may wish to instantiate [[`GuInstanceRole`]] yourself as a basis for this custom role, as it allows custom permissions\n * to be passed in.\n *\n * All EC2 instances in this group will be automatically associated with two security groups:\n * 1. [[`GuHttpsEgressSecurityGroup`]], which allows outbound traffic over HTTPS.\n * 2. [[`GuWazuhAccess`]], which allows instances to communicate with Wazuh (for security monitoring).\n *\n * If additional ingress or egress rules are required, define custom security groups and pass them in via the\n * `additionalSecurityGroups` prop.\n *\n * All EC2 instances provisioned via this construct will use\n * [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html).\n */\nexport class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) {\n public readonly app: string;\n public readonly amiParameter: GuAmiParameter;\n public readonly imageRecipe?: string | AmigoProps;\n\n constructor(scope: GuStack, id: string, props: GuAutoScalingGroupProps) {\n const {\n app,\n additionalSecurityGroups = [],\n blockDevices,\n imageId = new GuAmiParameter(scope, { app }),\n imageRecipe,\n instanceType,\n minimumInstances,\n maximumInstances,\n role = new GuInstanceRole(scope, { app }),\n targetGroup,\n userData: userDataLike,\n vpc,\n withoutImdsv2 = false,\n httpPutResponseHopLimit,\n } = props;\n\n // Ensure min and max are defined in the same way. Throwing an `Error` when necessary. For example when min is defined via a Mapping, but max is not.\n if (Token.isUnresolved(minimumInstances) && !Token.isUnresolved(maximumInstances)) {\n throw new Error(\n \"minimumInstances is defined via a Mapping, but maximumInstances is not. Create maximumInstances via a Mapping too.\"\n );\n }\n\n const userData = userDataLike instanceof UserData ? userDataLike : UserData.custom(userDataLike);\n\n // Generate an ID unique to this app\n const launchTemplateId = `${scope.stack}-${scope.stage}-${app}`;\n const launchTemplate = new LaunchTemplate(scope, launchTemplateId, {\n blockDevices,\n instanceType,\n machineImage: {\n getImage: (): MachineImageConfig => {\n return {\n osType: OperatingSystemType.LINUX,\n userData,\n imageId: imageId.valueAsString,\n };\n },\n },\n // Do not use the default AWS security group which allows egress on any port.\n // Favour HTTPS only egress rules by default.\n securityGroup: GuHttpsEgressSecurityGroup.forVpc(scope, { app, vpc }),\n requireImdsv2: !withoutImdsv2,\n userData,\n role,\n httpPutResponseHopLimit,\n });\n\n // Add Wazuh & additional consumer specified Security Groups\n // Note: Launch templates via CDK allow specifying only one SG, so use connections\n // https://github.com/aws/aws-cdk/issues/18712\n [GuWazuhAccess.getInstance(scope, vpc), ...additionalSecurityGroups].forEach((sg) =>\n launchTemplate.connections.addSecurityGroup(sg)\n );\n\n const asgProps = {\n ...props,\n launchTemplate,\n maxCapacity: maximumInstances ?? minimumInstances * 2,\n minCapacity: minimumInstances,\n\n // Omit userData, instanceType, blockDevices & role from asgProps\n // As this are specified by the LaunchTemplate and must not be duplicated\n blockDevices: undefined,\n instanceType: undefined,\n role: undefined,\n userData: undefined,\n };\n\n super(scope, id, asgProps);\n\n this.app = app;\n this.amiParameter = imageId;\n this.imageRecipe = imageRecipe;\n\n targetGroup && this.attachToApplicationTargetGroup(targetGroup);\n\n const cfnAsg = this.node.defaultChild as CfnAutoScalingGroup;\n\n // A CDK AutoScalingGroup comes with this update policy, whereas the CFN autscaling group\n // leaves it to the default value, which is actually false.\n // { UpdatePolicy: { autoScalingScheduledAction: { IgnoreUnmodifiedGroupSizeProperties: true }}\n cfnAsg.addDeletionOverride(\"UpdatePolicy\");\n }\n}\n"]}
@@ -1,10 +1,18 @@
1
- import { Function } from "aws-cdk-lib/aws-lambda";
2
1
  import type { FunctionProps } from "aws-cdk-lib/aws-lambda";
2
+ import { Alias, Function } from "aws-cdk-lib/aws-lambda";
3
3
  import { GuDistributable } from "../../types";
4
4
  import type { GuLambdaErrorPercentageMonitoringProps, GuLambdaThrottlingMonitoringProps } from "../cloudwatch";
5
5
  import type { GuStack } from "../core";
6
6
  import { AppIdentity } from "../core";
7
7
  export interface GuFunctionProps extends GuDistributable, Omit<FunctionProps, "code">, AppIdentity {
8
+ /**
9
+ * Create a new Lambda version and alias. This is only necessary if you want to use features which rely
10
+ * on versioning (e.g. SnapStart or Provisioned Concurrency).
11
+ *
12
+ * If you enable versioning you must ensure that your Lambda function is updated whenever a new build is deployed via
13
+ * CloudFormation. The simplest way to do this is to include the build number in the `fileName` prop.
14
+ */
15
+ enableVersioning?: boolean;
8
16
  /**
9
17
  * Alarm if error percentage exceeds a threshold.
10
18
  */
@@ -81,6 +89,7 @@ export declare class GuLambdaFunction extends Function {
81
89
  readonly bucketNamePath: string | undefined;
82
90
  readonly withoutArtifactUpload: boolean;
83
91
  readonly withoutFilePrefix: boolean;
92
+ readonly alias?: Alias;
84
93
  constructor(scope: GuStack, id: string, props: GuFunctionProps);
85
94
  }
86
95
  //# sourceMappingURL=lambda.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lambda.d.ts","sourceRoot":"","sources":["../../../src/constructs/lambda/lambda.ts"],"names":[],"mappings":"AAGA,OAAO,EAAQ,QAAQ,EAAiB,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,wBAAwB,CAAC;AAGrE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,sCAAsC,EAAE,iCAAiC,EAAE,MAAM,eAAe,CAAC;AAC/G,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAiC,MAAM,SAAS,CAAC;AAGrE,MAAM,WAAW,eAAgB,SAAQ,eAAe,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW;IAChG;;OAEG;IACH,yBAAyB,CAAC,EAAE,sCAAsC,CAAC;IACnE;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,iCAAiC,CAAC;IACzD;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,SAAgB,qBAAqB,EAAE,OAAO,CAAC;IAC/C,SAAgB,iBAAiB,EAAE,OAAO,CAAC;gBAE/B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe;CAmE/D"}
1
+ {"version":3,"file":"lambda.d.ts","sourceRoot":"","sources":["../../../src/constructs/lambda/lambda.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,KAAK,EAAQ,QAAQ,EAAiB,MAAM,wBAAwB,CAAC;AAG9E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,sCAAsC,EAAE,iCAAiC,EAAE,MAAM,eAAe,CAAC;AAE/G,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAiC,MAAM,SAAS,CAAC;AAGrE,MAAM,WAAW,eAAgB,SAAQ,eAAe,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW;IAChG;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;OAEG;IACH,yBAAyB,CAAC,EAAE,sCAAsC,CAAC;IACnE;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,iCAAiC,CAAC;IACzD;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,SAAgB,qBAAqB,EAAE,OAAO,CAAC;IAC/C,SAAgB,iBAAiB,EAAE,OAAO,CAAC;IAC3C,SAAgB,KAAK,CAAC,EAAE,KAAK,CAAC;gBAElB,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe;CA0E/D"}
@@ -83,6 +83,12 @@ class GuLambdaFunction extends aws_lambda_1.Function {
83
83
  this.bucketNamePath = bucketNamePath;
84
84
  this.withoutArtifactUpload = withoutArtifactUpload;
85
85
  this.withoutFilePrefix = withoutFilePrefix;
86
+ if (props.enableVersioning) {
87
+ this.alias = new aws_lambda_1.Alias(scope, `${id}-AliasForLambda`, {
88
+ aliasName: scope.stage,
89
+ version: this.currentVersion,
90
+ });
91
+ }
86
92
  if (props.errorPercentageMonitoring) {
87
93
  new cloudwatch_1.GuLambdaErrorPercentageAlarm(scope, `${id}-ErrorPercentageAlarmForLambda`, {
88
94
  ...props.errorPercentageMonitoring,
@@ -1 +1 @@
1
- {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../../src/constructs/lambda/lambda.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint \"@guardian/tsdoc-required/tsdoc-required\": 2 -- to begin rolling this out for public APIs. */\nimport { Duration } from \"aws-cdk-lib\";\nimport type { PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Code, Function, RuntimeFamily } from \"aws-cdk-lib/aws-lambda\";\nimport type { FunctionProps, Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { Bucket } from \"aws-cdk-lib/aws-s3\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { GuDistributable } from \"../../types\";\nimport { GuLambdaErrorPercentageAlarm, GuLambdaThrottlingAlarm } from \"../cloudwatch\";\nimport type { GuLambdaErrorPercentageMonitoringProps, GuLambdaThrottlingMonitoringProps } from \"../cloudwatch\";\nimport type { GuStack } from \"../core\";\nimport { AppIdentity, GuDistributionBucketParameter } from \"../core\";\nimport { ReadParametersByName, ReadParametersByPath } from \"../iam\";\n\nexport interface GuFunctionProps extends GuDistributable, Omit<FunctionProps, \"code\">, AppIdentity {\n /**\n * Alarm if error percentage exceeds a threshold.\n */\n errorPercentageMonitoring?: GuLambdaErrorPercentageMonitoringProps;\n /**\n * Alarm if throttling occurs. Note, it is also worth considering a\n * concurrency limit (the `reservedConcurrentExecutions` prop) if you are\n * concerned about throttling.\n *\n * @see https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html\n */\n throttlingMonitoring?: GuLambdaThrottlingMonitoringProps;\n /**\n * SSM parameter for the S3 bucket that contains your lambda file.\n *\n * Typically you should not override this but you may need to if, for example,\n * you are referencing a file that is shared across many apps and/or AWS\n * accounts.\n *\n * @defaultValue [[`GuDistributionBucketParameter`]]\n */\n bucketNamePath?: string;\n /**\n * Set to `true` to use the filename *without* the stage/stack/app prefix.\n *\n * Typically you should not override this but you may need to if, for example,\n * you are referencing a file that is shared across many apps and/or AWS\n * accounts.\n */\n withoutFilePrefix?: boolean;\n /**\n * Set to `true` this informs consumers of this function that upload is\n * managed elsewhere by DevX.\n *\n * This is used by RiffRaffYamlFileExperimental to skip generating\n * an uploadLambda step.\n */\n withoutArtifactUpload?: boolean;\n}\n\nfunction defaultMemorySize(runtime: Runtime, memorySize?: number): number {\n if (memorySize) {\n return memorySize;\n } else {\n switch (runtime.family) {\n case RuntimeFamily.JAVA:\n return 1024;\n default:\n return 512;\n }\n }\n}\n\n/**\n * Construct which creates a Lambda function.\n *\n * This Lambda relies on the code artifact residing in a standard location in\n * S3. For more details on the bucket used, see\n * [[`GuDistributionBucketParameter`]]. By default, the path used will be\n * `<stack>/<stage>/<app</<fileName>`. If required, e.g. if you are sharing\n * lambda code across apps or accounts, override the source bucket using the\n * `bucketNamePath` prop.\n *\n * The default memory size of this Lambda will vary depending on the runtime\n * chosen. For Java runtimes (i.e. resource hungry Scala Lambdas!), 1024MB will\n * be used. For all other runtimes, the memory size defaults to 512MB. This can\n * be overridden via the `memorySize` prop.\n *\n * By default, the timeout for this Lambda is 30 seconds. This can be overridden\n * via the `timeout` prop.\n *\n * By default the Lambda is granted permission to read from the SSM parameter\n * store subtree specific to this Lambda (i.e. it can read all keys under\n * `/<stage>/<stack>/<app>/`). If you need to add additional permissions, you\n * can use\n * [`addToRolePolicy`](`https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-lambda.FunctionBase.html#addwbrtowbrrolewbrpolicystatement`).\n *\n * The Lambda has `STACK`, `STAGE` and `APP` environment variables which can be\n * used to determine its identity.\n *\n * Note that this construct creates a Lambda without an event source. Depending\n * on your use-case, you may wish to consider using a pattern which instantiates\n * a Lambda with an event source e.g. [[`GuScheduledLambda`]].\n */\nexport class GuLambdaFunction extends Function {\n public readonly app: string;\n public readonly fileName: string;\n public readonly bucketNamePath: string | undefined;\n public readonly withoutArtifactUpload: boolean;\n public readonly withoutFilePrefix: boolean;\n\n constructor(scope: GuStack, id: string, props: GuFunctionProps) {\n const {\n app,\n fileName,\n runtime,\n memorySize,\n timeout,\n bucketNamePath,\n withoutFilePrefix = false,\n withoutArtifactUpload = false,\n } = props;\n\n const bucketName = bucketNamePath\n ? StringParameter.fromStringParameterName(scope, \"bucketoverride\", bucketNamePath).stringValue\n : GuDistributionBucketParameter.getInstance(scope).valueAsString;\n\n const defaultEnvironmentVariables = {\n STACK: scope.stack,\n STAGE: scope.stage,\n APP: app,\n };\n\n const bucket = Bucket.fromBucketName(scope, `${id}-bucket`, bucketName);\n const objectKey = withoutFilePrefix ? fileName : GuDistributable.getObjectKey(scope, { app }, { fileName });\n const code = Code.fromBucket(bucket, objectKey);\n super(scope, id, {\n ...props,\n environment: {\n ...props.environment,\n ...defaultEnvironmentVariables,\n },\n memorySize: defaultMemorySize(runtime, memorySize),\n timeout: timeout ?? Duration.seconds(30),\n code,\n });\n\n this.app = app;\n this.fileName = fileName;\n this.bucketNamePath = bucketNamePath;\n this.withoutArtifactUpload = withoutArtifactUpload;\n this.withoutFilePrefix = withoutFilePrefix;\n\n if (props.errorPercentageMonitoring) {\n new GuLambdaErrorPercentageAlarm(scope, `${id}-ErrorPercentageAlarmForLambda`, {\n ...props.errorPercentageMonitoring,\n lambda: this,\n });\n }\n\n if (props.throttlingMonitoring) {\n new GuLambdaThrottlingAlarm(scope, `${id}-ThrottlingAlarmForLambda`, {\n ...props.throttlingMonitoring,\n lambda: this,\n });\n }\n\n bucket.grantRead(this, objectKey);\n\n const ssmParamReadPolicies: PolicyStatement[] = [\n new ReadParametersByPath(scope, props),\n new ReadParametersByName(scope, props),\n ];\n\n ssmParamReadPolicies.map((policy) => this.addToRolePolicy(policy));\n\n AppIdentity.taggedConstruct(props, this);\n }\n}\n"]}
1
+ {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../../src/constructs/lambda/lambda.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint \"@guardian/tsdoc-required/tsdoc-required\": 2 -- to begin rolling this out for public APIs. */\nimport { Duration } from \"aws-cdk-lib\";\nimport type { PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport type { FunctionProps, Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { Alias, Code, Function, RuntimeFamily } from \"aws-cdk-lib/aws-lambda\";\nimport { Bucket } from \"aws-cdk-lib/aws-s3\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { GuDistributable } from \"../../types\";\nimport type { GuLambdaErrorPercentageMonitoringProps, GuLambdaThrottlingMonitoringProps } from \"../cloudwatch\";\nimport { GuLambdaErrorPercentageAlarm, GuLambdaThrottlingAlarm } from \"../cloudwatch\";\nimport type { GuStack } from \"../core\";\nimport { AppIdentity, GuDistributionBucketParameter } from \"../core\";\nimport { ReadParametersByName, ReadParametersByPath } from \"../iam\";\n\nexport interface GuFunctionProps extends GuDistributable, Omit<FunctionProps, \"code\">, AppIdentity {\n /**\n * Create a new Lambda version and alias. This is only necessary if you want to use features which rely\n * on versioning (e.g. SnapStart or Provisioned Concurrency).\n *\n * If you enable versioning you must ensure that your Lambda function is updated whenever a new build is deployed via\n * CloudFormation. The simplest way to do this is to include the build number in the `fileName` prop.\n */\n enableVersioning?: boolean;\n\n /**\n * Alarm if error percentage exceeds a threshold.\n */\n errorPercentageMonitoring?: GuLambdaErrorPercentageMonitoringProps;\n /**\n * Alarm if throttling occurs. Note, it is also worth considering a\n * concurrency limit (the `reservedConcurrentExecutions` prop) if you are\n * concerned about throttling.\n *\n * @see https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html\n */\n throttlingMonitoring?: GuLambdaThrottlingMonitoringProps;\n /**\n * SSM parameter for the S3 bucket that contains your lambda file.\n *\n * Typically you should not override this but you may need to if, for example,\n * you are referencing a file that is shared across many apps and/or AWS\n * accounts.\n *\n * @defaultValue [[`GuDistributionBucketParameter`]]\n */\n bucketNamePath?: string;\n /**\n * Set to `true` to use the filename *without* the stage/stack/app prefix.\n *\n * Typically you should not override this but you may need to if, for example,\n * you are referencing a file that is shared across many apps and/or AWS\n * accounts.\n */\n withoutFilePrefix?: boolean;\n /**\n * Set to `true` this informs consumers of this function that upload is\n * managed elsewhere by DevX.\n *\n * This is used by RiffRaffYamlFileExperimental to skip generating\n * an uploadLambda step.\n */\n withoutArtifactUpload?: boolean;\n}\n\nfunction defaultMemorySize(runtime: Runtime, memorySize?: number): number {\n if (memorySize) {\n return memorySize;\n } else {\n switch (runtime.family) {\n case RuntimeFamily.JAVA:\n return 1024;\n default:\n return 512;\n }\n }\n}\n\n/**\n * Construct which creates a Lambda function.\n *\n * This Lambda relies on the code artifact residing in a standard location in\n * S3. For more details on the bucket used, see\n * [[`GuDistributionBucketParameter`]]. By default, the path used will be\n * `<stack>/<stage>/<app</<fileName>`. If required, e.g. if you are sharing\n * lambda code across apps or accounts, override the source bucket using the\n * `bucketNamePath` prop.\n *\n * The default memory size of this Lambda will vary depending on the runtime\n * chosen. For Java runtimes (i.e. resource hungry Scala Lambdas!), 1024MB will\n * be used. For all other runtimes, the memory size defaults to 512MB. This can\n * be overridden via the `memorySize` prop.\n *\n * By default, the timeout for this Lambda is 30 seconds. This can be overridden\n * via the `timeout` prop.\n *\n * By default the Lambda is granted permission to read from the SSM parameter\n * store subtree specific to this Lambda (i.e. it can read all keys under\n * `/<stage>/<stack>/<app>/`). If you need to add additional permissions, you\n * can use\n * [`addToRolePolicy`](`https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-lambda.FunctionBase.html#addwbrtowbrrolewbrpolicystatement`).\n *\n * The Lambda has `STACK`, `STAGE` and `APP` environment variables which can be\n * used to determine its identity.\n *\n * Note that this construct creates a Lambda without an event source. Depending\n * on your use-case, you may wish to consider using a pattern which instantiates\n * a Lambda with an event source e.g. [[`GuScheduledLambda`]].\n */\nexport class GuLambdaFunction extends Function {\n public readonly app: string;\n public readonly fileName: string;\n public readonly bucketNamePath: string | undefined;\n public readonly withoutArtifactUpload: boolean;\n public readonly withoutFilePrefix: boolean;\n public readonly alias?: Alias;\n\n constructor(scope: GuStack, id: string, props: GuFunctionProps) {\n const {\n app,\n fileName,\n runtime,\n memorySize,\n timeout,\n bucketNamePath,\n withoutFilePrefix = false,\n withoutArtifactUpload = false,\n } = props;\n\n const bucketName = bucketNamePath\n ? StringParameter.fromStringParameterName(scope, \"bucketoverride\", bucketNamePath).stringValue\n : GuDistributionBucketParameter.getInstance(scope).valueAsString;\n\n const defaultEnvironmentVariables = {\n STACK: scope.stack,\n STAGE: scope.stage,\n APP: app,\n };\n\n const bucket = Bucket.fromBucketName(scope, `${id}-bucket`, bucketName);\n const objectKey = withoutFilePrefix ? fileName : GuDistributable.getObjectKey(scope, { app }, { fileName });\n const code = Code.fromBucket(bucket, objectKey);\n super(scope, id, {\n ...props,\n environment: {\n ...props.environment,\n ...defaultEnvironmentVariables,\n },\n memorySize: defaultMemorySize(runtime, memorySize),\n timeout: timeout ?? Duration.seconds(30),\n code,\n });\n\n this.app = app;\n this.fileName = fileName;\n this.bucketNamePath = bucketNamePath;\n this.withoutArtifactUpload = withoutArtifactUpload;\n this.withoutFilePrefix = withoutFilePrefix;\n\n if (props.enableVersioning) {\n this.alias = new Alias(scope, `${id}-AliasForLambda`, {\n aliasName: scope.stage,\n version: this.currentVersion,\n });\n }\n\n if (props.errorPercentageMonitoring) {\n new GuLambdaErrorPercentageAlarm(scope, `${id}-ErrorPercentageAlarmForLambda`, {\n ...props.errorPercentageMonitoring,\n lambda: this,\n });\n }\n\n if (props.throttlingMonitoring) {\n new GuLambdaThrottlingAlarm(scope, `${id}-ThrottlingAlarmForLambda`, {\n ...props.throttlingMonitoring,\n lambda: this,\n });\n }\n\n bucket.grantRead(this, objectKey);\n\n const ssmParamReadPolicies: PolicyStatement[] = [\n new ReadParametersByPath(scope, props),\n new ReadParametersByName(scope, props),\n ];\n\n ssmParamReadPolicies.map((policy) => this.addToRolePolicy(policy));\n\n AppIdentity.taggedConstruct(props, this);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"kinesis-lambda.d.ts","sourceRoot":"","sources":["../../../src/experimental/patterns/kinesis-lambda.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIpE,OAAO,KAAK,EAAE,sCAAsC,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAExG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAC9F,uBAAuB,EAAE,YAAY,GAAG,sCAAsC,CAAC;IAC/E,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,0BAA0B,EAAE,wBAAwB,CAAC;IACrD,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACjC,eAAe,CAAC,EAAE,qBAAqB,CAAC;CACzC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,2BAA4B,SAAQ,gBAAgB;IAC/D,SAAgB,aAAa,EAAE,OAAO,CAAC;gBAE3B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB;CA6BpE"}
1
+ {"version":3,"file":"kinesis-lambda.d.ts","sourceRoot":"","sources":["../../../src/experimental/patterns/kinesis-lambda.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIpE,OAAO,KAAK,EAAE,sCAAsC,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAExG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAC9F,uBAAuB,EAAE,YAAY,GAAG,sCAAsC,CAAC;IAC/E,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,0BAA0B,EAAE,wBAAwB,CAAC;IACrD,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACjC,eAAe,CAAC,EAAE,qBAAqB,CAAC;CACzC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,2BAA4B,SAAQ,gBAAgB;IAC/D,SAAgB,aAAa,EAAE,OAAO,CAAC;gBAE3B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB;CAiCpE"}
@@ -38,7 +38,10 @@ class GuKinesisLambdaExperimental extends lambda_1.GuLambdaFunction {
38
38
  ...props.processingProps,
39
39
  ...errorHandlingPropsToAwsProps,
40
40
  };
41
- this.addEventSource(new aws_lambda_event_sources_1.KinesisEventSource(this.kinesisStream, eventSourceProps));
41
+ // If we have an alias, use this to ensure that all events are sent to a published Lambda version.
42
+ // Otherwise, send all events to the latest unpublished version ($LATEST)
43
+ const eventSourceTarget = this.alias ?? this;
44
+ eventSourceTarget.addEventSource(new aws_lambda_event_sources_1.KinesisEventSource(this.kinesisStream, eventSourceProps));
42
45
  }
43
46
  }
44
47
  exports.GuKinesisLambdaExperimental = GuKinesisLambdaExperimental;
@@ -1 +1 @@
1
- {"version":3,"file":"kinesis-lambda.js","sourceRoot":"","sources":["../../../src/experimental/patterns/kinesis-lambda.ts"],"names":[],"mappings":";;;AAAA,yDAAmE;AAEnE,uDAA0D;AAC1D,mFAA0E;AAG1E,gDAAoD;AAEpD,sDAA2D;AAC3D,oDAA2D;AAE3D,+CAA6D;AAwD7D;;;;;;;;;;;;GAYG;AACH,MAAa,2BAA4B,SAAQ,yBAAgB;IAG/D,YAAY,KAAc,EAAE,EAAU,EAAE,KAA2B;QACjE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,GAAG,KAAK;YACR,yBAAyB,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,uBAAuB;SAClH,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAClC,MAAM,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC;QAE5D,IAAI,CAAC,aAAa,GAAG,qBAAqB;YACxC,CAAC,CAAC,oBAAM,CAAC,aAAa,CAClB,KAAK,EACL,qBAAqB,CAAC,yBAAyB,EAC/C,mBAAmB,MAAM,IAAI,OAAO,WAAW,qBAAqB,CAAC,yBAAyB,EAAE,CACjG;YACH,CAAC,CAAC,kBAAW,CAAC,eAAe,CACzB,KAAK,EACL,IAAI,yBAAe,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,UAAU,EAAE,8BAAgB,CAAC,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAAC,CAC7G,CAAC;QAEN,MAAM,4BAA4B,GAAG,IAAA,gCAAuB,EAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAE/F,MAAM,gBAAgB,GAA4B;YAChD,gBAAgB,EAAE,6BAAgB,CAAC,MAAM;YACzC,GAAG,KAAK,CAAC,eAAe;YACxB,GAAG,4BAA4B;SAChC,CAAC;QACF,IAAI,CAAC,cAAc,CAAC,IAAI,6CAAkB,CAAC,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACpF,CAAC;CACF;AAhCD,kEAgCC","sourcesContent":["import { Stream, StreamEncryption } from \"aws-cdk-lib/aws-kinesis\";\nimport type { IStream, StreamProps } from \"aws-cdk-lib/aws-kinesis\";\nimport { StartingPosition } from \"aws-cdk-lib/aws-lambda\";\nimport { KinesisEventSource } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport type { KinesisEventSourceProps } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport type { GuLambdaErrorPercentageMonitoringProps, NoMonitoring } from \"../../constructs/cloudwatch\";\nimport { AppIdentity } from \"../../constructs/core\";\nimport type { GuStack } from \"../../constructs/core\";\nimport { GuKinesisStream } from \"../../constructs/kinesis\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport type { GuFunctionProps } from \"../../constructs/lambda\";\nimport { toAwsErrorHandlingProps } from \"../../utils/lambda\";\nimport type { StreamErrorHandlingProps, StreamProcessingProps } from \"../../utils/lambda\";\n\n/**\n * Used to provide information about an existing Kinesis stream to the [[`GuKinesisLambda`]] pattern.\n *\n * Specify an `externalKinesisStreamName` to link the lambda to a Kinesis stream owned by a different stack\n * (or created outside of version control).\n */\nexport interface ExistingKinesisStream {\n externalKinesisStreamName: string;\n}\n\n/**\n * Configuration options for the [[`GuKinesisLambda`]] pattern.\n *\n * For all lambda function configuration options, see [[`GuFunctionProps`]].\n *\n * The `existingKinesisStream` property can be used to reference a Kinesis stream which\n * has been created outside of this pattern (i.e. via CloudFormation, or via a different `cdk` pattern, or stack).\n * For more details see [[`ExistingKinesisStream`]].\n *\n * If you have specific stream configuration requirements (e.g. data retention period), these can be set via\n * `kinesisStreamProps`.\n *\n * If you need to override the default stream processing options (e.g. batch size and parallelization), pass\n * [[`StreamProcessingProps`]] via `processingProps`.\n *\n * You must provide `errorHandlingConfiguration` to this pattern. Retry conditions can be configured\n * via [[`StreamErrorHandlingProps`]].\n *\n * It is advisable to configure an alarm based on the lambda's error percentage.\n * To do this, add the `monitoringConfiguration` property. The required properties for this are:\n *\n * ```typescript\n * monitoringConfiguration: {\n * toleratedErrorPercentage: <sensible_error_percentage_threshold>,\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * }\n * ```\n * Other alarm properties (e.g. alarm name and description) will be pre-populated with sensible defaults.\n * For a full list of optional properties, see [[`GuLambdaErrorPercentageMonitoringProps`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true } as NoMonitoring\n * ```\n */\nexport interface GuKinesisLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n monitoringConfiguration: NoMonitoring | GuLambdaErrorPercentageMonitoringProps;\n existingKinesisStream?: ExistingKinesisStream;\n errorHandlingConfiguration: StreamErrorHandlingProps;\n kinesisStreamProps?: StreamProps;\n processingProps?: StreamProcessingProps;\n}\n\n/**\n * Pattern which creates all of the resources needed to invoke a lambda function whenever a record is\n * put onto a Kinesis stream.\n *\n * This pattern will create a new Kinesis stream by default. If you are migrating a stack from CloudFormation,\n * you will need to opt-out of this behaviour. For information on overriding the default behaviour,\n * see [[`GuKinesisLambdaProps`]].\n *\n * The Kinesis stream is stateful, and is accessible via `kinesisStream`.\n * @see https://github.com/guardian/cdk/blob/main/docs/stateful-resources.md\n *\n * @experimental This pattern is in early development. The API is likely to change in future releases.\n */\nexport class GuKinesisLambdaExperimental extends GuLambdaFunction {\n public readonly kinesisStream: IStream;\n\n constructor(scope: GuStack, id: string, props: GuKinesisLambdaProps) {\n super(scope, id, {\n ...props,\n errorPercentageMonitoring: props.monitoringConfiguration.noMonitoring ? undefined : props.monitoringConfiguration,\n });\n\n const { account, region } = scope;\n const { existingKinesisStream, kinesisStreamProps } = props;\n\n this.kinesisStream = existingKinesisStream\n ? Stream.fromStreamArn(\n scope,\n existingKinesisStream.externalKinesisStreamName,\n `arn:aws:kinesis:${region}:${account}:stream/${existingKinesisStream.externalKinesisStreamName}`\n )\n : AppIdentity.taggedConstruct(\n props,\n new GuKinesisStream(scope, \"KinesisStream\", { encryption: StreamEncryption.MANAGED, ...kinesisStreamProps })\n );\n\n const errorHandlingPropsToAwsProps = toAwsErrorHandlingProps(props.errorHandlingConfiguration);\n\n const eventSourceProps: KinesisEventSourceProps = {\n startingPosition: StartingPosition.LATEST,\n ...props.processingProps,\n ...errorHandlingPropsToAwsProps,\n };\n this.addEventSource(new KinesisEventSource(this.kinesisStream, eventSourceProps));\n }\n}\n"]}
1
+ {"version":3,"file":"kinesis-lambda.js","sourceRoot":"","sources":["../../../src/experimental/patterns/kinesis-lambda.ts"],"names":[],"mappings":";;;AAAA,yDAAmE;AAEnE,uDAA0D;AAC1D,mFAA0E;AAG1E,gDAAoD;AAEpD,sDAA2D;AAC3D,oDAA2D;AAE3D,+CAA6D;AAwD7D;;;;;;;;;;;;GAYG;AACH,MAAa,2BAA4B,SAAQ,yBAAgB;IAG/D,YAAY,KAAc,EAAE,EAAU,EAAE,KAA2B;QACjE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,GAAG,KAAK;YACR,yBAAyB,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,uBAAuB;SAClH,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAClC,MAAM,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC;QAE5D,IAAI,CAAC,aAAa,GAAG,qBAAqB;YACxC,CAAC,CAAC,oBAAM,CAAC,aAAa,CAClB,KAAK,EACL,qBAAqB,CAAC,yBAAyB,EAC/C,mBAAmB,MAAM,IAAI,OAAO,WAAW,qBAAqB,CAAC,yBAAyB,EAAE,CACjG;YACH,CAAC,CAAC,kBAAW,CAAC,eAAe,CACzB,KAAK,EACL,IAAI,yBAAe,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,UAAU,EAAE,8BAAgB,CAAC,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAAC,CAC7G,CAAC;QAEN,MAAM,4BAA4B,GAAG,IAAA,gCAAuB,EAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAE/F,MAAM,gBAAgB,GAA4B;YAChD,gBAAgB,EAAE,6BAAgB,CAAC,MAAM;YACzC,GAAG,KAAK,CAAC,eAAe;YACxB,GAAG,4BAA4B;SAChC,CAAC;QAEF,kGAAkG;QAClG,yEAAyE;QACzE,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;QAC7C,iBAAiB,CAAC,cAAc,CAAC,IAAI,6CAAkB,CAAC,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACjG,CAAC;CACF;AApCD,kEAoCC","sourcesContent":["import { Stream, StreamEncryption } from \"aws-cdk-lib/aws-kinesis\";\nimport type { IStream, StreamProps } from \"aws-cdk-lib/aws-kinesis\";\nimport { StartingPosition } from \"aws-cdk-lib/aws-lambda\";\nimport { KinesisEventSource } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport type { KinesisEventSourceProps } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport type { GuLambdaErrorPercentageMonitoringProps, NoMonitoring } from \"../../constructs/cloudwatch\";\nimport { AppIdentity } from \"../../constructs/core\";\nimport type { GuStack } from \"../../constructs/core\";\nimport { GuKinesisStream } from \"../../constructs/kinesis\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport type { GuFunctionProps } from \"../../constructs/lambda\";\nimport { toAwsErrorHandlingProps } from \"../../utils/lambda\";\nimport type { StreamErrorHandlingProps, StreamProcessingProps } from \"../../utils/lambda\";\n\n/**\n * Used to provide information about an existing Kinesis stream to the [[`GuKinesisLambda`]] pattern.\n *\n * Specify an `externalKinesisStreamName` to link the lambda to a Kinesis stream owned by a different stack\n * (or created outside of version control).\n */\nexport interface ExistingKinesisStream {\n externalKinesisStreamName: string;\n}\n\n/**\n * Configuration options for the [[`GuKinesisLambda`]] pattern.\n *\n * For all lambda function configuration options, see [[`GuFunctionProps`]].\n *\n * The `existingKinesisStream` property can be used to reference a Kinesis stream which\n * has been created outside of this pattern (i.e. via CloudFormation, or via a different `cdk` pattern, or stack).\n * For more details see [[`ExistingKinesisStream`]].\n *\n * If you have specific stream configuration requirements (e.g. data retention period), these can be set via\n * `kinesisStreamProps`.\n *\n * If you need to override the default stream processing options (e.g. batch size and parallelization), pass\n * [[`StreamProcessingProps`]] via `processingProps`.\n *\n * You must provide `errorHandlingConfiguration` to this pattern. Retry conditions can be configured\n * via [[`StreamErrorHandlingProps`]].\n *\n * It is advisable to configure an alarm based on the lambda's error percentage.\n * To do this, add the `monitoringConfiguration` property. The required properties for this are:\n *\n * ```typescript\n * monitoringConfiguration: {\n * toleratedErrorPercentage: <sensible_error_percentage_threshold>,\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * }\n * ```\n * Other alarm properties (e.g. alarm name and description) will be pre-populated with sensible defaults.\n * For a full list of optional properties, see [[`GuLambdaErrorPercentageMonitoringProps`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true } as NoMonitoring\n * ```\n */\nexport interface GuKinesisLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n monitoringConfiguration: NoMonitoring | GuLambdaErrorPercentageMonitoringProps;\n existingKinesisStream?: ExistingKinesisStream;\n errorHandlingConfiguration: StreamErrorHandlingProps;\n kinesisStreamProps?: StreamProps;\n processingProps?: StreamProcessingProps;\n}\n\n/**\n * Pattern which creates all of the resources needed to invoke a lambda function whenever a record is\n * put onto a Kinesis stream.\n *\n * This pattern will create a new Kinesis stream by default. If you are migrating a stack from CloudFormation,\n * you will need to opt-out of this behaviour. For information on overriding the default behaviour,\n * see [[`GuKinesisLambdaProps`]].\n *\n * The Kinesis stream is stateful, and is accessible via `kinesisStream`.\n * @see https://github.com/guardian/cdk/blob/main/docs/stateful-resources.md\n *\n * @experimental This pattern is in early development. The API is likely to change in future releases.\n */\nexport class GuKinesisLambdaExperimental extends GuLambdaFunction {\n public readonly kinesisStream: IStream;\n\n constructor(scope: GuStack, id: string, props: GuKinesisLambdaProps) {\n super(scope, id, {\n ...props,\n errorPercentageMonitoring: props.monitoringConfiguration.noMonitoring ? undefined : props.monitoringConfiguration,\n });\n\n const { account, region } = scope;\n const { existingKinesisStream, kinesisStreamProps } = props;\n\n this.kinesisStream = existingKinesisStream\n ? Stream.fromStreamArn(\n scope,\n existingKinesisStream.externalKinesisStreamName,\n `arn:aws:kinesis:${region}:${account}:stream/${existingKinesisStream.externalKinesisStreamName}`\n )\n : AppIdentity.taggedConstruct(\n props,\n new GuKinesisStream(scope, \"KinesisStream\", { encryption: StreamEncryption.MANAGED, ...kinesisStreamProps })\n );\n\n const errorHandlingPropsToAwsProps = toAwsErrorHandlingProps(props.errorHandlingConfiguration);\n\n const eventSourceProps: KinesisEventSourceProps = {\n startingPosition: StartingPosition.LATEST,\n ...props.processingProps,\n ...errorHandlingPropsToAwsProps,\n };\n\n // If we have an alias, use this to ensure that all events are sent to a published Lambda version.\n // Otherwise, send all events to the latest unpublished version ($LATEST)\n const eventSourceTarget = this.alias ?? this;\n eventSourceTarget.addEventSource(new KinesisEventSource(this.kinesisStream, eventSourceProps));\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sns-lambda.d.ts","sourceRoot":"","sources":["../../../src/experimental/patterns/sns-lambda.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAE,sCAAsC,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAExG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAC1F,uBAAuB,EAAE,YAAY,GAAG,sCAAsC,CAAC;IAC/E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,uBAAwB,SAAQ,gBAAgB;IAC3D,SAAgB,QAAQ,EAAE,MAAM,CAAC;gBAErB,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CAoBhE"}
1
+ {"version":3,"file":"sns-lambda.d.ts","sourceRoot":"","sources":["../../../src/experimental/patterns/sns-lambda.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAE,sCAAsC,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAExG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAC1F,uBAAuB,EAAE,YAAY,GAAG,sCAAsC,CAAC;IAC/E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,uBAAwB,SAAQ,gBAAgB;IAC3D,SAAgB,QAAQ,EAAE,MAAM,CAAC;gBAErB,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CAuBhE"}
@@ -30,7 +30,10 @@ class GuSnsLambdaExperimental extends lambda_1.GuLambdaFunction {
30
30
  this.snsTopic = existingSnsTopic
31
31
  ? aws_sns_1.Topic.fromTopicArn(scope, `${id}-SnsExistingIncomingEventsTopic`, `arn:aws:sns:${region}:${account}:${existingSnsTopic.externalTopicName}`)
32
32
  : core_1.AppIdentity.taggedConstruct(props, new aws_sns_1.Topic(scope, "SnsIncomingEventsTopic"));
33
- this.addEventSource(new aws_lambda_event_sources_1.SnsEventSource(this.snsTopic));
33
+ // If we have an alias, use this to ensure that all events are sent to a published Lambda version.
34
+ // Otherwise, send all events to the latest unpublished version ($LATEST)
35
+ const eventSourceTarget = this.alias ?? this;
36
+ eventSourceTarget.addEventSource(new aws_lambda_event_sources_1.SnsEventSource(this.snsTopic));
34
37
  new aws_cdk_lib_1.CfnOutput(this, "TopicName", { value: this.snsTopic.topicName });
35
38
  }
36
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sns-lambda.js","sourceRoot":"","sources":["../../../src/experimental/patterns/sns-lambda.ts"],"names":[],"mappings":";;;AAAA,6CAAwC;AACxC,mFAAsE;AAEtE,iDAA4C;AAE5C,gDAAoD;AAEpD,oDAA2D;AA4C3D;;;;;;;;;;;;GAYG;AACH,MAAa,uBAAwB,SAAQ,yBAAgB;IAG3D,YAAY,KAAc,EAAE,EAAU,EAAE,KAAuB;QAC7D,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,GAAG,KAAK;YACR,yBAAyB,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,uBAAuB;SAClH,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAClC,MAAM,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;QAEnC,IAAI,CAAC,QAAQ,GAAG,gBAAgB;YAC9B,CAAC,CAAC,eAAK,CAAC,YAAY,CAChB,KAAK,EACL,GAAG,EAAE,iCAAiC,EACtC,eAAe,MAAM,IAAI,OAAO,IAAI,gBAAgB,CAAC,iBAAiB,EAAE,CACzE;YACH,CAAC,CAAC,kBAAW,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,eAAK,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAEnF,IAAI,CAAC,cAAc,CAAC,IAAI,yCAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvD,IAAI,uBAAS,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACvE,CAAC;CACF;AAvBD,0DAuBC","sourcesContent":["import { CfnOutput } from \"aws-cdk-lib\";\nimport { SnsEventSource } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport type { ITopic } from \"aws-cdk-lib/aws-sns\";\nimport { Topic } from \"aws-cdk-lib/aws-sns\";\nimport type { GuLambdaErrorPercentageMonitoringProps, NoMonitoring } from \"../../constructs/cloudwatch\";\nimport { AppIdentity } from \"../../constructs/core\";\nimport type { GuStack } from \"../../constructs/core\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport type { GuFunctionProps } from \"../../constructs/lambda\";\n\n/**\n * Used to provide information about an existing SNS topic to the [[`GuSnsLambda`]] pattern.\n *\n * Specify an `externalTopicName` to link the lambda to an SNS topic owned by a different stack\n * (or created outside of version control).\n */\nexport interface ExistingSnsTopic {\n externalTopicName: string;\n}\n\n/**\n * Configuration options for the [[`GuSnsLambda`]] pattern.\n *\n * For all lambda function configuration options, see [[`GuFunctionProps`]].\n *\n * The `existingSnsTopic` property can be used to inherit or reference an SNS topic which\n * has been created outside of `cdk`. If this property is omitted, the [[`GuSnsLambda`]] pattern\n * will create a new topic. For more details and example usage, see [[`ExistingSnsTopic`]].\n *\n * It is advisable to configure an alarm based on the lambda's error percentage.\n * To do this, add the `monitoringConfiguration` property. The required properties for this are:\n *\n * ```typescript\n * monitoringConfiguration: {\n * toleratedErrorPercentage: <sensible_error_percentage_threshold>,\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * }\n * ```\n * Other alarm properties (e.g. alarm name and description) will be pre-populated with sensible defaults.\n * For a full list of optional properties, see [[`GuLambdaErrorPercentageMonitoringProps`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true } as NoMonitoring\n * ```\n */\nexport interface GuSnsLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n monitoringConfiguration: NoMonitoring | GuLambdaErrorPercentageMonitoringProps;\n existingSnsTopic?: ExistingSnsTopic;\n}\n\n/**\n * Pattern which creates all of the resources needed to invoke a lambda function whenever a message\n * is published onto an SNS topic.\n *\n * This pattern will create a new SNS topic by default. If you are migrating a stack from CloudFormation,\n * you will need to opt-out of this behaviour. For information on overriding the default behaviour,\n * see [[`GuSnsLambdaProps`]].\n *\n * The SNS topic is stateful, and is accessible via `snsTopic`.\n * @see https://github.com/guardian/cdk/blob/main/docs/stateful-resources.md\n *\n * @experimental This pattern is in early development. The API is likely to change in future releases.\n */\nexport class GuSnsLambdaExperimental extends GuLambdaFunction {\n public readonly snsTopic: ITopic;\n\n constructor(scope: GuStack, id: string, props: GuSnsLambdaProps) {\n super(scope, id, {\n ...props,\n errorPercentageMonitoring: props.monitoringConfiguration.noMonitoring ? undefined : props.monitoringConfiguration,\n });\n\n const { account, region } = scope;\n const { existingSnsTopic } = props;\n\n this.snsTopic = existingSnsTopic\n ? Topic.fromTopicArn(\n scope,\n `${id}-SnsExistingIncomingEventsTopic`,\n `arn:aws:sns:${region}:${account}:${existingSnsTopic.externalTopicName}`\n )\n : AppIdentity.taggedConstruct(props, new Topic(scope, \"SnsIncomingEventsTopic\"));\n\n this.addEventSource(new SnsEventSource(this.snsTopic));\n new CfnOutput(this, \"TopicName\", { value: this.snsTopic.topicName });\n }\n}\n"]}
1
+ {"version":3,"file":"sns-lambda.js","sourceRoot":"","sources":["../../../src/experimental/patterns/sns-lambda.ts"],"names":[],"mappings":";;;AAAA,6CAAwC;AACxC,mFAAsE;AAEtE,iDAA4C;AAE5C,gDAAoD;AAEpD,oDAA2D;AA4C3D;;;;;;;;;;;;GAYG;AACH,MAAa,uBAAwB,SAAQ,yBAAgB;IAG3D,YAAY,KAAc,EAAE,EAAU,EAAE,KAAuB;QAC7D,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,GAAG,KAAK;YACR,yBAAyB,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,uBAAuB;SAClH,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAClC,MAAM,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;QAEnC,IAAI,CAAC,QAAQ,GAAG,gBAAgB;YAC9B,CAAC,CAAC,eAAK,CAAC,YAAY,CAChB,KAAK,EACL,GAAG,EAAE,iCAAiC,EACtC,eAAe,MAAM,IAAI,OAAO,IAAI,gBAAgB,CAAC,iBAAiB,EAAE,CACzE;YACH,CAAC,CAAC,kBAAW,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,eAAK,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAEnF,kGAAkG;QAClG,yEAAyE;QACzE,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;QAC7C,iBAAiB,CAAC,cAAc,CAAC,IAAI,yCAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpE,IAAI,uBAAS,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACvE,CAAC;CACF;AA1BD,0DA0BC","sourcesContent":["import { CfnOutput } from \"aws-cdk-lib\";\nimport { SnsEventSource } from \"aws-cdk-lib/aws-lambda-event-sources\";\nimport type { ITopic } from \"aws-cdk-lib/aws-sns\";\nimport { Topic } from \"aws-cdk-lib/aws-sns\";\nimport type { GuLambdaErrorPercentageMonitoringProps, NoMonitoring } from \"../../constructs/cloudwatch\";\nimport { AppIdentity } from \"../../constructs/core\";\nimport type { GuStack } from \"../../constructs/core\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport type { GuFunctionProps } from \"../../constructs/lambda\";\n\n/**\n * Used to provide information about an existing SNS topic to the [[`GuSnsLambda`]] pattern.\n *\n * Specify an `externalTopicName` to link the lambda to an SNS topic owned by a different stack\n * (or created outside of version control).\n */\nexport interface ExistingSnsTopic {\n externalTopicName: string;\n}\n\n/**\n * Configuration options for the [[`GuSnsLambda`]] pattern.\n *\n * For all lambda function configuration options, see [[`GuFunctionProps`]].\n *\n * The `existingSnsTopic` property can be used to inherit or reference an SNS topic which\n * has been created outside of `cdk`. If this property is omitted, the [[`GuSnsLambda`]] pattern\n * will create a new topic. For more details and example usage, see [[`ExistingSnsTopic`]].\n *\n * It is advisable to configure an alarm based on the lambda's error percentage.\n * To do this, add the `monitoringConfiguration` property. The required properties for this are:\n *\n * ```typescript\n * monitoringConfiguration: {\n * toleratedErrorPercentage: <sensible_error_percentage_threshold>,\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * }\n * ```\n * Other alarm properties (e.g. alarm name and description) will be pre-populated with sensible defaults.\n * For a full list of optional properties, see [[`GuLambdaErrorPercentageMonitoringProps`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true } as NoMonitoring\n * ```\n */\nexport interface GuSnsLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n monitoringConfiguration: NoMonitoring | GuLambdaErrorPercentageMonitoringProps;\n existingSnsTopic?: ExistingSnsTopic;\n}\n\n/**\n * Pattern which creates all of the resources needed to invoke a lambda function whenever a message\n * is published onto an SNS topic.\n *\n * This pattern will create a new SNS topic by default. If you are migrating a stack from CloudFormation,\n * you will need to opt-out of this behaviour. For information on overriding the default behaviour,\n * see [[`GuSnsLambdaProps`]].\n *\n * The SNS topic is stateful, and is accessible via `snsTopic`.\n * @see https://github.com/guardian/cdk/blob/main/docs/stateful-resources.md\n *\n * @experimental This pattern is in early development. The API is likely to change in future releases.\n */\nexport class GuSnsLambdaExperimental extends GuLambdaFunction {\n public readonly snsTopic: ITopic;\n\n constructor(scope: GuStack, id: string, props: GuSnsLambdaProps) {\n super(scope, id, {\n ...props,\n errorPercentageMonitoring: props.monitoringConfiguration.noMonitoring ? undefined : props.monitoringConfiguration,\n });\n\n const { account, region } = scope;\n const { existingSnsTopic } = props;\n\n this.snsTopic = existingSnsTopic\n ? Topic.fromTopicArn(\n scope,\n `${id}-SnsExistingIncomingEventsTopic`,\n `arn:aws:sns:${region}:${account}:${existingSnsTopic.externalTopicName}`\n )\n : AppIdentity.taggedConstruct(props, new Topic(scope, \"SnsIncomingEventsTopic\"));\n\n // If we have an alias, use this to ensure that all events are sent to a published Lambda version.\n // Otherwise, send all events to the latest unpublished version ($LATEST)\n const eventSourceTarget = this.alias ?? this;\n eventSourceTarget.addEventSource(new SnsEventSource(this.snsTopic));\n new CfnOutput(this, \"TopicName\", { value: this.snsTopic.topicName });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/riff-raff-yaml-file/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAqBvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAW;IAEtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqDG;IACH,OAAO,CAAC,mBAAmB;IAiC3B,OAAO,CAAC,6BAA6B;IAQrC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,oBAAoB;gBAKhB,GAAG,EAAE,GAAG;IAiEpB;;;OAGG;IACH,MAAM,IAAI,MAAM;IAiBhB;;;OAGG;IACH,KAAK,IAAI,IAAI;CAId"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/riff-raff-yaml-file/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAqBvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAW;IAEtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqDG;IACH,OAAO,CAAC,mBAAmB;IAiC3B,OAAO,CAAC,6BAA6B;IAQrC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,oBAAoB;gBAKhB,GAAG,EAAE,GAAG;IAoEpB;;;OAGG;IACH,MAAM,IAAI,MAAM;IAiBhB;;;OAGG;IACH,KAAK,IAAI,IAAI;CAId"}
@@ -186,7 +186,10 @@ class RiffRaffYamlFileExperimental {
186
186
  artifactUploads.forEach(({ name, props }) => deployments.set(name, props));
187
187
  const cfnDeployment = (0, cloudformation_1.cloudFormationDeployment)(stacks, artifactUploads, this.outdir);
188
188
  deployments.set(cfnDeployment.name, cfnDeployment.props);
189
- lambdas.forEach((lambda) => {
189
+ const lambdasWithoutAnAlias = lambdas.filter((lambda) => lambda.alias === undefined);
190
+ // If the Lambda has an alias it is using versioning. When using versioning, there is no need for Riff-Raff
191
+ // to modify the unpublished version of the function
192
+ lambdasWithoutAnAlias.forEach((lambda) => {
190
193
  const lambdaDeployment = (0, lambda_2.updateLambdaDeployment)(lambda, cfnDeployment);
191
194
  deployments.set(lambdaDeployment.name, lambdaDeployment.props);
192
195
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/experimental/riff-raff-yaml-file/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFileSync } from \"fs\";\nimport path from \"path\";\nimport type { App } from \"aws-cdk-lib\";\nimport { Token } from \"aws-cdk-lib\";\nimport { dump } from \"js-yaml\";\nimport { GuAutoScalingGroup } from \"../../constructs/autoscaling\";\nimport { GuStack } from \"../../constructs/core\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport { autoscalingDeployment, uploadAutoscalingArtifact } from \"./deployments/autoscaling\";\nimport { addAmiParametersToCloudFormationDeployment, cloudFormationDeployment } from \"./deployments/cloudformation\";\nimport { updateLambdaDeployment, uploadLambdaArtifact } from \"./deployments/lambda\";\nimport { groupByClassNameStackRegionStage } from \"./group-by\";\nimport type {\n GroupedCdkStacks,\n Region,\n RiffRaffDeployment,\n RiffRaffDeploymentName,\n RiffRaffDeploymentProps,\n RiffRaffYaml,\n StackTag,\n StageTag,\n} from \"./types\";\n\n/**\n * A class that creates a `riff-raff.yaml` file.\n *\n * Rather than using this directly, prefer to use [[`GuRoot`]] instead.\n *\n * Supports:\n * - Multiple CloudFormation stacks\n * - Multiple regions\n * - Lambda applications\n * - EC2 (autoscaling) applications\n *\n * For lambda applications, 3 deployments will be defined:\n * 1. Lambda upload (`aws-lambda`, `action: [uploadLambda]`)\n * 2. CloudFormation deploy (`cloud-formation`)\n * 3. Lambda update (`aws-lambda`, `action: [updateLambda]`)\n *\n * For EC2 applications, 3 deployments will be defined:\n * 1. Artifact upload (`autoscaling`, `action: [uploadArtifacts]`)\n * 2. CloudFormation deploy (`cloud-formation`)\n * 3. Autoscaling deploy (`autoscaling`, `action: [deploy]`)\n *\n * It assumes a Riff-Raff bundle structure as follows:\n *\n * ```\n * .\n * ├── cdk.out\n * │ └── MyApplication.template.json\n * ├── my-application\n * │ └── my-application.deb\n * └── my-lambda\n * └── my-lambda.zip\n * ```\n *\n * That is, all CloudFormation templates are in a `cdk.out` directory, and there is a directory per app.\n * Application artifact(s) are in the app directory.\n *\n * NOTE: The file extension is decided by you, the above file tree is used for illustration purposes.\n *\n * NOTE: Resources will be looked up by tags (Stack, Stage, App). Ensure your CFN stack is tagged appropriately!\n *\n * @see https://riffraff.gutools.co.uk/docs/reference/riff-raff.yaml.md\n * @see https://riffraff.gutools.co.uk/docs/magenta-lib/types\n */\nexport class RiffRaffYamlFileExperimental {\n private readonly allCdkStacks: GuStack[];\n private readonly allStackTags: StackTag[];\n private readonly allStageTags: StageTag[];\n private readonly allRegions: Region[];\n\n private readonly riffRaffYaml: RiffRaffYaml;\n private readonly outdir: string;\n\n private isCdkStackPresent(expectedStack: StackTag, expectedStage: StageTag): boolean {\n const matches = this.allCdkStacks.find((cdkStack) => {\n const { stack, stage } = cdkStack;\n return stack === expectedStack && stage === expectedStage;\n });\n\n return !!matches;\n }\n\n /**\n * Check there are the appropriate number of `GuStack`s.\n * Expect to find an instance for each combination of `stack`, and `stage`.\n *\n * If not valid, a message is logged describing what is missing to aid debugging.\n *\n * Given the following:\n *\n * ```ts\n * const app = new App();\n *\n * class MyApplicationStack extends GuStack { }\n *\n * new MyApplicationStack(app, \"App-CODE-deploy\", {\n * env: {\n * region: \"eu-west-1\",\n * },\n * stack: \"deploy\",\n * stage: \"CODE\"\n * });\n *\n * new MyApplicationStack(app, \"App-PROD-media-service\", {\n * env: {\n * region: \"eu-west-1\",\n * },\n * stack: \"media-service\",\n * stage: \"PROD\",\n * });\n *\n * new MyApplicationStack(app, \"App-PROD-deploy\", {\n * env: {\n * region: \"eu-west-1\",\n * },\n * stack: \"deploy\",\n * stage: \"PROD\"\n * });\n * ```\n *\n * This will log a message like this, where ❌ denotes something missing,\n * specifically there is no `CODE` template for `media-service`.\n *\n * ```log\n * Unable to produce a working riff-raff.yaml file; missing 1 definitions (details below)\n *\n * ┌───────────────┬──────┬──────┐\n * │ (index) │ CODE │ PROD │\n * ├───────────────┼──────┼──────┤\n * │ deploy │ '✅' │ '✅' │\n * │ media-service │ '❌' │ '✅' │\n * └───────────────┴──────┴──────┘\n * ```\n *\n * @private\n */\n private validateStacksInApp(): void {\n type Found = \"✅\";\n type NotFound = \"❌\";\n type AppValidation = Record<StackTag, Record<StageTag, Found | NotFound>>;\n\n const { allStackTags, allStageTags } = this;\n\n const checks: AppValidation = allStackTags.reduce((accStackTag, stackTag) => {\n return {\n ...accStackTag,\n [stackTag]: allStageTags.reduce((accStageTag, stageTag) => {\n return {\n ...accStageTag,\n [stageTag]: this.isCdkStackPresent(stackTag, stageTag) ? \"✅\" : \"❌\",\n };\n }, {}),\n };\n }, {});\n\n const missingDefinitions: Array<Found | NotFound> = Object.values(checks).flatMap((groupedByStackTag) => {\n return Object.values(groupedByStackTag).filter((_) => _ === \"❌\");\n });\n\n if (missingDefinitions.length > 0) {\n const message = `Unable to produce a working riff-raff.yaml file; missing ${missingDefinitions.length} definitions`;\n\n console.log(`${message} (details below)`);\n console.table(checks);\n\n throw new Error(message);\n }\n }\n\n private validateAllRegionsAreResolved(): void {\n const unresolved = this.allRegions.filter((region) => Token.isUnresolved(region));\n\n if (unresolved.length !== 0) {\n throw new Error(`Unable to produce a working riff-raff.yaml file; all stacks must have an explicit region set`);\n }\n }\n\n private getLambdas(cdkStack: GuStack): GuLambdaFunction[] {\n return cdkStack.node.findAll().filter((_) => _ instanceof GuLambdaFunction) as GuLambdaFunction[];\n }\n\n private getAutoScalingGroups(cdkStack: GuStack): GuAutoScalingGroup[] {\n return cdkStack.node.findAll().filter((_) => _ instanceof GuAutoScalingGroup) as GuAutoScalingGroup[];\n }\n\n // eslint-disable-next-line custom-rules/valid-constructors -- this needs to sit above GuStack on the cdk tree\n constructor(app: App) {\n this.allCdkStacks = app.node.findAll().filter((_) => _ instanceof GuStack) as GuStack[];\n const allowedStages = new Set(this.allCdkStacks.map(({ stage }) => stage));\n this.allStageTags = Array.from(allowedStages);\n this.allStackTags = Array.from(new Set(this.allCdkStacks.map(({ stack }) => stack)));\n this.allRegions = Array.from(new Set(this.allCdkStacks.map(({ region }) => region)));\n\n this.validateStacksInApp();\n this.validateAllRegionsAreResolved();\n\n this.outdir = app.outdir;\n\n const deployments = new Map<RiffRaffDeploymentName, RiffRaffDeploymentProps>();\n\n const groupedStacks: GroupedCdkStacks = groupByClassNameStackRegionStage(this.allCdkStacks);\n\n Object.values(groupedStacks).forEach((stackTagGroup) => {\n Object.values(stackTagGroup).forEach((regionGroup) => {\n Object.values(regionGroup).forEach((stageGroup) => {\n const stacks: GuStack[] = Object.values(stageGroup).flat();\n\n if (stacks.length === 0) {\n throw new Error(\"Unable to produce a working riff-raff.yaml file; there are no stacks!\");\n }\n\n // The items in `stacks` only differ by stage, so we can just use the first item in the list.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length of `stacks` is checked above\n const stack = stacks[0]!;\n\n const lambdas = this.getLambdas(stack);\n const autoscalingGroups = this.getAutoScalingGroups(stack);\n\n const artifactUploads: RiffRaffDeployment[] = [\n lambdas.filter((_) => !_.withoutArtifactUpload).map(uploadLambdaArtifact),\n autoscalingGroups.map(uploadAutoscalingArtifact),\n ].flat();\n artifactUploads.forEach(({ name, props }) => deployments.set(name, props));\n\n const cfnDeployment = cloudFormationDeployment(stacks, artifactUploads, this.outdir);\n deployments.set(cfnDeployment.name, cfnDeployment.props);\n\n lambdas.forEach((lambda) => {\n const lambdaDeployment = updateLambdaDeployment(lambda, cfnDeployment);\n deployments.set(lambdaDeployment.name, lambdaDeployment.props);\n });\n\n autoscalingGroups.forEach((asg) => {\n const asgDeployment = autoscalingDeployment(asg, cfnDeployment);\n deployments.set(asgDeployment.name, asgDeployment.props);\n });\n\n deployments.set(\n cfnDeployment.name,\n addAmiParametersToCloudFormationDeployment(cfnDeployment, autoscalingGroups)\n );\n });\n });\n });\n\n this.riffRaffYaml = {\n allowedStages,\n deployments,\n };\n }\n\n /**\n * The `riff-raff.yaml` file as a string.\n * Useful for testing.\n */\n toYAML(): string {\n // Add support for ES6 Set and Map. See https://github.com/nodeca/js-yaml/issues/436.\n const replacer = (_key: string, value: unknown) => {\n if (value instanceof Set) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- this is how `js-yaml` is typed\n return Array.from(value);\n }\n if (value instanceof Map) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- this is how `js-yaml` is typed\n return Object.fromEntries(value);\n }\n return value;\n };\n\n return dump(this.riffRaffYaml, { replacer });\n }\n\n /**\n * Write the `riff-raff.yaml` file to disk.\n * It'll be located with the CFN JSON templates generated by `cdk synth`.\n */\n synth(): void {\n const outPath = path.join(this.outdir, \"riff-raff.yaml\");\n writeFileSync(outPath, this.toYAML());\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/experimental/riff-raff-yaml-file/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFileSync } from \"fs\";\nimport path from \"path\";\nimport type { App } from \"aws-cdk-lib\";\nimport { Token } from \"aws-cdk-lib\";\nimport { dump } from \"js-yaml\";\nimport { GuAutoScalingGroup } from \"../../constructs/autoscaling\";\nimport { GuStack } from \"../../constructs/core\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport { autoscalingDeployment, uploadAutoscalingArtifact } from \"./deployments/autoscaling\";\nimport { addAmiParametersToCloudFormationDeployment, cloudFormationDeployment } from \"./deployments/cloudformation\";\nimport { updateLambdaDeployment, uploadLambdaArtifact } from \"./deployments/lambda\";\nimport { groupByClassNameStackRegionStage } from \"./group-by\";\nimport type {\n GroupedCdkStacks,\n Region,\n RiffRaffDeployment,\n RiffRaffDeploymentName,\n RiffRaffDeploymentProps,\n RiffRaffYaml,\n StackTag,\n StageTag,\n} from \"./types\";\n\n/**\n * A class that creates a `riff-raff.yaml` file.\n *\n * Rather than using this directly, prefer to use [[`GuRoot`]] instead.\n *\n * Supports:\n * - Multiple CloudFormation stacks\n * - Multiple regions\n * - Lambda applications\n * - EC2 (autoscaling) applications\n *\n * For lambda applications, 3 deployments will be defined:\n * 1. Lambda upload (`aws-lambda`, `action: [uploadLambda]`)\n * 2. CloudFormation deploy (`cloud-formation`)\n * 3. Lambda update (`aws-lambda`, `action: [updateLambda]`)\n *\n * For EC2 applications, 3 deployments will be defined:\n * 1. Artifact upload (`autoscaling`, `action: [uploadArtifacts]`)\n * 2. CloudFormation deploy (`cloud-formation`)\n * 3. Autoscaling deploy (`autoscaling`, `action: [deploy]`)\n *\n * It assumes a Riff-Raff bundle structure as follows:\n *\n * ```\n * .\n * ├── cdk.out\n * │ └── MyApplication.template.json\n * ├── my-application\n * │ └── my-application.deb\n * └── my-lambda\n * └── my-lambda.zip\n * ```\n *\n * That is, all CloudFormation templates are in a `cdk.out` directory, and there is a directory per app.\n * Application artifact(s) are in the app directory.\n *\n * NOTE: The file extension is decided by you, the above file tree is used for illustration purposes.\n *\n * NOTE: Resources will be looked up by tags (Stack, Stage, App). Ensure your CFN stack is tagged appropriately!\n *\n * @see https://riffraff.gutools.co.uk/docs/reference/riff-raff.yaml.md\n * @see https://riffraff.gutools.co.uk/docs/magenta-lib/types\n */\nexport class RiffRaffYamlFileExperimental {\n private readonly allCdkStacks: GuStack[];\n private readonly allStackTags: StackTag[];\n private readonly allStageTags: StageTag[];\n private readonly allRegions: Region[];\n\n private readonly riffRaffYaml: RiffRaffYaml;\n private readonly outdir: string;\n\n private isCdkStackPresent(expectedStack: StackTag, expectedStage: StageTag): boolean {\n const matches = this.allCdkStacks.find((cdkStack) => {\n const { stack, stage } = cdkStack;\n return stack === expectedStack && stage === expectedStage;\n });\n\n return !!matches;\n }\n\n /**\n * Check there are the appropriate number of `GuStack`s.\n * Expect to find an instance for each combination of `stack`, and `stage`.\n *\n * If not valid, a message is logged describing what is missing to aid debugging.\n *\n * Given the following:\n *\n * ```ts\n * const app = new App();\n *\n * class MyApplicationStack extends GuStack { }\n *\n * new MyApplicationStack(app, \"App-CODE-deploy\", {\n * env: {\n * region: \"eu-west-1\",\n * },\n * stack: \"deploy\",\n * stage: \"CODE\"\n * });\n *\n * new MyApplicationStack(app, \"App-PROD-media-service\", {\n * env: {\n * region: \"eu-west-1\",\n * },\n * stack: \"media-service\",\n * stage: \"PROD\",\n * });\n *\n * new MyApplicationStack(app, \"App-PROD-deploy\", {\n * env: {\n * region: \"eu-west-1\",\n * },\n * stack: \"deploy\",\n * stage: \"PROD\"\n * });\n * ```\n *\n * This will log a message like this, where ❌ denotes something missing,\n * specifically there is no `CODE` template for `media-service`.\n *\n * ```log\n * Unable to produce a working riff-raff.yaml file; missing 1 definitions (details below)\n *\n * ┌───────────────┬──────┬──────┐\n * │ (index) │ CODE │ PROD │\n * ├───────────────┼──────┼──────┤\n * │ deploy │ '✅' │ '✅' │\n * │ media-service │ '❌' │ '✅' │\n * └───────────────┴──────┴──────┘\n * ```\n *\n * @private\n */\n private validateStacksInApp(): void {\n type Found = \"✅\";\n type NotFound = \"❌\";\n type AppValidation = Record<StackTag, Record<StageTag, Found | NotFound>>;\n\n const { allStackTags, allStageTags } = this;\n\n const checks: AppValidation = allStackTags.reduce((accStackTag, stackTag) => {\n return {\n ...accStackTag,\n [stackTag]: allStageTags.reduce((accStageTag, stageTag) => {\n return {\n ...accStageTag,\n [stageTag]: this.isCdkStackPresent(stackTag, stageTag) ? \"✅\" : \"❌\",\n };\n }, {}),\n };\n }, {});\n\n const missingDefinitions: Array<Found | NotFound> = Object.values(checks).flatMap((groupedByStackTag) => {\n return Object.values(groupedByStackTag).filter((_) => _ === \"❌\");\n });\n\n if (missingDefinitions.length > 0) {\n const message = `Unable to produce a working riff-raff.yaml file; missing ${missingDefinitions.length} definitions`;\n\n console.log(`${message} (details below)`);\n console.table(checks);\n\n throw new Error(message);\n }\n }\n\n private validateAllRegionsAreResolved(): void {\n const unresolved = this.allRegions.filter((region) => Token.isUnresolved(region));\n\n if (unresolved.length !== 0) {\n throw new Error(`Unable to produce a working riff-raff.yaml file; all stacks must have an explicit region set`);\n }\n }\n\n private getLambdas(cdkStack: GuStack): GuLambdaFunction[] {\n return cdkStack.node.findAll().filter((_) => _ instanceof GuLambdaFunction) as GuLambdaFunction[];\n }\n\n private getAutoScalingGroups(cdkStack: GuStack): GuAutoScalingGroup[] {\n return cdkStack.node.findAll().filter((_) => _ instanceof GuAutoScalingGroup) as GuAutoScalingGroup[];\n }\n\n // eslint-disable-next-line custom-rules/valid-constructors -- this needs to sit above GuStack on the cdk tree\n constructor(app: App) {\n this.allCdkStacks = app.node.findAll().filter((_) => _ instanceof GuStack) as GuStack[];\n const allowedStages = new Set(this.allCdkStacks.map(({ stage }) => stage));\n this.allStageTags = Array.from(allowedStages);\n this.allStackTags = Array.from(new Set(this.allCdkStacks.map(({ stack }) => stack)));\n this.allRegions = Array.from(new Set(this.allCdkStacks.map(({ region }) => region)));\n\n this.validateStacksInApp();\n this.validateAllRegionsAreResolved();\n\n this.outdir = app.outdir;\n\n const deployments = new Map<RiffRaffDeploymentName, RiffRaffDeploymentProps>();\n\n const groupedStacks: GroupedCdkStacks = groupByClassNameStackRegionStage(this.allCdkStacks);\n\n Object.values(groupedStacks).forEach((stackTagGroup) => {\n Object.values(stackTagGroup).forEach((regionGroup) => {\n Object.values(regionGroup).forEach((stageGroup) => {\n const stacks: GuStack[] = Object.values(stageGroup).flat();\n\n if (stacks.length === 0) {\n throw new Error(\"Unable to produce a working riff-raff.yaml file; there are no stacks!\");\n }\n\n // The items in `stacks` only differ by stage, so we can just use the first item in the list.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length of `stacks` is checked above\n const stack = stacks[0]!;\n\n const lambdas = this.getLambdas(stack);\n const autoscalingGroups = this.getAutoScalingGroups(stack);\n\n const artifactUploads: RiffRaffDeployment[] = [\n lambdas.filter((_) => !_.withoutArtifactUpload).map(uploadLambdaArtifact),\n autoscalingGroups.map(uploadAutoscalingArtifact),\n ].flat();\n artifactUploads.forEach(({ name, props }) => deployments.set(name, props));\n\n const cfnDeployment = cloudFormationDeployment(stacks, artifactUploads, this.outdir);\n deployments.set(cfnDeployment.name, cfnDeployment.props);\n\n const lambdasWithoutAnAlias = lambdas.filter((lambda) => lambda.alias === undefined);\n // If the Lambda has an alias it is using versioning. When using versioning, there is no need for Riff-Raff\n // to modify the unpublished version of the function\n lambdasWithoutAnAlias.forEach((lambda) => {\n const lambdaDeployment = updateLambdaDeployment(lambda, cfnDeployment);\n deployments.set(lambdaDeployment.name, lambdaDeployment.props);\n });\n\n autoscalingGroups.forEach((asg) => {\n const asgDeployment = autoscalingDeployment(asg, cfnDeployment);\n deployments.set(asgDeployment.name, asgDeployment.props);\n });\n\n deployments.set(\n cfnDeployment.name,\n addAmiParametersToCloudFormationDeployment(cfnDeployment, autoscalingGroups)\n );\n });\n });\n });\n\n this.riffRaffYaml = {\n allowedStages,\n deployments,\n };\n }\n\n /**\n * The `riff-raff.yaml` file as a string.\n * Useful for testing.\n */\n toYAML(): string {\n // Add support for ES6 Set and Map. See https://github.com/nodeca/js-yaml/issues/436.\n const replacer = (_key: string, value: unknown) => {\n if (value instanceof Set) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- this is how `js-yaml` is typed\n return Array.from(value);\n }\n if (value instanceof Map) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- this is how `js-yaml` is typed\n return Object.fromEntries(value);\n }\n return value;\n };\n\n return dump(this.riffRaffYaml, { replacer });\n }\n\n /**\n * Write the `riff-raff.yaml` file to disk.\n * It'll be located with the CFN JSON templates generated by `cdk synth`.\n */\n synth(): void {\n const outPath = path.join(this.outdir, \"riff-raff.yaml\");\n writeFileSync(outPath, this.toYAML());\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"api-lambda.d.ts","sourceRoot":"","sources":["../../src/patterns/api-lambda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,UAAU,QAAS,SAAQ,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC;IAC5D,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAC1F;;OAEG;IACH,GAAG,EAAE,QAAQ,CAAC;IACd;;;;;;;OAOG;IACH,uBAAuB,EAAE,YAAY,GAAG,gBAAgB,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,WAAY,SAAQ,gBAAgB;IAC/C,SAAgB,GAAG,EAAE,aAAa,CAAC;gBAEvB,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CAuBhE"}
1
+ {"version":3,"file":"api-lambda.d.ts","sourceRoot":"","sources":["../../src/patterns/api-lambda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,UAAU,QAAS,SAAQ,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC;IAC5D,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAC1F;;OAEG;IACH,GAAG,EAAE,QAAQ,CAAC;IACd;;;;;;;OAOG;IACH,uBAAuB,EAAE,YAAY,GAAG,gBAAgB,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,WAAY,SAAQ,gBAAgB;IAC/C,SAAgB,GAAG,EAAE,aAAa,CAAC;gBAEvB,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB;CA2BhE"}
@@ -39,8 +39,11 @@ class GuApiLambda extends lambda_1.GuLambdaFunction {
39
39
  super(scope, id, {
40
40
  ...props,
41
41
  });
42
+ // If we have an alias, use this to ensure that all requests are routed to a published Lambda version.
43
+ // Otherwise, use the latest unpublished version ($LATEST)
44
+ const resourceToInvoke = this.alias ?? this;
42
45
  this.api = new aws_apigateway_1.LambdaRestApi(this, props.api.id, {
43
- handler: this,
46
+ handler: resourceToInvoke,
44
47
  // Override to avoid clashes as default is just api ID, which is often shared across stages.
45
48
  restApiName: `${scope.stack}-${scope.stage}-${props.api.id}`,
46
49
  ...props.api,
@@ -1 +1 @@
1
- {"version":3,"file":"api-lambda.js","sourceRoot":"","sources":["../../src/patterns/api-lambda.ts"],"names":[],"mappings":";;;AAAA,+DAA2D;AAG3D,oFAA6F;AAE7F,iDAAwD;AAwBxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAa,WAAY,SAAQ,yBAAgB;IAG/C,YAAY,KAAc,EAAE,EAAU,EAAE,KAAuB;QAC7D,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,GAAG,KAAK;SACT,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,GAAG,IAAI,8BAAa,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;YAC/C,OAAO,EAAE,IAAI;YAEb,4FAA4F;YAC5F,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;YAE5D,GAAG,KAAK,CAAC,GAAG;SACb,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,YAAY,EAAE;YAC/C,IAAI,mDAA8B,CAAC,KAAK,EAAE;gBACxC,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,kBAAkB,EAAE,IAAI,CAAC,GAAG;gBAC5B,YAAY,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY;gBACxD,GAAG,KAAK,CAAC,uBAAuB,CAAC,YAAY;aAC9C,CAAC,CAAC;SACJ;IACH,CAAC;CACF;AA1BD,kCA0BC","sourcesContent":["import { LambdaRestApi } from \"aws-cdk-lib/aws-apigateway\";\nimport type { LambdaRestApiProps } from \"aws-cdk-lib/aws-apigateway\";\nimport type { NoMonitoring } from \"../constructs/cloudwatch\";\nimport { GuApiGateway5xxPercentageAlarm } from \"../constructs/cloudwatch/api-gateway-alarms\";\nimport type { GuStack } from \"../constructs/core\";\nimport { GuLambdaFunction } from \"../constructs/lambda\";\nimport type { GuFunctionProps } from \"../constructs/lambda\";\nimport type { ApiGatewayAlarms } from \"./api-multiple-lambdas\";\n\ninterface ApiProps extends Omit<LambdaRestApiProps, \"handler\"> {\n id: string;\n}\n\nexport interface GuApiLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n /**\n * [[`LambdaRestApiProps`]] to configure for the lambda.\n */\n api: ApiProps;\n /**\n * Alarm configuration for your API. For more details, see [[`ApiGatewayAlarms`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true }\n * ```\n */\n monitoringConfiguration: NoMonitoring | ApiGatewayAlarms;\n}\n\n/**\n * A pattern to create a Lambda triggered by API Gateway\n * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-lambda-integration.html\n *\n * This pattern should be used if you intend to serve all traffic via a single Lambda\n * (for example, if your Lambda uses an application framework, like https://github.com/vendia/serverless-express).\n * If you need to configure path-based routing to serve different requests with different\n * Lambdas, use the [[`GuApiGatewayWithLambdaByPath`]] pattern instead.\n *\n * For all configuration options, see [[`GuApiLambdaProps`]].\n *\n * Example usage:\n *\n * ```typescript\n * new GuApiLambda(stack, \"my-lambda\", {\n * fileName: \"my-app.zip\",\n * handler: \"handler.ts\",\n * runtime: Runtime.NODEJS_14_X,\n * monitoringConfiguration: {\n * http5xxAlarm: { tolerated5xxPercentage: 5 },\n * snsTopicName: \"alerts-topic\",\n * },\n * app: \"my-app\",\n * api: {\n * id: \"my-api\",\n * description: \"...\",\n * },\n * });\n * ```\n */\nexport class GuApiLambda extends GuLambdaFunction {\n public readonly api: LambdaRestApi;\n\n constructor(scope: GuStack, id: string, props: GuApiLambdaProps) {\n super(scope, id, {\n ...props,\n });\n\n this.api = new LambdaRestApi(this, props.api.id, {\n handler: this,\n\n // Override to avoid clashes as default is just api ID, which is often shared across stages.\n restApiName: `${scope.stack}-${scope.stage}-${props.api.id}`,\n\n ...props.api,\n });\n\n if (!props.monitoringConfiguration.noMonitoring) {\n new GuApiGateway5xxPercentageAlarm(scope, {\n app: props.app,\n apiGatewayInstance: this.api,\n snsTopicName: props.monitoringConfiguration.snsTopicName,\n ...props.monitoringConfiguration.http5xxAlarm,\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"api-lambda.js","sourceRoot":"","sources":["../../src/patterns/api-lambda.ts"],"names":[],"mappings":";;;AAAA,+DAA2D;AAG3D,oFAA6F;AAE7F,iDAAwD;AAwBxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAa,WAAY,SAAQ,yBAAgB;IAG/C,YAAY,KAAc,EAAE,EAAU,EAAE,KAAuB;QAC7D,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,GAAG,KAAK;SACT,CAAC,CAAC;QAEH,sGAAsG;QACtG,0DAA0D;QAC1D,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;QAE5C,IAAI,CAAC,GAAG,GAAG,IAAI,8BAAa,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;YAC/C,OAAO,EAAE,gBAAgB;YAEzB,4FAA4F;YAC5F,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;YAE5D,GAAG,KAAK,CAAC,GAAG;SACb,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,YAAY,EAAE;YAC/C,IAAI,mDAA8B,CAAC,KAAK,EAAE;gBACxC,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,kBAAkB,EAAE,IAAI,CAAC,GAAG;gBAC5B,YAAY,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY;gBACxD,GAAG,KAAK,CAAC,uBAAuB,CAAC,YAAY;aAC9C,CAAC,CAAC;SACJ;IACH,CAAC;CACF;AA9BD,kCA8BC","sourcesContent":["import { LambdaRestApi } from \"aws-cdk-lib/aws-apigateway\";\nimport type { LambdaRestApiProps } from \"aws-cdk-lib/aws-apigateway\";\nimport type { NoMonitoring } from \"../constructs/cloudwatch\";\nimport { GuApiGateway5xxPercentageAlarm } from \"../constructs/cloudwatch/api-gateway-alarms\";\nimport type { GuStack } from \"../constructs/core\";\nimport { GuLambdaFunction } from \"../constructs/lambda\";\nimport type { GuFunctionProps } from \"../constructs/lambda\";\nimport type { ApiGatewayAlarms } from \"./api-multiple-lambdas\";\n\ninterface ApiProps extends Omit<LambdaRestApiProps, \"handler\"> {\n id: string;\n}\n\nexport interface GuApiLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n /**\n * [[`LambdaRestApiProps`]] to configure for the lambda.\n */\n api: ApiProps;\n /**\n * Alarm configuration for your API. For more details, see [[`ApiGatewayAlarms`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true }\n * ```\n */\n monitoringConfiguration: NoMonitoring | ApiGatewayAlarms;\n}\n\n/**\n * A pattern to create a Lambda triggered by API Gateway\n * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-lambda-integration.html\n *\n * This pattern should be used if you intend to serve all traffic via a single Lambda\n * (for example, if your Lambda uses an application framework, like https://github.com/vendia/serverless-express).\n * If you need to configure path-based routing to serve different requests with different\n * Lambdas, use the [[`GuApiGatewayWithLambdaByPath`]] pattern instead.\n *\n * For all configuration options, see [[`GuApiLambdaProps`]].\n *\n * Example usage:\n *\n * ```typescript\n * new GuApiLambda(stack, \"my-lambda\", {\n * fileName: \"my-app.zip\",\n * handler: \"handler.ts\",\n * runtime: Runtime.NODEJS_14_X,\n * monitoringConfiguration: {\n * http5xxAlarm: { tolerated5xxPercentage: 5 },\n * snsTopicName: \"alerts-topic\",\n * },\n * app: \"my-app\",\n * api: {\n * id: \"my-api\",\n * description: \"...\",\n * },\n * });\n * ```\n */\nexport class GuApiLambda extends GuLambdaFunction {\n public readonly api: LambdaRestApi;\n\n constructor(scope: GuStack, id: string, props: GuApiLambdaProps) {\n super(scope, id, {\n ...props,\n });\n\n // If we have an alias, use this to ensure that all requests are routed to a published Lambda version.\n // Otherwise, use the latest unpublished version ($LATEST)\n const resourceToInvoke = this.alias ?? this;\n\n this.api = new LambdaRestApi(this, props.api.id, {\n handler: resourceToInvoke,\n\n // Override to avoid clashes as default is just api ID, which is often shared across stages.\n restApiName: `${scope.stack}-${scope.stage}-${props.api.id}`,\n\n ...props.api,\n });\n\n if (!props.monitoringConfiguration.noMonitoring) {\n new GuApiGateway5xxPercentageAlarm(scope, {\n app: props.app,\n apiGatewayInstance: this.api,\n snsTopicName: props.monitoringConfiguration.snsTopicName,\n ...props.monitoringConfiguration.http5xxAlarm,\n });\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"api-multiple-lambdas.d.ts","sourceRoot":"","sources":["../../src/patterns/api-multiple-lambdas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAqB,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAEhF,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAC;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,YAAY,EAAE,iBAAiB,CAAC;IAChC;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,iCAAkC,SAAQ,YAAY,EAAE,WAAW;IAClF;;OAEG;IACH,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;;;;OAOG;IACH,uBAAuB,EAAE,YAAY,GAAG,gBAAgB,CAAC;CAC1D;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,qBAAa,4BAA6B,SAAQ,SAAS;IACzD,SAAgB,GAAG,EAAE,OAAO,CAAC;gBAEjB,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,iCAAiC;CAwBrE"}
1
+ {"version":3,"file":"api-multiple-lambdas.d.ts","sourceRoot":"","sources":["../../src/patterns/api-multiple-lambdas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAqB,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAEhF,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAC;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,YAAY,EAAE,iBAAiB,CAAC;IAChC;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,iCAAkC,SAAQ,YAAY,EAAE,WAAW;IAClF;;OAEG;IACH,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;;;;OAOG;IACH,uBAAuB,EAAE,YAAY,GAAG,gBAAgB,CAAC;CAC1D;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,qBAAa,4BAA6B,SAAQ,SAAS;IACzD,SAAgB,GAAG,EAAE,OAAO,CAAC;gBAEjB,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,iCAAiC;CA2BrE"}
@@ -72,7 +72,10 @@ class GuApiGatewayWithLambdaByPath extends constructs_1.Construct {
72
72
  this.api = apiGateway;
73
73
  props.targets.map((target) => {
74
74
  const resource = apiGateway.root.resourceForPath(target.path);
75
- resource.addMethod(target.httpMethod, new aws_apigateway_1.LambdaIntegration(target.lambda), {
75
+ // If we have an alias, use this to ensure that all requests are routed to a published Lambda version.
76
+ // Otherwise, use the latest unpublished version ($LATEST)
77
+ const lambdaTarget = target.lambda.alias ?? target.lambda;
78
+ resource.addMethod(target.httpMethod, new aws_apigateway_1.LambdaIntegration(lambdaTarget), {
76
79
  apiKeyRequired: target.apiKeyRequired,
77
80
  });
78
81
  });
@@ -1 +1 @@
1
- {"version":3,"file":"api-multiple-lambdas.js","sourceRoot":"","sources":["../../src/patterns/api-multiple-lambdas.ts"],"names":[],"mappings":";;;AACA,+DAAwE;AACxE,2CAAuC;AAEvC,oFAA6F;AAiE7F,SAAS,cAAc,CACrB,uBAAwD;IAExD,OAAsB,uBAAwB,CAAC,YAAY,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAa,4BAA6B,SAAQ,sBAAS;IAGzD,YAAY,KAAc,EAAE,KAAwC;QAClE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,oCAAoC;QAC7D,MAAM,UAAU,GAAG,IAAI,wBAAO,CAAC,KAAK,EAAE,SAAS,EAAE;YAC/C,4FAA4F;YAC5F,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,EAAE;YACzD,GAAG,KAAK;SACT,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC;QACtB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC3B,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9D,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,kCAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;gBAC1E,cAAc,EAAE,MAAM,CAAC,cAAc;aACtC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,uBAAuB,CAAC,EAAE;YAClD,IAAI,mDAA8B,CAAC,KAAK,EAAE;gBACxC,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,kBAAkB,EAAE,UAAU;gBAC9B,YAAY,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY;gBACxD,GAAG,KAAK,CAAC,uBAAuB,CAAC,YAAY;aAC9C,CAAC,CAAC;SACJ;IACH,CAAC;CACF;AA3BD,oEA2BC","sourcesContent":["import type { RestApiProps } from \"aws-cdk-lib/aws-apigateway\";\nimport { LambdaIntegration, RestApi } from \"aws-cdk-lib/aws-apigateway\";\nimport { Construct } from \"constructs\";\nimport type { Http5xxAlarmProps, NoMonitoring } from \"../constructs/cloudwatch\";\nimport { GuApiGateway5xxPercentageAlarm } from \"../constructs/cloudwatch/api-gateway-alarms\";\nimport type { AppIdentity, GuStack } from \"../constructs/core\";\nimport type { GuLambdaFunction } from \"../constructs/lambda\";\n\n/**\n * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods\n */\nexport type HttpMethod = \"GET\" | \"HEAD\" | \"POST\" | \"PUT\" | \"DELETE\" | \"CONNECT\" | \"OPTIONS\" | \"TRACE\" | \"PATCH\";\n\n/**\n * API target props.\n */\nexport interface ApiTarget {\n /**\n * The path for the request (e.g. /test).\n */\n path: string;\n /**\n * The [[`HttpMethod`]] for the target (e.g. GET, POST, PUT).\n */\n httpMethod: HttpMethod;\n /**\n * The Lambda function responsible for handling the request.\n */\n lambda: GuLambdaFunction;\n /**\n * Whether an apiKey is required for this method.\n */\n apiKeyRequired?: true;\n}\n\n/**\n * Alarm props.\n */\nexport interface ApiGatewayAlarms {\n /**\n * (SNS) Topic name where alarm notifications will be sent.\n */\n snsTopicName: string;\n /**\n * Configuration the 5xx alarm.\n */\n http5xxAlarm: Http5xxAlarmProps;\n /**\n * Internal flag - users of this library should ignore this setting.\n */\n noMonitoring?: false;\n}\n\nexport interface GuApiGatewayWithLambdaByPathProps extends RestApiProps, AppIdentity {\n /**\n * A list of [[`ApiTarget`]]s to configure for the API Gateway instance.\n */\n targets: ApiTarget[];\n /**\n * Alarm configuration for your API. For more details, see [[`ApiGatewayAlarms`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true }\n * ```\n */\n monitoringConfiguration: NoMonitoring | ApiGatewayAlarms;\n}\n\nfunction isNoMonitoring(\n monitoringConfiguration: NoMonitoring | ApiGatewayAlarms\n): monitoringConfiguration is NoMonitoring {\n return (<NoMonitoring>monitoringConfiguration).noMonitoring;\n}\n\n/**\n * A pattern to create an API Gateway instance which uses path-based routing to route requests\n * to two or more Lambda functions.\n *\n * This pattern should be used if you need to configure path-based routing to serve different\n * requests with different Lambdas. If you intend to serve all traffic via a single Lambda, use\n * the [[`GuApiLambda`]] pattern instead.\n *\n * Example usage:\n *\n * ```typescript\n * // Configure lambdas\n * const lambdaOne = new GuLambdaFunction(this, \"lambda-one\", {\n * app: \"example-lambda-one\",\n * runtime: Runtime.NODEJS_14_X,\n * handler: \"lambda-one.handler\",\n * fileName: \"lambda-one.zip\",\n * });\n * const lambdaTwo = new GuLambdaFunction(this, \"lambda-two\", {\n * app: \"example-lambda-two\",\n * runtime: Runtime.NODEJS_14_X,\n * handler: \"lambda-two.handler\",\n * fileName: \"lambda-two.zip\",\n * });\n *\n * // Wire up the API\n * new GuApiGatewayWithLambdaByPath(this, {\n * app: \"example-api-gateway-instance\",\n * targets: [\n * {\n * path: \"lambda-one\",\n * httpMethod: \"GET\",\n * lambda: lambdaOne,\n * },\n * {\n * path: \"lambda-two\",\n * httpMethod: \"GET\",\n * lambda: lambdaTwo,\n * },\n * ],\n * // Create an alarm\n * monitoringConfiguration: {\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * }\n * }\n * });\n * ```\n *\n * For all API configuration options, see [[`GuApiGatewayWithLambdaByPathProps`]].\n *\n * For details on configuring the individual Lambda functions, see [[`GuLambdaFunction`]].\n */\nexport class GuApiGatewayWithLambdaByPath extends Construct {\n public readonly api: RestApi;\n\n constructor(scope: GuStack, props: GuApiGatewayWithLambdaByPathProps) {\n super(scope, props.app); // The assumption is `app` is unique\n const apiGateway = new RestApi(scope, \"RestApi\", {\n // Override to avoid clashes as default is just api ID, which is often shared across stages.\n restApiName: `${scope.stack}-${scope.stage}-${props.app}`,\n ...props,\n });\n\n this.api = apiGateway;\n props.targets.map((target) => {\n const resource = apiGateway.root.resourceForPath(target.path);\n resource.addMethod(target.httpMethod, new LambdaIntegration(target.lambda), {\n apiKeyRequired: target.apiKeyRequired,\n });\n });\n if (!isNoMonitoring(props.monitoringConfiguration)) {\n new GuApiGateway5xxPercentageAlarm(scope, {\n app: props.app,\n apiGatewayInstance: apiGateway,\n snsTopicName: props.monitoringConfiguration.snsTopicName,\n ...props.monitoringConfiguration.http5xxAlarm,\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"api-multiple-lambdas.js","sourceRoot":"","sources":["../../src/patterns/api-multiple-lambdas.ts"],"names":[],"mappings":";;;AACA,+DAAwE;AACxE,2CAAuC;AAEvC,oFAA6F;AAiE7F,SAAS,cAAc,CACrB,uBAAwD;IAExD,OAAsB,uBAAwB,CAAC,YAAY,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAa,4BAA6B,SAAQ,sBAAS;IAGzD,YAAY,KAAc,EAAE,KAAwC;QAClE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,oCAAoC;QAC7D,MAAM,UAAU,GAAG,IAAI,wBAAO,CAAC,KAAK,EAAE,SAAS,EAAE;YAC/C,4FAA4F;YAC5F,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,EAAE;YACzD,GAAG,KAAK;SACT,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC;QACtB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC3B,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9D,sGAAsG;YACtG,0DAA0D;YAC1D,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC;YAC1D,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,kCAAiB,CAAC,YAAY,CAAC,EAAE;gBACzE,cAAc,EAAE,MAAM,CAAC,cAAc;aACtC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,uBAAuB,CAAC,EAAE;YAClD,IAAI,mDAA8B,CAAC,KAAK,EAAE;gBACxC,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,kBAAkB,EAAE,UAAU;gBAC9B,YAAY,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY;gBACxD,GAAG,KAAK,CAAC,uBAAuB,CAAC,YAAY;aAC9C,CAAC,CAAC;SACJ;IACH,CAAC;CACF;AA9BD,oEA8BC","sourcesContent":["import type { RestApiProps } from \"aws-cdk-lib/aws-apigateway\";\nimport { LambdaIntegration, RestApi } from \"aws-cdk-lib/aws-apigateway\";\nimport { Construct } from \"constructs\";\nimport type { Http5xxAlarmProps, NoMonitoring } from \"../constructs/cloudwatch\";\nimport { GuApiGateway5xxPercentageAlarm } from \"../constructs/cloudwatch/api-gateway-alarms\";\nimport type { AppIdentity, GuStack } from \"../constructs/core\";\nimport type { GuLambdaFunction } from \"../constructs/lambda\";\n\n/**\n * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods\n */\nexport type HttpMethod = \"GET\" | \"HEAD\" | \"POST\" | \"PUT\" | \"DELETE\" | \"CONNECT\" | \"OPTIONS\" | \"TRACE\" | \"PATCH\";\n\n/**\n * API target props.\n */\nexport interface ApiTarget {\n /**\n * The path for the request (e.g. /test).\n */\n path: string;\n /**\n * The [[`HttpMethod`]] for the target (e.g. GET, POST, PUT).\n */\n httpMethod: HttpMethod;\n /**\n * The Lambda function responsible for handling the request.\n */\n lambda: GuLambdaFunction;\n /**\n * Whether an apiKey is required for this method.\n */\n apiKeyRequired?: true;\n}\n\n/**\n * Alarm props.\n */\nexport interface ApiGatewayAlarms {\n /**\n * (SNS) Topic name where alarm notifications will be sent.\n */\n snsTopicName: string;\n /**\n * Configuration the 5xx alarm.\n */\n http5xxAlarm: Http5xxAlarmProps;\n /**\n * Internal flag - users of this library should ignore this setting.\n */\n noMonitoring?: false;\n}\n\nexport interface GuApiGatewayWithLambdaByPathProps extends RestApiProps, AppIdentity {\n /**\n * A list of [[`ApiTarget`]]s to configure for the API Gateway instance.\n */\n targets: ApiTarget[];\n /**\n * Alarm configuration for your API. For more details, see [[`ApiGatewayAlarms`]].\n *\n * If your team do not use CloudWatch, it's possible to opt-out with the following configuration:\n * ```typescript\n * monitoringConfiguration: { noMonitoring: true }\n * ```\n */\n monitoringConfiguration: NoMonitoring | ApiGatewayAlarms;\n}\n\nfunction isNoMonitoring(\n monitoringConfiguration: NoMonitoring | ApiGatewayAlarms\n): monitoringConfiguration is NoMonitoring {\n return (<NoMonitoring>monitoringConfiguration).noMonitoring;\n}\n\n/**\n * A pattern to create an API Gateway instance which uses path-based routing to route requests\n * to two or more Lambda functions.\n *\n * This pattern should be used if you need to configure path-based routing to serve different\n * requests with different Lambdas. If you intend to serve all traffic via a single Lambda, use\n * the [[`GuApiLambda`]] pattern instead.\n *\n * Example usage:\n *\n * ```typescript\n * // Configure lambdas\n * const lambdaOne = new GuLambdaFunction(this, \"lambda-one\", {\n * app: \"example-lambda-one\",\n * runtime: Runtime.NODEJS_14_X,\n * handler: \"lambda-one.handler\",\n * fileName: \"lambda-one.zip\",\n * });\n * const lambdaTwo = new GuLambdaFunction(this, \"lambda-two\", {\n * app: \"example-lambda-two\",\n * runtime: Runtime.NODEJS_14_X,\n * handler: \"lambda-two.handler\",\n * fileName: \"lambda-two.zip\",\n * });\n *\n * // Wire up the API\n * new GuApiGatewayWithLambdaByPath(this, {\n * app: \"example-api-gateway-instance\",\n * targets: [\n * {\n * path: \"lambda-one\",\n * httpMethod: \"GET\",\n * lambda: lambdaOne,\n * },\n * {\n * path: \"lambda-two\",\n * httpMethod: \"GET\",\n * lambda: lambdaTwo,\n * },\n * ],\n * // Create an alarm\n * monitoringConfiguration: {\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * }\n * }\n * });\n * ```\n *\n * For all API configuration options, see [[`GuApiGatewayWithLambdaByPathProps`]].\n *\n * For details on configuring the individual Lambda functions, see [[`GuLambdaFunction`]].\n */\nexport class GuApiGatewayWithLambdaByPath extends Construct {\n public readonly api: RestApi;\n\n constructor(scope: GuStack, props: GuApiGatewayWithLambdaByPathProps) {\n super(scope, props.app); // The assumption is `app` is unique\n const apiGateway = new RestApi(scope, \"RestApi\", {\n // Override to avoid clashes as default is just api ID, which is often shared across stages.\n restApiName: `${scope.stack}-${scope.stage}-${props.app}`,\n ...props,\n });\n\n this.api = apiGateway;\n props.targets.map((target) => {\n const resource = apiGateway.root.resourceForPath(target.path);\n // If we have an alias, use this to ensure that all requests are routed to a published Lambda version.\n // Otherwise, use the latest unpublished version ($LATEST)\n const lambdaTarget = target.lambda.alias ?? target.lambda;\n resource.addMethod(target.httpMethod, new LambdaIntegration(lambdaTarget), {\n apiKeyRequired: target.apiKeyRequired,\n });\n });\n if (!isNoMonitoring(props.monitoringConfiguration)) {\n new GuApiGateway5xxPercentageAlarm(scope, {\n app: props.app,\n apiGatewayInstance: apiGateway,\n snsTopicName: props.monitoringConfiguration.snsTopicName,\n ...props.monitoringConfiguration.http5xxAlarm,\n });\n }\n }\n}\n"]}
@@ -241,6 +241,12 @@ export interface GuEc2AppProps extends AppIdentity {
241
241
  * Specify custom healthcheck
242
242
  */
243
243
  healthcheck?: ALBHealthCheck;
244
+ /**
245
+ * Set http put response hop limit for the launch template.
246
+ * It can be necessary to raise this value from the default of 1
247
+ * for example when sharing the instance profile with a docker container running on the instance.
248
+ */
249
+ instanceMetadataHopLimit?: number;
244
250
  }
245
251
  /**
246
252
  * Pattern which creates the resources needed to run an application on EC2
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAQ/D,OAAO,KAAK,EAAE,YAAY,EAAS,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE9E,OAAO,KAAK,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAO5F,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAc,MAAM,8BAA8B,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEnF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAmD,MAAM,uBAAuB,CAAC;AAErG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGhE,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,YAAY,EAAE,KAAK,GAAG,iBAAiB,CAAC;IACxC;;OAEG;IACH,uBAAuB,EAAE,OAAO,CAAC;IACjC;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD;;OAEG;IACH,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,MAAM,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC;;OAEG;IACH,uBAAuB,EAAE,MAAM,GAAG,YAAY,CAAC;IAC/C;;;OAGG;IACH,YAAY,EAAE,YAAY,CAAC;IAC3B;;OAEG;IACH,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C;;OAEG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;OAEG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B;;OAEG;IACH,OAAO,EAAE,aAAa,CAAC;IACvB;;OAEG;IACH,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC;;;;OAIG;IACH,GAAG,CAAC,EAAE,IAAI,CAAC;IACX;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;IAE3B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAE1B;;OAEG;IACH,UAAU,CAAC,EAAE;QACX;;;;;;;;;;;;;;;;WAgBG;QACH,OAAO,EAAE,IAAI,CAAC;QACd;;;;WAIG;QACH,MAAM,EAAE,MAAM,CAAC;QACf;;;;;;;;;;WAUG;QACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB;;;;;;;;;WASG;QACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC;;;;;;;;;;;;;;;;;;WAkBG;QACH,6BAA6B,CAAC,EAAE,MAAM,CAAC;KACxC,CAAC;IAEF;;OAEG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAUD;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,SAAS;IASrC,SAAgB,GAAG,EAAE,IAAI,CAAC;IAC1B,SAAgB,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5C,SAAgB,YAAY,EAAE,yBAAyB,CAAC;IACxD,SAAgB,gBAAgB,EAAE,kBAAkB,CAAC;IACrD,SAAgB,QAAQ,EAAE,0BAA0B,CAAC;IACrD,SAAgB,WAAW,EAAE,wBAAwB,CAAC;gBAE1C,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa;CAkTjD"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"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"}
@@ -45,7 +45,7 @@ class GuEc2App extends constructs_1.Construct {
45
45
  constructor(scope, props) {
46
46
  const { access, accessLogging = { enabled: false }, app,
47
47
  // We should update this default once a significant number of apps have migrated to devx-logs
48
- applicationLogging = { enabled: false }, applicationPort, blockDevices, certificateProps, instanceType, monitoringConfiguration, roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] }, scaling: { minimumInstances, maximumInstances = minimumInstances * 2 }, userData, withoutImdsv2, imageRecipe, vpc = ec2_1.GuVpc.fromIdParameter(scope, core_1.AppIdentity.suffixText({ app }, "VPC")), privateSubnets = ec2_1.GuVpc.subnetsFromParameter(scope, { type: ec2_1.SubnetType.PRIVATE, app }), publicSubnets = ec2_1.GuVpc.subnetsFromParameter(scope, { type: ec2_1.SubnetType.PUBLIC, app }), } = props;
48
+ applicationLogging = { enabled: false }, applicationPort, blockDevices, certificateProps, instanceType, monitoringConfiguration, roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] }, scaling: { minimumInstances, maximumInstances = minimumInstances * 2 }, userData, withoutImdsv2, imageRecipe, vpc = ec2_1.GuVpc.fromIdParameter(scope, core_1.AppIdentity.suffixText({ app }, "VPC")), privateSubnets = ec2_1.GuVpc.subnetsFromParameter(scope, { type: ec2_1.SubnetType.PRIVATE, app }), publicSubnets = ec2_1.GuVpc.subnetsFromParameter(scope, { type: ec2_1.SubnetType.PUBLIC, app }), instanceMetadataHopLimit, } = props;
49
49
  super(scope, app); // The assumption is `app` is unique
50
50
  // We should really prevent users from doing this via the type system,
51
51
  // but that requires a breaking change to the API
@@ -81,6 +81,7 @@ class GuEc2App extends constructs_1.Construct {
81
81
  vpcSubnets: { subnets: privateSubnets },
82
82
  ...(blockDevices && { blockDevices }),
83
83
  imageRecipe,
84
+ httpPutResponseHopLimit: instanceMetadataHopLimit,
84
85
  });
85
86
  // This allows automatic shipping of instance Cloud Init logs when using the
86
87
  // `cdk-base` Amigo role on your AMI.
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint \"@guardian/tsdoc-required/tsdoc-required\": 2 -- to begin rolling this out for public APIs. */\nimport crypto from \"crypto\";\nimport { Duration, SecretValue, Tags } from \"aws-cdk-lib\";\nimport type { BlockDevice } from \"aws-cdk-lib/aws-autoscaling\";\nimport { HealthCheck } from \"aws-cdk-lib/aws-autoscaling\";\nimport {\n ProviderAttribute,\n UserPool,\n UserPoolClientIdentityProvider,\n UserPoolIdentityProviderGoogle,\n} from \"aws-cdk-lib/aws-cognito\";\nimport type { InstanceType, IPeer, ISubnet, IVpc } from \"aws-cdk-lib/aws-ec2\";\nimport { Port } from \"aws-cdk-lib/aws-ec2\";\nimport type { HealthCheck as ALBHealthCheck } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport { ApplicationProtocol, ListenerAction } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport { AuthenticateCognitoAction } from \"aws-cdk-lib/aws-elasticloadbalancingv2-actions\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Architecture, Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { Bucket } from \"aws-cdk-lib/aws-s3\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\nimport { AccessScope, MetadataKeys, NAMED_SSM_PARAMETER_PATHS } from \"../../constants\";\nimport { GuCertificate } from \"../../constructs/acm\";\nimport type { GuUserDataProps } from \"../../constructs/autoscaling\";\nimport { GuAutoScalingGroup, GuUserData } from \"../../constructs/autoscaling\";\nimport type { Http5xxAlarmProps, NoMonitoring } from \"../../constructs/cloudwatch\";\nimport { GuAlb5xxPercentageAlarm, GuUnhealthyInstancesAlarm } from \"../../constructs/cloudwatch\";\nimport type { GuStack } from \"../../constructs/core\";\nimport { AppIdentity, GuLoggingStreamNameParameter, GuStringParameter } from \"../../constructs/core\";\nimport { GuHttpsEgressSecurityGroup, GuSecurityGroup, GuVpc, SubnetType } from \"../../constructs/ec2\";\nimport type { GuInstanceRoleProps } from \"../../constructs/iam\";\nimport { GuGetPrivateConfigPolicy, GuInstanceRole } from \"../../constructs/iam\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport {\n GuApplicationLoadBalancer,\n GuApplicationTargetGroup,\n GuHttpsApplicationListener,\n} from \"../../constructs/loadbalancing\";\nimport { AppAccess } from \"../../types\";\nimport type { GuAsgCapacity, GuDomainName } from \"../../types\";\nimport type { AmigoProps } from \"../../types/amigo\";\n\nexport interface AccessLoggingProps {\n /**\n * Enable (load balancer) access logs.\n *\n * Note, you will need to specify a region in your stack declaration to use\n * this.\n * See`https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html#logwbraccesswbrlogsbucket-prefix`\n */\n enabled: boolean;\n /**\n * S3 prefix for the logs.\n *\n * @defaultValue no prefix\n */\n prefix?: string;\n}\n\n/**\n * To ship your application logs to ELK automatically, you must:\n *\n * 1. Set the `enabled` flag to true\n * 2. Include the `cdk-base` Amigo role in your AMI\n * 3. Log to `journald`. We recommend doing this by logging to `stdout` and\n * using `systemd` to start your app\n * 4. Confirm that your [[`systemdUnitName`]] is configured properly.\n *\n * Unless you have explicitly opted-out, appropriate IAM permissions for logging\n * to Kinesis will be configured automatically via the [[`GuEc2App`]] pattern.\n */\nexport interface ApplicationLoggingProps {\n /**\n * Enables forwarding of application logs to the Guardian ELK stack.\n *\n * Note, to work, you will need to also do the following non-CDK things:\n *\n * 1. Include the `cdk-base` Amigo role in your AMI.\n * 2. Log to `journald`. We recommend doing this by logging to `stdout` and\n * using `systemd` to start your app\n * 3. Confirm that your [[`systemdUnitName`]] is configured properly.\n *\n * Unless you have explicitly opted-out, appropriate IAM permissions for\n * logging to Kinesis will be configured automatically via the [[`GuEc2App`]]\n * pattern.\n *\n * @see https://github.com/guardian/amigo/tree/main/roles/cdk-base\n */\n enabled: boolean;\n /**\n * This needs to match the name of your SystemD unit.\n *\n * If your systemd unit is not `<app>.service` set this value.\n *\n * @defaultValue `<app>.service`\n */\n systemdUnitName?: string;\n}\n\n/**\n * @privateRemarks we should rename this to AlarmsProps.\n */\nexport interface Alarms {\n /**\n * Name of the target (SNS Topic) for alarm notifications.\n */\n snsTopicName: string;\n /**\n * Enable the 5xx alarm with settings.\n */\n http5xxAlarm: false | Http5xxAlarmProps;\n /**\n * Enable the unhealthy instances alarm.\n */\n unhealthyInstancesAlarm: boolean;\n /**\n * Internal flag - users of this library should ignore this setting.\n */\n noMonitoring?: false;\n}\n\nexport interface GuEc2AppProps extends AppIdentity {\n /**\n * User data for the autoscaling group.\n */\n userData: GuUserDataProps | string;\n /**\n * Network access restrictions for your load balancer.\n *\n * Note, this merely provides defence in depth; you should, for example, limit\n * access to the VPN and then treat that as sufficient. Instead, use Google\n * Auth for human access, or a suitable machine auth mechanism.\n */\n access: AppAccess;\n /**\n * The port your application runs on.\n */\n applicationPort: number;\n /**\n * Configure IAM roles for autoscaling group EC2 instances.\n */\n roleConfiguration?: GuInstanceRoleProps;\n /**\n * Enable and configure alarms.\n */\n monitoringConfiguration: Alarms | NoMonitoring;\n /**\n * EC2 instance type. Note, ensure your code is built for the same\n * architecture family (arm64 - 'Graviton' instances - or x64).\n */\n instanceType: InstanceType;\n /**\n * Enable and configures application logs.\n */\n applicationLogging?: ApplicationLoggingProps;\n /**\n * Enable and configures access logs.\n */\n accessLogging?: AccessLoggingProps;\n /**\n * Add block devices (additional storage).\n */\n blockDevices?: BlockDevice[];\n /**\n * Autoscaling group min and max sizes.\n */\n scaling: GuAsgCapacity;\n /**\n * Specify certificate for the load balancer.\n */\n certificateProps?: GuDomainName;\n /**\n * Disable imdsv2. Most of the time you should not set this.\n *\n * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html\n */\n withoutImdsv2?: boolean;\n /**\n * Configure Amigo image recipe.\n */\n imageRecipe?: string | AmigoProps;\n /**\n * Specify the VPC to use.\n *\n * @see https://github.com/guardian/aws-account-setup\n */\n vpc?: IVpc;\n /**\n * Specify private subnets if using a non-default VPC or (generally\n * discouraged) to limit to a subset of the available subnets.\n */\n privateSubnets?: ISubnet[];\n\n /**\n * Specify private subnets if using a non-default VPC or (generally\n * discouraged) to limit to a subset of the available subnets.\n */\n publicSubnets?: ISubnet[];\n\n /**\n * Configure Google Auth.\n */\n googleAuth?: {\n /**\n * Enables Google Auth (via Cognito). **Additional MANUAL steps required -\n * see below.**\n *\n * Limits access to members of the allowed Google groups.\n *\n * Note, this does not currently support simultaneous machine access, so\n * only set to true if you only require staff access to your service, or are\n * supporting machine access in some other way.\n *\n * MANUAL STEPS: to get this to work, we need a Google Project and\n * associated credentials. Full instructions can be found here:\n *\n * https://docs.google.com/document/d/1_k1FSE52AZHXufWLTiKTI3xy5cGpziyHazSHTKrYfco/edit?usp=sharing\n *\n * DevX hope to automate this process in the near future.\n */\n enabled: true;\n /**\n * The domain users will access your service.\n *\n * Set this to the same as for certificateProps.\n */\n domain: string;\n /**\n * Groups used for membership checks.\n *\n * If specified, cannot be empty. Users must be a member of at least one\n * group to gain access.\n *\n * WARNING: groups must be specified with the `guardian.co.uk` domain, even\n * if that is the non-idiomatic choice for daily use.\n *\n * @defaultValue [`engineering@guardian.co.uk`]\n */\n allowedGroups?: string[];\n /**\n * The number of minutes before the session expires.\n *\n * Set this value to a safe period of time that revoked users\n * sessions will continue to function.\n *\n * NOTE: This value cannot be larger than 60 minutes.\n *\n * @defaultValue 15\n */\n sessionTimeoutInMinutes?: number;\n /**\n * Secrets Manager path containing Google OAuth2 Client credentials.\n *\n * NOTE: you do not need to set this value, but you DO need to generate and\n * store the associated credentials in Secrets Manager.\n *\n * Credentials should be stored in Secrets Manager as JSON:\n *\n * ```json\n * {\n * \"clientId\": \"my-client-id\",\n * \"clientSecret\": \"my-client-secret\"\n * }\n * ```\n *\n * @see `googleAuth.enabled` for how to generate.\n *\n * @defaultValue /:STAGE/:stack/:app/google-auth-credentials\n */\n credentialsSecretsManagerPath?: string;\n };\n\n /**\n * Specify custom healthcheck\n */\n healthcheck?: ALBHealthCheck;\n}\n\nfunction restrictedCidrRanges(ranges: IPeer[]) {\n return ranges.map((range) => ({\n range,\n port: Port.tcp(443),\n description: `Allow access on port 443 from ${range.uniqueId}`,\n }));\n}\n\n/**\n * Pattern which creates the resources needed to run an application on EC2\n * behind a load balancer. For convenience, you may wish to use [[`GuPlayApp`]]\n * or [[`GuNodeApp`]], which extend this class.\n *\n * See props for further details.\n */\nexport class GuEc2App extends Construct {\n /*\n * These are public for now, as this allows users to\n * modify these constructs as desired to fit their\n * specific needs.\n * In the future, we might build functionality to better enable users\n * to access in-pattern constructs, but this would allow teams to be unblocked\n * in the short term.\n * */\n public readonly vpc: IVpc;\n public readonly certificate?: GuCertificate;\n public readonly loadBalancer: GuApplicationLoadBalancer;\n public readonly autoScalingGroup: GuAutoScalingGroup;\n public readonly listener: GuHttpsApplicationListener;\n public readonly targetGroup: GuApplicationTargetGroup;\n\n constructor(scope: GuStack, props: GuEc2AppProps) {\n const {\n access,\n accessLogging = { enabled: false },\n app,\n // We should update this default once a significant number of apps have migrated to devx-logs\n applicationLogging = { enabled: false },\n applicationPort,\n blockDevices,\n certificateProps,\n instanceType,\n monitoringConfiguration,\n roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] },\n scaling: { minimumInstances, maximumInstances = minimumInstances * 2 },\n userData,\n withoutImdsv2,\n imageRecipe,\n vpc = GuVpc.fromIdParameter(scope, AppIdentity.suffixText({ app }, \"VPC\")),\n privateSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PRIVATE, app }),\n publicSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PUBLIC, app }),\n } = props;\n\n super(scope, app); // The assumption is `app` is unique\n\n // We should really prevent users from doing this via the type system,\n // but that requires a breaking change to the API\n if (applicationLogging.enabled && roleConfiguration.withoutLogShipping) {\n throw new Error(\n \"Application logging has been enabled (via the `applicationLogging` prop) but your `roleConfiguration` sets \" +\n \"`withoutLogShipping` to true. Please turn off application logging or remove `withoutLogShipping`\"\n );\n }\n\n AppAccess.validate(access);\n\n const certificate =\n typeof certificateProps !== \"undefined\"\n ? new GuCertificate(scope, {\n app,\n domainName: certificateProps.domainName,\n hostedZoneId: certificateProps.hostedZoneId,\n })\n : undefined;\n\n const maybePrivateConfigPolicy =\n typeof userData !== \"string\" && userData.configuration\n ? [new GuGetPrivateConfigPolicy(scope, \"GetPrivateConfigFromS3Policy\", userData.configuration)]\n : [];\n\n const mergedRoleConfiguration: GuInstanceRoleProps = {\n withoutLogShipping: roleConfiguration.withoutLogShipping,\n additionalPolicies: maybePrivateConfigPolicy.concat(roleConfiguration.additionalPolicies ?? []),\n };\n\n const autoScalingGroup = new GuAutoScalingGroup(scope, \"AutoScalingGroup\", {\n app,\n vpc,\n instanceType,\n minimumInstances,\n maximumInstances,\n withoutImdsv2,\n role: new GuInstanceRole(scope, { app, ...mergedRoleConfiguration }),\n healthCheck: HealthCheck.elb({ grace: Duration.minutes(2) }), // should this be defaulted at pattern or construct level?\n userData: typeof userData !== \"string\" ? new GuUserData(scope, { app, ...userData }).userData : userData,\n vpcSubnets: { subnets: privateSubnets },\n ...(blockDevices && { blockDevices }),\n imageRecipe,\n });\n\n // This allows automatic shipping of instance Cloud Init logs when using the\n // `cdk-base` Amigo role on your AMI.\n Tags.of(autoScalingGroup).add(\n MetadataKeys.LOG_KINESIS_STREAM_NAME,\n GuLoggingStreamNameParameter.getInstance(scope).valueAsString\n );\n\n if (applicationLogging.enabled) {\n // This allows automatic shipping of application logs when using the\n // `cdk-base` Amigo role on your AMI.\n Tags.of(autoScalingGroup).add(\n MetadataKeys.SYSTEMD_UNIT,\n applicationLogging.systemdUnitName ? `${applicationLogging.systemdUnitName}.service` : `${app}.service`\n );\n }\n\n const loadBalancer = new GuApplicationLoadBalancer(scope, \"LoadBalancer\", {\n app,\n vpc,\n // Setting internetFacing to true does not necessarily allow public access to the load balancer itself. That is handled by the listener's `open` prop.\n internetFacing: access.scope !== AccessScope.INTERNAL,\n vpcSubnets: {\n subnets: access.scope === AccessScope.INTERNAL ? privateSubnets : publicSubnets,\n },\n });\n\n if (accessLogging.enabled) {\n const accessLoggingBucket = new GuStringParameter(scope, \"AccessLoggingBucket\", {\n description: NAMED_SSM_PARAMETER_PATHS.AccessLoggingBucket.description,\n default: NAMED_SSM_PARAMETER_PATHS.AccessLoggingBucket.path,\n fromSSM: true,\n });\n\n loadBalancer.logAccessLogs(\n Bucket.fromBucketName(\n scope,\n AppIdentity.suffixText(props, \"AccessLoggingBucket\"),\n accessLoggingBucket.valueAsString\n ),\n accessLogging.prefix\n );\n }\n\n const targetGroup = new GuApplicationTargetGroup(scope, \"TargetGroup\", {\n app,\n vpc,\n protocol: ApplicationProtocol.HTTP,\n targets: [autoScalingGroup],\n port: applicationPort,\n healthCheck: props.healthcheck,\n });\n\n const listener = new GuHttpsApplicationListener(scope, \"Listener\", {\n app,\n loadBalancer,\n certificate,\n targetGroup,\n // When open=true, AWS will create a security group which allows all inbound traffic over HTTPS\n open: access.scope === AccessScope.PUBLIC && typeof certificate !== \"undefined\",\n });\n\n // Since AWS won't create a security group automatically when open=false, we need to add our own\n if (access.scope !== AccessScope.PUBLIC) {\n loadBalancer.addSecurityGroup(\n new GuSecurityGroup(scope, `${access.scope}IngressSecurityGroup`, {\n app,\n vpc,\n description: \"Allow restricted ingress from CIDR ranges\",\n allowAllOutbound: false,\n ingresses: restrictedCidrRanges(access.cidrRanges),\n })\n );\n }\n\n if (!monitoringConfiguration.noMonitoring) {\n const { http5xxAlarm, snsTopicName, unhealthyInstancesAlarm } = monitoringConfiguration;\n\n if (http5xxAlarm) {\n new GuAlb5xxPercentageAlarm(scope, {\n app,\n loadBalancer,\n snsTopicName,\n ...http5xxAlarm,\n });\n }\n if (unhealthyInstancesAlarm) {\n new GuUnhealthyInstancesAlarm(scope, {\n app,\n targetGroup,\n snsTopicName,\n });\n }\n }\n\n if (props.googleAuth?.enabled) {\n const prefix = `/${scope.stage}/${scope.stack}/${app}`;\n\n const {\n allowedGroups = [\"engineering@guardian.co.uk\"],\n sessionTimeoutInMinutes = 15,\n credentialsSecretsManagerPath = `${prefix}/google-auth-credentials`,\n } = props.googleAuth;\n\n if (sessionTimeoutInMinutes > 60) {\n throw new Error(\"googleAuth.sessionTimeoutInMinutes must be <= 60!\");\n }\n\n if (allowedGroups.length < 1) {\n throw new Error(\"googleAuth.allowedGroups cannot be empty!\");\n }\n\n if (allowedGroups.find((group) => !group.endsWith(\"@guardian.co.uk\"))) {\n throw new Error(\"googleAuth.allowedGroups must use the @guardian.co.uk domain.\");\n }\n\n const deployToolsAccountId = StringParameter.fromStringParameterName(\n scope,\n \"deploy-tools-account-id-parameter\",\n NAMED_SSM_PARAMETER_PATHS.DeployToolsAccountId.path\n );\n\n // See https://github.com/guardian/cognito-auth-lambdas for the source\n // code here. ARN format is:\n // arn:aws:lambda:aws-region:acct-id:function:helloworld.\n const gatekeeperFunctionArn = `arn:aws:lambda:eu-west-1:${deployToolsAccountId.stringValue}:function:deploy-PROD-gatekeeper-lambda`;\n\n // Note, handler and filename must match here:\n // https://github.com/guardian/cognito-auth-lambdas.\n const authLambda = new GuLambdaFunction(scope, \"auth-lambda\", {\n app: app,\n memorySize: 128,\n handler: \"devx-cognito-lambda-amd64-v1\",\n runtime: Runtime.GO_1_X,\n fileName: \"deploy/INFRA/cognito-lambda/devx-cognito-lambda-amd64-v1.zip\",\n withoutFilePrefix: true,\n withoutArtifactUpload: true,\n bucketNamePath: NAMED_SSM_PARAMETER_PATHS.OrganisationDistributionBucket.path,\n architecture: Architecture.X86_64,\n environment: {\n ALLOWED_GROUPS: allowedGroups.join(\",\"),\n GATEKEEPER_FUNCTION_ARN: gatekeeperFunctionArn,\n },\n });\n\n authLambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"lambda:InvokeFunction\"],\n resources: [gatekeeperFunctionArn],\n })\n );\n\n // Cognito user pool. We require both lambdas: pre-sign-up runs the first\n // time a user attempts to authenticate (before they exist in the User\n // Pool); pre-auth runs in subsequent authentication flows.\n const userPool = new UserPool(this, \"user-pool\", {\n lambdaTriggers: {\n preAuthentication: authLambda,\n preSignUp: authLambda,\n },\n });\n\n // These help ensure domain is deterministic but also unique. Key\n // assumption is that app/stack/stage combo are unique within Guardian.\n const domainPrefix = `com-gu-${app.toLowerCase()}-${scope.stage.toLowerCase()}`;\n const suffix = crypto.createHash(\"md5\").update(domainPrefix).digest(\"hex\");\n\n const userPoolDomain = userPool.addDomain(\"domain\", {\n cognitoDomain: {\n domainPrefix: `${domainPrefix}-${suffix}`,\n },\n });\n\n const clientId = SecretValue.secretsManager(credentialsSecretsManagerPath, { jsonField: \"clientId\" });\n const clientSecret = SecretValue.secretsManager(credentialsSecretsManagerPath, { jsonField: \"clientSecret\" });\n\n const userPoolIdp = new UserPoolIdentityProviderGoogle(scope, \"google-idp\", {\n userPool: userPool,\n clientId: clientId.toString(),\n clientSecret: clientSecret.toString(),\n attributeMapping: {\n email: ProviderAttribute.GOOGLE_EMAIL,\n givenName: ProviderAttribute.GOOGLE_GIVEN_NAME,\n familyName: ProviderAttribute.GOOGLE_FAMILY_NAME,\n profilePicture: ProviderAttribute.GOOGLE_PICTURE,\n custom: {\n name: ProviderAttribute.GOOGLE_NAME,\n },\n },\n scopes: [\"openid\", \"email\", \"profile\"],\n });\n\n const userPoolClient = userPool.addClient(\"alb-client\", {\n supportedIdentityProviders: [UserPoolClientIdentityProvider.GOOGLE],\n generateSecret: true,\n oAuth: {\n callbackUrls: [`https://${props.googleAuth.domain}/oauth2/idpresponse`],\n },\n\n // Note: id and access validity token validity cannot be less than one\n // hour (this is the cognito cookie duration). To quickly invalidate\n // credentials, disable the user in Cognito. It might be that we want to\n // parameterise these going forward, but that would require Infosec\n // discussion.\n idTokenValidity: Duration.hours(1),\n accessTokenValidity: Duration.hours(1),\n refreshTokenValidity: Duration.days(7),\n });\n\n userPoolClient.node.addDependency(userPoolIdp);\n\n listener.addAction(\"CognitoAuth\", {\n action: new AuthenticateCognitoAction({\n userPool: userPool,\n userPoolClient: userPoolClient,\n userPoolDomain: userPoolDomain,\n next: ListenerAction.forward([targetGroup]),\n sessionTimeout: Duration.minutes(sessionTimeoutInMinutes),\n }),\n });\n\n // Need to give the ALB outbound access on 443 for the IdP endpoints.\n const idpEgressSecurityGroup = new GuHttpsEgressSecurityGroup(scope, \"ldp-access\", {\n app,\n vpc,\n });\n\n loadBalancer.addSecurityGroup(idpEgressSecurityGroup);\n }\n\n this.vpc = vpc;\n this.certificate = certificate;\n this.loadBalancer = loadBalancer;\n this.autoScalingGroup = autoScalingGroup;\n this.listener = listener;\n this.targetGroup = targetGroup;\n }\n}\n"]}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint \"@guardian/tsdoc-required/tsdoc-required\": 2 -- to begin rolling this out for public APIs. */\nimport crypto from \"crypto\";\nimport { Duration, SecretValue, Tags } from \"aws-cdk-lib\";\nimport type { BlockDevice } from \"aws-cdk-lib/aws-autoscaling\";\nimport { HealthCheck } from \"aws-cdk-lib/aws-autoscaling\";\nimport {\n ProviderAttribute,\n UserPool,\n UserPoolClientIdentityProvider,\n UserPoolIdentityProviderGoogle,\n} from \"aws-cdk-lib/aws-cognito\";\nimport type { InstanceType, IPeer, ISubnet, IVpc } from \"aws-cdk-lib/aws-ec2\";\nimport { Port } from \"aws-cdk-lib/aws-ec2\";\nimport type { HealthCheck as ALBHealthCheck } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport { ApplicationProtocol, ListenerAction } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport { AuthenticateCognitoAction } from \"aws-cdk-lib/aws-elasticloadbalancingv2-actions\";\nimport { Effect, PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Architecture, Runtime } from \"aws-cdk-lib/aws-lambda\";\nimport { Bucket } from \"aws-cdk-lib/aws-s3\";\nimport { StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { Construct } from \"constructs\";\nimport { AccessScope, MetadataKeys, NAMED_SSM_PARAMETER_PATHS } from \"../../constants\";\nimport { GuCertificate } from \"../../constructs/acm\";\nimport type { GuUserDataProps } from \"../../constructs/autoscaling\";\nimport { GuAutoScalingGroup, GuUserData } from \"../../constructs/autoscaling\";\nimport type { Http5xxAlarmProps, NoMonitoring } from \"../../constructs/cloudwatch\";\nimport { GuAlb5xxPercentageAlarm, GuUnhealthyInstancesAlarm } from \"../../constructs/cloudwatch\";\nimport type { GuStack } from \"../../constructs/core\";\nimport { AppIdentity, GuLoggingStreamNameParameter, GuStringParameter } from \"../../constructs/core\";\nimport { GuHttpsEgressSecurityGroup, GuSecurityGroup, GuVpc, SubnetType } from \"../../constructs/ec2\";\nimport type { GuInstanceRoleProps } from \"../../constructs/iam\";\nimport { GuGetPrivateConfigPolicy, GuInstanceRole } from \"../../constructs/iam\";\nimport { GuLambdaFunction } from \"../../constructs/lambda\";\nimport {\n GuApplicationLoadBalancer,\n GuApplicationTargetGroup,\n GuHttpsApplicationListener,\n} from \"../../constructs/loadbalancing\";\nimport { AppAccess } from \"../../types\";\nimport type { GuAsgCapacity, GuDomainName } from \"../../types\";\nimport type { AmigoProps } from \"../../types/amigo\";\n\nexport interface AccessLoggingProps {\n /**\n * Enable (load balancer) access logs.\n *\n * Note, you will need to specify a region in your stack declaration to use\n * this.\n * See`https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html#logwbraccesswbrlogsbucket-prefix`\n */\n enabled: boolean;\n /**\n * S3 prefix for the logs.\n *\n * @defaultValue no prefix\n */\n prefix?: string;\n}\n\n/**\n * To ship your application logs to ELK automatically, you must:\n *\n * 1. Set the `enabled` flag to true\n * 2. Include the `cdk-base` Amigo role in your AMI\n * 3. Log to `journald`. We recommend doing this by logging to `stdout` and\n * using `systemd` to start your app\n * 4. Confirm that your [[`systemdUnitName`]] is configured properly.\n *\n * Unless you have explicitly opted-out, appropriate IAM permissions for logging\n * to Kinesis will be configured automatically via the [[`GuEc2App`]] pattern.\n */\nexport interface ApplicationLoggingProps {\n /**\n * Enables forwarding of application logs to the Guardian ELK stack.\n *\n * Note, to work, you will need to also do the following non-CDK things:\n *\n * 1. Include the `cdk-base` Amigo role in your AMI.\n * 2. Log to `journald`. We recommend doing this by logging to `stdout` and\n * using `systemd` to start your app\n * 3. Confirm that your [[`systemdUnitName`]] is configured properly.\n *\n * Unless you have explicitly opted-out, appropriate IAM permissions for\n * logging to Kinesis will be configured automatically via the [[`GuEc2App`]]\n * pattern.\n *\n * @see https://github.com/guardian/amigo/tree/main/roles/cdk-base\n */\n enabled: boolean;\n /**\n * This needs to match the name of your SystemD unit.\n *\n * If your systemd unit is not `<app>.service` set this value.\n *\n * @defaultValue `<app>.service`\n */\n systemdUnitName?: string;\n}\n\n/**\n * @privateRemarks we should rename this to AlarmsProps.\n */\nexport interface Alarms {\n /**\n * Name of the target (SNS Topic) for alarm notifications.\n */\n snsTopicName: string;\n /**\n * Enable the 5xx alarm with settings.\n */\n http5xxAlarm: false | Http5xxAlarmProps;\n /**\n * Enable the unhealthy instances alarm.\n */\n unhealthyInstancesAlarm: boolean;\n /**\n * Internal flag - users of this library should ignore this setting.\n */\n noMonitoring?: false;\n}\n\nexport interface GuEc2AppProps extends AppIdentity {\n /**\n * User data for the autoscaling group.\n */\n userData: GuUserDataProps | string;\n /**\n * Network access restrictions for your load balancer.\n *\n * Note, this merely provides defence in depth; you should, for example, limit\n * access to the VPN and then treat that as sufficient. Instead, use Google\n * Auth for human access, or a suitable machine auth mechanism.\n */\n access: AppAccess;\n /**\n * The port your application runs on.\n */\n applicationPort: number;\n /**\n * Configure IAM roles for autoscaling group EC2 instances.\n */\n roleConfiguration?: GuInstanceRoleProps;\n /**\n * Enable and configure alarms.\n */\n monitoringConfiguration: Alarms | NoMonitoring;\n /**\n * EC2 instance type. Note, ensure your code is built for the same\n * architecture family (arm64 - 'Graviton' instances - or x64).\n */\n instanceType: InstanceType;\n /**\n * Enable and configures application logs.\n */\n applicationLogging?: ApplicationLoggingProps;\n /**\n * Enable and configures access logs.\n */\n accessLogging?: AccessLoggingProps;\n /**\n * Add block devices (additional storage).\n */\n blockDevices?: BlockDevice[];\n /**\n * Autoscaling group min and max sizes.\n */\n scaling: GuAsgCapacity;\n /**\n * Specify certificate for the load balancer.\n */\n certificateProps?: GuDomainName;\n /**\n * Disable imdsv2. Most of the time you should not set this.\n *\n * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html\n */\n withoutImdsv2?: boolean;\n /**\n * Configure Amigo image recipe.\n */\n imageRecipe?: string | AmigoProps;\n /**\n * Specify the VPC to use.\n *\n * @see https://github.com/guardian/aws-account-setup\n */\n vpc?: IVpc;\n /**\n * Specify private subnets if using a non-default VPC or (generally\n * discouraged) to limit to a subset of the available subnets.\n */\n privateSubnets?: ISubnet[];\n\n /**\n * Specify private subnets if using a non-default VPC or (generally\n * discouraged) to limit to a subset of the available subnets.\n */\n publicSubnets?: ISubnet[];\n\n /**\n * Configure Google Auth.\n */\n googleAuth?: {\n /**\n * Enables Google Auth (via Cognito). **Additional MANUAL steps required -\n * see below.**\n *\n * Limits access to members of the allowed Google groups.\n *\n * Note, this does not currently support simultaneous machine access, so\n * only set to true if you only require staff access to your service, or are\n * supporting machine access in some other way.\n *\n * MANUAL STEPS: to get this to work, we need a Google Project and\n * associated credentials. Full instructions can be found here:\n *\n * https://docs.google.com/document/d/1_k1FSE52AZHXufWLTiKTI3xy5cGpziyHazSHTKrYfco/edit?usp=sharing\n *\n * DevX hope to automate this process in the near future.\n */\n enabled: true;\n /**\n * The domain users will access your service.\n *\n * Set this to the same as for certificateProps.\n */\n domain: string;\n /**\n * Groups used for membership checks.\n *\n * If specified, cannot be empty. Users must be a member of at least one\n * group to gain access.\n *\n * WARNING: groups must be specified with the `guardian.co.uk` domain, even\n * if that is the non-idiomatic choice for daily use.\n *\n * @defaultValue [`engineering@guardian.co.uk`]\n */\n allowedGroups?: string[];\n /**\n * The number of minutes before the session expires.\n *\n * Set this value to a safe period of time that revoked users\n * sessions will continue to function.\n *\n * NOTE: This value cannot be larger than 60 minutes.\n *\n * @defaultValue 15\n */\n sessionTimeoutInMinutes?: number;\n /**\n * Secrets Manager path containing Google OAuth2 Client credentials.\n *\n * NOTE: you do not need to set this value, but you DO need to generate and\n * store the associated credentials in Secrets Manager.\n *\n * Credentials should be stored in Secrets Manager as JSON:\n *\n * ```json\n * {\n * \"clientId\": \"my-client-id\",\n * \"clientSecret\": \"my-client-secret\"\n * }\n * ```\n *\n * @see `googleAuth.enabled` for how to generate.\n *\n * @defaultValue /:STAGE/:stack/:app/google-auth-credentials\n */\n credentialsSecretsManagerPath?: string;\n };\n\n /**\n * Specify custom healthcheck\n */\n healthcheck?: ALBHealthCheck;\n\n /**\n * Set http put response hop limit for the launch template.\n * It can be necessary to raise this value from the default of 1\n * for example when sharing the instance profile with a docker container running on the instance.\n */\n instanceMetadataHopLimit?: number;\n}\n\nfunction restrictedCidrRanges(ranges: IPeer[]) {\n return ranges.map((range) => ({\n range,\n port: Port.tcp(443),\n description: `Allow access on port 443 from ${range.uniqueId}`,\n }));\n}\n\n/**\n * Pattern which creates the resources needed to run an application on EC2\n * behind a load balancer. For convenience, you may wish to use [[`GuPlayApp`]]\n * or [[`GuNodeApp`]], which extend this class.\n *\n * See props for further details.\n */\nexport class GuEc2App extends Construct {\n /*\n * These are public for now, as this allows users to\n * modify these constructs as desired to fit their\n * specific needs.\n * In the future, we might build functionality to better enable users\n * to access in-pattern constructs, but this would allow teams to be unblocked\n * in the short term.\n * */\n public readonly vpc: IVpc;\n public readonly certificate?: GuCertificate;\n public readonly loadBalancer: GuApplicationLoadBalancer;\n public readonly autoScalingGroup: GuAutoScalingGroup;\n public readonly listener: GuHttpsApplicationListener;\n public readonly targetGroup: GuApplicationTargetGroup;\n\n constructor(scope: GuStack, props: GuEc2AppProps) {\n const {\n access,\n accessLogging = { enabled: false },\n app,\n // We should update this default once a significant number of apps have migrated to devx-logs\n applicationLogging = { enabled: false },\n applicationPort,\n blockDevices,\n certificateProps,\n instanceType,\n monitoringConfiguration,\n roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] },\n scaling: { minimumInstances, maximumInstances = minimumInstances * 2 },\n userData,\n withoutImdsv2,\n imageRecipe,\n vpc = GuVpc.fromIdParameter(scope, AppIdentity.suffixText({ app }, \"VPC\")),\n privateSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PRIVATE, app }),\n publicSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PUBLIC, app }),\n instanceMetadataHopLimit,\n } = props;\n\n super(scope, app); // The assumption is `app` is unique\n\n // We should really prevent users from doing this via the type system,\n // but that requires a breaking change to the API\n if (applicationLogging.enabled && roleConfiguration.withoutLogShipping) {\n throw new Error(\n \"Application logging has been enabled (via the `applicationLogging` prop) but your `roleConfiguration` sets \" +\n \"`withoutLogShipping` to true. Please turn off application logging or remove `withoutLogShipping`\"\n );\n }\n\n AppAccess.validate(access);\n\n const certificate =\n typeof certificateProps !== \"undefined\"\n ? new GuCertificate(scope, {\n app,\n domainName: certificateProps.domainName,\n hostedZoneId: certificateProps.hostedZoneId,\n })\n : undefined;\n\n const maybePrivateConfigPolicy =\n typeof userData !== \"string\" && userData.configuration\n ? [new GuGetPrivateConfigPolicy(scope, \"GetPrivateConfigFromS3Policy\", userData.configuration)]\n : [];\n\n const mergedRoleConfiguration: GuInstanceRoleProps = {\n withoutLogShipping: roleConfiguration.withoutLogShipping,\n additionalPolicies: maybePrivateConfigPolicy.concat(roleConfiguration.additionalPolicies ?? []),\n };\n\n const autoScalingGroup = new GuAutoScalingGroup(scope, \"AutoScalingGroup\", {\n app,\n vpc,\n instanceType,\n minimumInstances,\n maximumInstances,\n withoutImdsv2,\n role: new GuInstanceRole(scope, { app, ...mergedRoleConfiguration }),\n healthCheck: HealthCheck.elb({ grace: Duration.minutes(2) }), // should this be defaulted at pattern or construct level?\n userData: typeof userData !== \"string\" ? new GuUserData(scope, { app, ...userData }).userData : userData,\n vpcSubnets: { subnets: privateSubnets },\n ...(blockDevices && { blockDevices }),\n imageRecipe,\n httpPutResponseHopLimit: instanceMetadataHopLimit,\n });\n\n // This allows automatic shipping of instance Cloud Init logs when using the\n // `cdk-base` Amigo role on your AMI.\n Tags.of(autoScalingGroup).add(\n MetadataKeys.LOG_KINESIS_STREAM_NAME,\n GuLoggingStreamNameParameter.getInstance(scope).valueAsString\n );\n\n if (applicationLogging.enabled) {\n // This allows automatic shipping of application logs when using the\n // `cdk-base` Amigo role on your AMI.\n Tags.of(autoScalingGroup).add(\n MetadataKeys.SYSTEMD_UNIT,\n applicationLogging.systemdUnitName ? `${applicationLogging.systemdUnitName}.service` : `${app}.service`\n );\n }\n\n const loadBalancer = new GuApplicationLoadBalancer(scope, \"LoadBalancer\", {\n app,\n vpc,\n // Setting internetFacing to true does not necessarily allow public access to the load balancer itself. That is handled by the listener's `open` prop.\n internetFacing: access.scope !== AccessScope.INTERNAL,\n vpcSubnets: {\n subnets: access.scope === AccessScope.INTERNAL ? privateSubnets : publicSubnets,\n },\n });\n\n if (accessLogging.enabled) {\n const accessLoggingBucket = new GuStringParameter(scope, \"AccessLoggingBucket\", {\n description: NAMED_SSM_PARAMETER_PATHS.AccessLoggingBucket.description,\n default: NAMED_SSM_PARAMETER_PATHS.AccessLoggingBucket.path,\n fromSSM: true,\n });\n\n loadBalancer.logAccessLogs(\n Bucket.fromBucketName(\n scope,\n AppIdentity.suffixText(props, \"AccessLoggingBucket\"),\n accessLoggingBucket.valueAsString\n ),\n accessLogging.prefix\n );\n }\n\n const targetGroup = new GuApplicationTargetGroup(scope, \"TargetGroup\", {\n app,\n vpc,\n protocol: ApplicationProtocol.HTTP,\n targets: [autoScalingGroup],\n port: applicationPort,\n healthCheck: props.healthcheck,\n });\n\n const listener = new GuHttpsApplicationListener(scope, \"Listener\", {\n app,\n loadBalancer,\n certificate,\n targetGroup,\n // When open=true, AWS will create a security group which allows all inbound traffic over HTTPS\n open: access.scope === AccessScope.PUBLIC && typeof certificate !== \"undefined\",\n });\n\n // Since AWS won't create a security group automatically when open=false, we need to add our own\n if (access.scope !== AccessScope.PUBLIC) {\n loadBalancer.addSecurityGroup(\n new GuSecurityGroup(scope, `${access.scope}IngressSecurityGroup`, {\n app,\n vpc,\n description: \"Allow restricted ingress from CIDR ranges\",\n allowAllOutbound: false,\n ingresses: restrictedCidrRanges(access.cidrRanges),\n })\n );\n }\n\n if (!monitoringConfiguration.noMonitoring) {\n const { http5xxAlarm, snsTopicName, unhealthyInstancesAlarm } = monitoringConfiguration;\n\n if (http5xxAlarm) {\n new GuAlb5xxPercentageAlarm(scope, {\n app,\n loadBalancer,\n snsTopicName,\n ...http5xxAlarm,\n });\n }\n if (unhealthyInstancesAlarm) {\n new GuUnhealthyInstancesAlarm(scope, {\n app,\n targetGroup,\n snsTopicName,\n });\n }\n }\n\n if (props.googleAuth?.enabled) {\n const prefix = `/${scope.stage}/${scope.stack}/${app}`;\n\n const {\n allowedGroups = [\"engineering@guardian.co.uk\"],\n sessionTimeoutInMinutes = 15,\n credentialsSecretsManagerPath = `${prefix}/google-auth-credentials`,\n } = props.googleAuth;\n\n if (sessionTimeoutInMinutes > 60) {\n throw new Error(\"googleAuth.sessionTimeoutInMinutes must be <= 60!\");\n }\n\n if (allowedGroups.length < 1) {\n throw new Error(\"googleAuth.allowedGroups cannot be empty!\");\n }\n\n if (allowedGroups.find((group) => !group.endsWith(\"@guardian.co.uk\"))) {\n throw new Error(\"googleAuth.allowedGroups must use the @guardian.co.uk domain.\");\n }\n\n const deployToolsAccountId = StringParameter.fromStringParameterName(\n scope,\n \"deploy-tools-account-id-parameter\",\n NAMED_SSM_PARAMETER_PATHS.DeployToolsAccountId.path\n );\n\n // See https://github.com/guardian/cognito-auth-lambdas for the source\n // code here. ARN format is:\n // arn:aws:lambda:aws-region:acct-id:function:helloworld.\n const gatekeeperFunctionArn = `arn:aws:lambda:eu-west-1:${deployToolsAccountId.stringValue}:function:deploy-PROD-gatekeeper-lambda`;\n\n // Note, handler and filename must match here:\n // https://github.com/guardian/cognito-auth-lambdas.\n const authLambda = new GuLambdaFunction(scope, \"auth-lambda\", {\n app: app,\n memorySize: 128,\n handler: \"devx-cognito-lambda-amd64-v1\",\n runtime: Runtime.GO_1_X,\n fileName: \"deploy/INFRA/cognito-lambda/devx-cognito-lambda-amd64-v1.zip\",\n withoutFilePrefix: true,\n withoutArtifactUpload: true,\n bucketNamePath: NAMED_SSM_PARAMETER_PATHS.OrganisationDistributionBucket.path,\n architecture: Architecture.X86_64,\n environment: {\n ALLOWED_GROUPS: allowedGroups.join(\",\"),\n GATEKEEPER_FUNCTION_ARN: gatekeeperFunctionArn,\n },\n });\n\n authLambda.addToRolePolicy(\n new PolicyStatement({\n effect: Effect.ALLOW,\n actions: [\"lambda:InvokeFunction\"],\n resources: [gatekeeperFunctionArn],\n })\n );\n\n // Cognito user pool. We require both lambdas: pre-sign-up runs the first\n // time a user attempts to authenticate (before they exist in the User\n // Pool); pre-auth runs in subsequent authentication flows.\n const userPool = new UserPool(this, \"user-pool\", {\n lambdaTriggers: {\n preAuthentication: authLambda,\n preSignUp: authLambda,\n },\n });\n\n // These help ensure domain is deterministic but also unique. Key\n // assumption is that app/stack/stage combo are unique within Guardian.\n const domainPrefix = `com-gu-${app.toLowerCase()}-${scope.stage.toLowerCase()}`;\n const suffix = crypto.createHash(\"md5\").update(domainPrefix).digest(\"hex\");\n\n const userPoolDomain = userPool.addDomain(\"domain\", {\n cognitoDomain: {\n domainPrefix: `${domainPrefix}-${suffix}`,\n },\n });\n\n const clientId = SecretValue.secretsManager(credentialsSecretsManagerPath, { jsonField: \"clientId\" });\n const clientSecret = SecretValue.secretsManager(credentialsSecretsManagerPath, { jsonField: \"clientSecret\" });\n\n const userPoolIdp = new UserPoolIdentityProviderGoogle(scope, \"google-idp\", {\n userPool: userPool,\n clientId: clientId.toString(),\n clientSecret: clientSecret.toString(),\n attributeMapping: {\n email: ProviderAttribute.GOOGLE_EMAIL,\n givenName: ProviderAttribute.GOOGLE_GIVEN_NAME,\n familyName: ProviderAttribute.GOOGLE_FAMILY_NAME,\n profilePicture: ProviderAttribute.GOOGLE_PICTURE,\n custom: {\n name: ProviderAttribute.GOOGLE_NAME,\n },\n },\n scopes: [\"openid\", \"email\", \"profile\"],\n });\n\n const userPoolClient = userPool.addClient(\"alb-client\", {\n supportedIdentityProviders: [UserPoolClientIdentityProvider.GOOGLE],\n generateSecret: true,\n oAuth: {\n callbackUrls: [`https://${props.googleAuth.domain}/oauth2/idpresponse`],\n },\n\n // Note: id and access validity token validity cannot be less than one\n // hour (this is the cognito cookie duration). To quickly invalidate\n // credentials, disable the user in Cognito. It might be that we want to\n // parameterise these going forward, but that would require Infosec\n // discussion.\n idTokenValidity: Duration.hours(1),\n accessTokenValidity: Duration.hours(1),\n refreshTokenValidity: Duration.days(7),\n });\n\n userPoolClient.node.addDependency(userPoolIdp);\n\n listener.addAction(\"CognitoAuth\", {\n action: new AuthenticateCognitoAction({\n userPool: userPool,\n userPoolClient: userPoolClient,\n userPoolDomain: userPoolDomain,\n next: ListenerAction.forward([targetGroup]),\n sessionTimeout: Duration.minutes(sessionTimeoutInMinutes),\n }),\n });\n\n // Need to give the ALB outbound access on 443 for the IdP endpoints.\n const idpEgressSecurityGroup = new GuHttpsEgressSecurityGroup(scope, \"ldp-access\", {\n app,\n vpc,\n });\n\n loadBalancer.addSecurityGroup(idpEgressSecurityGroup);\n }\n\n this.vpc = vpc;\n this.certificate = certificate;\n this.loadBalancer = loadBalancer;\n this.autoScalingGroup = autoScalingGroup;\n this.listener = listener;\n this.targetGroup = targetGroup;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduled-lambda.d.ts","sourceRoot":"","sources":["../../src/patterns/scheduled-lambda.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,sCAAsC,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACrG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAChG;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;QACX;;;;;WAKG;QACH,QAAQ,EAAE,QAAQ,CAAC;QACnB;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH;;;;OAIG;IACH,uBAAuB,EAAE,YAAY,GAAG,sCAAsC,CAAC;CAChF;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;gBACzC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB;CAiBtE"}
1
+ {"version":3,"file":"scheduled-lambda.d.ts","sourceRoot":"","sources":["../../src/patterns/scheduled-lambda.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,sCAAsC,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACrG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC;IAChG;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;QACX;;;;;WAKG;QACH,QAAQ,EAAE,QAAQ,CAAC;QACnB;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH;;;;OAIG;IACH,uBAAuB,EAAE,YAAY,GAAG,sCAAsC,CAAC;CAChF;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;gBACzC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB;CAmBtE"}
@@ -17,10 +17,12 @@ class GuScheduledLambda extends lambda_1.GuLambdaFunction {
17
17
  };
18
18
  super(scope, id, lambdaProps);
19
19
  props.rules.forEach((rule, index) => {
20
- const target = new aws_events_targets_1.LambdaFunction(this);
20
+ // If we have an alias, use this to ensure that all invocations are handled by a published Lambda version.
21
+ // Otherwise, use the latest unpublished version ($LATEST)
22
+ const resourceToInvoke = this.alias ?? this;
21
23
  new aws_events_1.Rule(this, `${id}-${rule.schedule.expressionString}-${index}`, {
22
24
  schedule: rule.schedule,
23
- targets: [target],
25
+ targets: [new aws_events_targets_1.LambdaFunction(resourceToInvoke)],
24
26
  ...(rule.description && { description: rule.description }),
25
27
  enabled: true,
26
28
  });
@@ -1 +1 @@
1
- {"version":3,"file":"scheduled-lambda.js","sourceRoot":"","sources":["../../src/patterns/scheduled-lambda.ts"],"names":[],"mappings":";;;AAAA,uDAA8C;AAE9C,uEAAgE;AAGhE,iDAAwD;AA4BxD;;;;GAIG;AACH,MAAa,iBAAkB,SAAQ,yBAAgB;IACrD,YAAY,KAAc,EAAE,EAAU,EAAE,KAA6B;QACnE,MAAM,WAAW,GAAoB;YACnC,GAAG,KAAK;YACR,yBAAyB,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,uBAAuB;SAClH,CAAC;QACF,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAE9B,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAClC,MAAM,MAAM,GAAG,IAAI,mCAAc,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,iBAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,IAAI,KAAK,EAAE,EAAE;gBACjE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,CAAC,MAAM,CAAC;gBACjB,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC1D,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAlBD,8CAkBC","sourcesContent":["import { Rule } from \"aws-cdk-lib/aws-events\";\nimport type { Schedule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport type { GuLambdaErrorPercentageMonitoringProps, NoMonitoring } from \"../constructs/cloudwatch\";\nimport type { GuStack } from \"../constructs/core\";\nimport { GuLambdaFunction } from \"../constructs/lambda\";\nimport type { GuFunctionProps } from \"../constructs/lambda\";\n\nexport interface GuScheduledLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n /**\n * Schedule(s) for the lambda task.\n */\n rules: Array<{\n /**\n * E.g.:\n *\n * - `Schedule.expression(\"cron(0 8 ? * MON-FRI *)\")`\n * - `Schedule.rate(Duration.minutes(5))`\n */\n schedule: Schedule;\n /**\n * Optional description.\n */\n description?: string;\n }>;\n /**\n * Monitoring configuration for the lambda.\n *\n * Opting-out via the `NoMonitoring` type is supported but discouraged.\n */\n monitoringConfiguration: NoMonitoring | GuLambdaErrorPercentageMonitoringProps;\n}\n\n/**\n * Pattern which creates all of the resources needed to invoke a lambda function on a schedule.\n *\n * For all configuration options, see [[`GuScheduledLambdaProps`]].\n */\nexport class GuScheduledLambda extends GuLambdaFunction {\n constructor(scope: GuStack, id: string, props: GuScheduledLambdaProps) {\n const lambdaProps: GuFunctionProps = {\n ...props,\n errorPercentageMonitoring: props.monitoringConfiguration.noMonitoring ? undefined : props.monitoringConfiguration,\n };\n super(scope, id, lambdaProps);\n\n props.rules.forEach((rule, index) => {\n const target = new LambdaFunction(this);\n new Rule(this, `${id}-${rule.schedule.expressionString}-${index}`, {\n schedule: rule.schedule,\n targets: [target],\n ...(rule.description && { description: rule.description }),\n enabled: true,\n });\n });\n }\n}\n"]}
1
+ {"version":3,"file":"scheduled-lambda.js","sourceRoot":"","sources":["../../src/patterns/scheduled-lambda.ts"],"names":[],"mappings":";;;AAAA,uDAA8C;AAE9C,uEAAgE;AAGhE,iDAAwD;AA4BxD;;;;GAIG;AACH,MAAa,iBAAkB,SAAQ,yBAAgB;IACrD,YAAY,KAAc,EAAE,EAAU,EAAE,KAA6B;QACnE,MAAM,WAAW,GAAoB;YACnC,GAAG,KAAK;YACR,yBAAyB,EAAE,KAAK,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,uBAAuB;SAClH,CAAC;QACF,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAE9B,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAClC,0GAA0G;YAC1G,0DAA0D;YAC1D,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;YAC5C,IAAI,iBAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,IAAI,KAAK,EAAE,EAAE;gBACjE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,CAAC,IAAI,mCAAc,CAAC,gBAAgB,CAAC,CAAC;gBAC/C,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC1D,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AApBD,8CAoBC","sourcesContent":["import { Rule } from \"aws-cdk-lib/aws-events\";\nimport type { Schedule } from \"aws-cdk-lib/aws-events\";\nimport { LambdaFunction } from \"aws-cdk-lib/aws-events-targets\";\nimport type { GuLambdaErrorPercentageMonitoringProps, NoMonitoring } from \"../constructs/cloudwatch\";\nimport type { GuStack } from \"../constructs/core\";\nimport { GuLambdaFunction } from \"../constructs/lambda\";\nimport type { GuFunctionProps } from \"../constructs/lambda\";\n\nexport interface GuScheduledLambdaProps extends Omit<GuFunctionProps, \"errorPercentageMonitoring\"> {\n /**\n * Schedule(s) for the lambda task.\n */\n rules: Array<{\n /**\n * E.g.:\n *\n * - `Schedule.expression(\"cron(0 8 ? * MON-FRI *)\")`\n * - `Schedule.rate(Duration.minutes(5))`\n */\n schedule: Schedule;\n /**\n * Optional description.\n */\n description?: string;\n }>;\n /**\n * Monitoring configuration for the lambda.\n *\n * Opting-out via the `NoMonitoring` type is supported but discouraged.\n */\n monitoringConfiguration: NoMonitoring | GuLambdaErrorPercentageMonitoringProps;\n}\n\n/**\n * Pattern which creates all of the resources needed to invoke a lambda function on a schedule.\n *\n * For all configuration options, see [[`GuScheduledLambdaProps`]].\n */\nexport class GuScheduledLambda extends GuLambdaFunction {\n constructor(scope: GuStack, id: string, props: GuScheduledLambdaProps) {\n const lambdaProps: GuFunctionProps = {\n ...props,\n errorPercentageMonitoring: props.monitoringConfiguration.noMonitoring ? undefined : props.monitoringConfiguration,\n };\n super(scope, id, lambdaProps);\n\n props.rules.forEach((rule, index) => {\n // If we have an alias, use this to ensure that all invocations are handled by a published Lambda version.\n // Otherwise, use the latest unpublished version ($LATEST)\n const resourceToInvoke = this.alias ?? this;\n new Rule(this, `${id}-${rule.schedule.expressionString}-${index}`, {\n schedule: rule.schedule,\n targets: [new LambdaFunction(resourceToInvoke)],\n ...(rule.description && { description: rule.description }),\n enabled: true,\n });\n });\n }\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@guardian/cdk",
3
3
  "description": "Generic Guardian flavoured AWS CDK components",
4
- "version": "50.8.2",
4
+ "version": "50.10.0",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "files": [