@digitraffic/common 2022.11.2-1 → 2022.11.11-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/aws/infra/canaries/database-checker.d.ts +22 -10
  2. package/dist/aws/infra/canaries/database-checker.js +38 -28
  3. package/dist/aws/infra/canaries/database-checker.js.map +1 -1
  4. package/dist/aws/infra/import-util.d.ts +21 -0
  5. package/dist/aws/infra/import-util.js +53 -0
  6. package/dist/aws/infra/import-util.js.map +1 -0
  7. package/dist/aws/infra/stack/lambda-configs.d.ts +0 -8
  8. package/dist/aws/infra/stack/lambda-configs.js +7 -7
  9. package/dist/aws/infra/stack/rest_apis.d.ts +1 -1
  10. package/dist/aws/infra/stack/rest_apis.js +2 -2
  11. package/dist/aws/infra/stack/rest_apis.js.map +1 -1
  12. package/dist/aws/infra/stacks/db-dns-stack.d.ts +11 -0
  13. package/dist/aws/infra/stacks/db-dns-stack.js +63 -0
  14. package/dist/aws/infra/stacks/db-dns-stack.js.map +1 -0
  15. package/dist/aws/infra/stacks/db-proxy-stack.d.ts +19 -0
  16. package/dist/aws/infra/stacks/db-proxy-stack.js +74 -0
  17. package/dist/aws/infra/stacks/db-proxy-stack.js.map +1 -0
  18. package/dist/aws/infra/stacks/db-stack.d.ts +31 -0
  19. package/dist/aws/infra/stacks/db-stack.js +91 -0
  20. package/dist/aws/infra/stacks/db-stack.js.map +1 -0
  21. package/dist/aws/infra/stacks/intra-stack-configuration.d.ts +5 -0
  22. package/dist/aws/infra/stacks/intra-stack-configuration.js +3 -0
  23. package/dist/aws/infra/stacks/intra-stack-configuration.js.map +1 -0
  24. package/dist/aws/infra/stacks/network-stack.d.ts +12 -0
  25. package/dist/aws/infra/stacks/network-stack.js +36 -0
  26. package/dist/aws/infra/stacks/network-stack.js.map +1 -0
  27. package/dist/aws/infra/usage-plans.d.ts +3 -2
  28. package/dist/aws/infra/usage-plans.js +5 -4
  29. package/dist/aws/infra/usage-plans.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/aws/infra/canaries/database-checker.ts +48 -44
  32. package/src/aws/infra/import-util.ts +57 -0
  33. package/src/aws/infra/stack/lambda-configs.ts +7 -16
  34. package/src/aws/infra/stack/rest_apis.ts +2 -2
  35. package/src/aws/infra/stacks/db-dns-stack.ts +88 -0
  36. package/src/aws/infra/stacks/db-proxy-stack.ts +129 -0
  37. package/src/aws/infra/stacks/db-stack.ts +165 -0
  38. package/src/aws/infra/stacks/intra-stack-configuration.ts +6 -0
  39. package/src/aws/infra/stacks/network-stack.ts +46 -0
  40. package/src/aws/infra/usage-plans.ts +15 -6
