|
1 | 1 | import { |
2 | 2 | Stack, |
3 | 3 | aws_rds as rds, |
| 4 | + aws_ec2 as ec2, |
4 | 5 | aws_secretsmanager as secretsmanager, |
| 6 | + aws_lambda, |
| 7 | + CustomResource, |
| 8 | + RemovalPolicy, |
| 9 | + Duration, |
| 10 | + aws_logs, |
| 11 | + |
5 | 12 | } from "aws-cdk-lib"; |
6 | 13 | import { Construct } from "constructs"; |
7 | | -import { BootstrapPgStac, BootstrapPgStacProps } from "../bootstrapper"; |
| 14 | +import { CustomLambdaFunctionProps } from "../utils"; |
8 | 15 |
|
9 | 16 | const instanceSizes: Record<string, number> = require("./instance-memory.json"); |
| 17 | +const DEFAULT_PGSTAC_VERSION = "0.7.10"; |
| 18 | + |
| 19 | +function hasVpc( |
| 20 | + instance: rds.DatabaseInstance | rds.IDatabaseInstance |
| 21 | +): instance is rds.DatabaseInstance { |
| 22 | + return (instance as rds.DatabaseInstance).vpc !== undefined; |
| 23 | +} |
10 | 24 |
|
11 | 25 | /** |
12 | 26 | * An RDS instance with pgSTAC installed. This is a wrapper around the |
@@ -45,17 +59,76 @@ export class PgStacDatabase extends Construct { |
45 | 59 | ...props, |
46 | 60 | }); |
47 | 61 |
|
48 | | - const bootstrap = new BootstrapPgStac(this, "bootstrap-pgstac-instance", { |
49 | | - vpc: props.vpc, |
50 | | - database: this.db, |
51 | | - dbSecret: this.db.secret!, |
52 | | - pgstacDbName: props.pgstacDbName, |
53 | | - pgstacVersion: props.pgstacVersion, |
54 | | - pgstacUsername: props.pgstacUsername, |
55 | | - secretsPrefix: props.secretsPrefix, |
| 62 | + const handler = new aws_lambda.Function(this, "lambda", { |
| 63 | + // defaults for configurable properties |
| 64 | + runtime: aws_lambda.Runtime.PYTHON_3_11, |
| 65 | + handler: "handler.handler", |
| 66 | + memorySize: 128, |
| 67 | + logRetention: aws_logs.RetentionDays.ONE_WEEK, |
| 68 | + timeout: Duration.minutes(2), |
| 69 | + code: aws_lambda.Code.fromDockerBuild(__dirname, { |
| 70 | + file: "bootstrapper_runtime/Dockerfile", |
| 71 | + buildArgs: {PGSTAC_VERSION: DEFAULT_PGSTAC_VERSION, PYTHON_VERSION: "3.11"} |
| 72 | + }), |
| 73 | + // overwrites defaults with user-provided configurable properties |
| 74 | + ...props.bootstrapperLambdaFunctionOptions, |
| 75 | + // Non configurable properties that are going to be overwritten even if provided by the user |
| 76 | + vpc: hasVpc(this.db) ? this.db.vpc : props.vpc, |
| 77 | + allowPublicSubnet: true |
| 78 | + }); |
| 79 | + |
| 80 | + this.pgstacSecret = new secretsmanager.Secret(this, "bootstrappersecret", { |
| 81 | + secretName: [ |
| 82 | + props.secretsPrefix || "pgstac", |
| 83 | + id, |
| 84 | + this.node.addr.slice(-8), |
| 85 | + ].join("/"), |
| 86 | + generateSecretString: { |
| 87 | + secretStringTemplate: JSON.stringify({ |
| 88 | + dbname: props.pgstacDbName || "pgstac", |
| 89 | + engine: "postgres", |
| 90 | + port: 5432, |
| 91 | + host: this.db.instanceEndpoint.hostname, |
| 92 | + username: props.pgstacUsername || "pgstac_user", |
| 93 | + }), |
| 94 | + generateStringKey: "password", |
| 95 | + excludePunctuation: true, |
| 96 | + }, |
| 97 | + description: `PgSTAC database bootstrapped by ${ |
| 98 | + Stack.of(this).stackName |
| 99 | + }`, |
| 100 | + }); |
| 101 | + |
| 102 | + // Allow lambda to... |
| 103 | + // read new user secret |
| 104 | + this.pgstacSecret.grantRead(handler); |
| 105 | + // read database secret |
| 106 | + this.db.secret!.grantRead(handler); |
| 107 | + // connect to database |
| 108 | + this.db.connections.allowFrom(handler, ec2.Port.tcp(5432)); |
| 109 | + |
| 110 | + let customResourceProperties : { [key: string]: any} = {}; |
| 111 | + |
| 112 | + // if customResourceProperties are provided, fill in the values. |
| 113 | + if (props.customResourceProperties) { |
| 114 | + Object.assign(customResourceProperties, props.customResourceProperties); |
| 115 | + } |
| 116 | + |
| 117 | + // update properties |
| 118 | + customResourceProperties["conn_secret_arn"] = this.db.secret!.secretArn; |
| 119 | + customResourceProperties["new_user_secret_arn"] = this.pgstacSecret.secretArn; |
| 120 | + |
| 121 | + // if props.lambdaFunctionOptions doesn't have 'code' defined, update pgstac_version (needed for default runtime) |
| 122 | + if (!props.bootstrapperLambdaFunctionOptions?.code) { |
| 123 | + customResourceProperties["pgstac_version"] = DEFAULT_PGSTAC_VERSION; |
| 124 | + } |
| 125 | + // this.connections = props.database.connections; |
| 126 | + new CustomResource(this, "bootstrapper", { |
| 127 | + serviceToken: handler.functionArn, |
| 128 | + properties: customResourceProperties, |
| 129 | + removalPolicy: RemovalPolicy.RETAIN, // This retains the custom resource (which doesn't really exist), not the database |
56 | 130 | }); |
57 | 131 |
|
58 | | - this.pgstacSecret = bootstrap.secret; |
59 | 132 | } |
60 | 133 |
|
61 | 134 | public getParameters( |
@@ -99,10 +172,43 @@ export class PgStacDatabase extends Construct { |
99 | 172 | } |
100 | 173 |
|
101 | 174 | export interface PgStacDatabaseProps extends rds.DatabaseInstanceProps { |
102 | | - readonly pgstacDbName?: BootstrapPgStacProps["pgstacDbName"]; |
103 | | - readonly pgstacVersion?: BootstrapPgStacProps["pgstacVersion"]; |
104 | | - readonly pgstacUsername?: BootstrapPgStacProps["pgstacUsername"]; |
105 | | - readonly secretsPrefix?: BootstrapPgStacProps["secretsPrefix"]; |
| 175 | + /** |
| 176 | + * Name of database that is to be created and onto which pgSTAC will be installed. |
| 177 | + * |
| 178 | + * @default pgstac |
| 179 | + */ |
| 180 | + readonly pgstacDbName?: string; |
| 181 | + |
| 182 | + /** |
| 183 | + * Prefix to assign to the generated `secrets_manager.Secret` |
| 184 | + * |
| 185 | + * @default pgstac |
| 186 | + */ |
| 187 | + readonly secretsPrefix?: string; |
| 188 | + |
| 189 | + /** |
| 190 | + * Name of user that will be generated for connecting to the pgSTAC database. |
| 191 | + * |
| 192 | + * @default pgstac_user |
| 193 | + */ |
| 194 | + readonly pgstacUsername?: string; |
| 195 | + |
| 196 | + /** |
| 197 | + * Lambda function Custom Resource properties. A custom resource property is going to be created |
| 198 | + * to trigger the boostrapping lambda function. This parameter allows the user to specify additional properties |
| 199 | + * on top of the defaults ones. |
| 200 | + * |
| 201 | + */ |
| 202 | + readonly customResourceProperties?: { |
| 203 | + [key: string]: any; |
| 204 | +} |
| 205 | + |
| 206 | + /** |
| 207 | + * Optional settings for the bootstrapper lambda function. Can be anything that can be configured on the lambda function, but some will be overwritten by values defined here. |
| 208 | + * |
| 209 | + * @default - defined in the construct. |
| 210 | + */ |
| 211 | + readonly bootstrapperLambdaFunctionOptions?: CustomLambdaFunctionProps; |
106 | 212 | } |
107 | 213 |
|
108 | 214 | export interface DatabaseParameters { |
|
0 commit comments