Skip to content

Commit 31d0ec0

Browse files
authored
fix: refactor Lambda constructs to only build custom image if provided (#187)
1 parent e301bb2 commit 31d0ec0

File tree

8 files changed

+103
-36
lines changed

8 files changed

+103
-36
lines changed

lib/database/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {
1010
aws_secretsmanager as secretsmanager,
1111
} from "aws-cdk-lib";
1212
import { Construct } from "constructs";
13-
import { CustomLambdaFunctionProps, DEFAULT_PGSTAC_VERSION } from "../utils";
13+
import {
14+
CustomLambdaFunctionProps,
15+
DEFAULT_PGSTAC_VERSION,
16+
resolveLambdaCode,
17+
} from "../utils";
1418
import { PgBouncer } from "./PgBouncer";
1519

1620
const instanceSizes: Record<string, number> = require("./instance-memory.json");
@@ -111,14 +115,17 @@ export class PgStacDatabase extends Construct {
111115

112116
this.pgstacVersion = props.pgstacVersion || DEFAULT_PGSTAC_VERSION;
113117

118+
const { code: userCode, ...otherLambdaOptions } =
119+
props.bootstrapperLambdaFunctionOptions || {};
120+
114121
const handler = new aws_lambda.Function(this, "lambda", {
115122
// defaults
116123
runtime: aws_lambda.Runtime.PYTHON_3_12,
117124
handler: "handler.handler",
118125
memorySize: 128,
119126
logRetention: aws_logs.RetentionDays.ONE_WEEK,
120127
timeout: Duration.minutes(2),
121-
code: aws_lambda.Code.fromDockerBuild(__dirname, {
128+
code: resolveLambdaCode(userCode, __dirname, {
122129
file: "bootstrapper_runtime/Dockerfile",
123130
buildArgs: {
124131
PYTHON_VERSION: "3.12",
@@ -128,7 +135,7 @@ export class PgStacDatabase extends Construct {
128135
vpc: hasVpc(this.db) ? this.db.vpc : props.vpc,
129136
allowPublicSubnet: true,
130137
// overwrites defaults with user-provided configurable properties,
131-
...props.bootstrapperLambdaFunctionOptions,
138+
...otherLambdaOptions,
132139
});
133140

134141
this.pgstacSecret = new secretsmanager.Secret(this, "bootstrappersecret", {
@@ -172,7 +179,7 @@ export class PgStacDatabase extends Construct {
172179
this.pgstacSecret.secretArn;
173180

174181
// if props.lambdaFunctionOptions doesn't have 'code' defined, update pgstac_version (needed for default runtime)
175-
if (!props.bootstrapperLambdaFunctionOptions?.code) {
182+
if (!userCode) {
176183
customResourceProperties["pgstac_version"] = this.pgstacVersion;
177184
}
178185

lib/ingestor-api/index.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import {
1313
Stack,
1414
} from "aws-cdk-lib";
1515
import { Construct } from "constructs";
16-
import { CustomLambdaFunctionProps, DEFAULT_PGSTAC_VERSION } from "../utils";
16+
import {
17+
CustomLambdaFunctionProps,
18+
DEFAULT_PGSTAC_VERSION,
19+
resolveLambdaCode,
20+
} from "../utils";
1721

1822
export class StacIngestor extends Construct {
1923
table: dynamodb.Table;
@@ -116,14 +120,17 @@ export class StacIngestor extends Construct {
116120
lambdaFunctionOptions?: CustomLambdaFunctionProps;
117121
pgstacVersion?: string;
118122
}): lambda.Function {
123+
const { code: userCode, ...otherLambdaOptions } =
124+
props.lambdaFunctionOptions || {};
125+
119126
const handler = new lambda.Function(this, "api-handler", {
120127
// defaults
121128
runtime: lambda.Runtime.PYTHON_3_12,
122129
handler: "src.handler.handler",
123130
memorySize: 2048,
124131
logRetention: aws_logs.RetentionDays.ONE_WEEK,
125132
timeout: Duration.seconds(30),
126-
code: lambda.Code.fromDockerBuild(__dirname, {
133+
code: resolveLambdaCode(userCode, __dirname, {
127134
file: "runtime/Dockerfile",
128135
buildArgs: {
129136
PYTHON_VERSION: "3.12",
@@ -136,7 +143,7 @@ export class StacIngestor extends Construct {
136143
environment: { DB_SECRET_ARN: props.dbSecret.secretArn, ...props.env },
137144
role: this.handlerRole,
138145
// overwrites defaults with user-provided configurable properties
139-
...props.lambdaFunctionOptions,
146+
...otherLambdaOptions,
140147
});
141148

142149
// Allow handler to read DB secret
@@ -167,14 +174,16 @@ export class StacIngestor extends Construct {
167174
lambdaFunctionOptions?: CustomLambdaFunctionProps;
168175
pgstacVersion?: string;
169176
}): lambda.Function {
177+
const { code: userCode, ...otherLambdaOptions } =
178+
props.lambdaFunctionOptions || {};
170179
const handler = new lambda.Function(this, "stac-ingestor", {
171180
// defaults
172181
runtime: lambda.Runtime.PYTHON_3_12,
173182
handler: "src.ingestor.handler",
174183
memorySize: 2048,
175184
logRetention: aws_logs.RetentionDays.ONE_WEEK,
176185
timeout: Duration.seconds(180),
177-
code: lambda.Code.fromDockerBuild(__dirname, {
186+
code: resolveLambdaCode(userCode, __dirname, {
178187
file: "runtime/Dockerfile",
179188
buildArgs: {
180189
PYTHON_VERSION: "3.12",
@@ -187,7 +196,7 @@ export class StacIngestor extends Construct {
187196
environment: { DB_SECRET_ARN: props.dbSecret.secretArn, ...props.env },
188197
role: this.handlerRole,
189198
// overwrites defaults with user-provided configurable properties
190-
...props.lambdaFunctionOptions,
199+
...otherLambdaOptions,
191200
});
192201

193202
// Allow handler to read DB secret

lib/stac-api/index.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { Construct } from "constructs";
1313
import * as path from "path";
1414
import { LambdaApiGateway } from "../lambda-api-gateway";
15-
import { CustomLambdaFunctionProps } from "../utils";
15+
import { CustomLambdaFunctionProps, resolveLambdaCode } from "../utils";
1616

1717
export const EXTENSIONS = {
1818
QUERY: "query",
@@ -69,17 +69,23 @@ export class PgStacApiLambdaRuntime extends Construct {
6969

7070
const enabledExtensions = props.enabledExtensions || defaultExtensions;
7171

72+
const { code: userCode, ...otherLambdaOptions } = props.lambdaFunctionOptions || {};
73+
7274
this.lambdaFunction = new lambda.Function(this, "lambda", {
7375
// defaults
7476
runtime: lambda.Runtime.PYTHON_3_12,
7577
handler: "handler.handler",
7678
memorySize: 8192,
7779
logRetention: aws_logs.RetentionDays.ONE_WEEK,
7880
timeout: Duration.seconds(30),
79-
code: lambda.Code.fromDockerBuild(path.join(__dirname, ".."), {
80-
file: "stac-api/runtime/Dockerfile",
81-
buildArgs: { PYTHON_VERSION: "3.12" },
82-
}),
81+
code: resolveLambdaCode(
82+
userCode,
83+
path.join(__dirname, ".."),
84+
{
85+
file: "stac-api/runtime/Dockerfile",
86+
buildArgs: { PYTHON_VERSION: "3.12" },
87+
}
88+
),
8389
vpc: props.vpc,
8490
vpcSubnets: props.subnetSelection,
8591
allowPublicSubnet: true,
@@ -90,8 +96,8 @@ export class PgStacApiLambdaRuntime extends Construct {
9096
ENABLED_EXTENSIONS: enabledExtensions.join(","),
9197
...props.apiEnv,
9298
},
93-
// overwrites defaults with user-provided configurable properties
94-
...props.lambdaFunctionOptions,
99+
// overwrites defaults with user-provided configurable properties (excluding code)
100+
...otherLambdaOptions,
95101
});
96102

97103
props.dbSecret.grantRead(this.lambdaFunction);

lib/stac-auth-proxy/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as lambda from "aws-cdk-lib/aws-lambda";
44
import * as apigatewayv2 from "aws-cdk-lib/aws-apigatewayv2";
55
import { Construct } from "constructs";
66
import { LambdaApiGateway } from "../lambda-api-gateway";
7-
import { CustomLambdaFunctionProps } from "../utils";
7+
import { CustomLambdaFunctionProps, resolveLambdaCode } from "../utils";
88
import * as path from "path";
99

1010
export class StacAuthProxyLambdaRuntime extends Construct {
@@ -17,13 +17,16 @@ export class StacAuthProxyLambdaRuntime extends Construct {
1717
) {
1818
super(scope, id);
1919

20+
const { code: userCode, ...otherLambdaOptions } =
21+
props.lambdaFunctionOptions || {};
22+
2023
this.lambdaFunction = new lambda.Function(this, "lambda", {
2124
runtime: lambda.Runtime.PYTHON_3_13,
2225
handler: "handler.handler",
2326
memorySize: 8192,
2427
logRetention: cdk.aws_logs.RetentionDays.ONE_WEEK,
2528
timeout: cdk.Duration.seconds(30),
26-
code: lambda.Code.fromDockerBuild(path.join(__dirname, ".."), {
29+
code: resolveLambdaCode(userCode, path.join(__dirname, ".."), {
2730
file: "stac-auth-proxy/runtime/Dockerfile",
2831
buildArgs: { PYTHON_VERSION: "3.13" },
2932
}),
@@ -47,7 +50,7 @@ export class StacAuthProxyLambdaRuntime extends Construct {
4750
...props.apiEnv,
4851
},
4952
// overwrites defaults with user-provided configurable properties
50-
...props.lambdaFunctionOptions,
53+
...otherLambdaOptions,
5154
});
5255
}
5356
}

lib/stac-loader/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { Construct } from "constructs";
1414
import * as path from "path";
1515
import { PgStacDatabase } from "../database";
16-
import { CustomLambdaFunctionProps } from "../utils";
16+
import { CustomLambdaFunctionProps, resolveLambdaCode } from "../utils";
1717

1818
/**
1919
* Configuration properties for the StacLoader construct.
@@ -412,12 +412,15 @@ export class StacLoader extends Construct {
412412
);
413413

414414
// Create the lambda function
415+
const { code: userCode, ...otherLambdaOptions } =
416+
props.lambdaFunctionOptions || {};
417+
415418
this.lambdaFunction = new lambda.Function(this, "Function", {
416419
runtime: lambdaRuntime,
417420
handler: "stac_loader.handler.handler",
418421
vpc: props.vpc,
419422
vpcSubnets: props.subnetSelection,
420-
code: lambda.Code.fromDockerBuild(path.join(__dirname, ".."), {
423+
code: resolveLambdaCode(userCode, path.join(__dirname, ".."), {
421424
file: "stac-loader/runtime/Dockerfile",
422425
platform: "linux/amd64",
423426
buildArgs: {
@@ -434,7 +437,7 @@ export class StacLoader extends Construct {
434437
...props.environment,
435438
},
436439
// overwrites defaults with user-provided configurable properties
437-
...props.lambdaFunctionOptions,
440+
...otherLambdaOptions,
438441
});
439442

440443
// Grant permissions to read the database secret

lib/tipg-api/index.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,31 @@ import {
1212
import { Construct } from "constructs";
1313
import * as path from "path";
1414
import { LambdaApiGateway } from "../lambda-api-gateway";
15-
import { CustomLambdaFunctionProps } from "../utils";
15+
import { CustomLambdaFunctionProps, resolveLambdaCode } from "../utils";
1616

1717
export class TiPgApiLambdaRuntime extends Construct {
1818
public readonly lambdaFunction: lambda.Function;
1919

2020
constructor(scope: Construct, id: string, props: TiPgApiLambdaRuntimeProps) {
2121
super(scope, id);
2222

23+
const { code: userCode, ...otherLambdaOptions } = props.lambdaFunctionOptions || {};
24+
2325
this.lambdaFunction = new lambda.Function(this, "lambda", {
2426
// defaults
2527
runtime: lambda.Runtime.PYTHON_3_12,
2628
handler: "handler.handler",
2729
memorySize: 1024,
2830
logRetention: logs.RetentionDays.ONE_WEEK,
2931
timeout: Duration.seconds(30),
30-
code: lambda.Code.fromDockerBuild(path.join(__dirname, ".."), {
31-
file: "tipg-api/runtime/Dockerfile",
32-
buildArgs: { PYTHON_VERSION: "3.12" },
33-
}),
32+
code: resolveLambdaCode(
33+
userCode,
34+
path.join(__dirname, ".."),
35+
{
36+
file: "tipg-api/runtime/Dockerfile",
37+
buildArgs: { PYTHON_VERSION: "3.12" },
38+
}
39+
),
3440
vpc: props.vpc,
3541
vpcSubnets: props.subnetSelection,
3642
allowPublicSubnet: true,
@@ -40,8 +46,8 @@ export class TiPgApiLambdaRuntime extends Construct {
4046
DB_MAX_CONN_SIZE: "1",
4147
...props.apiEnv,
4248
},
43-
// overwrites defaults with user-provided configurable properties
44-
...props.lambdaFunctionOptions,
49+
// overwrites defaults with user-provided configurable properties (excluding code)
50+
...otherLambdaOptions,
4551
});
4652

4753
props.dbSecret.grantRead(this.lambdaFunction);

lib/titiler-pgstac-api/index.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { Construct } from "constructs";
1414
import * as path from "path";
1515
import { LambdaApiGateway } from "../lambda-api-gateway";
16-
import { CustomLambdaFunctionProps } from "../utils";
16+
import { CustomLambdaFunctionProps, resolveLambdaCode } from "../utils";
1717

1818
// default settings that can be overridden by the user-provided environment.
1919
let defaultTitilerPgstacEnv: Record<string, string> = {
@@ -41,17 +41,23 @@ export class TitilerPgstacApiLambdaRuntime extends Construct {
4141
) {
4242
super(scope, id);
4343

44+
const { code: userCode, ...otherLambdaOptions } = props.lambdaFunctionOptions || {};
45+
4446
this.lambdaFunction = new lambda.Function(this, "lambda", {
4547
// defaults
4648
runtime: lambda.Runtime.PYTHON_3_12,
4749
handler: "handler.handler",
4850
memorySize: 3008,
4951
logRetention: aws_logs.RetentionDays.ONE_WEEK,
5052
timeout: Duration.seconds(30),
51-
code: lambda.Code.fromDockerBuild(path.join(__dirname, ".."), {
52-
file: "titiler-pgstac-api/runtime/Dockerfile",
53-
buildArgs: { PYTHON_VERSION: "3.12" },
54-
}),
53+
code: resolveLambdaCode(
54+
userCode,
55+
path.join(__dirname, ".."),
56+
{
57+
file: "titiler-pgstac-api/runtime/Dockerfile",
58+
buildArgs: { PYTHON_VERSION: "3.12" },
59+
}
60+
),
5561
vpc: props.vpc,
5662
vpcSubnets: props.subnetSelection,
5763
allowPublicSubnet: true,
@@ -60,8 +66,8 @@ export class TitilerPgstacApiLambdaRuntime extends Construct {
6066
...props.apiEnv, // if user provided environment variables, merge them with the defaults.
6167
PGSTAC_SECRET_ARN: props.dbSecret.secretArn,
6268
},
63-
// overwrites defaults with user-provided configurable properties
64-
...props.lambdaFunctionOptions,
69+
// overwrites defaults with user-provided configurable properties (excluding code)
70+
...otherLambdaOptions,
6571
});
6672

6773
// grant access to buckets using addToRolePolicy

lib/utils/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,30 @@ import { aws_lambda as lambda } from "aws-cdk-lib";
22

33
export type CustomLambdaFunctionProps = lambda.FunctionProps | any;
44
export const DEFAULT_PGSTAC_VERSION = "0.9.5";
5+
6+
/**
7+
* Resolves Lambda code by using custom user code if provided,
8+
* otherwise builds a Docker image with the specified arguments.
9+
*
10+
* @param userCode - User-provided custom code (optional)
11+
* @param dockerBuildPath - Path for Docker build
12+
* @param dockerBuildOptions - Options for Docker build
13+
* @returns Lambda code configuration
14+
*/
15+
export function resolveLambdaCode(
16+
userCode?: lambda.Code,
17+
dockerBuildPath?: string,
18+
dockerBuildOptions?: lambda.DockerBuildAssetOptions
19+
): lambda.Code {
20+
if (userCode) {
21+
return userCode;
22+
}
23+
24+
if (!dockerBuildPath || !dockerBuildOptions) {
25+
throw new Error(
26+
"dockerBuildPath and dockerBuildOptions are required when no custom code is provided"
27+
);
28+
}
29+
30+
return lambda.Code.fromDockerBuild(dockerBuildPath, dockerBuildOptions);
31+
}

0 commit comments

Comments
 (0)