@@ -0,0 +1,129 @@
1
+ import { Duration, Stack } from "aws-cdk-lib";
2
+ import { Construct } from "constructs";
3
+ import {
4
+ CfnDBProxyEndpoint,
5
+ DatabaseCluster,
6
+ DatabaseClusterEngine,
7
+ DatabaseProxy,
8
+ ProxyTarget,
9
+ } from "aws-cdk-lib/aws-rds";
10
+ import { ISecret, Secret } from "aws-cdk-lib/aws-secretsmanager";
11
+ import { IVpc, SecurityGroup } from "aws-cdk-lib/aws-ec2";
12
+ import { InfraStackConfiguration } from "./intra-stack-configuration";
13
+ import { DbConfiguration, DbStack } from "./db-stack";
14
+ import { exportValue, importValue, importVpc } from "../import-util";
15
+
16
+ /**
17
+ * A stack that creates a Database proxy.
18
+ */
19
+ export class DbProxyStack extends Stack {
20
+ public static PROXY_READER_EXPORT_NAME = "db-reader-endpoint";
21
+ public static PROXY_WRITER_EXPORT_NAME = "db-writer-endpoint";
22
+
23
+ readonly isc: InfraStackConfiguration;
24
+
25
+ constructor(
26
+ scope: Construct,
27
+ id: string,
28
+ isc: InfraStackConfiguration,
29
+ configuration: DbConfiguration
30
+ ) {
31
+ super(scope, id, {
32
+ env: isc.env,
33
+ });
34
+
35
+ this.isc = isc;
36
+
37
+ const vpc = importVpc(this, isc.environmentName);
38
+ const secret = Secret.fromSecretAttributes(this, "proxy-secret", {
39
+ secretCompleteArn: configuration.secretArn,
40
+ });
41
+ const proxy = this.createProxy(vpc, secret, configuration);
42
+ const readerEndpoint = this.createProxyEndpoints(
43
+ vpc,
44
+ proxy,
45
+ configuration.securityGroupId
46
+ );
47
+ this.setOutputs(configuration, proxy, readerEndpoint);
48
+ }
49
+
50
+ createProxy(vpc: IVpc, secret: ISecret, configuration: DbConfiguration) {
51
+ const proxyId = `${this.isc.environmentName}-proxy`;
52
+ const securityGroup = SecurityGroup.fromSecurityGroupId(
53
+ this,
54
+ "securitygroup",
55
+ configuration.securityGroupId
56
+ );
57
+
58
+ const cluster = DatabaseCluster.fromDatabaseClusterAttributes(
59
+ this,
60
+ "db-cluster",
61
+ {
62
+ clusterIdentifier: importValue(
63
+ this.isc.environmentName,
64
+ DbStack.CLUSTER_IDENTIFIER_EXPORT_NAME
65
+ ),
66
+ engine: DatabaseClusterEngine.AURORA_POSTGRESQL,
67
+ port: DbStack.CLUSTER_PORT,
68
+ }
69
+ );
70
+
71
+ // CDK tries to allow connections between proxy and cluster
72
+ // this does not work on cluster references
73
+ cluster.connections.allowDefaultPortFrom = () => {
74
+ /* nothing */
75
+ };
76
+
77
+ return new DatabaseProxy(this, proxyId, {
78
+ dbProxyName: configuration.dbProxyName ?? "AuroraProxy",
79
+ securityGroups: [securityGroup],
80
+ proxyTarget: ProxyTarget.fromCluster(cluster),
81
+ idleClientTimeout: Duration.seconds(1800),
82
+ maxConnectionsPercent: 50,
83
+ maxIdleConnectionsPercent: 25,
84
+ borrowTimeout: Duration.seconds(120),
85
+ requireTLS: false,
86
+ secrets: [secret],
87
+ vpc: vpc,
88
+ });
89
+ }
90
+
91
+ createProxyEndpoints(
92
+ vpc: IVpc,
93
+ proxy: DatabaseProxy,
94
+ securityGroupId: string
95
+ ) {
96
+ return new CfnDBProxyEndpoint(this, "ReaderEndpoint", {
97
+ dbProxyEndpointName: "ReaderEndpoint",
98
+ dbProxyName: proxy.dbProxyName,
99
+ vpcSubnetIds: vpc.privateSubnets.map((sub) => sub.subnetId),
100
+ vpcSecurityGroupIds: [securityGroupId],
101
+ targetRole: "READ_ONLY",
102
+ });
103
+ }
104
+
105
+ setOutputs(
106
+ configuration: DbConfiguration,
107
+ proxy: DatabaseProxy,
108
+ proxyEndpoint: CfnDBProxyEndpoint
109
+ ) {
110
+ const readerEndpoint =
111
+ configuration.instances > 1
112
+ ? proxyEndpoint.attrEndpoint
113
+ : proxy.endpoint;
114
+
115
+ // if only one instance, then there is no reader-endpoint
116
+ exportValue(
117
+ this,
118
+ this.isc.environmentName,
119
+ DbProxyStack.PROXY_READER_EXPORT_NAME,
120
+ readerEndpoint
121
+ );
122
+ exportValue(
123
+ this,
124
+ this.isc.environmentName,
125
+ DbProxyStack.PROXY_WRITER_EXPORT_NAME,
126
+ proxy.endpoint
127
+ );
128
+ }
129
+ }
@@ -0,0 +1,165 @@
1
+ import { Duration, RemovalPolicy, Stack } from "aws-cdk-lib";
2
+ import { Construct } from "constructs";
3
+ import { SecurityGroup, SubnetType } from "aws-cdk-lib/aws-ec2";
4
+ import {
5
+ AuroraPostgresEngineVersion,
6
+ CfnDBInstance,
7
+ Credentials,
8
+ DatabaseCluster,
9
+ DatabaseClusterEngine,
10
+ DatabaseClusterFromSnapshot,
11
+ InstanceUpdateBehaviour,
12
+ ParameterGroup,
13
+ } from "aws-cdk-lib/aws-rds";
14
+ import { Secret } from "aws-cdk-lib/aws-secretsmanager";
15
+ import { exportValue, importVpc } from "../import-util";
16
+ import { InstanceType } from "aws-cdk-lib/aws-ec2";
17
+ import { InfraStackConfiguration } from "./intra-stack-configuration";
18
+
19
+ export interface DbConfiguration {
20
+ readonly secretArn: string;
21
+
22
+ readonly dbVersion: AuroraPostgresEngineVersion;
23
+ readonly dbInstanceType: InstanceType;
24
+ readonly snapshotIdentifier: string;
25
+ readonly instances: number;
26
+ readonly customParameterGroup: boolean;
27
+ readonly securityGroupId: string;
28
+
29
+ readonly dbProxyName?: string;
30
+ }
31
+
32
+ /**
33
+ * How to upgrade major version?
34
+ * 0. Set correct SG for db-stack and db-proxy-stack(this step will be removed in the future)
35
+ * 1. Update db-stack WITHOUT parameter group
36
+ * 2. Upgrade extensions by hand
37
+ * 3. Upgrade database from the AWS console
38
+ * 4. Update db-stack with the upgraded version and custom parameter group
39
+ */
40
+
41
+ export class DbStack extends Stack {
42
+ public static CLUSTER_IDENTIFIER_EXPORT_NAME = "db-cluster";
43
+ public static CLUSTER_READ_ENDPOINT_EXPORT_NAME =
44
+ "db-cluster-reader-endpoint";
45
+ public static CLUSTER_WRITE_ENDPOINT_EXPORT_NAME =
46
+ "db-cluster-writer-endpoint";
47
+
48
+ public static CLUSTER_PORT = 5432;
49
+
50
+ constructor(
51
+ scope: Construct,
52
+ id: string,
53
+ isc: InfraStackConfiguration,
54
+ configuration: DbConfiguration
55
+ ) {
56
+ super(scope, id, {
57
+ env: isc.env,
58
+ });
59
+
60
+ const cluster = this.createAuroraCluster(isc, configuration);
61
+
62
+ exportValue(
63
+ this,
64
+ isc.environmentName,
65
+ DbStack.CLUSTER_IDENTIFIER_EXPORT_NAME,
66
+ cluster.clusterIdentifier
67
+ );
68
+ exportValue(
69
+ this,
70
+ isc.environmentName,
71
+ DbStack.CLUSTER_WRITE_ENDPOINT_EXPORT_NAME,
72
+ cluster.clusterEndpoint.hostname
73
+ );
74
+ exportValue(
75
+ this,
76
+ isc.environmentName,
77
+ DbStack.CLUSTER_READ_ENDPOINT_EXPORT_NAME,
78
+ cluster.clusterReadEndpoint.hostname
79
+ );
80
+ }
81
+
82
+ createAuroraCluster(
83
+ isc: InfraStackConfiguration,
84
+ configuration: DbConfiguration
85
+ ): DatabaseCluster {
86
+ const instanceName = isc.environmentName + "-db";
87
+ const secret = Secret.fromSecretAttributes(this, "db-secret", {
88
+ secretCompleteArn: configuration.secretArn,
89
+ });
90
+ const securityGroup = SecurityGroup.fromSecurityGroupId(
91
+ this,
92
+ "securitygroup",
93
+ configuration.securityGroupId
94
+ );
95
+ const vpc = importVpc(this, isc.environmentName);
96
+
97
+ const parameterGroup = configuration.customParameterGroup
98
+ ? new ParameterGroup(
99
+ this,
100
+ `parameter-group-${configuration.dbVersion.auroraPostgresMajorVersion}`,
101
+ {
102
+ engine: DatabaseClusterEngine.auroraPostgres({
103
+ version: configuration.dbVersion,
104
+ }),
105
+ parameters: {
106
+ "pg_stat_statements.track": "ALL",
107
+ random_page_cost: "1",
108
+ },
109
+ }
110
+ )
111
+ : ParameterGroup.fromParameterGroupName(
112
+ this,
113
+ "ParameterGroup",
114
+ `default.aurora-postgresql${configuration.dbVersion.auroraPostgresMajorVersion}`
115
+ );
116
+
117
+ const cluster = new DatabaseClusterFromSnapshot(this, instanceName, {
118
+ snapshotIdentifier: configuration.snapshotIdentifier,
119
+ engine: DatabaseClusterEngine.auroraPostgres({
120
+ version: configuration.dbVersion,
121
+ }),
122
+ instances: configuration.instances,
123
+ instanceUpdateBehaviour: InstanceUpdateBehaviour.ROLLING,
124
+ instanceIdentifierBase: instanceName + "-",
125
+ cloudwatchLogsExports: ["postgresql"],
126
+ backup: {
127
+ retention: Duration.days(35),
128
+ preferredWindow: "01:00-02:00",
129
+ },
130
+ preferredMaintenanceWindow: "mon:03:00-mon:04:00",
131
+ deletionProtection: true,
132
+ removalPolicy: RemovalPolicy.RETAIN,
133
+ port: DbStack.CLUSTER_PORT,
134
+ instanceProps: {
135
+ autoMinorVersionUpgrade: true,
136
+ allowMajorVersionUpgrade: false,
137
+ enablePerformanceInsights: true,
138
+ vpc,
139
+ securityGroups: [securityGroup],
140
+ vpcSubnets: {
141
+ subnetType: SubnetType.PRIVATE_WITH_NAT,
142
+ },
143
+ instanceType: configuration.dbInstanceType,
144
+ parameterGroup,
145
+ },
146
+ credentials: Credentials.fromSecret(secret),
147
+ parameterGroup,
148
+ });
149
+
150
+ // this workaround should prevent stack failing on version upgrade
151
+ const cfnInstances = cluster.node.children.filter(
152
+ (child): child is CfnDBInstance => child instanceof CfnDBInstance
153
+ );
154
+ if (cfnInstances.length === 0) {
155
+ throw new Error(
156
+ "Couldn't pull CfnDBInstances from the L1 constructs!"
157
+ );
158
+ }
159
+ cfnInstances.forEach(
160
+ (cfnInstance) => delete cfnInstance.engineVersion
161
+ );
162
+
163
+ return cluster;
164
+ }
165
+ }
@@ -0,0 +1,6 @@
1
+ import { Environment } from "aws-cdk-lib";
2
+
3
+ export interface InfraStackConfiguration {
4
+ readonly env: Environment;
5
+ readonly environmentName: string;
6
+ }
@@ -0,0 +1,46 @@
1
+ import { Stack } from "aws-cdk-lib";
2
+ import { Construct } from "constructs";
3
+ import { SubnetType, Vpc } from "aws-cdk-lib/aws-ec2";
4
+ import { InfraStackConfiguration } from "./intra-stack-configuration";
5
+
6
+ export interface NetworkConfiguration {
7
+ readonly vpcName: string;
8
+ readonly cidr: string;
9
+ }
10
+
11
+ export class NetworkStack extends Stack {
12
+ constructor(
13
+ scope: Construct,
14
+ id: string,
15
+ isc: InfraStackConfiguration,
16
+ configuration: NetworkConfiguration
17
+ ) {
18
+ super(scope, id, {
19
+ env: isc.env,
20
+ });
21
+
22
+ this.createVpc(configuration);
23
+ }
24
+
25
+ createVpc(configuration: NetworkConfiguration): Vpc {
26
+ return new Vpc(this, "DigitrafficVPC", {
27
+ vpcName: configuration.vpcName,
28
+ availabilityZones: ["eu-west-1a", "eu-west-1b"],
29
+ enableDnsHostnames: true,
30
+ enableDnsSupport: true,
31
+ cidr: configuration.cidr,
32
+ subnetConfiguration: [
33
+ {
34
+ name: "public",
35
+ cidrMask: 24,
36
+ subnetType: SubnetType.PUBLIC,
37
+ },
38
+ {
39
+ name: "private",
40
+ cidrMask: 24,
41
+ subnetType: SubnetType.PRIVATE_WITH_NAT,
42
+ },
43
+ ],
44
+ });
45
+ }
46
+ }
@@ -1,4 +1,4 @@
1
- import {IApiKey, RestApi} from 'aws-cdk-lib/aws-apigateway';
1
+ import { IApiKey, RestApi } from "aws-cdk-lib/aws-apigateway";
2
2
 
