@guardian/cdk 47.3.4 → 48.0.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.
package/README.md CHANGED
@@ -11,7 +11,7 @@ development framework to define cloud infrastructure in code and provision it
11
11
  through AWS CloudFormation.
12
12
 
13
13
  `@guardian/cdk` builds on CDK to provide Guardian-specific [patterns](./src/patterns) and
14
- [constructs](./src/construcst). It is an opinionated and secure-by-default way to describe and
14
+ [constructs](./src/constructs). It is an opinionated and secure-by-default way to describe and
15
15
  provision your AWS resources.
16
16
 
17
17
  Jump to:
@@ -18,7 +18,7 @@ function getCommands(packageManager, cwd) {
18
18
  return {
19
19
  installDependencies: () => runTask(packageManager, cwd, "install"),
20
20
  lint: () => runTask(packageManager, cwd, "run lint"),
21
- test: () => runTask(packageManager, cwd, "test"),
21
+ test: () => runTask(packageManager, cwd, "test -- -u"),
22
22
  synth: () => runTask(packageManager, cwd, "run synth"),
23
23
  };
24
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../src/bin/commands/new-project/utils/utils.ts"],"names":[],"mappings":";;;;;;AAAA,wEAAyC;AACzC,0EAA2C;AAC3C,iDAAiD;AAG1C,MAAM,UAAU,GAAG,CAAC,GAAW,EAAU,EAAE;IAChD,OAAO,IAAA,2BAAU,EAAC,IAAA,0BAAS,EAAC,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC,CAAC;AAFW,QAAA,UAAU,cAErB;AAOF,KAAK,UAAU,OAAO,CAAC,cAA8B,EAAE,GAAW,EAAE,IAAY;IAC9E,OAAO,MAAM,IAAA,cAAO,EAAC,GAAG,cAAc,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,SAAgB,WAAW,CACzB,cAA8B,EAC9B,GAAW;IAOX,OAAO;QACL,mBAAmB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,SAAS,CAAC;QAClE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,UAAU,CAAC;QACpD,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,MAAM,CAAC;QAChD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,WAAW,CAAC;KACvD,CAAC;AACJ,CAAC;AAfD,kCAeC","sourcesContent":["import camelCase from \"lodash.camelcase\";\nimport upperFirst from \"lodash.upperfirst\";\nimport { execute } from \"../../../../utils/exec\";\nimport type { PackageManager } from \"../index\";\n\nexport const pascalCase = (str: string): string => {\n return upperFirst(camelCase(str));\n};\n\nexport interface Name {\n kebab: string;\n pascal: string;\n}\n\nasync function runTask(packageManager: PackageManager, cwd: string, task: string): Promise<string> {\n return await execute(`${packageManager} ${task}`, [], { cwd });\n}\n\nexport function getCommands(\n packageManager: PackageManager,\n cwd: string\n): {\n installDependencies: () => Promise<string>;\n lint: () => Promise<string>;\n synth: () => Promise<string>;\n test: () => Promise<string>;\n} {\n return {\n installDependencies: () => runTask(packageManager, cwd, \"install\"),\n lint: () => runTask(packageManager, cwd, \"run lint\"),\n test: () => runTask(packageManager, cwd, \"test\"),\n synth: () => runTask(packageManager, cwd, \"run synth\"),\n };\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../src/bin/commands/new-project/utils/utils.ts"],"names":[],"mappings":";;;;;;AAAA,wEAAyC;AACzC,0EAA2C;AAC3C,iDAAiD;AAG1C,MAAM,UAAU,GAAG,CAAC,GAAW,EAAU,EAAE;IAChD,OAAO,IAAA,2BAAU,EAAC,IAAA,0BAAS,EAAC,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC,CAAC;AAFW,QAAA,UAAU,cAErB;AAOF,KAAK,UAAU,OAAO,CAAC,cAA8B,EAAE,GAAW,EAAE,IAAY;IAC9E,OAAO,MAAM,IAAA,cAAO,EAAC,GAAG,cAAc,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,SAAgB,WAAW,CACzB,cAA8B,EAC9B,GAAW;IAOX,OAAO;QACL,mBAAmB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,SAAS,CAAC;QAClE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,UAAU,CAAC;QACpD,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,YAAY,CAAC;QACtD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,WAAW,CAAC;KACvD,CAAC;AACJ,CAAC;AAfD,kCAeC","sourcesContent":["import camelCase from \"lodash.camelcase\";\nimport upperFirst from \"lodash.upperfirst\";\nimport { execute } from \"../../../../utils/exec\";\nimport type { PackageManager } from \"../index\";\n\nexport const pascalCase = (str: string): string => {\n return upperFirst(camelCase(str));\n};\n\nexport interface Name {\n kebab: string;\n pascal: string;\n}\n\nasync function runTask(packageManager: PackageManager, cwd: string, task: string): Promise<string> {\n return await execute(`${packageManager} ${task}`, [], { cwd });\n}\n\nexport function getCommands(\n packageManager: PackageManager,\n cwd: string\n): {\n installDependencies: () => Promise<string>;\n lint: () => Promise<string>;\n synth: () => Promise<string>;\n test: () => Promise<string>;\n} {\n return {\n installDependencies: () => runTask(packageManager, cwd, \"install\"),\n lint: () => runTask(packageManager, cwd, \"run lint\"),\n test: () => runTask(packageManager, cwd, \"test -- -u\"),\n synth: () => runTask(packageManager, cwd, \"run synth\"),\n };\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { Duration } from "aws-cdk-lib";
2
+ import { Construct } from "constructs";
2
3
  import type { GuDomainName } from "../../types";
3
4
  import type { AppIdentity, GuStack } from "../core";
4
5
  export declare enum RecordType {
@@ -16,7 +17,7 @@ export interface GuDnsRecordSetProps {
16
17
  * Prefer to use [[`GuCname`]] when creating a CNAME for a load balancer,
17
18
  * as this requires less boilerplate.
18
19
  */
19
- export declare class GuDnsRecordSet {
20
+ export declare class GuDnsRecordSet extends Construct {
20
21
  constructor(scope: GuStack, id: string, props: GuDnsRecordSetProps);
21
22
  }
22
23
  export interface GuCnameProps extends GuDomainName, AppIdentity {
@@ -1 +1 @@
1
- {"version":3,"file":"dns-records.d.ts","sourceRoot":"","sources":["../../../src/constructs/dns/dns-records.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEpD,oBAAY,UAAU;IACpB,KAAK,UAAU;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,GAAG,EAAE,QAAQ,CAAC;CACf;AAED;;;;;GAKG;AACH,qBAAa,cAAc;gBACb,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB;CAmCnE;AAED,MAAM,WAAW,YAAa,SAAQ,YAAY,EAAE,WAAW;IAC7D,qFAAqF;IACrF,cAAc,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,GAAG,EAAE,QAAQ,CAAC;CACf;AAED;;;;GAIG;AACH,qBAAa,OAAQ,SAAQ,cAAc;gBAC7B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY;CAU5D"}
1
+ {"version":3,"file":"dns-records.d.ts","sourceRoot":"","sources":["../../../src/constructs/dns/dns-records.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEpD,oBAAY,UAAU;IACpB,KAAK,UAAU;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,GAAG,EAAE,QAAQ,CAAC;CACf;AAED;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB;CA6CnE;AAED,MAAM,WAAW,YAAa,SAAQ,YAAY,EAAE,WAAW;IAC7D,qFAAqF;IACrF,cAAc,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,GAAG,EAAE,QAAQ,CAAC;CACf;AAED;;;;GAIG;AACH,qBAAa,OAAQ,SAAQ,cAAc;gBAC7B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY;CAU5D"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GuCname = exports.GuDnsRecordSet = exports.RecordType = void 0;
4
4
  const aws_cdk_lib_1 = require("aws-cdk-lib");
5
+ const constructs_1 = require("constructs");
5
6
  var RecordType;
6
7
  (function (RecordType) {
7
8
  RecordType["CNAME"] = "CNAME";
@@ -12,10 +13,18 @@ var RecordType;
12
13
  * Prefer to use [[`GuCname`]] when creating a CNAME for a load balancer,
13
14
  * as this requires less boilerplate.
14
15
  */
15
- class GuDnsRecordSet {
16
+ class GuDnsRecordSet extends constructs_1.Construct {
16
17
  constructor(scope, id, props) {
17
18
  const { name, recordType, resourceRecords, ttl } = props;
18
19
  const { stage } = scope;
20
+ /*
21
+ Nodes in the CDK tree must have a unique ID. This class adds two nodes to the tree, so we have two IDs.
22
+ `id`, by definition, must be unique. `name` represents a fully qualified domain name, which must also be unique.
23
+ `id` being given to the level 1 construct means it also becomes the logicalId in the template.
24
+ */
25
+ const level2ConstructId = name;
26
+ const level1ConstructId = id;
27
+ super(scope, level2ConstructId);
19
28
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- more `RecordType`s will be added soon!
20
29
  if (recordType === RecordType.CNAME) {
21
30
  /*
@@ -33,7 +42,7 @@ class GuDnsRecordSet {
33
42
  }
34
43
  // The spec for this private resource type can be found here:
35
44
  // https://github.com/guardian/cfn-private-resource-types/tree/main/dns/guardian-dns-record-set-type/docs#syntax
36
- new aws_cdk_lib_1.CfnResource(scope, id, {
45
+ new aws_cdk_lib_1.CfnResource(scope, level1ConstructId, {
37
46
  type: "Guardian::DNS::RecordSet",
38
47
  properties: {
39
48
  Name: name,
@@ -1 +1 @@
1
- {"version":3,"file":"dns-records.js","sourceRoot":"","sources":["../../../src/constructs/dns/dns-records.ts"],"names":[],"mappings":";;;AACA,6CAA0C;AAI1C,IAAY,UAEX;AAFD,WAAY,UAAU;IACpB,6BAAe,CAAA;AACjB,CAAC,EAFW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAErB;AASD;;;;;GAKG;AACH,MAAa,cAAc;IACzB,YAAY,KAAc,EAAE,EAAU,EAAE,KAA0B;QAChE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACzD,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;QAExB,iHAAiH;QACjH,IAAI,UAAU,KAAK,UAAU,CAAC,KAAK,EAAE;YACnC;;;;;;;;eAQG;YACH,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE;gBAChC,MAAM,IAAI,KAAK,CACb,qHAAqH,CACtH,CAAC;aACH;SACF;QAED,6DAA6D;QAC7D,gHAAgH;QAChH,IAAI,yBAAW,CAAC,KAAK,EAAE,EAAE,EAAE;YACzB,IAAI,EAAE,0BAA0B;YAChC,UAAU,EAAE;gBACV,IAAI,EAAE,IAAI;gBACV,eAAe,EAAE,eAAe;gBAChC,UAAU,EAAE,UAAU;gBACtB,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE;gBACpB,KAAK,EAAE,KAAK;aACb;SACF,CAAC,CAAC;IACL,CAAC;CACF;AApCD,wCAoCC;AASD;;;;GAIG;AACH,MAAa,OAAQ,SAAQ,cAAc;IACzC,YAAY,KAAc,EAAE,EAAU,EAAE,KAAmB;QACzD,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QAExD,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,IAAI;YACJ,UAAU,EAAE,UAAU,CAAC,KAAK;YAC5B,eAAe,EAAE,CAAC,cAAc,CAAC;YACjC,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;CACF;AAXD,0BAWC","sourcesContent":["import type { Duration } from \"aws-cdk-lib\";\nimport { CfnResource } from \"aws-cdk-lib\";\nimport type { GuDomainName } from \"../../types\";\nimport type { AppIdentity, GuStack } from \"../core\";\n\nexport enum RecordType {\n CNAME = \"CNAME\",\n}\n\nexport interface GuDnsRecordSetProps {\n name: string;\n recordType: RecordType;\n resourceRecords: string[];\n ttl: Duration;\n}\n\n/**\n * This construct can be used to create DNS records in NS1.\n *\n * Prefer to use [[`GuCname`]] when creating a CNAME for a load balancer,\n * as this requires less boilerplate.\n */\nexport class GuDnsRecordSet {\n constructor(scope: GuStack, id: string, props: GuDnsRecordSetProps) {\n const { name, recordType, resourceRecords, ttl } = props;\n const { stage } = scope;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- more `RecordType`s will be added soon!\n if (recordType === RecordType.CNAME) {\n /*\n If you try to create a CNAME with multiple records within NS1, you are greeted with:\n\n According to RFC, a CNAME record should not return multiple answers.\n Doing so may cause problems during resolution.\n If you want to use multiple answers, you should ensure you have the correct filters in place (such as SELECT_FIRST_N 1) to limit them to a single answer at resolution time.\n\n `Guardian::DNS::RecordSet` does not implement \"correct filters\", so fail fast by throwing.\n */\n if (resourceRecords.length !== 1) {\n throw new Error(\n \"According to RFC, a CNAME record should not return multiple answers. Doing so may cause problems during resolution.\"\n );\n }\n }\n\n // The spec for this private resource type can be found here:\n // https://github.com/guardian/cfn-private-resource-types/tree/main/dns/guardian-dns-record-set-type/docs#syntax\n new CfnResource(scope, id, {\n type: \"Guardian::DNS::RecordSet\",\n properties: {\n Name: name,\n ResourceRecords: resourceRecords,\n RecordType: recordType,\n TTL: ttl.toSeconds(),\n Stage: stage,\n },\n });\n }\n}\n\nexport interface GuCnameProps extends GuDomainName, AppIdentity {\n /** The record your CNAME should point to, for example your Load Balancer DNS name */\n resourceRecord: string;\n /** The time to live for the DNS record */\n ttl: Duration;\n}\n\n/**\n * Construct for creating CNAME records in NS1.\n *\n * See [[`GuCnameProps`]] for configuration options.\n */\nexport class GuCname extends GuDnsRecordSet {\n constructor(scope: GuStack, id: string, props: GuCnameProps) {\n const { domainName: name, resourceRecord, ttl } = props;\n\n super(scope, id, {\n name,\n recordType: RecordType.CNAME,\n resourceRecords: [resourceRecord],\n ttl,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"dns-records.js","sourceRoot":"","sources":["../../../src/constructs/dns/dns-records.ts"],"names":[],"mappings":";;;AACA,6CAA0C;AAC1C,2CAAuC;AAIvC,IAAY,UAEX;AAFD,WAAY,UAAU;IACpB,6BAAe,CAAA;AACjB,CAAC,EAFW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAErB;AASD;;;;;GAKG;AACH,MAAa,cAAe,SAAQ,sBAAS;IAC3C,YAAY,KAAc,EAAE,EAAU,EAAE,KAA0B;QAChE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACzD,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;QAExB;;;;WAIG;QACH,MAAM,iBAAiB,GAAG,IAAI,CAAC;QAC/B,MAAM,iBAAiB,GAAG,EAAE,CAAC;QAE7B,KAAK,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QAEhC,iHAAiH;QACjH,IAAI,UAAU,KAAK,UAAU,CAAC,KAAK,EAAE;YACnC;;;;;;;;eAQG;YACH,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE;gBAChC,MAAM,IAAI,KAAK,CACb,qHAAqH,CACtH,CAAC;aACH;SACF;QAED,6DAA6D;QAC7D,gHAAgH;QAChH,IAAI,yBAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE;YACxC,IAAI,EAAE,0BAA0B;YAChC,UAAU,EAAE;gBACV,IAAI,EAAE,IAAI;gBACV,eAAe,EAAE,eAAe;gBAChC,UAAU,EAAE,UAAU;gBACtB,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE;gBACpB,KAAK,EAAE,KAAK;aACb;SACF,CAAC,CAAC;IACL,CAAC;CACF;AA9CD,wCA8CC;AASD;;;;GAIG;AACH,MAAa,OAAQ,SAAQ,cAAc;IACzC,YAAY,KAAc,EAAE,EAAU,EAAE,KAAmB;QACzD,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QAExD,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE;YACf,IAAI;YACJ,UAAU,EAAE,UAAU,CAAC,KAAK;YAC5B,eAAe,EAAE,CAAC,cAAc,CAAC;YACjC,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;CACF;AAXD,0BAWC","sourcesContent":["import type { Duration } from \"aws-cdk-lib\";\nimport { CfnResource } from \"aws-cdk-lib\";\nimport { Construct } from \"constructs\";\nimport type { GuDomainName } from \"../../types\";\nimport type { AppIdentity, GuStack } from \"../core\";\n\nexport enum RecordType {\n CNAME = \"CNAME\",\n}\n\nexport interface GuDnsRecordSetProps {\n name: string;\n recordType: RecordType;\n resourceRecords: string[];\n ttl: Duration;\n}\n\n/**\n * This construct can be used to create DNS records in NS1.\n *\n * Prefer to use [[`GuCname`]] when creating a CNAME for a load balancer,\n * as this requires less boilerplate.\n */\nexport class GuDnsRecordSet extends Construct {\n constructor(scope: GuStack, id: string, props: GuDnsRecordSetProps) {\n const { name, recordType, resourceRecords, ttl } = props;\n const { stage } = scope;\n\n /*\n Nodes in the CDK tree must have a unique ID. This class adds two nodes to the tree, so we have two IDs.\n `id`, by definition, must be unique. `name` represents a fully qualified domain name, which must also be unique.\n `id` being given to the level 1 construct means it also becomes the logicalId in the template.\n */\n const level2ConstructId = name;\n const level1ConstructId = id;\n\n super(scope, level2ConstructId);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- more `RecordType`s will be added soon!\n if (recordType === RecordType.CNAME) {\n /*\n If you try to create a CNAME with multiple records within NS1, you are greeted with:\n\n According to RFC, a CNAME record should not return multiple answers.\n Doing so may cause problems during resolution.\n If you want to use multiple answers, you should ensure you have the correct filters in place (such as SELECT_FIRST_N 1) to limit them to a single answer at resolution time.\n\n `Guardian::DNS::RecordSet` does not implement \"correct filters\", so fail fast by throwing.\n */\n if (resourceRecords.length !== 1) {\n throw new Error(\n \"According to RFC, a CNAME record should not return multiple answers. Doing so may cause problems during resolution.\"\n );\n }\n }\n\n // The spec for this private resource type can be found here:\n // https://github.com/guardian/cfn-private-resource-types/tree/main/dns/guardian-dns-record-set-type/docs#syntax\n new CfnResource(scope, level1ConstructId, {\n type: \"Guardian::DNS::RecordSet\",\n properties: {\n Name: name,\n ResourceRecords: resourceRecords,\n RecordType: recordType,\n TTL: ttl.toSeconds(),\n Stage: stage,\n },\n });\n }\n}\n\nexport interface GuCnameProps extends GuDomainName, AppIdentity {\n /** The record your CNAME should point to, for example your Load Balancer DNS name */\n resourceRecord: string;\n /** The time to live for the DNS record */\n ttl: Duration;\n}\n\n/**\n * Construct for creating CNAME records in NS1.\n *\n * See [[`GuCnameProps`]] for configuration options.\n */\nexport class GuCname extends GuDnsRecordSet {\n constructor(scope: GuStack, id: string, props: GuCnameProps) {\n const { domainName: name, resourceRecord, ttl } = props;\n\n super(scope, id, {\n name,\n recordType: RecordType.CNAME,\n resourceRecords: [resourceRecord],\n ttl,\n });\n }\n}\n"]}
@@ -3,6 +3,7 @@ import type { IRepository } from "aws-cdk-lib/aws-ecr";
3
3
  import type { PolicyStatement } from "aws-cdk-lib/aws-iam";
4
4
  import { StateMachine } from "aws-cdk-lib/aws-stepfunctions";
5
5
  import type { TaskEnvironmentVariable } from "aws-cdk-lib/aws-stepfunctions-tasks";
6
+ import { Construct } from "constructs";
6
7
  import type { NoMonitoring } from "../cloudwatch";
7
8
  import type { GuStack } from "../core";
8
9
  import { AppIdentity } from "../core";
@@ -105,7 +106,7 @@ export interface GuEcsTaskProps extends AppIdentity {
105
106
  * Note that if your task reliably completes in less than 15 minutes then you should probably use a [[`GuLambda`]] instead. This
106
107
  * pattern was mainly created to work around the 15 minute lambda timeout.
107
108
  */
108
- export declare class GuEcsTask {
109
+ export declare class GuEcsTask extends Construct {
109
110
  stateMachine: StateMachine;
110
111
  constructor(scope: GuStack, id: string, props: GuEcsTaskProps);
111
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ecs-task.d.ts","sourceRoot":"","sources":["../../../src/constructs/ecs/ecs-task.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAsB,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAEnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,oBAAY,mBAAmB,GAAG;IAChC,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF,oBAAY,iBAAiB,GAAG;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,oBAAY,sBAAsB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAE7E,oBAAY,wBAAwB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,GAAG,EAAE,IAAI,CAAC;IACV,sBAAsB,EAAE,sBAAsB,CAAC;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,YAAY,GAAG,wBAAwB,CAAC;IACjE,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;IACvC,oBAAoB,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAcD;;;;;;;;;GASG;AACH,qBAAa,SAAS;IACpB,YAAY,EAAE,YAAY,CAAC;gBAEf,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc;CA+H9D"}
1
+ {"version":3,"file":"ecs-task.d.ts","sourceRoot":"","sources":["../../../src/constructs/ecs/ecs-task.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAsB,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAEnF,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,oBAAY,mBAAmB,GAAG;IAChC,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF,oBAAY,iBAAiB,GAAG;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,oBAAY,sBAAsB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAE7E,oBAAY,wBAAwB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,GAAG,EAAE,IAAI,CAAC;IACV,sBAAsB,EAAE,sBAAsB,CAAC;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,YAAY,GAAG,wBAAwB,CAAC;IACjE,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;IACvC,oBAAoB,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAcD;;;;;;;;;GASG;AACH,qBAAa,SAAU,SAAQ,SAAS;IACtC,YAAY,EAAE,YAAY,CAAC;gBAEf,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc;CAiI9D"}
@@ -8,6 +8,7 @@ const aws_ecs_1 = require("aws-cdk-lib/aws-ecs");
8
8
  const aws_sns_1 = require("aws-cdk-lib/aws-sns");
9
9
  const aws_stepfunctions_1 = require("aws-cdk-lib/aws-stepfunctions");
10
10
  const aws_stepfunctions_tasks_1 = require("aws-cdk-lib/aws-stepfunctions-tasks");
11
+ const constructs_1 = require("constructs");
11
12
  const core_1 = require("../core");
12
13
  const iam_1 = require("../iam");
13
14
  /**
@@ -32,8 +33,9 @@ const getContainer = (config) => {
32
33
  * Note that if your task reliably completes in less than 15 minutes then you should probably use a [[`GuLambda`]] instead. This
33
34
  * pattern was mainly created to work around the 15 minute lambda timeout.
34
35
  */
35
- class GuEcsTask {
36
+ class GuEcsTask extends constructs_1.Construct {
36
37
  constructor(scope, id, props) {
38
+ super(scope, id);
37
39
  const { app,
38
40
  // see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-cpu for details
39
41
  cpu = 2048, // 2 cores and from 4-16GB memory
@@ -1 +1 @@
1
- {"version":3,"file":"ecs-task.js","sourceRoot":"","sources":["../../../src/constructs/ecs/ecs-task.ts"],"names":[],"mappings":"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","sourcesContent":["import { CfnOutput, Duration } from \"aws-cdk-lib\";\nimport { Alarm, TreatMissingData } from \"aws-cdk-lib/aws-cloudwatch\";\nimport { SnsAction } from \"aws-cdk-lib/aws-cloudwatch-actions\";\nimport type { ISecurityGroup, IVpc } from \"aws-cdk-lib/aws-ec2\";\nimport type { IRepository } from \"aws-cdk-lib/aws-ecr\";\nimport {\n Cluster,\n Compatibility,\n ContainerImage,\n FargatePlatformVersion,\n LogDrivers,\n TaskDefinition,\n} from \"aws-cdk-lib/aws-ecs\";\nimport type { PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Topic } from \"aws-cdk-lib/aws-sns\";\nimport { IntegrationPattern, StateMachine } from \"aws-cdk-lib/aws-stepfunctions\";\nimport type { TaskEnvironmentVariable } from \"aws-cdk-lib/aws-stepfunctions-tasks\";\nimport { EcsFargateLaunchTarget, EcsRunTask } from \"aws-cdk-lib/aws-stepfunctions-tasks\";\nimport type { NoMonitoring } from \"../cloudwatch\";\nimport type { GuStack } from \"../core\";\nimport { AppIdentity } from \"../core\";\nimport { GuGetDistributablePolicyStatement } from \"../iam\";\n\n/**\n * Configuration to determine what container to use for the task\n * For example, to run the task in the latest node container:\n *\n * ```typescript\n * const containerConfiguration = {\n * id: 'node:latest'\n * }\n * ```\n *\n * Alternatively you can specify a repository and version, for example for an ECR repository:\n * ```typescript\n * import { Repository } from \"aws-cdk-lib/aws-ecr\";\n * const repository = new Repository(scope, `${app}-repository`, {\n repositoryName: app,\n });\n * const containerConfiguration = {\n * repository: Repository.fromRepositoryArn(\"<repository arn>\"),\n * version: '1'\n * }\n * ```\n */\n\nexport type RepositoryContainer = {\n repository: IRepository;\n version: string;\n type: \"repository\";\n};\n\nexport type RegistryContainer = {\n id?: string;\n type: \"registry\";\n};\n\nexport type ContainerConfiguration = RepositoryContainer | RegistryContainer;\n\nexport type GuEcsTaskMonitoringProps = { snsTopicArn: string; noMonitoring: false };\n\n/**\n * Configuration options for the [[`GuEcsTask`]] pattern.\n *\n * See [[`ContainerConfiguration`]] for details of how to configure the container used to run the task.\n *\n * `taskTimeoutInMinutes` does what is says on the tin. The default timeout is 15 minutes.\n *\n * The `taskCommand` prop allows you to specify a command to run when the task starts (this can also be done via a CMD statement in\n * your Dockerfile). For example:\n *\n * const props = {\n * //other props\n * taskCommand: `aws s3 cp s3://${distbucket}/${stack}/${stage}/${app}/task.sh . && ./task.sh\n }\n *\n * It is advisable to configure alarms for when the job fails/times out. To do this specify the alarmSnsTopicArn prop.\n *\n * `customTaskPolicies` allows your task to interact with other AWS services. By default a task\n * will have read access to the distribution bucket for your account.\n *\n * You can specify security groups to apply to task using the `securityGroups` prop.\n *\n * You can also set the memory and cpu units for your task. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#task_size\n * for further details.\n *\n * If you want to pass input from the step function into your EcsTask you can do so via the `environmentOverrides` prop, which allows you to wire up\n * step function input JSON to environment variables set on the container. For example,\n * const props = {\n * ...otherProps\n * environmentOverrides: [\n {\n name: \"VERSION\",\n value: JsonPath.stringAt(\"$.version\"),\n },\n }\n * With the above override, your task will attempt to find a `version` property in the JSON input passed to the step function, and apply it to the\n * VERSION environment variable. Alternatively, you could hard code a value for the variable in CDK.\n * See https://docs.aws.amazon.com/step-functions/latest/dg/connect-ecs.html for further detail and other override options - this construct currently\n * only supports environment variables.\n */\nexport interface GuEcsTaskProps extends AppIdentity {\n vpc: IVpc;\n containerConfiguration: ContainerConfiguration;\n taskTimeoutInMinutes?: number;\n cpu?: number;\n memory?: number;\n taskCommand?: string;\n monitoringConfiguration: NoMonitoring | GuEcsTaskMonitoringProps;\n securityGroups?: ISecurityGroup[];\n customTaskPolicies?: PolicyStatement[];\n environmentOverrides?: TaskEnvironmentVariable[];\n storage?: number;\n}\n\n/**\n * Containers can be specified either via a repository and version or by container id (in which case it will\n * be fetched from docker hub).\n */\nconst getContainer = (config: ContainerConfiguration) => {\n if (config.type == \"repository\") {\n return ContainerImage.fromEcrRepository(config.repository, config.version);\n } else {\n return ContainerImage.fromRegistry(config.id ?? \"ubuntu:focal\");\n }\n};\n\n/**\n * Pattern which creates all of the resources needed for a fargate task\n *\n * The task will be wrapped in a step function to allow for easier triggering and alarming on failure.\n *\n * For all configuration options, see [[`GuEcsTaskProps`]].\n *\n * Note that if your task reliably completes in less than 15 minutes then you should probably use a [[`GuLambda`]] instead. This\n * pattern was mainly created to work around the 15 minute lambda timeout.\n */\nexport class GuEcsTask {\n stateMachine: StateMachine;\n\n constructor(scope: GuStack, id: string, props: GuEcsTaskProps) {\n const {\n app,\n\n // see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-cpu for details\n cpu = 2048, // 2 cores and from 4-16GB memory\n memory = 4096, // 4GB\n storage, // default is 20 GB when not provided in props\n containerConfiguration,\n taskCommand,\n taskTimeoutInMinutes = 15,\n customTaskPolicies,\n vpc,\n monitoringConfiguration,\n securityGroups = [],\n environmentOverrides,\n } = props;\n\n if (storage && storage < 21) {\n throw new Error(\n \"Storage must be at least 21. See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-ephemeralstorage.html\"\n );\n }\n\n const { stack, stage } = scope;\n\n const cluster = new Cluster(scope, `${id}-Cluster`, {\n clusterName: `${app}-cluster-${stage}`,\n enableFargateCapacityProviders: true,\n vpc,\n });\n\n const taskDefinition = new TaskDefinition(scope, `${id}-TaskDefinition`, {\n compatibility: Compatibility.FARGATE,\n cpu: cpu.toString(),\n memoryMiB: memory.toString(),\n family: `${stack}-${stage}-${app}`,\n ephemeralStorageGiB: storage,\n });\n\n const containerDefinition = taskDefinition.addContainer(`${id}-TaskContainer`, {\n image: getContainer(containerConfiguration),\n entryPoint: taskCommand ? [\"/bin/sh\"] : undefined,\n command: taskCommand ? [\"-c\", taskCommand] : undefined, // if unset, falls back to CMD in docker file, or no command will be run\n cpu,\n memoryLimitMiB: memory,\n logging: LogDrivers.awsLogs({\n streamPrefix: app,\n logRetention: 14,\n }),\n });\n\n const distPolicy = new GuGetDistributablePolicyStatement(scope, { app });\n\n taskDefinition.addToTaskRolePolicy(distPolicy);\n (customTaskPolicies ?? []).forEach((p) => taskDefinition.addToTaskRolePolicy(p));\n\n const task = new EcsRunTask(scope, `${id}-task`, {\n cluster,\n launchTarget: new EcsFargateLaunchTarget({\n platformVersion: FargatePlatformVersion.LATEST,\n }),\n taskDefinition,\n integrationPattern: IntegrationPattern.RUN_JOB,\n resultPath: \"DISCARD\",\n timeout: Duration.minutes(taskTimeoutInMinutes),\n securityGroups,\n containerOverrides: [\n {\n containerDefinition: containerDefinition,\n environment: environmentOverrides,\n },\n ],\n });\n\n this.stateMachine = new StateMachine(scope, `${id}-StateMachine`, {\n definition: task,\n stateMachineName: `${app}-${stage}`,\n });\n\n if (!monitoringConfiguration.noMonitoring) {\n const alarmTopic = Topic.fromTopicArn(\n scope,\n AppIdentity.suffixText(props, \"AlarmTopic\"),\n monitoringConfiguration.snsTopicArn\n );\n const alarms = [\n {\n name: `${app}-execution-failed`,\n description: `${app}-${stage} job failed `,\n metric: this.stateMachine.metricFailed({\n period: Duration.hours(1),\n statistic: \"sum\",\n }),\n },\n {\n name: `${app}-timeout`,\n description: `${app}-${stage} job timed out `,\n metric: this.stateMachine.metricTimedOut({\n period: Duration.hours(1),\n statistic: \"sum\",\n }),\n },\n ];\n\n alarms.forEach(({ name, description, metric }) => {\n const alarm = new Alarm(scope, name, {\n alarmDescription: description,\n actionsEnabled: true,\n metric: metric,\n // default for comparisonOperator is GreaterThanOrEqualToThreshold\n threshold: 1,\n evaluationPeriods: 1,\n treatMissingData: TreatMissingData.NOT_BREACHING,\n });\n alarm.addAlarmAction(new SnsAction(alarmTopic));\n AppIdentity.taggedConstruct({ app }, alarm);\n });\n }\n\n // Tag all constructs with correct app tag\n [cluster, task, taskDefinition, this.stateMachine].forEach((c) => AppIdentity.taggedConstruct({ app }, c));\n\n new CfnOutput(scope, `${id}-StateMachineArnOutput`, {\n value: this.stateMachine.stateMachineArn,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"ecs-task.js","sourceRoot":"","sources":["../../../src/constructs/ecs/ecs-task.ts"],"names":[],"mappings":"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","sourcesContent":["import { CfnOutput, Duration } from \"aws-cdk-lib\";\nimport { Alarm, TreatMissingData } from \"aws-cdk-lib/aws-cloudwatch\";\nimport { SnsAction } from \"aws-cdk-lib/aws-cloudwatch-actions\";\nimport type { ISecurityGroup, IVpc } from \"aws-cdk-lib/aws-ec2\";\nimport type { IRepository } from \"aws-cdk-lib/aws-ecr\";\nimport {\n Cluster,\n Compatibility,\n ContainerImage,\n FargatePlatformVersion,\n LogDrivers,\n TaskDefinition,\n} from \"aws-cdk-lib/aws-ecs\";\nimport type { PolicyStatement } from \"aws-cdk-lib/aws-iam\";\nimport { Topic } from \"aws-cdk-lib/aws-sns\";\nimport { IntegrationPattern, StateMachine } from \"aws-cdk-lib/aws-stepfunctions\";\nimport type { TaskEnvironmentVariable } from \"aws-cdk-lib/aws-stepfunctions-tasks\";\nimport { EcsFargateLaunchTarget, EcsRunTask } from \"aws-cdk-lib/aws-stepfunctions-tasks\";\nimport { Construct } from \"constructs\";\nimport type { NoMonitoring } from \"../cloudwatch\";\nimport type { GuStack } from \"../core\";\nimport { AppIdentity } from \"../core\";\nimport { GuGetDistributablePolicyStatement } from \"../iam\";\n\n/**\n * Configuration to determine what container to use for the task\n * For example, to run the task in the latest node container:\n *\n * ```typescript\n * const containerConfiguration = {\n * id: 'node:latest'\n * }\n * ```\n *\n * Alternatively you can specify a repository and version, for example for an ECR repository:\n * ```typescript\n * import { Repository } from \"aws-cdk-lib/aws-ecr\";\n * const repository = new Repository(scope, `${app}-repository`, {\n repositoryName: app,\n });\n * const containerConfiguration = {\n * repository: Repository.fromRepositoryArn(\"<repository arn>\"),\n * version: '1'\n * }\n * ```\n */\n\nexport type RepositoryContainer = {\n repository: IRepository;\n version: string;\n type: \"repository\";\n};\n\nexport type RegistryContainer = {\n id?: string;\n type: \"registry\";\n};\n\nexport type ContainerConfiguration = RepositoryContainer | RegistryContainer;\n\nexport type GuEcsTaskMonitoringProps = { snsTopicArn: string; noMonitoring: false };\n\n/**\n * Configuration options for the [[`GuEcsTask`]] pattern.\n *\n * See [[`ContainerConfiguration`]] for details of how to configure the container used to run the task.\n *\n * `taskTimeoutInMinutes` does what is says on the tin. The default timeout is 15 minutes.\n *\n * The `taskCommand` prop allows you to specify a command to run when the task starts (this can also be done via a CMD statement in\n * your Dockerfile). For example:\n *\n * const props = {\n * //other props\n * taskCommand: `aws s3 cp s3://${distbucket}/${stack}/${stage}/${app}/task.sh . && ./task.sh\n }\n *\n * It is advisable to configure alarms for when the job fails/times out. To do this specify the alarmSnsTopicArn prop.\n *\n * `customTaskPolicies` allows your task to interact with other AWS services. By default a task\n * will have read access to the distribution bucket for your account.\n *\n * You can specify security groups to apply to task using the `securityGroups` prop.\n *\n * You can also set the memory and cpu units for your task. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#task_size\n * for further details.\n *\n * If you want to pass input from the step function into your EcsTask you can do so via the `environmentOverrides` prop, which allows you to wire up\n * step function input JSON to environment variables set on the container. For example,\n * const props = {\n * ...otherProps\n * environmentOverrides: [\n {\n name: \"VERSION\",\n value: JsonPath.stringAt(\"$.version\"),\n },\n }\n * With the above override, your task will attempt to find a `version` property in the JSON input passed to the step function, and apply it to the\n * VERSION environment variable. Alternatively, you could hard code a value for the variable in CDK.\n * See https://docs.aws.amazon.com/step-functions/latest/dg/connect-ecs.html for further detail and other override options - this construct currently\n * only supports environment variables.\n */\nexport interface GuEcsTaskProps extends AppIdentity {\n vpc: IVpc;\n containerConfiguration: ContainerConfiguration;\n taskTimeoutInMinutes?: number;\n cpu?: number;\n memory?: number;\n taskCommand?: string;\n monitoringConfiguration: NoMonitoring | GuEcsTaskMonitoringProps;\n securityGroups?: ISecurityGroup[];\n customTaskPolicies?: PolicyStatement[];\n environmentOverrides?: TaskEnvironmentVariable[];\n storage?: number;\n}\n\n/**\n * Containers can be specified either via a repository and version or by container id (in which case it will\n * be fetched from docker hub).\n */\nconst getContainer = (config: ContainerConfiguration) => {\n if (config.type == \"repository\") {\n return ContainerImage.fromEcrRepository(config.repository, config.version);\n } else {\n return ContainerImage.fromRegistry(config.id ?? \"ubuntu:focal\");\n }\n};\n\n/**\n * Pattern which creates all of the resources needed for a fargate task\n *\n * The task will be wrapped in a step function to allow for easier triggering and alarming on failure.\n *\n * For all configuration options, see [[`GuEcsTaskProps`]].\n *\n * Note that if your task reliably completes in less than 15 minutes then you should probably use a [[`GuLambda`]] instead. This\n * pattern was mainly created to work around the 15 minute lambda timeout.\n */\nexport class GuEcsTask extends Construct {\n stateMachine: StateMachine;\n\n constructor(scope: GuStack, id: string, props: GuEcsTaskProps) {\n super(scope, id);\n\n const {\n app,\n\n // see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-cpu for details\n cpu = 2048, // 2 cores and from 4-16GB memory\n memory = 4096, // 4GB\n storage, // default is 20 GB when not provided in props\n containerConfiguration,\n taskCommand,\n taskTimeoutInMinutes = 15,\n customTaskPolicies,\n vpc,\n monitoringConfiguration,\n securityGroups = [],\n environmentOverrides,\n } = props;\n\n if (storage && storage < 21) {\n throw new Error(\n \"Storage must be at least 21. See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-ephemeralstorage.html\"\n );\n }\n\n const { stack, stage } = scope;\n\n const cluster = new Cluster(scope, `${id}-Cluster`, {\n clusterName: `${app}-cluster-${stage}`,\n enableFargateCapacityProviders: true,\n vpc,\n });\n\n const taskDefinition = new TaskDefinition(scope, `${id}-TaskDefinition`, {\n compatibility: Compatibility.FARGATE,\n cpu: cpu.toString(),\n memoryMiB: memory.toString(),\n family: `${stack}-${stage}-${app}`,\n ephemeralStorageGiB: storage,\n });\n\n const containerDefinition = taskDefinition.addContainer(`${id}-TaskContainer`, {\n image: getContainer(containerConfiguration),\n entryPoint: taskCommand ? [\"/bin/sh\"] : undefined,\n command: taskCommand ? [\"-c\", taskCommand] : undefined, // if unset, falls back to CMD in docker file, or no command will be run\n cpu,\n memoryLimitMiB: memory,\n logging: LogDrivers.awsLogs({\n streamPrefix: app,\n logRetention: 14,\n }),\n });\n\n const distPolicy = new GuGetDistributablePolicyStatement(scope, { app });\n\n taskDefinition.addToTaskRolePolicy(distPolicy);\n (customTaskPolicies ?? []).forEach((p) => taskDefinition.addToTaskRolePolicy(p));\n\n const task = new EcsRunTask(scope, `${id}-task`, {\n cluster,\n launchTarget: new EcsFargateLaunchTarget({\n platformVersion: FargatePlatformVersion.LATEST,\n }),\n taskDefinition,\n integrationPattern: IntegrationPattern.RUN_JOB,\n resultPath: \"DISCARD\",\n timeout: Duration.minutes(taskTimeoutInMinutes),\n securityGroups,\n containerOverrides: [\n {\n containerDefinition: containerDefinition,\n environment: environmentOverrides,\n },\n ],\n });\n\n this.stateMachine = new StateMachine(scope, `${id}-StateMachine`, {\n definition: task,\n stateMachineName: `${app}-${stage}`,\n });\n\n if (!monitoringConfiguration.noMonitoring) {\n const alarmTopic = Topic.fromTopicArn(\n scope,\n AppIdentity.suffixText(props, \"AlarmTopic\"),\n monitoringConfiguration.snsTopicArn\n );\n const alarms = [\n {\n name: `${app}-execution-failed`,\n description: `${app}-${stage} job failed `,\n metric: this.stateMachine.metricFailed({\n period: Duration.hours(1),\n statistic: \"sum\",\n }),\n },\n {\n name: `${app}-timeout`,\n description: `${app}-${stage} job timed out `,\n metric: this.stateMachine.metricTimedOut({\n period: Duration.hours(1),\n statistic: \"sum\",\n }),\n },\n ];\n\n alarms.forEach(({ name, description, metric }) => {\n const alarm = new Alarm(scope, name, {\n alarmDescription: description,\n actionsEnabled: true,\n metric: metric,\n // default for comparisonOperator is GreaterThanOrEqualToThreshold\n threshold: 1,\n evaluationPeriods: 1,\n treatMissingData: TreatMissingData.NOT_BREACHING,\n });\n alarm.addAlarmAction(new SnsAction(alarmTopic));\n AppIdentity.taggedConstruct({ app }, alarm);\n });\n }\n\n // Tag all constructs with correct app tag\n [cluster, task, taskDefinition, this.stateMachine].forEach((c) => AppIdentity.taggedConstruct({ app }, c));\n\n new CfnOutput(scope, `${id}-StateMachineArnOutput`, {\n value: this.stateMachine.stateMachineArn,\n });\n }\n}\n"]}
@@ -1,27 +1,7 @@
1
1
  import type { VpcProps } from "aws-cdk-lib/aws-ec2";
2
2
  import { Vpc } from "aws-cdk-lib/aws-ec2";
3
3
  import type { GuStack } from "../core";
4
- export interface GuVpcCustomProps {
5
- /**
6
- * Whether to add SSM Parameters containing VPC metadata, which are expected
7
- * to exist by many other Guardian CDK patterns.
8
- *
9
- * Defaults to 'true'.
10
- */
11
- ssmParameters?: boolean;
12
- /**
13
- * An identifier for the VPC to namespace SSM parameters. Customise when you
14
- * have multiple teams/VPCs in the same account.
15
- *
16
- * This will be combined with the /account/vpc prefix for the full parameter
17
- * name. e.g. '/account/vpc/primary'.
18
- *
19
- * Defaults to 'primary'.
20
- */
21
- ssmParametersNamespace?: string;
22
- }
23
- export interface GuVpcProps extends GuVpcCustomProps, VpcProps {
24
- }
4
+ export declare type GuVpcProps = VpcProps;
25
5
  /**
26
6
  * Construct which creates a Virtual Private Cloud.
27
7
  *
@@ -1 +1 @@
1
- {"version":3,"file":"vpc.d.ts","sourceRoot":"","sources":["../../../src/constructs/vpc/vpc.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAA4C,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAGpF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,UAAW,SAAQ,gBAAgB,EAAE,QAAQ;CAAG;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,KAAM,SAAQ,GAAG;IAC5B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;gBAc7B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU;CAqD3D"}
1
+ {"version":3,"file":"vpc.d.ts","sourceRoot":"","sources":["../../../src/constructs/vpc/vpc.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAA4C,GAAG,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,oBAAY,UAAU,GAAG,QAAQ,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,KAAM,SAAQ,GAAG;IAC5B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;gBAc7B,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU;CA4B3D"}
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GuVpc = void 0;
4
4
  const aws_cdk_lib_1 = require("aws-cdk-lib");
5
5
  const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
6
- const aws_ssm_1 = require("aws-cdk-lib/aws-ssm");
7
- const constants_1 = require("../../constants");
8
6
  /**
9
7
  * Construct which creates a Virtual Private Cloud.
10
8
  *
@@ -85,29 +83,9 @@ class GuVpc extends aws_ec2_1.Vpc {
85
83
  },
86
84
  ],
87
85
  };
88
- const defaultCustomProps = {
89
- ssmParameters: true,
90
- ssmParametersNamespace: "primary",
91
- };
92
86
  // Set the context BEFORE the `super` call to avoid `Error: Cannot set context after children have been added`
93
87
  GuVpc.setAvailabilityZoneContext(scope);
94
88
  super(scope, id, { ...defaultVpcProps, ...props });
95
- if (props?.ssmParameters ?? defaultCustomProps.ssmParameters) {
96
- const namespace = props?.ssmParametersNamespace ?? defaultCustomProps.ssmParametersNamespace;
97
- const prefix = `${constants_1.VPC_SSM_PARAMETER_PREFIX}/${namespace}`;
98
- new aws_ssm_1.StringParameter(scope, "vpcID", {
99
- parameterName: `${prefix}/id`,
100
- stringValue: this.vpcId,
101
- });
102
- new aws_ssm_1.StringListParameter(scope, "publicSubnets", {
103
- parameterName: `${prefix}/subnets/public`,
104
- stringListValue: this.publicSubnets.map((subnet) => subnet.subnetId),
105
- });
106
- new aws_ssm_1.StringListParameter(scope, "privateSubnets", {
107
- parameterName: `${prefix}/subnets/private`,
108
- stringListValue: this.privateSubnets.map((subnet) => subnet.subnetId),
109
- });
110
- }
111
89
  }
112
90
  }
113
91
  exports.GuVpc = GuVpc;
@@ -1 +1 @@
1
- {"version":3,"file":"vpc.js","sourceRoot":"","sources":["../../../src/constructs/vpc/vpc.ts"],"names":[],"mappings":";;;AAAA,6CAAoC;AAEpC,iDAAoF;AACpF,iDAA2E;AAC3E,+CAA2D;AA0B3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAa,KAAM,SAAQ,aAAG;IAC5B;;;;;;;OAOG;IACK,MAAM,CAAC,0BAA0B,CAAC,EAAE,OAAO,EAAE,IAAI,EAAW;QAClE,IAAI,mBAAK,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE;YAC/B,MAAM,IAAI,KAAK,CACb,8JAA8J,CAC/J,CAAC;SACH;QAED,IAAI,CAAC,UAAU,CAAC,8BAA8B,OAAO,mBAAmB,EAAE;YACxE,YAAY;YACZ,YAAY;YACZ,YAAY;SACb,CAAC,CAAC;IACL,CAAC;IAED,YAAY,KAAc,EAAE,EAAU,EAAE,KAAkB;QACxD,MAAM,eAAe,GAAa;YAChC,gBAAgB,EAAE;gBAChB,EAAE,EAAE;oBACF,OAAO,EAAE,sCAA4B,CAAC,EAAE;iBACzC;gBACD,QAAQ,EAAE;oBACR,OAAO,EAAE,sCAA4B,CAAC,QAAQ;iBAC/C;aACF;YAED,mBAAmB,EAAE;gBACnB;oBACE,IAAI,EAAE,SAAS;oBACf,UAAU,EAAE,oBAAU,CAAC,MAAM;iBAC9B;gBACD;oBACE,IAAI,EAAE,aAAa;oBACnB,UAAU,EAAE,oBAAU,CAAC,gBAAgB;iBACxC;aACF;SACF,CAAC;QAEF,MAAM,kBAAkB,GAA+B;YACrD,aAAa,EAAE,IAAI;YACnB,sBAAsB,EAAE,SAAS;SAClC,CAAC;QAEF,8GAA8G;QAC9G,KAAK,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC;QAExC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,eAAe,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QAEnD,IAAI,KAAK,EAAE,aAAa,IAAI,kBAAkB,CAAC,aAAa,EAAE;YAC5D,MAAM,SAAS,GAAG,KAAK,EAAE,sBAAsB,IAAI,kBAAkB,CAAC,sBAAsB,CAAC;YAC7F,MAAM,MAAM,GAAG,GAAG,oCAAwB,IAAI,SAAS,EAAE,CAAC;YAE1D,IAAI,yBAAe,CAAC,KAAK,EAAE,OAAO,EAAE;gBAClC,aAAa,EAAE,GAAG,MAAM,KAAK;gBAC7B,WAAW,EAAE,IAAI,CAAC,KAAK;aACxB,CAAC,CAAC;YAEH,IAAI,6BAAmB,CAAC,KAAK,EAAE,eAAe,EAAE;gBAC9C,aAAa,EAAE,GAAG,MAAM,iBAAiB;gBACzC,eAAe,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;aACrE,CAAC,CAAC;YAEH,IAAI,6BAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE;gBAC/C,aAAa,EAAE,GAAG,MAAM,kBAAkB;gBAC1C,eAAe,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;aACtE,CAAC,CAAC;SACJ;IACH,CAAC;CACF;AA5ED,sBA4EC","sourcesContent":["import { Token } from \"aws-cdk-lib\";\nimport type { VpcProps } from \"aws-cdk-lib/aws-ec2\";\nimport { GatewayVpcEndpointAwsService, SubnetType, Vpc } from \"aws-cdk-lib/aws-ec2\";\nimport { StringListParameter, StringParameter } from \"aws-cdk-lib/aws-ssm\";\nimport { VPC_SSM_PARAMETER_PREFIX } from \"../../constants\";\nimport type { GuStack } from \"../core\";\n\nexport interface GuVpcCustomProps {\n /**\n * Whether to add SSM Parameters containing VPC metadata, which are expected\n * to exist by many other Guardian CDK patterns.\n *\n * Defaults to 'true'.\n */\n ssmParameters?: boolean;\n\n /**\n * An identifier for the VPC to namespace SSM parameters. Customise when you\n * have multiple teams/VPCs in the same account.\n *\n * This will be combined with the /account/vpc prefix for the full parameter\n * name. e.g. '/account/vpc/primary'.\n *\n * Defaults to 'primary'.\n */\n ssmParametersNamespace?: string;\n}\n\nexport interface GuVpcProps extends GuVpcCustomProps, VpcProps {}\n\n/**\n * Construct which creates a Virtual Private Cloud.\n *\n * NOTE: This construct requires an\n * [environment](https://docs.aws.amazon.com/cdk/latest/guide/environments.html)\n * to be set to function correctly. Without this, an environment-agnostic\n * template will be produced, which will only use two AZs even if the region\n * contains more than that. To set this, set the `env` prop when instantiating\n * your stack.\n *\n * NOTE: If using this construct outside eu-west-1, you'll need to commit the\n * `cdk.context.json` file that's created after synthesising locally.\n *\n * Be aware that account IDs are considered sensitive information and should NOT\n * be committed to public repos.\n *\n * The VPC is provisioned with a public and private subnet for each availability\n * zone, with IPs spread evenly across these. Instances in private subnets\n * cannot be accessed directly over the internet. You should locate services in\n * instances in the private subnets, and provide HTTP(S) as required via load\n * balancers living in the public subnets.\n *\n * A CIDR block is a combined IP and network mask that specifies the IP\n * addresses in your VPC. For testing purposes any (AWS supported) CIDR block\n * will do, but for production you should:\n *\n * - use a /21 network mask (providing up to 2048 IPs, which is plenty for most\n * accounts)\n * - ask Enterprise Tech for an IP address to go with this range (so that\n * peering with other company VPCs is possible without IP clashes)\n *\n * A managed NAT is created for each private subnet to allow access to the\n * internet.\n *\n * For recommendations on how best to configure your VPC see:\n * https://github.com/guardian/recommendations/blob/main/AWS.md#vpc\n *\n * For more information on VPCs and AWS see:\n * https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html.\n */\nexport class GuVpc extends Vpc {\n /**\n * Programmatically sets the CDK context with a list of AZs for eu-west-1.\n * This means consuming stacks do NOT have to commit a `cdk.context.json`\n * file when using this construct in eu-west-1.\n *\n * @throws {Error} if the account ID has not been explicitly set on the parent GuStack\n * @private\n */\n private static setAvailabilityZoneContext({ account, node }: GuStack) {\n if (Token.isUnresolved(account)) {\n throw new Error(\n `Account ID not set - the resulting VPC might not be shaped how you'd expect. See https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.StackProps.html#env`\n );\n }\n\n node.setContext(`availability-zones:account=${account}:region=eu-west-1`, [\n \"eu-west-1a\",\n \"eu-west-1b\",\n \"eu-west-1c\",\n ]);\n }\n\n constructor(scope: GuStack, id: string, props?: GuVpcProps) {\n const defaultVpcProps: VpcProps = {\n gatewayEndpoints: {\n s3: {\n service: GatewayVpcEndpointAwsService.S3,\n },\n dynamodb: {\n service: GatewayVpcEndpointAwsService.DYNAMODB,\n },\n },\n\n subnetConfiguration: [\n {\n name: \"ingress\",\n subnetType: SubnetType.PUBLIC,\n },\n {\n name: \"application\",\n subnetType: SubnetType.PRIVATE_WITH_NAT,\n },\n ],\n };\n\n const defaultCustomProps: Required<GuVpcCustomProps> = {\n ssmParameters: true,\n ssmParametersNamespace: \"primary\",\n };\n\n // Set the context BEFORE the `super` call to avoid `Error: Cannot set context after children have been added`\n GuVpc.setAvailabilityZoneContext(scope);\n\n super(scope, id, { ...defaultVpcProps, ...props });\n\n if (props?.ssmParameters ?? defaultCustomProps.ssmParameters) {\n const namespace = props?.ssmParametersNamespace ?? defaultCustomProps.ssmParametersNamespace;\n const prefix = `${VPC_SSM_PARAMETER_PREFIX}/${namespace}`;\n\n new StringParameter(scope, \"vpcID\", {\n parameterName: `${prefix}/id`,\n stringValue: this.vpcId,\n });\n\n new StringListParameter(scope, \"publicSubnets\", {\n parameterName: `${prefix}/subnets/public`,\n stringListValue: this.publicSubnets.map((subnet) => subnet.subnetId),\n });\n\n new StringListParameter(scope, \"privateSubnets\", {\n parameterName: `${prefix}/subnets/private`,\n stringListValue: this.privateSubnets.map((subnet) => subnet.subnetId),\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"vpc.js","sourceRoot":"","sources":["../../../src/constructs/vpc/vpc.ts"],"names":[],"mappings":";;;AAAA,6CAAoC;AAEpC,iDAAoF;AAKpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAa,KAAM,SAAQ,aAAG;IAC5B;;;;;;;OAOG;IACK,MAAM,CAAC,0BAA0B,CAAC,EAAE,OAAO,EAAE,IAAI,EAAW;QAClE,IAAI,mBAAK,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE;YAC/B,MAAM,IAAI,KAAK,CACb,8JAA8J,CAC/J,CAAC;SACH;QAED,IAAI,CAAC,UAAU,CAAC,8BAA8B,OAAO,mBAAmB,EAAE;YACxE,YAAY;YACZ,YAAY;YACZ,YAAY;SACb,CAAC,CAAC;IACL,CAAC;IAED,YAAY,KAAc,EAAE,EAAU,EAAE,KAAkB;QACxD,MAAM,eAAe,GAAa;YAChC,gBAAgB,EAAE;gBAChB,EAAE,EAAE;oBACF,OAAO,EAAE,sCAA4B,CAAC,EAAE;iBACzC;gBACD,QAAQ,EAAE;oBACR,OAAO,EAAE,sCAA4B,CAAC,QAAQ;iBAC/C;aACF;YAED,mBAAmB,EAAE;gBACnB;oBACE,IAAI,EAAE,SAAS;oBACf,UAAU,EAAE,oBAAU,CAAC,MAAM;iBAC9B;gBACD;oBACE,IAAI,EAAE,aAAa;oBACnB,UAAU,EAAE,oBAAU,CAAC,gBAAgB;iBACxC;aACF;SACF,CAAC;QAEF,8GAA8G;QAC9G,KAAK,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC;QAExC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,eAAe,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;CACF;AAnDD,sBAmDC","sourcesContent":["import { Token } from \"aws-cdk-lib\";\nimport type { VpcProps } from \"aws-cdk-lib/aws-ec2\";\nimport { GatewayVpcEndpointAwsService, SubnetType, Vpc } from \"aws-cdk-lib/aws-ec2\";\nimport type { GuStack } from \"../core\";\n\nexport type GuVpcProps = VpcProps;\n\n/**\n * Construct which creates a Virtual Private Cloud.\n *\n * NOTE: This construct requires an\n * [environment](https://docs.aws.amazon.com/cdk/latest/guide/environments.html)\n * to be set to function correctly. Without this, an environment-agnostic\n * template will be produced, which will only use two AZs even if the region\n * contains more than that. To set this, set the `env` prop when instantiating\n * your stack.\n *\n * NOTE: If using this construct outside eu-west-1, you'll need to commit the\n * `cdk.context.json` file that's created after synthesising locally.\n *\n * Be aware that account IDs are considered sensitive information and should NOT\n * be committed to public repos.\n *\n * The VPC is provisioned with a public and private subnet for each availability\n * zone, with IPs spread evenly across these. Instances in private subnets\n * cannot be accessed directly over the internet. You should locate services in\n * instances in the private subnets, and provide HTTP(S) as required via load\n * balancers living in the public subnets.\n *\n * A CIDR block is a combined IP and network mask that specifies the IP\n * addresses in your VPC. For testing purposes any (AWS supported) CIDR block\n * will do, but for production you should:\n *\n * - use a /21 network mask (providing up to 2048 IPs, which is plenty for most\n * accounts)\n * - ask Enterprise Tech for an IP address to go with this range (so that\n * peering with other company VPCs is possible without IP clashes)\n *\n * A managed NAT is created for each private subnet to allow access to the\n * internet.\n *\n * For recommendations on how best to configure your VPC see:\n * https://github.com/guardian/recommendations/blob/main/AWS.md#vpc\n *\n * For more information on VPCs and AWS see:\n * https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html.\n */\nexport class GuVpc extends Vpc {\n /**\n * Programmatically sets the CDK context with a list of AZs for eu-west-1.\n * This means consuming stacks do NOT have to commit a `cdk.context.json`\n * file when using this construct in eu-west-1.\n *\n * @throws {Error} if the account ID has not been explicitly set on the parent GuStack\n * @private\n */\n private static setAvailabilityZoneContext({ account, node }: GuStack) {\n if (Token.isUnresolved(account)) {\n throw new Error(\n `Account ID not set - the resulting VPC might not be shaped how you'd expect. See https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.StackProps.html#env`\n );\n }\n\n node.setContext(`availability-zones:account=${account}:region=eu-west-1`, [\n \"eu-west-1a\",\n \"eu-west-1b\",\n \"eu-west-1c\",\n ]);\n }\n\n constructor(scope: GuStack, id: string, props?: GuVpcProps) {\n const defaultVpcProps: VpcProps = {\n gatewayEndpoints: {\n s3: {\n service: GatewayVpcEndpointAwsService.S3,\n },\n dynamodb: {\n service: GatewayVpcEndpointAwsService.DYNAMODB,\n },\n },\n\n subnetConfiguration: [\n {\n name: \"ingress\",\n subnetType: SubnetType.PUBLIC,\n },\n {\n name: \"application\",\n subnetType: SubnetType.PRIVATE_WITH_NAT,\n },\n ],\n };\n\n // Set the context BEFORE the `super` call to avoid `Error: Cannot set context after children have been added`\n GuVpc.setAvailabilityZoneContext(scope);\n\n super(scope, id, { ...defaultVpcProps, ...props });\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { RestApiProps } from "aws-cdk-lib/aws-apigateway";
2
2
  import { RestApi } from "aws-cdk-lib/aws-apigateway";
3
+ import { Construct } from "constructs";
3
4
  import type { Http5xxAlarmProps, NoMonitoring } from "../constructs/cloudwatch";
4
5
  import type { AppIdentity, GuStack } from "../constructs/core";
5
6
  import type { GuLambdaFunction } from "../constructs/lambda";
@@ -106,7 +107,7 @@ export interface GuApiGatewayWithLambdaByPathProps extends RestApiProps, AppIden
106
107
  *
107
108
  * For details on configuring the individual Lambda functions, see [[`GuLambdaFunction`]].
108
109
  */
109
- export declare class GuApiGatewayWithLambdaByPath {
110
+ export declare class GuApiGatewayWithLambdaByPath extends Construct {
110
111
  readonly api: RestApi;
111
112
  constructor(scope: GuStack, props: GuApiGatewayWithLambdaByPathProps);
112
113
  }
@@ -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,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;AAG7D,oBAAY,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,iBAAiB,CAAC;IAChC,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,4BAA4B;IACvC,SAAgB,GAAG,EAAE,OAAO,CAAC;gBAEjB,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,iCAAiC;CAqBrE"}
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;AAG7D,oBAAY,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,iBAAiB,CAAC;IAChC,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;CAsBrE"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GuApiGatewayWithLambdaByPath = void 0;
4
4
  const aws_apigateway_1 = require("aws-cdk-lib/aws-apigateway");
5
+ const constructs_1 = require("constructs");
5
6
  const api_gateway_alarms_1 = require("../constructs/cloudwatch/api-gateway-alarms");
6
7
  function isNoMonitoring(monitoringConfiguration) {
7
8
  return monitoringConfiguration.noMonitoring;
@@ -60,8 +61,9 @@ function isNoMonitoring(monitoringConfiguration) {
60
61
  *
61
62
  * For details on configuring the individual Lambda functions, see [[`GuLambdaFunction`]].
62
63
  */
63
- class GuApiGatewayWithLambdaByPath {
64
+ class GuApiGatewayWithLambdaByPath extends constructs_1.Construct {
64
65
  constructor(scope, props) {
66
+ super(scope, props.app); // The assumption is `app` is unique
65
67
  const apiGateway = new aws_apigateway_1.RestApi(scope, "RestApi", {
66
68
  // Override to avoid clashes as default is just api ID, which is often shared across stages.
67
69
  restApiName: `${scope.stack}-${scope.stage}-${props.app}`,
@@ -1 +1 @@
1
- {"version":3,"file":"api-multiple-lambdas.js","sourceRoot":"","sources":["../../src/patterns/api-multiple-lambdas.ts"],"names":[],"mappings":";;;AACA,+DAAwE;AAExE,oFAA6F;AA0D7F,SAAS,cAAc,CACrB,uBAAwD;IAExD,OAAsB,uBAAwB,CAAC,YAAY,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAa,4BAA4B;IAGvC,YAAY,KAAc,EAAE,KAAwC;QAClE,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,CAAC,CAAC;QAC9E,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;AAxBD,oEAwBC","sourcesContent":["import type { RestApiProps } from \"aws-cdk-lib/aws-apigateway\";\nimport { LambdaIntegration, RestApi } from \"aws-cdk-lib/aws-apigateway\";\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// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods\nexport type HttpMethod = \"GET\" | \"HEAD\" | \"POST\" | \"PUT\" | \"DELETE\" | \"CONNECT\" | \"OPTIONS\" | \"TRACE\" | \"PATCH\";\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\n/**\n * Configuration for an alarm based on the percentage of 5XX responses served by the API Gateway instance.\n *\n * For example:\n *\n * ```typescript\n * monitoringConfiguration: {\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: <sensible_error_percentage_threshold>,\n * }\n * }\n * ```\n */\nexport interface ApiGatewayAlarms {\n snsTopicName: string;\n http5xxAlarm: Http5xxAlarmProps;\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 {\n public readonly api: RestApi;\n\n constructor(scope: GuStack, props: GuApiGatewayWithLambdaByPathProps) {\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 });\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;AA0D7F,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,CAAC,CAAC;QAC9E,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;AAzBD,oEAyBC","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// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods\nexport type HttpMethod = \"GET\" | \"HEAD\" | \"POST\" | \"PUT\" | \"DELETE\" | \"CONNECT\" | \"OPTIONS\" | \"TRACE\" | \"PATCH\";\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\n/**\n * Configuration for an alarm based on the percentage of 5XX responses served by the API Gateway instance.\n *\n * For example:\n *\n * ```typescript\n * monitoringConfiguration: {\n * snsTopicName: \"my-topic-for-cloudwatch-alerts\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: <sensible_error_percentage_threshold>,\n * }\n * }\n * ```\n */\nexport interface ApiGatewayAlarms {\n snsTopicName: string;\n http5xxAlarm: Http5xxAlarmProps;\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 });\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,5 +1,6 @@
1
1
  import type { BlockDevice } from "aws-cdk-lib/aws-autoscaling";
2
2
  import type { InstanceType, IVpc } from "aws-cdk-lib/aws-ec2";
3
+ import { Construct } from "constructs";
3
4
  import { GuCertificate } from "../../constructs/acm";
4
5
  import type { GuUserDataProps } from "../../constructs/autoscaling";
5
6
  import { GuAutoScalingGroup } from "../../constructs/autoscaling";
@@ -287,7 +288,7 @@ export interface GuEc2AppProps extends AppIdentity {
287
288
  * cfnLb.securityGroups = [sg.securityGroupId];
288
289
  * ```
289
290
  */
290
- export declare class GuEc2App {
291
+ export declare class GuEc2App extends Construct {
291
292
  readonly vpc: IVpc;
292
293
  readonly certificate: GuCertificate;
293
294
  readonly loadBalancer: GuApplicationLoadBalancer;
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAS,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAKrE,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;AAEhE,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;AAE/D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,MAAM;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,KAAK,GAAG,iBAAiB,CAAC;IACxC,uBAAuB,EAAE,OAAO,CAAC;IACjC,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC;IACnC,MAAM,EAAE,SAAS,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC,uBAAuB,EAAE,MAAM,GAAG,YAAY,CAAC;IAC/C,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,OAAO,EAAE,aAAa,CAAC;IACvB,gBAAgB,EAAE,YAAY,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgKG;AACH,qBAAa,QAAQ;IASnB,SAAgB,GAAG,EAAE,IAAI,CAAC;IAC1B,SAAgB,WAAW,EAAE,aAAa,CAAC;IAC3C,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;CA6KjD"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAS,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAIrE,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;AAEhE,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;AAE/D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,MAAM;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,KAAK,GAAG,iBAAiB,CAAC;IACxC,uBAAuB,EAAE,OAAO,CAAC;IACjC,YAAY,CAAC,EAAE,KAAK,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC;IACnC,MAAM,EAAE,SAAS,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC,uBAAuB,EAAE,MAAM,GAAG,YAAY,CAAC;IAC/C,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,OAAO,EAAE,aAAa,CAAC;IACvB,gBAAgB,EAAE,YAAY,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgKG;AACH,qBAAa,QAAS,SAAQ,SAAS;IASrC,SAAgB,GAAG,EAAE,IAAI,CAAC;IAC1B,SAAgB,WAAW,EAAE,aAAa,CAAC;IAC3C,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;CA+KjD"}
@@ -6,6 +6,7 @@ const aws_autoscaling_1 = require("aws-cdk-lib/aws-autoscaling");
6
6
  const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
7
7
  const aws_elasticloadbalancingv2_1 = require("aws-cdk-lib/aws-elasticloadbalancingv2");
8
8
  const aws_s3_1 = require("aws-cdk-lib/aws-s3");
9
+ const constructs_1 = require("constructs");
9
10
  const constants_1 = require("../../constants");
10
11
  const acm_1 = require("../../constructs/acm");
11
12
  const autoscaling_1 = require("../../constructs/autoscaling");
@@ -183,11 +184,12 @@ function restrictedCidrRanges(ranges) {
183
184
  * cfnLb.securityGroups = [sg.securityGroupId];
184
185
  * ```
185
186
  */
186
- class GuEc2App {
187
+ class GuEc2App extends constructs_1.Construct {
187
188
  constructor(scope, props) {
188
189
  const { access, accessLogging = { enabled: false }, app,
189
190
  // We should update this default once a significant number of apps have migrated to devx-logs
190
191
  applicationLogging = { enabled: false }, applicationPort, blockDevices, certificateProps: { domainName, hostedZoneId }, instanceType, monitoringConfiguration, roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] }, scaling: { minimumInstances, maximumInstances = minimumInstances * 2 }, userData, withoutImdsv2, imageRecipe, } = props;
192
+ super(scope, app); // The assumption is `app` is unique
191
193
  // We should really prevent users from doing this via the type system,
192
194
  // but that requires a breaking change to the API
193
195
  if (applicationLogging.enabled && roleConfiguration.withoutLogShipping) {
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/patterns/ec2-app/base.ts"],"names":[],"mappings":"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","sourcesContent":["import { Duration, Tags } from \"aws-cdk-lib\";\nimport type { BlockDevice } from \"aws-cdk-lib/aws-autoscaling\";\nimport { HealthCheck } from \"aws-cdk-lib/aws-autoscaling\";\nimport type { InstanceType, IPeer, IVpc } from \"aws-cdk-lib/aws-ec2\";\nimport { Port } from \"aws-cdk-lib/aws-ec2\";\nimport { ApplicationProtocol } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport { Bucket } from \"aws-cdk-lib/aws-s3\";\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 { GuSecurityGroup, GuVpc, SubnetType } from \"../../constructs/ec2\";\nimport type { GuInstanceRoleProps } from \"../../constructs/iam\";\nimport { GuGetPrivateConfigPolicy, GuInstanceRole } from \"../../constructs/iam\";\nimport {\n GuApplicationLoadBalancer,\n GuApplicationTargetGroup,\n GuHttpsApplicationListener,\n} from \"../../constructs/loadbalancing\";\nimport { AppAccess } from \"../../types\";\nimport type { GuAsgCapacity, GuDomainName } from \"../../types\";\n\nexport interface AccessLoggingProps {\n enabled: boolean;\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 enabled: boolean;\n /**\n * Defaults to app name. That is, if your app runs as `<app>.service`\n * (e.g. `janus.service`), this will 'just work'.\n *\n * If it runs with a non-standard name, you will need to override the default\n * behavour. I.e. if your app is running as `some-different-name.service`, then\n * this prop should be set to `some-different-name`.\n */\n systemdUnitName?: string;\n}\n\nexport interface Alarms {\n snsTopicName: string;\n http5xxAlarm: false | Http5xxAlarmProps;\n unhealthyInstancesAlarm: boolean;\n noMonitoring?: false;\n}\n\n/**\n * Configuration options for the [[`GuEc2App`]] pattern.\n *\n * To grant EC2 instances additional IAM permissions, use the `roleConfiguration` prop. For example,\n * to allow your app to write to DynamoDB:\n *\n * ```typescript\n * // other props\n * roleConfiguration: {\n * additionalPolicies: [new GuDynamoDBWritePolicy(stack, \"DynamoTable\", { tableName: \"my-dynamo-table\" })],\n * }\n * ```\n *\n * To create alarms (recommended), use:\n * ```typescript\n * // other props\n * monitoringConfiguration: {\n * snsTopicName: \"alerts-topic-for-my-team\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * },\n * unhealthyInstancesAlarm: true,\n * }\n * ```\n *\n * To opt out of creating alarms, use:\n *```typescript\n * // other props\n * monitoringConfiguration: { noMonitoring: true }\n * ```\n *\n * To automatically ship application logs from `stdout` to ELK, use:\n *\n * ```typescript\n * {\n * // other props\n * applicationLogging: { enabled: true }\n * }\n * ```\n *\n * For more details on the requirements for application log shipping, see [[`ApplicationLoggingProps`]].\n *\n * To enable access logging for your load balancer, you can specify the prefix to write the logs to.\n * The S3 bucket used to hold these access logs must be specified in SSM at `/account/services/access-logging/bucket`\n * You must specify a region in your stack declaration if you are to use this prop, as specified here:\n * https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html#logwbraccesswbrlogsbucket-prefix\n * For example:\n * ```typescript\n * {\n * // other props\n * accessLogging: {\n * enabled: true,\n * prefix: \"my-application-logs\"\n * }\n * }\n *\n * If you would like to enable access logging at the root of the S3 bucket (ie without a prefix), you can omit the prefix\n * For example:\n * ```typescript\n * {\n * // other props\n * accessLogging: {\n * enabled: true,\n * }\n * }\n * ```\n */\nexport interface GuEc2AppProps extends AppIdentity {\n userData: GuUserDataProps | string;\n access: AppAccess;\n applicationPort: number;\n roleConfiguration?: GuInstanceRoleProps;\n monitoringConfiguration: Alarms | NoMonitoring;\n instanceType: InstanceType;\n applicationLogging?: ApplicationLoggingProps;\n accessLogging?: AccessLoggingProps;\n blockDevices?: BlockDevice[];\n scaling: GuAsgCapacity;\n certificateProps: GuDomainName;\n withoutImdsv2?: boolean;\n imageRecipe?: string;\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 instances.\n * For convenience, you may wish to use [[`GuPlayApp`]] or [[`GuNodeApp`]], which extend this class.\n *\n * This pattern will grant your EC2 instances a number of commonly needed IAM permissions. For more information on\n * this, see [[`GuInstanceRole`]]. To add additional permissions to your EC2 instances, see [[`GuEc2AppProps`]].\n *\n * This pattern will automatically create security groups/rules which allow for:\n * 1. Incoming traffic over HTTPS (from the whole internet or from the specified CIDR ranges, depending on the\n * [[`AppAccess`]] specified).\n * 2. Communication between the load balancer and the EC2 instances over HTTP, via the specified application port.\n * 3. Outbound traffic from your EC2 instances over HTTPS (to enable communication with third-party APIs).\n *\n * Example usage for a public facing app (open to the internet):\n * ```typescript\n * new GuEc2App(stack, {\n * applicationPort: 1234,\n * app: \"app-name\",\n * access: { scope: AccessScope.PUBLIC },\n * instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),\n * certificateProps:{\n * domainName: \"prod-guardian.com\",\n * },\n * monitoringConfiguration: {\n * snsTopicName: \"alerts-topic-for-my-team\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * },\n * unhealthyInstancesAlarm: true,\n * },\n * userData: {\n * distributable: {\n * fileName: \"app-name.deb\",\n * executionStatement: `dpkg -i /app-name/app-name.deb`,\n * }\n * },\n * });\n * ```\n *\n * Example usage for an app which is restricted to specific CIDR ranges:\n * ```typescript\n * new GuEc2App(stack, {\n * applicationPort: 1234,\n * app: \"app-name\",\n * access: {\n * scope: AccessScope.RESTRICTED,\n * cidrRanges: [Peer.ipv4(\"192.168.1.1/32\"), Peer.ipv4(\"8.8.8.8/32\")],\n * },\n * instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),\n * certificateProps:{\n * domainName: \"prod-guardian.com\",\n * },\n * monitoringConfiguration: {\n * snsTopicName: \"alerts-topic-for-my-team\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * },\n * unhealthyInstancesAlarm: true,\n * }\n * userData: {\n * distributable: {\n * fileName: \"app-name.deb\",\n * executionStatement: `dpkg -i /app-name/app-name.deb`,\n * }\n * },\n * });\n * ```\n *\n * ### Varying values by stage\n *\n * There are times when you want a resource's configuration to be stage aware,\n * for example the number of instances in an ASG.\n *\n * To do this, we can use a simple ternary:\n * ```typescript\n * new GuEc2App(this, {\n * // other required properties\n * scaling: this.stage === \"PROD\" ? { minimumInstances: 6 } : { minimumInstances: 1 }\n * });\n * ```\n *\n * If multiple properties need to be stage aware, consider encoding this into the `props` of the calling class:\n *\n * ```typescript\n * export interface MyAppProps extends GuStackProps {\n * domainName: string;\n * scaling: GuAsgCapacity;\n * monitoringConfiguration: Alarms | NoMonitoring;\n * }\n *\n * export class MyApp extends GuStack {\n * private static app = \"cdk-playground\";\n *\n * constructor(scope: App, id: string, props: MyAppProps) {\n * const { stage, domainName, scaling, monitoringConfiguration } = props;\n *\n * super(scope, id, props);\n *\n * new GuPlayApp(this, {\n * app: \"my-app\",\n * instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MICRO),\n * access: { scope: AccessScope.PUBLIC },\n * userData: {\n * distributable: {\n * fileName: `my-app.deb`,\n * executionStatement: `dpkg -i /my-app/my-app.deb`,\n * },\n * },\n * certificateProps: {\n * domainName,\n * },\n * monitoringConfiguration,\n * scaling,\n * });\n * }\n * }\n *\n * new MyApp(app, \"MyApp-CODE\", {\n * stage: \"CODE\",\n * domainName: \"my-app.code.dev-gutools.co.uk\",\n * scaling: { minimumInstances: 1 },\n * monitoringConfiguration: { noMonitoring: true },\n * });\n *\n * new MyApp(app, \"MyApp-PROD\", {\n * stage: \"PROD\",\n * domainName: \"my-app.prod.gutools.co.uk\",\n * scaling: { minimumInstances: 6 },\n * monitoringConfiguration: {\n * // config to enable alarms in PROD\n * },\n * });\n * ```\n *\n *\n * ### Customising the infrastructure generated by this pattern\n *\n * Although we allow users to customise many aspects of their infrastructure via [[`GuEc2AppProps`]], it's possible\n * that there are less common use-cases which are currently unsupported via the API. In these circumstances escape\n * hatches can be used to override specific resources in the stack.\n *\n * In order to do this:\n *\n * 1. Create desired resource using Guardian or AWS constructs, for example:\n * ```typescript\n * const sg = new GuSecurityGroup(\n * // custom parameters\n * );\n * ```\n * 2. Access the CloudFormation version of the resource that you wish to customise, for example:\n * ```typescript\n * const pattern = new GuEc2App(\n * // all parameters\n * )\n * const cfnLb = pattern.loadBalancer.node.defaultChild as CfnLoadBalancer;\n * ```\n * 3. Replace the resource generated by the pattern with your bespoke resource, for example:\n * ```typescript\n * cfnLb.securityGroups = [sg.securityGroupId];\n * ```\n */\nexport class GuEc2App {\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: { domainName, hostedZoneId },\n instanceType,\n monitoringConfiguration,\n roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] },\n scaling: { minimumInstances, maximumInstances = minimumInstances * 2 },\n userData,\n withoutImdsv2,\n imageRecipe,\n } = props;\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 const vpc = GuVpc.fromIdParameter(scope, AppIdentity.suffixText({ app }, \"VPC\"));\n const privateSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PRIVATE, app });\n\n AppAccess.validate(access);\n\n const certificate = new GuCertificate(scope, {\n app,\n domainName,\n hostedZoneId,\n });\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 // We are selectively tagging the ASG so that we can expose the number of stacks using this pattern\n // based on which autoscaling groups possess this tag. It may become useful or necessary to tag all resources in the future,\n // but we have decided that this is sufficient for now.\n // TODO: Do we need to tag all resources with this value? What would the use-cases be?\n Tags.of(autoScalingGroup).add(MetadataKeys.PATTERN_NAME, this.constructor.name, { applyToLaunchedInstances: true });\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:\n access.scope === AccessScope.INTERNAL\n ? privateSubnets\n : GuVpc.subnetsFromParameter(scope, { type: SubnetType.PUBLIC, app }),\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 });\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,\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 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":["import { Duration, Tags } from \"aws-cdk-lib\";\nimport type { BlockDevice } from \"aws-cdk-lib/aws-autoscaling\";\nimport { HealthCheck } from \"aws-cdk-lib/aws-autoscaling\";\nimport type { InstanceType, IPeer, IVpc } from \"aws-cdk-lib/aws-ec2\";\nimport { Port } from \"aws-cdk-lib/aws-ec2\";\nimport { ApplicationProtocol } from \"aws-cdk-lib/aws-elasticloadbalancingv2\";\nimport { Bucket } from \"aws-cdk-lib/aws-s3\";\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 { GuSecurityGroup, GuVpc, SubnetType } from \"../../constructs/ec2\";\nimport type { GuInstanceRoleProps } from \"../../constructs/iam\";\nimport { GuGetPrivateConfigPolicy, GuInstanceRole } from \"../../constructs/iam\";\nimport {\n GuApplicationLoadBalancer,\n GuApplicationTargetGroup,\n GuHttpsApplicationListener,\n} from \"../../constructs/loadbalancing\";\nimport { AppAccess } from \"../../types\";\nimport type { GuAsgCapacity, GuDomainName } from \"../../types\";\n\nexport interface AccessLoggingProps {\n enabled: boolean;\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 enabled: boolean;\n /**\n * Defaults to app name. That is, if your app runs as `<app>.service`\n * (e.g. `janus.service`), this will 'just work'.\n *\n * If it runs with a non-standard name, you will need to override the default\n * behavour. I.e. if your app is running as `some-different-name.service`, then\n * this prop should be set to `some-different-name`.\n */\n systemdUnitName?: string;\n}\n\nexport interface Alarms {\n snsTopicName: string;\n http5xxAlarm: false | Http5xxAlarmProps;\n unhealthyInstancesAlarm: boolean;\n noMonitoring?: false;\n}\n\n/**\n * Configuration options for the [[`GuEc2App`]] pattern.\n *\n * To grant EC2 instances additional IAM permissions, use the `roleConfiguration` prop. For example,\n * to allow your app to write to DynamoDB:\n *\n * ```typescript\n * // other props\n * roleConfiguration: {\n * additionalPolicies: [new GuDynamoDBWritePolicy(stack, \"DynamoTable\", { tableName: \"my-dynamo-table\" })],\n * }\n * ```\n *\n * To create alarms (recommended), use:\n * ```typescript\n * // other props\n * monitoringConfiguration: {\n * snsTopicName: \"alerts-topic-for-my-team\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * },\n * unhealthyInstancesAlarm: true,\n * }\n * ```\n *\n * To opt out of creating alarms, use:\n *```typescript\n * // other props\n * monitoringConfiguration: { noMonitoring: true }\n * ```\n *\n * To automatically ship application logs from `stdout` to ELK, use:\n *\n * ```typescript\n * {\n * // other props\n * applicationLogging: { enabled: true }\n * }\n * ```\n *\n * For more details on the requirements for application log shipping, see [[`ApplicationLoggingProps`]].\n *\n * To enable access logging for your load balancer, you can specify the prefix to write the logs to.\n * The S3 bucket used to hold these access logs must be specified in SSM at `/account/services/access-logging/bucket`\n * You must specify a region in your stack declaration if you are to use this prop, as specified here:\n * https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.ApplicationLoadBalancer.html#logwbraccesswbrlogsbucket-prefix\n * For example:\n * ```typescript\n * {\n * // other props\n * accessLogging: {\n * enabled: true,\n * prefix: \"my-application-logs\"\n * }\n * }\n *\n * If you would like to enable access logging at the root of the S3 bucket (ie without a prefix), you can omit the prefix\n * For example:\n * ```typescript\n * {\n * // other props\n * accessLogging: {\n * enabled: true,\n * }\n * }\n * ```\n */\nexport interface GuEc2AppProps extends AppIdentity {\n userData: GuUserDataProps | string;\n access: AppAccess;\n applicationPort: number;\n roleConfiguration?: GuInstanceRoleProps;\n monitoringConfiguration: Alarms | NoMonitoring;\n instanceType: InstanceType;\n applicationLogging?: ApplicationLoggingProps;\n accessLogging?: AccessLoggingProps;\n blockDevices?: BlockDevice[];\n scaling: GuAsgCapacity;\n certificateProps: GuDomainName;\n withoutImdsv2?: boolean;\n imageRecipe?: string;\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 instances.\n * For convenience, you may wish to use [[`GuPlayApp`]] or [[`GuNodeApp`]], which extend this class.\n *\n * This pattern will grant your EC2 instances a number of commonly needed IAM permissions. For more information on\n * this, see [[`GuInstanceRole`]]. To add additional permissions to your EC2 instances, see [[`GuEc2AppProps`]].\n *\n * This pattern will automatically create security groups/rules which allow for:\n * 1. Incoming traffic over HTTPS (from the whole internet or from the specified CIDR ranges, depending on the\n * [[`AppAccess`]] specified).\n * 2. Communication between the load balancer and the EC2 instances over HTTP, via the specified application port.\n * 3. Outbound traffic from your EC2 instances over HTTPS (to enable communication with third-party APIs).\n *\n * Example usage for a public facing app (open to the internet):\n * ```typescript\n * new GuEc2App(stack, {\n * applicationPort: 1234,\n * app: \"app-name\",\n * access: { scope: AccessScope.PUBLIC },\n * instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),\n * certificateProps:{\n * domainName: \"prod-guardian.com\",\n * },\n * monitoringConfiguration: {\n * snsTopicName: \"alerts-topic-for-my-team\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * },\n * unhealthyInstancesAlarm: true,\n * },\n * userData: {\n * distributable: {\n * fileName: \"app-name.deb\",\n * executionStatement: `dpkg -i /app-name/app-name.deb`,\n * }\n * },\n * });\n * ```\n *\n * Example usage for an app which is restricted to specific CIDR ranges:\n * ```typescript\n * new GuEc2App(stack, {\n * applicationPort: 1234,\n * app: \"app-name\",\n * access: {\n * scope: AccessScope.RESTRICTED,\n * cidrRanges: [Peer.ipv4(\"192.168.1.1/32\"), Peer.ipv4(\"8.8.8.8/32\")],\n * },\n * instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),\n * certificateProps:{\n * domainName: \"prod-guardian.com\",\n * },\n * monitoringConfiguration: {\n * snsTopicName: \"alerts-topic-for-my-team\",\n * http5xxAlarm: {\n * tolerated5xxPercentage: 1,\n * },\n * unhealthyInstancesAlarm: true,\n * }\n * userData: {\n * distributable: {\n * fileName: \"app-name.deb\",\n * executionStatement: `dpkg -i /app-name/app-name.deb`,\n * }\n * },\n * });\n * ```\n *\n * ### Varying values by stage\n *\n * There are times when you want a resource's configuration to be stage aware,\n * for example the number of instances in an ASG.\n *\n * To do this, we can use a simple ternary:\n * ```typescript\n * new GuEc2App(this, {\n * // other required properties\n * scaling: this.stage === \"PROD\" ? { minimumInstances: 6 } : { minimumInstances: 1 }\n * });\n * ```\n *\n * If multiple properties need to be stage aware, consider encoding this into the `props` of the calling class:\n *\n * ```typescript\n * export interface MyAppProps extends GuStackProps {\n * domainName: string;\n * scaling: GuAsgCapacity;\n * monitoringConfiguration: Alarms | NoMonitoring;\n * }\n *\n * export class MyApp extends GuStack {\n * private static app = \"cdk-playground\";\n *\n * constructor(scope: App, id: string, props: MyAppProps) {\n * const { stage, domainName, scaling, monitoringConfiguration } = props;\n *\n * super(scope, id, props);\n *\n * new GuPlayApp(this, {\n * app: \"my-app\",\n * instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MICRO),\n * access: { scope: AccessScope.PUBLIC },\n * userData: {\n * distributable: {\n * fileName: `my-app.deb`,\n * executionStatement: `dpkg -i /my-app/my-app.deb`,\n * },\n * },\n * certificateProps: {\n * domainName,\n * },\n * monitoringConfiguration,\n * scaling,\n * });\n * }\n * }\n *\n * new MyApp(app, \"MyApp-CODE\", {\n * stage: \"CODE\",\n * domainName: \"my-app.code.dev-gutools.co.uk\",\n * scaling: { minimumInstances: 1 },\n * monitoringConfiguration: { noMonitoring: true },\n * });\n *\n * new MyApp(app, \"MyApp-PROD\", {\n * stage: \"PROD\",\n * domainName: \"my-app.prod.gutools.co.uk\",\n * scaling: { minimumInstances: 6 },\n * monitoringConfiguration: {\n * // config to enable alarms in PROD\n * },\n * });\n * ```\n *\n *\n * ### Customising the infrastructure generated by this pattern\n *\n * Although we allow users to customise many aspects of their infrastructure via [[`GuEc2AppProps`]], it's possible\n * that there are less common use-cases which are currently unsupported via the API. In these circumstances escape\n * hatches can be used to override specific resources in the stack.\n *\n * In order to do this:\n *\n * 1. Create desired resource using Guardian or AWS constructs, for example:\n * ```typescript\n * const sg = new GuSecurityGroup(\n * // custom parameters\n * );\n * ```\n * 2. Access the CloudFormation version of the resource that you wish to customise, for example:\n * ```typescript\n * const pattern = new GuEc2App(\n * // all parameters\n * )\n * const cfnLb = pattern.loadBalancer.node.defaultChild as CfnLoadBalancer;\n * ```\n * 3. Replace the resource generated by the pattern with your bespoke resource, for example:\n * ```typescript\n * cfnLb.securityGroups = [sg.securityGroupId];\n * ```\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: { domainName, hostedZoneId },\n instanceType,\n monitoringConfiguration,\n roleConfiguration = { withoutLogShipping: false, additionalPolicies: [] },\n scaling: { minimumInstances, maximumInstances = minimumInstances * 2 },\n userData,\n withoutImdsv2,\n imageRecipe,\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 const vpc = GuVpc.fromIdParameter(scope, AppIdentity.suffixText({ app }, \"VPC\"));\n const privateSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PRIVATE, app });\n\n AppAccess.validate(access);\n\n const certificate = new GuCertificate(scope, {\n app,\n domainName,\n hostedZoneId,\n });\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 // We are selectively tagging the ASG so that we can expose the number of stacks using this pattern\n // based on which autoscaling groups possess this tag. It may become useful or necessary to tag all resources in the future,\n // but we have decided that this is sufficient for now.\n // TODO: Do we need to tag all resources with this value? What would the use-cases be?\n Tags.of(autoScalingGroup).add(MetadataKeys.PATTERN_NAME, this.constructor.name, { applyToLaunchedInstances: true });\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:\n access.scope === AccessScope.INTERNAL\n ? privateSubnets\n : GuVpc.subnetsFromParameter(scope, { type: SubnetType.PUBLIC, app }),\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 });\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,\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 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"]}
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": "47.3.4",
4
+ "version": "48.0.0",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "files": [
@@ -28,43 +28,43 @@
28
28
  "cli:dev": "ts-node src/bin/index.ts"
29
29
  },
30
30
  "devDependencies": {
31
- "@guardian/eslint-config-typescript": "1.0.9",
31
+ "@guardian/eslint-config-typescript": "1.0.11",
32
32
  "@types/git-url-parse": "^9.0.1",
33
- "@types/jest": "^27.5.0",
33
+ "@types/jest": "^29.1.1",
34
34
  "@types/js-yaml": "^4.0.5",
35
35
  "@types/lodash.camelcase": "^4.3.7",
36
36
  "@types/lodash.kebabcase": "^4.1.7",
37
37
  "@types/lodash.upperfirst": "^4.3.7",
38
- "@types/node": "18.7.15",
39
- "@types/yargs": "^17.0.12",
38
+ "@types/node": "18.8.0",
39
+ "@types/yargs": "^17.0.13",
40
40
  "aws-cdk": "2.44.0",
41
41
  "cz-conventional-changelog": "^3.3.0",
42
- "eslint": "^8.23.0",
42
+ "eslint": "^8.24.0",
43
43
  "eslint-plugin-custom-rules": "file:tools/eslint",
44
44
  "gh-pages": "^4.0.0",
45
- "jest": "^27.5.1",
45
+ "jest": "^29.1.2",
46
46
  "prettier": "^2.7.1",
47
47
  "semantic-release": "^19.0.5",
48
48
  "serve": "^14.0.1",
49
- "ts-jest": "^27.1.4",
49
+ "ts-jest": "^29.0.3",
50
50
  "ts-node": "^10.9.1",
51
- "typedoc": "^0.23.14",
52
- "typescript": "~4.7.4"
51
+ "typedoc": "^0.23.15",
52
+ "typescript": "~4.8.4"
53
53
  },
54
54
  "dependencies": {
55
- "@oclif/core": "1.16.0",
55
+ "@oclif/core": "1.16.4",
56
56
  "aws-cdk-lib": "2.44.0",
57
- "aws-sdk": "^2.1214.0",
57
+ "aws-sdk": "^2.1227.0",
58
58
  "chalk": "^4.1.2",
59
- "codemaker": "^1.67.0",
59
+ "codemaker": "^1.69.0",
60
60
  "constructs": "10.1.117",
61
- "git-url-parse": "^13.0.0",
61
+ "git-url-parse": "^13.1.0",
62
62
  "js-yaml": "^4.1.0",
63
63
  "lodash.camelcase": "^4.3.0",
64
64
  "lodash.kebabcase": "^4.1.1",
65
65
  "lodash.upperfirst": "^4.3.1",
66
66
  "read-pkg-up": "7.0.1",
67
- "yargs": "^17.5.1"
67
+ "yargs": "^17.6.0"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "aws-cdk": "2.44.0",