Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom runtimes, optional VPC, python 3.11 #74

Merged
merged 12 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 0 additions & 142 deletions lib/bootstrapper/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
FROM lambci/lambda:build-python3.8
ARG PYTHON_VERSION
FROM --platform=linux/amd64 public.ecr.aws/lambda/python:${PYTHON_VERSION}

ARG PGSTAC_VERSION
RUN echo "Using PGSTAC Version ${PGSTAC_VERSION}"
RUN echo "PGSTAC_VERSION: ${PGSTAC_VERSION}"
RUN echo "PYTHON_VERSION: ${PYTHON_VERSION}"

WORKDIR /tmp

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

COPY runtime/handler.py /asset/handler.py
COPY bootstrapper_runtime/handler.py /asset/handler.py

# https://stackoverflow.com/a/61746719
# Tip from eoAPI: turns out, asyncio is part of python
Expand Down
134 changes: 120 additions & 14 deletions lib/database/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import {
Stack,
aws_rds as rds,
aws_ec2 as ec2,
aws_secretsmanager as secretsmanager,
aws_lambda,
CustomResource,
RemovalPolicy,
Duration,
aws_logs,

} from "aws-cdk-lib";
import { Construct } from "constructs";
import { BootstrapPgStac, BootstrapPgStacProps } from "../bootstrapper";
import { CustomLambdaFunctionProps } from "../utils";

const instanceSizes: Record<string, number> = require("./instance-memory.json");
const DEFAULT_PGSTAC_VERSION = "0.7.10";

function hasVpc(
instance: rds.DatabaseInstance | rds.IDatabaseInstance
): instance is rds.DatabaseInstance {
return (instance as rds.DatabaseInstance).vpc !== undefined;
}

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

const bootstrap = new BootstrapPgStac(this, "bootstrap-pgstac-instance", {
vpc: props.vpc,
database: this.db,
dbSecret: this.db.secret!,
pgstacDbName: props.pgstacDbName,
pgstacVersion: props.pgstacVersion,
pgstacUsername: props.pgstacUsername,
secretsPrefix: props.secretsPrefix,
const handler = new aws_lambda.Function(this, "lambda", {
// defaults for configurable properties
runtime: aws_lambda.Runtime.PYTHON_3_11,
handler: "handler.handler",
memorySize: 128,
logRetention: aws_logs.RetentionDays.ONE_WEEK,
timeout: Duration.minutes(2),
code: aws_lambda.Code.fromDockerBuild(__dirname, {
file: "bootstrapper_runtime/Dockerfile",
buildArgs: {PGSTAC_VERSION: DEFAULT_PGSTAC_VERSION, PYTHON_VERSION: "3.11"}
}),
// overwrites defaults with user-provided configurable properties
...props.bootstrapperLambdaFunctionOptions,
// Non configurable properties that are going to be overwritten even if provided by the user
vpc: hasVpc(this.db) ? this.db.vpc : props.vpc,
allowPublicSubnet: true
});

this.pgstacSecret = new secretsmanager.Secret(this, "bootstrappersecret", {
secretName: [
props.secretsPrefix || "pgstac",
id,
this.node.addr.slice(-8),
].join("/"),
generateSecretString: {
secretStringTemplate: JSON.stringify({
dbname: props.pgstacDbName || "pgstac",
engine: "postgres",
port: 5432,
host: this.db.instanceEndpoint.hostname,
username: props.pgstacUsername || "pgstac_user",
}),
generateStringKey: "password",
excludePunctuation: true,
},
description: `PgSTAC database bootstrapped by ${
Stack.of(this).stackName
}`,
});

// Allow lambda to...
// read new user secret
this.pgstacSecret.grantRead(handler);
// read database secret
this.db.secret!.grantRead(handler);
// connect to database
this.db.connections.allowFrom(handler, ec2.Port.tcp(5432));

let customResourceProperties : { [key: string]: any} = {};

// if customResourceProperties are provided, fill in the values.
if (props.customResourceProperties) {
Object.assign(customResourceProperties, props.customResourceProperties);
}

// update properties
customResourceProperties["conn_secret_arn"] = this.db.secret!.secretArn;
customResourceProperties["new_user_secret_arn"] = this.pgstacSecret.secretArn;

// if props.lambdaFunctionOptions doesn't have 'code' defined, update pgstac_version (needed for default runtime)
if (!props.bootstrapperLambdaFunctionOptions?.code) {
customResourceProperties["pgstac_version"] = DEFAULT_PGSTAC_VERSION;
}
// this.connections = props.database.connections;
new CustomResource(this, "bootstrapper", {
serviceToken: handler.functionArn,
properties: customResourceProperties,
removalPolicy: RemovalPolicy.RETAIN, // This retains the custom resource (which doesn't really exist), not the database
});

this.pgstacSecret = bootstrap.secret;
}

public getParameters(
Expand Down Expand Up @@ -99,10 +172,43 @@ export class PgStacDatabase extends Construct {
}

export interface PgStacDatabaseProps extends rds.DatabaseInstanceProps {
readonly pgstacDbName?: BootstrapPgStacProps["pgstacDbName"];
readonly pgstacVersion?: BootstrapPgStacProps["pgstacVersion"];
readonly pgstacUsername?: BootstrapPgStacProps["pgstacUsername"];
readonly secretsPrefix?: BootstrapPgStacProps["secretsPrefix"];
/**
* Name of database that is to be created and onto which pgSTAC will be installed.
*
* @default pgstac
*/
readonly pgstacDbName?: string;

/**
* Prefix to assign to the generated `secrets_manager.Secret`
*
* @default pgstac
*/
readonly secretsPrefix?: string;

/**
* Name of user that will be generated for connecting to the pgSTAC database.
*
* @default pgstac_user
*/
readonly pgstacUsername?: string;

/**
* Lambda function Custom Resource properties. A custom resource property is going to be created
* to trigger the boostrapping lambda function. This parameter allows the user to specify additional properties
* on top of the defaults ones.
*
*/
readonly customResourceProperties?: {
[key: string]: any;
}

/**
* 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.
*
* @default - defined in the construct.
*/
readonly bootstrapperLambdaFunctionOptions?: CustomLambdaFunctionProps;
}

export interface DatabaseParameters {
Expand Down
2 changes: 1 addition & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export * from "./bastion-host";
export * from "./bootstrapper";
export * from "./database";
export * from "./ingestor-api";
export * from "./stac-api";
export * from "./titiler-pgstac-api";
export * from "./stac-browser";
export * from "./tipg-api";
export * from "./utils";
Loading