Skip to content

Commit ba6bf09

Browse files
authored
feat: custom runtimes, optional VPC, python 3.11 (#74)
* database bootstrapper lambda is configurable. As a result, we had to merge the `database` and `bootstrapper` constructs together, thus the `bootstrapper` construct is no longer available. * Switched to `Function` and `FromDockerBuild` for the `Code` for all lambdas to allow for more flexible configurability * made VPC optional for lambdas to allow for low-security deployments that do not necessitate a NAT gateway * harmonized pgstac to 0.7.10 in default runtimes. * harmonized python to 3.11 in default runtimes. BREAKING CHANGE: the `bootstrapper` construct was deleted and is no longer available. In addition, we switched from `PythonFunction` to `Function` for all lambdas.
1 parent 239b0a9 commit ba6bf09

File tree

23 files changed

+3437
-678
lines changed

23 files changed

+3437
-678
lines changed

lib/bootstrapper/index.ts

Lines changed: 0 additions & 142 deletions
This file was deleted.

lib/bootstrapper/runtime/Dockerfile renamed to lib/database/bootstrapper_runtime/Dockerfile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
FROM lambci/lambda:build-python3.8
1+
ARG PYTHON_VERSION
2+
FROM --platform=linux/amd64 public.ecr.aws/lambda/python:${PYTHON_VERSION}
23

34
ARG PGSTAC_VERSION
4-
RUN echo "Using PGSTAC Version ${PGSTAC_VERSION}"
5+
RUN echo "PGSTAC_VERSION: ${PGSTAC_VERSION}"
6+
RUN echo "PYTHON_VERSION: ${PYTHON_VERSION}"
57

68
WORKDIR /tmp
79

810
RUN pip install httpx psycopg[binary,pool] pypgstac==${PGSTAC_VERSION} -t /asset
911

10-
COPY runtime/handler.py /asset/handler.py
12+
COPY bootstrapper_runtime/handler.py /asset/handler.py
1113

1214
# https://stackoverflow.com/a/61746719
1315
# Tip from eoAPI: turns out, asyncio is part of python
File renamed without changes.

lib/database/index.ts

Lines changed: 120 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import {
22
Stack,
33
aws_rds as rds,
4+
aws_ec2 as ec2,
45
aws_secretsmanager as secretsmanager,
6+
aws_lambda,
7+
CustomResource,
8+
RemovalPolicy,
9+
Duration,
10+
aws_logs,
11+
512
} from "aws-cdk-lib";
613
import { Construct } from "constructs";
7-
import { BootstrapPgStac, BootstrapPgStacProps } from "../bootstrapper";
14+
import { CustomLambdaFunctionProps } from "../utils";
815

916
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+
}
1024

1125
/**
1226
* An RDS instance with pgSTAC installed. This is a wrapper around the
@@ -45,17 +59,76 @@ export class PgStacDatabase extends Construct {
4559
...props,
4660
});
4761

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
56130
});
57131

58-
this.pgstacSecret = bootstrap.secret;
59132
}
60133

61134
public getParameters(
@@ -99,10 +172,43 @@ export class PgStacDatabase extends Construct {
99172
}
100173

101174
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;
106212
}
107213

108214
export interface DatabaseParameters {

lib/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export * from "./bastion-host";
2-
export * from "./bootstrapper";
32
export * from "./database";
43
export * from "./ingestor-api";
54
export * from "./stac-api";
65
export * from "./titiler-pgstac-api";
76
export * from "./stac-browser";
87
export * from "./tipg-api";
8+
export * from "./utils";

0 commit comments

Comments
 (0)