sst 2.20.1 → 2.21.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.
- package/constructs/Function.d.ts +14 -1
- package/constructs/Function.js +1 -0
- package/constructs/Job.d.ts +50 -9
- package/constructs/Job.js +136 -99
- package/constructs/util/permission.js +1 -1
- package/node/job/index.d.ts +4 -1
- package/node/job/index.js +17 -6
- package/package.json +1 -1
- package/runtime/handlers/container.js +160 -32
- package/runtime/handlers.d.ts +1 -1
- package/sst.mjs +169 -41
- package/support/{job-invoker → job-manager}/index.mjs +14281 -27
package/constructs/Function.d.ts
CHANGED
|
@@ -79,8 +79,9 @@ export interface FunctionProps extends Omit<FunctionOptions, "functionName" | "m
|
|
|
79
79
|
*/
|
|
80
80
|
python?: PythonProps;
|
|
81
81
|
/**
|
|
82
|
-
* Used to configure
|
|
82
|
+
* Used to configure container function properties
|
|
83
83
|
*/
|
|
84
|
+
container?: ContainerProps;
|
|
84
85
|
/**
|
|
85
86
|
* Hooks to run before and after function builds
|
|
86
87
|
*/
|
|
@@ -507,6 +508,18 @@ export interface JavaProps {
|
|
|
507
508
|
*/
|
|
508
509
|
experimentalUseProvidedRuntime?: "provided" | "provided.al2";
|
|
509
510
|
}
|
|
511
|
+
export interface ContainerProps {
|
|
512
|
+
/**
|
|
513
|
+
* Specify or override the CMD on the Docker image.
|
|
514
|
+
* @example
|
|
515
|
+
* ```js
|
|
516
|
+
* container: {
|
|
517
|
+
* cmd: ["index.handler"]
|
|
518
|
+
* }
|
|
519
|
+
* ```
|
|
520
|
+
*/
|
|
521
|
+
cmd?: string[];
|
|
522
|
+
}
|
|
510
523
|
/**
|
|
511
524
|
* Used to configure additional files to copy into the function bundle
|
|
512
525
|
*
|
package/constructs/Function.js
CHANGED
|
@@ -208,6 +208,7 @@ export class Function extends CDKFunction {
|
|
|
208
208
|
...(architecture?.dockerPlatform
|
|
209
209
|
? { platform: Platform.custom(architecture.dockerPlatform) }
|
|
210
210
|
: {}),
|
|
211
|
+
...(props.container?.cmd ? { cmd: props.container.cmd } : {}),
|
|
211
212
|
}),
|
|
212
213
|
handler: CDKHandler.FROM_IMAGE,
|
|
213
214
|
runtime: CDKRuntime.FROM_IMAGE,
|
package/constructs/Job.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
|
+
import { Function as CdkFunction } from "aws-cdk-lib/aws-lambda";
|
|
2
3
|
import { RetentionDays } from "aws-cdk-lib/aws-logs";
|
|
3
4
|
import { SSTConstruct } from "./Construct.js";
|
|
4
|
-
import {
|
|
5
|
+
import { NodeJSProps, FunctionCopyFilesProps } from "./Function.js";
|
|
5
6
|
import { Duration } from "./util/duration.js";
|
|
6
7
|
import { Permissions } from "./util/permission.js";
|
|
7
8
|
import { FunctionBindingProps } from "./util/functionBinding.js";
|
|
@@ -9,10 +10,34 @@ import { ISecurityGroup, IVpc, SubnetSelection } from "aws-cdk-lib/aws-ec2";
|
|
|
9
10
|
export type JobMemorySize = "3 GB" | "7 GB" | "15 GB" | "145 GB";
|
|
10
11
|
export interface JobNodeJSProps extends NodeJSProps {
|
|
11
12
|
}
|
|
13
|
+
export interface JobContainerProps {
|
|
14
|
+
/**
|
|
15
|
+
* Specify or override the CMD on the Docker image.
|
|
16
|
+
* @example
|
|
17
|
+
* ```js
|
|
18
|
+
* container: {
|
|
19
|
+
* cmd: ["python3", "my_script.py"]
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
cmd: string[];
|
|
24
|
+
}
|
|
12
25
|
export interface JobProps {
|
|
13
26
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
27
|
+
* The runtime environment for the job.
|
|
28
|
+
* @default "nodejs"
|
|
29
|
+
* @example
|
|
30
|
+
* ```js
|
|
31
|
+
* new Function(stack, "Function", {
|
|
32
|
+
* runtime: "container",
|
|
33
|
+
* handler: "src/job",
|
|
34
|
+
* })
|
|
35
|
+
*```
|
|
36
|
+
*/
|
|
37
|
+
runtime?: "nodejs" | "container";
|
|
38
|
+
/**
|
|
39
|
+
* For "nodejs" runtime, point to the entry point and handler function.
|
|
40
|
+
* Of the format: `/path/to/file.function`.
|
|
16
41
|
*
|
|
17
42
|
* @example
|
|
18
43
|
* ```js
|
|
@@ -20,6 +45,17 @@ export interface JobProps {
|
|
|
20
45
|
* handler: "src/job.handler",
|
|
21
46
|
* })
|
|
22
47
|
*```
|
|
48
|
+
*
|
|
49
|
+
* For "container" runtime, point the handler to the directory containing
|
|
50
|
+
* the Dockerfile.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```js
|
|
54
|
+
* new Job(stack, "MyJob", {
|
|
55
|
+
* runtime: "container",
|
|
56
|
+
* handler: "src/job", // Dockerfile is at "src/job/Dockerfile"
|
|
57
|
+
* })
|
|
58
|
+
*```
|
|
23
59
|
*/
|
|
24
60
|
handler: string;
|
|
25
61
|
/**
|
|
@@ -65,6 +101,10 @@ export interface JobProps {
|
|
|
65
101
|
* Used to configure nodejs function properties
|
|
66
102
|
*/
|
|
67
103
|
nodejs?: JobNodeJSProps;
|
|
104
|
+
/**
|
|
105
|
+
* Used to configure container properties
|
|
106
|
+
*/
|
|
107
|
+
container?: JobContainerProps;
|
|
68
108
|
/**
|
|
69
109
|
* Can be used to disable Live Lambda Development when using `sst start`. Useful for things like Custom Resources that need to execute during deployment.
|
|
70
110
|
*
|
|
@@ -204,10 +244,10 @@ export interface JobProps {
|
|
|
204
244
|
*/
|
|
205
245
|
export declare class Job extends Construct implements SSTConstruct {
|
|
206
246
|
readonly id: string;
|
|
207
|
-
private readonly localId;
|
|
208
247
|
private readonly props;
|
|
209
248
|
private readonly job;
|
|
210
|
-
readonly
|
|
249
|
+
private readonly liveDevJob?;
|
|
250
|
+
readonly _jobManager: CdkFunction;
|
|
211
251
|
constructor(scope: Construct, id: string, props: JobProps);
|
|
212
252
|
getConstructMetadata(): {
|
|
213
253
|
type: "Job";
|
|
@@ -246,15 +286,16 @@ export declare class Job extends Construct implements SSTConstruct {
|
|
|
246
286
|
* ```
|
|
247
287
|
*/
|
|
248
288
|
addEnvironment(name: string, value: string): void;
|
|
249
|
-
private
|
|
289
|
+
private createCodeBuildJob;
|
|
290
|
+
private createLiveDevJob;
|
|
250
291
|
private createLogRetention;
|
|
251
292
|
private buildCodeBuildProjectCode;
|
|
252
|
-
private
|
|
253
|
-
private createLocalInvoker;
|
|
254
|
-
private createCodeBuildInvoker;
|
|
293
|
+
private createJobManager;
|
|
255
294
|
private bindForCodeBuild;
|
|
256
295
|
private attachPermissionsForCodeBuild;
|
|
257
296
|
private addEnvironmentForCodeBuild;
|
|
297
|
+
private validateContainerProps;
|
|
258
298
|
private normalizeMemorySize;
|
|
259
299
|
private normalizeTimeout;
|
|
300
|
+
private convertJobRuntimeToFunctionRuntime;
|
|
260
301
|
}
|
package/constructs/Job.js
CHANGED
|
@@ -2,8 +2,9 @@ import url from "url";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import { Construct } from "constructs";
|
|
5
|
+
import { Duration as CdkDuration } from "aws-cdk-lib/core";
|
|
5
6
|
import { PolicyStatement, Effect } from "aws-cdk-lib/aws-iam";
|
|
6
|
-
import { AssetCode } from "aws-cdk-lib/aws-lambda";
|
|
7
|
+
import { AssetCode, Code, Runtime, Function as CdkFunction, } from "aws-cdk-lib/aws-lambda";
|
|
7
8
|
import { Project, LinuxBuildImage, BuildSpec, ComputeType, } from "aws-cdk-lib/aws-codebuild";
|
|
8
9
|
import { RetentionDays, LogRetention } from "aws-cdk-lib/aws-logs";
|
|
9
10
|
import { Stack } from "./Stack.js";
|
|
@@ -14,6 +15,7 @@ import { bindEnvironment, bindPermissions, getReferencedSecrets, } from "./util/
|
|
|
14
15
|
import { useDeferredTasks } from "./deferred_task.js";
|
|
15
16
|
import { useProject } from "../project.js";
|
|
16
17
|
import { useRuntimeHandlers } from "../runtime/handlers.js";
|
|
18
|
+
import { Platform } from "aws-cdk-lib/aws-ecr-assets";
|
|
17
19
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
18
20
|
/////////////////////
|
|
19
21
|
// Construct
|
|
@@ -34,43 +36,40 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
|
34
36
|
*/
|
|
35
37
|
export class Job extends Construct {
|
|
36
38
|
id;
|
|
37
|
-
localId;
|
|
38
39
|
props;
|
|
39
40
|
job;
|
|
40
|
-
|
|
41
|
+
liveDevJob;
|
|
42
|
+
_jobManager;
|
|
41
43
|
constructor(scope, id, props) {
|
|
42
44
|
super(scope, props.cdk?.id || id);
|
|
43
45
|
const app = this.node.root;
|
|
44
46
|
const stack = Stack.of(scope);
|
|
45
47
|
this.id = id;
|
|
46
48
|
this.props = props;
|
|
47
|
-
useFunctions().add(this.node.addr, {
|
|
48
|
-
...props,
|
|
49
|
-
runtime: "nodejs16.x",
|
|
50
|
-
});
|
|
51
|
-
this.localId = path.posix
|
|
52
|
-
.join(scope.node.path, id)
|
|
53
|
-
.replace(/\$/g, "-")
|
|
54
|
-
.replace(/\//g, "-")
|
|
55
|
-
.replace(/\./g, "-");
|
|
56
49
|
const isLiveDevEnabled = app.mode === "dev" && (this.props.enableLiveDev === false ? false : true);
|
|
57
|
-
this.
|
|
58
|
-
this.
|
|
50
|
+
this.validateContainerProps();
|
|
51
|
+
this.job = this.createCodeBuildJob();
|
|
59
52
|
if (!stack.isActive) {
|
|
60
|
-
this.
|
|
53
|
+
this._jobManager = this.createJobManager();
|
|
61
54
|
}
|
|
62
55
|
else if (isLiveDevEnabled) {
|
|
63
|
-
this.
|
|
56
|
+
this.liveDevJob = this.createLiveDevJob();
|
|
57
|
+
this._jobManager = this.createJobManager();
|
|
64
58
|
}
|
|
65
59
|
else {
|
|
66
|
-
this.
|
|
60
|
+
this._jobManager = this.createJobManager();
|
|
67
61
|
this.buildCodeBuildProjectCode();
|
|
68
62
|
}
|
|
63
|
+
this.createLogRetention();
|
|
69
64
|
this.attachPermissions(props.permissions || []);
|
|
70
65
|
this.bind(props.bind || []);
|
|
71
66
|
Object.entries(props.environment || {}).forEach(([key, value]) => {
|
|
72
67
|
this.addEnvironment(key, value);
|
|
73
68
|
});
|
|
69
|
+
useFunctions().add(this.node.addr, {
|
|
70
|
+
...props,
|
|
71
|
+
runtime: this.convertJobRuntimeToFunctionRuntime(),
|
|
72
|
+
});
|
|
74
73
|
}
|
|
75
74
|
getConstructMetadata() {
|
|
76
75
|
return {
|
|
@@ -87,11 +86,11 @@ export class Job extends Construct {
|
|
|
87
86
|
variables: {
|
|
88
87
|
functionName: {
|
|
89
88
|
type: "plain",
|
|
90
|
-
value: this.
|
|
89
|
+
value: this._jobManager.functionName,
|
|
91
90
|
},
|
|
92
91
|
},
|
|
93
92
|
permissions: {
|
|
94
|
-
"lambda:*": [this.
|
|
93
|
+
"lambda:*": [this._jobManager.functionArn],
|
|
95
94
|
},
|
|
96
95
|
};
|
|
97
96
|
}
|
|
@@ -104,7 +103,7 @@ export class Job extends Construct {
|
|
|
104
103
|
* ```
|
|
105
104
|
*/
|
|
106
105
|
bind(constructs) {
|
|
107
|
-
this.
|
|
106
|
+
this.liveDevJob?.bind(constructs);
|
|
108
107
|
this.bindForCodeBuild(constructs);
|
|
109
108
|
}
|
|
110
109
|
/**
|
|
@@ -116,7 +115,7 @@ export class Job extends Construct {
|
|
|
116
115
|
* ```
|
|
117
116
|
*/
|
|
118
117
|
attachPermissions(permissions) {
|
|
119
|
-
this.
|
|
118
|
+
this.liveDevJob?.attachPermissions(permissions);
|
|
120
119
|
this.attachPermissionsForCodeBuild(permissions);
|
|
121
120
|
}
|
|
122
121
|
/**
|
|
@@ -130,22 +129,15 @@ export class Job extends Construct {
|
|
|
130
129
|
* ```
|
|
131
130
|
*/
|
|
132
131
|
addEnvironment(name, value) {
|
|
133
|
-
this.
|
|
132
|
+
this.liveDevJob?.addEnvironment(name, value);
|
|
134
133
|
this.addEnvironmentForCodeBuild(name, value);
|
|
135
134
|
}
|
|
136
|
-
|
|
137
|
-
const { cdk, memorySize, timeout } = this.props;
|
|
135
|
+
createCodeBuildJob() {
|
|
136
|
+
const { cdk, runtime, handler, memorySize, timeout, container } = this.props;
|
|
138
137
|
const app = this.node.root;
|
|
139
138
|
return new Project(this, "JobProject", {
|
|
140
139
|
projectName: app.logicalPrefixedName(this.node.id),
|
|
141
140
|
environment: {
|
|
142
|
-
// CodeBuild offers different build images. The newer ones have much quicker
|
|
143
|
-
// boot time. The latest build image is STANDARD_6_0, which support Node.js 16.
|
|
144
|
-
// But while testing, I found STANDARD_6_0 took 100s to boot. So for the
|
|
145
|
-
// purpose of this demo, I use STANDARD_5_0. It takes 30s to boot.
|
|
146
|
-
//buildImage: codebuild.LinuxBuildImage.STANDARD_6_0,
|
|
147
|
-
//buildImage: codebuild.LinuxBuildImage.STANDARD_5_0,
|
|
148
|
-
buildImage: LinuxBuildImage.fromDockerRegistry("amazon/aws-lambda-nodejs:16"),
|
|
149
141
|
computeType: this.normalizeMemorySize(memorySize || "3 GB"),
|
|
150
142
|
},
|
|
151
143
|
environmentVariables: {
|
|
@@ -169,6 +161,23 @@ export class Job extends Construct {
|
|
|
169
161
|
subnetSelection: cdk?.vpcSubnets,
|
|
170
162
|
});
|
|
171
163
|
}
|
|
164
|
+
createLiveDevJob() {
|
|
165
|
+
// Note: make the invoker function the same ID as the Job
|
|
166
|
+
// construct so users can identify the invoker function
|
|
167
|
+
// in the Console.
|
|
168
|
+
const fn = new Function(this, this.node.id, {
|
|
169
|
+
...this.props,
|
|
170
|
+
runtime: this.convertJobRuntimeToFunctionRuntime(),
|
|
171
|
+
memorySize: 1024,
|
|
172
|
+
timeout: "10 seconds",
|
|
173
|
+
environment: {
|
|
174
|
+
...this.props.environment,
|
|
175
|
+
SST_DEBUG_JOB: "true",
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
fn._doNotAllowOthersToBind = true;
|
|
179
|
+
return fn;
|
|
180
|
+
}
|
|
172
181
|
createLogRetention() {
|
|
173
182
|
const { logRetention } = this.props;
|
|
174
183
|
if (!logRetention)
|
|
@@ -182,17 +191,44 @@ export class Job extends Construct {
|
|
|
182
191
|
});
|
|
183
192
|
}
|
|
184
193
|
buildCodeBuildProjectCode() {
|
|
185
|
-
const
|
|
194
|
+
const { handler, runtime, container } = this.props;
|
|
186
195
|
useDeferredTasks().add(async () => {
|
|
187
196
|
// Build function
|
|
188
197
|
const result = await useRuntimeHandlers().build(this.node.addr, "deploy");
|
|
189
|
-
// create wrapper that calls the handler
|
|
190
198
|
if (result.type === "error") {
|
|
191
|
-
throw new Error([
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
199
|
+
throw new Error([`Failed to build job "${handler}"`, ...result.errors].join("\n"));
|
|
200
|
+
}
|
|
201
|
+
// No need to update code for container runtime
|
|
202
|
+
// Note: we could set the commands in `createCodeBuildJob` but
|
|
203
|
+
// in `sst dev`, we want to avoid changing the CodeBuild resources
|
|
204
|
+
// when `cmd` changes.
|
|
205
|
+
if (runtime === "container") {
|
|
206
|
+
const image = LinuxBuildImage.fromAsset(this, "ContainerImage", {
|
|
207
|
+
directory: handler,
|
|
208
|
+
platform: Platform.custom("linux/amd64"),
|
|
209
|
+
});
|
|
210
|
+
image.repository?.grantPull(this.job.role);
|
|
211
|
+
const project = this.job.node.defaultChild;
|
|
212
|
+
project.environment = {
|
|
213
|
+
...project.environment,
|
|
214
|
+
image: image.imageId,
|
|
215
|
+
imagePullCredentialsType: "SERVICE_ROLE",
|
|
216
|
+
};
|
|
217
|
+
project.source = {
|
|
218
|
+
type: "NO_SOURCE",
|
|
219
|
+
buildSpec: [
|
|
220
|
+
"version: 0.2",
|
|
221
|
+
"phases:",
|
|
222
|
+
" build:",
|
|
223
|
+
" commands:",
|
|
224
|
+
` - ${container.cmd
|
|
225
|
+
.map((arg) => (arg.includes(" ") ? `"${arg}"` : arg))
|
|
226
|
+
.join(" ")}`,
|
|
227
|
+
].join("\n"),
|
|
228
|
+
};
|
|
229
|
+
return;
|
|
195
230
|
}
|
|
231
|
+
// Create wrapper that calls the handler
|
|
196
232
|
const parsed = path.parse(result.handler);
|
|
197
233
|
const importName = parsed.ext.substring(1);
|
|
198
234
|
const importPath = `./${path
|
|
@@ -219,76 +255,65 @@ export class Job extends Construct {
|
|
|
219
255
|
`console.log("")`,
|
|
220
256
|
`process.exit(0)`,
|
|
221
257
|
].join("\n"));
|
|
258
|
+
// Update job's commands
|
|
222
259
|
const code = AssetCode.fromAsset(result.out);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
createLocalInvoker() {
|
|
253
|
-
// Note: make the invoker function the same ID as the Job
|
|
254
|
-
// construct so users can identify the invoker function
|
|
255
|
-
// in the Console.
|
|
256
|
-
const fn = new Function(this, this.node.id, {
|
|
257
|
-
runtime: "nodejs16.x",
|
|
258
|
-
memorySize: 1024,
|
|
259
|
-
environment: {
|
|
260
|
-
...this.props.environment,
|
|
261
|
-
SST_DEBUG_TYPE: "job",
|
|
262
|
-
},
|
|
263
|
-
...this.props,
|
|
264
|
-
timeout: "15 minutes",
|
|
260
|
+
const codeConfig = code.bind(this);
|
|
261
|
+
const project = this.job.node.defaultChild;
|
|
262
|
+
const image = LinuxBuildImage.fromDockerRegistry("amazon/aws-lambda-nodejs:16");
|
|
263
|
+
project.environment = {
|
|
264
|
+
...project.environment,
|
|
265
|
+
image: image.imageId,
|
|
266
|
+
};
|
|
267
|
+
image.repository?.grantPull(this.job.role);
|
|
268
|
+
project.source = {
|
|
269
|
+
type: "S3",
|
|
270
|
+
location: `${codeConfig.s3Location?.bucketName}/${codeConfig.s3Location?.objectKey}`,
|
|
271
|
+
buildSpec: [
|
|
272
|
+
"version: 0.2",
|
|
273
|
+
"phases:",
|
|
274
|
+
" build:",
|
|
275
|
+
" commands:",
|
|
276
|
+
` - node handler-wrapper.mjs`,
|
|
277
|
+
].join("\n"),
|
|
278
|
+
};
|
|
279
|
+
this.attachPermissions([
|
|
280
|
+
new PolicyStatement({
|
|
281
|
+
actions: ["s3:*"],
|
|
282
|
+
effect: Effect.ALLOW,
|
|
283
|
+
resources: [
|
|
284
|
+
`arn:${Stack.of(this).partition}:s3:::${codeConfig.s3Location?.bucketName}/${codeConfig.s3Location?.objectKey}`,
|
|
285
|
+
],
|
|
286
|
+
}),
|
|
287
|
+
]);
|
|
265
288
|
});
|
|
266
|
-
fn._doNotAllowOthersToBind = true;
|
|
267
|
-
return fn;
|
|
268
289
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
290
|
+
createJobManager() {
|
|
291
|
+
return new CdkFunction(this, "Manager", {
|
|
292
|
+
code: Code.fromAsset(path.join(__dirname, "../support/job-manager/")),
|
|
293
|
+
handler: "index.handler",
|
|
294
|
+
runtime: Runtime.NODEJS_16_X,
|
|
295
|
+
timeout: CdkDuration.seconds(10),
|
|
274
296
|
memorySize: 1024,
|
|
275
297
|
environment: {
|
|
276
|
-
|
|
298
|
+
SST_JOB_PROVIDER: this.liveDevJob ? "lambda" : "codebuild",
|
|
299
|
+
SST_JOB_RUNNER: this.liveDevJob
|
|
300
|
+
? this.liveDevJob.functionArn
|
|
301
|
+
: this.job.projectName,
|
|
277
302
|
},
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
303
|
+
initialPolicy: [
|
|
304
|
+
this.liveDevJob
|
|
305
|
+
? new PolicyStatement({
|
|
306
|
+
effect: Effect.ALLOW,
|
|
307
|
+
actions: ["lambda:InvokeFunction"],
|
|
308
|
+
resources: [this.liveDevJob.functionArn],
|
|
309
|
+
})
|
|
310
|
+
: new PolicyStatement({
|
|
311
|
+
effect: Effect.ALLOW,
|
|
312
|
+
actions: ["codebuild:StartBuild", "codebuild:StopBuild"],
|
|
313
|
+
resources: [this.job.projectArn],
|
|
314
|
+
}),
|
|
284
315
|
],
|
|
285
|
-
nodejs: {
|
|
286
|
-
format: "esm",
|
|
287
|
-
},
|
|
288
|
-
enableLiveDev: false,
|
|
289
316
|
});
|
|
290
|
-
fn._doNotAllowOthersToBind = true;
|
|
291
|
-
return fn;
|
|
292
317
|
}
|
|
293
318
|
bindForCodeBuild(constructs) {
|
|
294
319
|
// Get referenced secrets
|
|
@@ -318,6 +343,14 @@ export class Job extends Construct {
|
|
|
318
343
|
const envVars = env.environmentVariables;
|
|
319
344
|
envVars.push({ name, value });
|
|
320
345
|
}
|
|
346
|
+
validateContainerProps() {
|
|
347
|
+
const { runtime, container } = this.props;
|
|
348
|
+
if (runtime === "container") {
|
|
349
|
+
if (!container) {
|
|
350
|
+
throw new Error(`No commands defined for the ${this.node.id} Job.`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
321
354
|
normalizeMemorySize(memorySize) {
|
|
322
355
|
if (memorySize === "3 GB") {
|
|
323
356
|
return ComputeType.SMALL;
|
|
@@ -340,4 +373,8 @@ export class Job extends Construct {
|
|
|
340
373
|
}
|
|
341
374
|
return value;
|
|
342
375
|
}
|
|
376
|
+
convertJobRuntimeToFunctionRuntime() {
|
|
377
|
+
const { runtime } = this.props;
|
|
378
|
+
return runtime === "container" ? "container" : "nodejs16.x";
|
|
379
|
+
}
|
|
343
380
|
}
|
|
@@ -143,7 +143,7 @@ function permissionsToStatementsAndGrants(permissions) {
|
|
|
143
143
|
statements.push(buildPolicyStatement("lambda:*", [permission.functionArn]));
|
|
144
144
|
}
|
|
145
145
|
else if (permission instanceof Job) {
|
|
146
|
-
statements.push(buildPolicyStatement("lambda:*", [permission.
|
|
146
|
+
statements.push(buildPolicyStatement("lambda:*", [permission._jobManager.functionArn]));
|
|
147
147
|
}
|
|
148
148
|
////////////////////////////////////
|
|
149
149
|
// Case: CDK constructs
|
package/node/job/index.d.ts
CHANGED
|
@@ -10,7 +10,10 @@ export type JobType = {
|
|
|
10
10
|
};
|
|
11
11
|
export declare const Job: JobType;
|
|
12
12
|
declare function JobControl<Name extends keyof JobResources>(name: Name, vars: Record<string, string>): {
|
|
13
|
-
run(props: JobRunProps<Name>): Promise<
|
|
13
|
+
run(props: JobRunProps<Name>): Promise<{
|
|
14
|
+
jobId: string;
|
|
15
|
+
}>;
|
|
16
|
+
cancel(jobId: string): Promise<void>;
|
|
14
17
|
};
|
|
15
18
|
/**
|
|
16
19
|
* Create a new job handler.
|
package/node/job/index.js
CHANGED
|
@@ -11,19 +11,30 @@ export const Job = /* @__PURE__ */ (() => {
|
|
|
11
11
|
return result;
|
|
12
12
|
})();
|
|
13
13
|
function JobControl(name, vars) {
|
|
14
|
+
const functionName = vars.functionName;
|
|
14
15
|
return {
|
|
15
16
|
async run(props) {
|
|
16
|
-
// Handle job permission not granted
|
|
17
|
-
const functionName = vars.functionName;
|
|
18
17
|
// Invoke the Lambda function
|
|
19
18
|
const ret = await lambda.send(new InvokeCommand({
|
|
20
19
|
FunctionName: functionName,
|
|
21
|
-
Payload: props?.payload
|
|
22
|
-
? undefined
|
|
23
|
-
: Buffer.from(JSON.stringify(props?.payload)),
|
|
20
|
+
Payload: Buffer.from(JSON.stringify({ action: "run", payload: props?.payload })),
|
|
24
21
|
}));
|
|
25
22
|
if (ret.FunctionError) {
|
|
26
|
-
throw new Error(`Failed to invoke the ${name}
|
|
23
|
+
throw new Error(`Failed to invoke the "${name}" job. Error: ${ret.FunctionError}`);
|
|
24
|
+
}
|
|
25
|
+
const resp = JSON.parse(Buffer.from(ret.Payload).toString());
|
|
26
|
+
return {
|
|
27
|
+
jobId: resp.jobId,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
async cancel(jobId) {
|
|
31
|
+
// Invoke the Lambda function
|
|
32
|
+
const ret = await lambda.send(new InvokeCommand({
|
|
33
|
+
FunctionName: functionName,
|
|
34
|
+
Payload: Buffer.from(JSON.stringify({ action: "cancel", jobId })),
|
|
35
|
+
}));
|
|
36
|
+
if (ret.FunctionError) {
|
|
37
|
+
throw new Error(`Failed to cancel the "${name}" job id ${jobId}. Error: ${ret.FunctionError}`);
|
|
27
38
|
}
|
|
28
39
|
},
|
|
29
40
|
};
|