3
3
  /**
4
4
  * Creates an usage plan for a REST API with a single API key
@@ -7,7 +7,11 @@ import {IApiKey, RestApi} from 'aws-cdk-lib/aws-apigateway';
7
7
  * @param apiKeyName Name for the API key, this is displayed in the AWS Console
8
8
  * @deprecated Creates randomized API key names, use createDefaultUsagePlan instead
9
9
  */
10
- export function createUsagePlan(api: RestApi, apiKeyId: string, apiKeyName: string): IApiKey {
10
+ export function createUsagePlan(
11
+ api: RestApi,
12
+ apiKeyId: string,
13
+ apiKeyName: string
14
+ ): IApiKey {
11
15
  const apiKey = api.addApiKey(apiKeyId);
12
16
  const plan = api.addUsagePlan(apiKeyName, {
13
17
  name: apiKeyName,
@@ -24,11 +28,16 @@ export function createUsagePlan(api: RestApi, apiKeyId: string, apiKeyName: stri
24
28
  * Creates a default usage plan for a REST API with a single API key
25
29
  * @param api The REST API
26
30
  * @param apiName Name of the api. Will generate key: apiName + ' API Key' and plan: apiName + ' API Usage Plan'
31
+ * @param value Optional value for the API key
27
32
  */
28
- export function createDefaultUsagePlan(api: RestApi, apiName: string): IApiKey {
29
- const apiKeyName = apiName + ' API Key';
30
- const usagePlanName = apiName + ' API Usage Plan';
31
- const apiKey = api.addApiKey(apiKeyName, { apiKeyName: apiKeyName });
33
+ export function createDefaultUsagePlan(
34
+ api: RestApi,
35
+ apiName: string,
36
+ value?: string
37
+ ): IApiKey {
38
+ const apiKeyName = apiName + " API Key";
39
+ const usagePlanName = apiName + " API Usage Plan";
40
+ const apiKey = api.addApiKey(apiKeyName, { apiKeyName: apiKeyName, value });
32
41
  const plan = api.addUsagePlan(usagePlanName, {
33
42
  name: usagePlanName,
34
43
  });