@takaro/aws 0.0.0-next.0da151e
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/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +31 -0
- package/dist/config.js.map +1 -0
- package/dist/createLambda.d.ts +6 -0
- package/dist/createLambda.d.ts.map +1 -0
- package/dist/createLambda.js +38 -0
- package/dist/createLambda.js.map +1 -0
- package/dist/deleteLambda.d.ts +6 -0
- package/dist/deleteLambda.d.ts.map +1 -0
- package/dist/deleteLambda.js +18 -0
- package/dist/deleteLambda.js.map +1 -0
- package/dist/executeLambda.d.ts +14 -0
- package/dist/executeLambda.d.ts.map +1 -0
- package/dist/executeLambda.js +68 -0
- package/dist/executeLambda.js.map +1 -0
- package/dist/main.d.ts +4 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -0
- package/package.json +15 -0
- package/src/config.ts +41 -0
- package/src/createLambda.ts +48 -0
- package/src/deleteLambda.ts +24 -0
- package/src/executeLambda.ts +83 -0
- package/src/main.ts +3 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +8 -0
- package/typedoc.json +3 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Config, IBaseConfig } from '@takaro/config';
|
|
2
|
+
interface IAwsConfig extends IBaseConfig {
|
|
3
|
+
aws: {
|
|
4
|
+
region: string;
|
|
5
|
+
accessKeyId: string;
|
|
6
|
+
secretAccessKey: string;
|
|
7
|
+
s3Bucket: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare const config: Config<IAwsConfig>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAErD,UAAU,UAAW,SAAQ,WAAW;IACtC,GAAG,EAAE;QACH,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AA+BD,eAAO,MAAM,MAAM,oBAAyC,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Config } from '@takaro/config';
|
|
2
|
+
const configSchema = {
|
|
3
|
+
aws: {
|
|
4
|
+
region: {
|
|
5
|
+
doc: 'The AWS region to use',
|
|
6
|
+
format: String,
|
|
7
|
+
default: 'eu-west-3',
|
|
8
|
+
env: 'AWS_REGION',
|
|
9
|
+
},
|
|
10
|
+
s3Bucket: {
|
|
11
|
+
doc: 'The AWS S3 bucket to use',
|
|
12
|
+
format: String,
|
|
13
|
+
default: 'takaro-template-code',
|
|
14
|
+
env: 'AWS_S3_BUCKET',
|
|
15
|
+
},
|
|
16
|
+
accessKeyId: {
|
|
17
|
+
doc: 'The AWS access key id to use',
|
|
18
|
+
format: String,
|
|
19
|
+
default: '',
|
|
20
|
+
env: 'AWS_ACCESS_KEY_ID',
|
|
21
|
+
},
|
|
22
|
+
secretAccessKey: {
|
|
23
|
+
doc: 'The AWS secret access key to use',
|
|
24
|
+
format: String,
|
|
25
|
+
default: '',
|
|
26
|
+
env: 'AWS_SECRET_ACCESS_KEY',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export const config = new Config([configSchema]);
|
|
31
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,gBAAgB,CAAC;AAWrD,MAAM,YAAY,GAAG;IACnB,GAAG,EAAE;QACH,MAAM,EAAE;YACN,GAAG,EAAE,uBAAuB;YAC5B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,WAAW;YACpB,GAAG,EAAE,YAAY;SAClB;QACD,QAAQ,EAAE;YACR,GAAG,EAAE,0BAA0B;YAC/B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,sBAAsB;YAC/B,GAAG,EAAE,eAAe;SACrB;QACD,WAAW,EAAE;YACX,GAAG,EAAE,8BAA8B;YACnC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,mBAAmB;SACzB;QACD,eAAe,EAAE;YACf,GAAG,EAAE,kCAAkC;YACvC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,uBAAuB;SAC7B;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAa,CAAC,YAAY,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createLambda.d.ts","sourceRoot":"","sources":["../src/createLambda.ts"],"names":[],"mappings":"AAIA,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,wBAAsB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE,mBAAmB,iBAsCnE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Lambda, waitUntilFunctionActive } from '@aws-sdk/client-lambda';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
import { logger } from '@takaro/util';
|
|
4
|
+
const log = logger('aws:lambda');
|
|
5
|
+
export async function createLambda({ domainId }) {
|
|
6
|
+
if (!config.get('aws.accessKeyId') && !config.get('aws.secretAccessKey')) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const lambda = new Lambda({
|
|
10
|
+
region: config.get('aws.region'),
|
|
11
|
+
credentials: {
|
|
12
|
+
accessKeyId: config.get('aws.accessKeyId'),
|
|
13
|
+
secretAccessKey: config.get('aws.secretAccessKey'),
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const templateFn = await lambda.getFunction({
|
|
17
|
+
FunctionName: 'takaro_template',
|
|
18
|
+
});
|
|
19
|
+
await lambda.createFunction({
|
|
20
|
+
...templateFn.Configuration,
|
|
21
|
+
FunctionName: domainId,
|
|
22
|
+
Role: templateFn.Configuration?.Role,
|
|
23
|
+
Layers: templateFn.Configuration?.Layers?.map((layer) => layer.Arn).filter((arn) => !!arn),
|
|
24
|
+
Tags: {
|
|
25
|
+
domainId,
|
|
26
|
+
},
|
|
27
|
+
Code: {
|
|
28
|
+
S3Bucket: config.get('aws.s3Bucket'),
|
|
29
|
+
S3Key: 'code',
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
log.debug('Created lambda function, waiting for it to be ready', domainId);
|
|
33
|
+
await waitUntilFunctionActive({
|
|
34
|
+
client: lambda,
|
|
35
|
+
maxWaitTime: 60,
|
|
36
|
+
}, { FunctionName: domainId });
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=createLambda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createLambda.js","sourceRoot":"","sources":["../src/createLambda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAKtC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAEjC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAuB;IAClE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;QAChC,WAAW,EAAE;YACX,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC;YAC1C,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC;SACnD;KACF,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;QAC1C,YAAY,EAAE,iBAAiB;KAChC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,cAAc,CAAC;QAC1B,GAAG,UAAU,CAAC,aAAa;QAC3B,YAAY,EAAE,QAAQ;QACtB,IAAI,EAAE,UAAU,CAAC,aAAa,EAAE,IAAI;QACpC,MAAM,EAAE,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACzG,IAAI,EAAE;YACJ,QAAQ;SACT;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;YACpC,KAAK,EAAE,MAAM;SACd;KACF,CAAC,CAAC;IACH,GAAG,CAAC,KAAK,CAAC,qDAAqD,EAAE,QAAQ,CAAC,CAAC;IAC3E,MAAM,uBAAuB,CAC3B;QACE,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,EAAE;KAChB,EACD,EAAE,YAAY,EAAE,QAAQ,EAAE,CAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deleteLambda.d.ts","sourceRoot":"","sources":["../src/deleteLambda.ts"],"names":[],"mappings":"AAGA,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE,mBAAmB,iBAgBnE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Lambda } from '@aws-sdk/client-lambda';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
export async function deleteLambda({ domainId }) {
|
|
4
|
+
if (!config.get('aws.accessKeyId') && !config.get('aws.secretAccessKey')) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const lambda = new Lambda({
|
|
8
|
+
region: config.get('aws.region'),
|
|
9
|
+
credentials: {
|
|
10
|
+
accessKeyId: config.get('aws.accessKeyId'),
|
|
11
|
+
secretAccessKey: config.get('aws.secretAccessKey'),
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
await lambda.deleteFunction({
|
|
15
|
+
FunctionName: domainId,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=deleteLambda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deleteLambda.js","sourceRoot":"","sources":["../src/deleteLambda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMrC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAuB;IAClE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;QAChC,WAAW,EAAE;YACX,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC;YAC1C,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC;SACnD;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,cAAc,CAAC;QAC1B,YAAY,EAAE,QAAQ;KACvB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface executeLambdaOpts {
|
|
2
|
+
domainId: string;
|
|
3
|
+
fn: string;
|
|
4
|
+
data: Record<string, unknown>;
|
|
5
|
+
token: string;
|
|
6
|
+
}
|
|
7
|
+
interface IFunctionResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
logs: any[];
|
|
10
|
+
requestId?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function executeLambda({ data, fn, token, domainId }: executeLambdaOpts): Promise<IFunctionResult>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=executeLambda.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executeLambda.d.ts","sourceRoot":"","sources":["../src/executeLambda.ts"],"names":[],"mappings":"AAKA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAYD,wBAAsB,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,iBAAiB,4BAqBnF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Lambda } from '@aws-sdk/client-lambda';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
import { createLambda } from './createLambda.js';
|
|
4
|
+
import { errors, logger } from '@takaro/util';
|
|
5
|
+
const lambda = new Lambda({
|
|
6
|
+
region: config.get('aws.region'),
|
|
7
|
+
credentials: {
|
|
8
|
+
accessKeyId: config.get('aws.accessKeyId'),
|
|
9
|
+
secretAccessKey: config.get('aws.secretAccessKey'),
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
const log = logger('aws:lambda');
|
|
13
|
+
export async function executeLambda({ data, fn, token, domainId }) {
|
|
14
|
+
if (!config.get('aws.accessKeyId') && !config.get('aws.secretAccessKey')) {
|
|
15
|
+
throw new errors.ConfigError('AWS credentials not set');
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const res = await tryExecuteLambda({ data, fn, token, domainId });
|
|
19
|
+
return res;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof Error && error.name === 'ResourceNotFoundException') {
|
|
23
|
+
log.warn('Lambda not found, creating...');
|
|
24
|
+
await createLambda({ domainId });
|
|
25
|
+
return await tryExecuteLambda({ data, fn, token, domainId });
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
log.error('executeLambda', error);
|
|
29
|
+
return {
|
|
30
|
+
logs: [],
|
|
31
|
+
success: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function tryExecuteLambda({ data, fn, token, domainId }) {
|
|
37
|
+
const result = await lambda.invoke({ FunctionName: domainId, Payload: JSON.stringify({ data, token, fn }) });
|
|
38
|
+
let returnVal = {
|
|
39
|
+
requestId: result.$metadata.requestId,
|
|
40
|
+
logs: [],
|
|
41
|
+
success: false,
|
|
42
|
+
};
|
|
43
|
+
if (result.Payload) {
|
|
44
|
+
const tmpResult = Buffer.from(result.Payload).toString();
|
|
45
|
+
const parsedRes = JSON.parse(tmpResult);
|
|
46
|
+
if (parsedRes.errorMessage && parsedRes.errorMessage.includes('Task timed out')) {
|
|
47
|
+
returnVal['success'] = false;
|
|
48
|
+
returnVal['logs'] = [
|
|
49
|
+
{
|
|
50
|
+
msg: 'Task timed out',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
else if (parsedRes.body.includes('Unexpected end of input')) {
|
|
55
|
+
returnVal['success'] = false;
|
|
56
|
+
returnVal['logs'] = [
|
|
57
|
+
{
|
|
58
|
+
msg: 'Syntax error, your javascript code is invalid',
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
returnVal = JSON.parse(parsedRes.body);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return returnVal;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=executeLambda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executeLambda.js","sourceRoot":"","sources":["../src/executeLambda.ts"],"names":[],"mappings":"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"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|
package/dist/main.js
ADDED
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@takaro/aws",
|
|
3
|
+
"version": "0.0.0-next.0da151e",
|
|
4
|
+
"description": "AWS helper functions",
|
|
5
|
+
"main": "dist/main.js",
|
|
6
|
+
"types": "dist/main.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"start:dev": "tsc --watch --preserveWatchOutput -p ./tsconfig.build.json",
|
|
10
|
+
"build": "tsc -p ./tsconfig.build.json"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC"
|
|
15
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Config, IBaseConfig } from '@takaro/config';
|
|
2
|
+
|
|
3
|
+
interface IAwsConfig extends IBaseConfig {
|
|
4
|
+
aws: {
|
|
5
|
+
region: string;
|
|
6
|
+
accessKeyId: string;
|
|
7
|
+
secretAccessKey: string;
|
|
8
|
+
s3Bucket: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const configSchema = {
|
|
13
|
+
aws: {
|
|
14
|
+
region: {
|
|
15
|
+
doc: 'The AWS region to use',
|
|
16
|
+
format: String,
|
|
17
|
+
default: 'eu-west-3',
|
|
18
|
+
env: 'AWS_REGION',
|
|
19
|
+
},
|
|
20
|
+
s3Bucket: {
|
|
21
|
+
doc: 'The AWS S3 bucket to use',
|
|
22
|
+
format: String,
|
|
23
|
+
default: 'takaro-template-code',
|
|
24
|
+
env: 'AWS_S3_BUCKET',
|
|
25
|
+
},
|
|
26
|
+
accessKeyId: {
|
|
27
|
+
doc: 'The AWS access key id to use',
|
|
28
|
+
format: String,
|
|
29
|
+
default: '',
|
|
30
|
+
env: 'AWS_ACCESS_KEY_ID',
|
|
31
|
+
},
|
|
32
|
+
secretAccessKey: {
|
|
33
|
+
doc: 'The AWS secret access key to use',
|
|
34
|
+
format: String,
|
|
35
|
+
default: '',
|
|
36
|
+
env: 'AWS_SECRET_ACCESS_KEY',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const config = new Config<IAwsConfig>([configSchema]);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Lambda, waitUntilFunctionActive } from '@aws-sdk/client-lambda';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
import { logger } from '@takaro/util';
|
|
4
|
+
|
|
5
|
+
interface CreateLambdaOptions {
|
|
6
|
+
domainId: string;
|
|
7
|
+
}
|
|
8
|
+
const log = logger('aws:lambda');
|
|
9
|
+
|
|
10
|
+
export async function createLambda({ domainId }: CreateLambdaOptions) {
|
|
11
|
+
if (!config.get('aws.accessKeyId') && !config.get('aws.secretAccessKey')) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const lambda = new Lambda({
|
|
16
|
+
region: config.get('aws.region'),
|
|
17
|
+
credentials: {
|
|
18
|
+
accessKeyId: config.get('aws.accessKeyId'),
|
|
19
|
+
secretAccessKey: config.get('aws.secretAccessKey'),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const templateFn = await lambda.getFunction({
|
|
24
|
+
FunctionName: 'takaro_template',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await lambda.createFunction({
|
|
28
|
+
...templateFn.Configuration,
|
|
29
|
+
FunctionName: domainId,
|
|
30
|
+
Role: templateFn.Configuration?.Role,
|
|
31
|
+
Layers: templateFn.Configuration?.Layers?.map((layer) => layer.Arn).filter((arn): arn is string => !!arn),
|
|
32
|
+
Tags: {
|
|
33
|
+
domainId,
|
|
34
|
+
},
|
|
35
|
+
Code: {
|
|
36
|
+
S3Bucket: config.get('aws.s3Bucket'),
|
|
37
|
+
S3Key: 'code',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
log.debug('Created lambda function, waiting for it to be ready', domainId);
|
|
41
|
+
await waitUntilFunctionActive(
|
|
42
|
+
{
|
|
43
|
+
client: lambda,
|
|
44
|
+
maxWaitTime: 60,
|
|
45
|
+
},
|
|
46
|
+
{ FunctionName: domainId },
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Lambda } from '@aws-sdk/client-lambda';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
|
|
4
|
+
interface DeleteLambdaOptions {
|
|
5
|
+
domainId: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function deleteLambda({ domainId }: DeleteLambdaOptions) {
|
|
9
|
+
if (!config.get('aws.accessKeyId') && !config.get('aws.secretAccessKey')) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const lambda = new Lambda({
|
|
14
|
+
region: config.get('aws.region'),
|
|
15
|
+
credentials: {
|
|
16
|
+
accessKeyId: config.get('aws.accessKeyId'),
|
|
17
|
+
secretAccessKey: config.get('aws.secretAccessKey'),
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
await lambda.deleteFunction({
|
|
22
|
+
FunctionName: domainId,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Lambda } from '@aws-sdk/client-lambda';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
import { createLambda } from './createLambda.js';
|
|
4
|
+
import { errors, logger } from '@takaro/util';
|
|
5
|
+
|
|
6
|
+
interface executeLambdaOpts {
|
|
7
|
+
domainId: string;
|
|
8
|
+
fn: string;
|
|
9
|
+
data: Record<string, unknown>;
|
|
10
|
+
token: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface IFunctionResult {
|
|
14
|
+
success: boolean;
|
|
15
|
+
logs: any[];
|
|
16
|
+
requestId?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const lambda = new Lambda({
|
|
20
|
+
region: config.get('aws.region'),
|
|
21
|
+
credentials: {
|
|
22
|
+
accessKeyId: config.get('aws.accessKeyId'),
|
|
23
|
+
secretAccessKey: config.get('aws.secretAccessKey'),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const log = logger('aws:lambda');
|
|
28
|
+
|
|
29
|
+
export async function executeLambda({ data, fn, token, domainId }: executeLambdaOpts) {
|
|
30
|
+
if (!config.get('aws.accessKeyId') && !config.get('aws.secretAccessKey')) {
|
|
31
|
+
throw new errors.ConfigError('AWS credentials not set');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const res = await tryExecuteLambda({ data, fn, token, domainId });
|
|
36
|
+
return res;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error instanceof Error && error.name === 'ResourceNotFoundException') {
|
|
39
|
+
log.warn('Lambda not found, creating...');
|
|
40
|
+
await createLambda({ domainId });
|
|
41
|
+
return await tryExecuteLambda({ data, fn, token, domainId });
|
|
42
|
+
} else {
|
|
43
|
+
log.error('executeLambda', error);
|
|
44
|
+
return {
|
|
45
|
+
logs: [],
|
|
46
|
+
success: false,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function tryExecuteLambda({ data, fn, token, domainId }: executeLambdaOpts) {
|
|
53
|
+
const result = await lambda.invoke({ FunctionName: domainId, Payload: JSON.stringify({ data, token, fn }) });
|
|
54
|
+
let returnVal: IFunctionResult = {
|
|
55
|
+
requestId: result.$metadata.requestId,
|
|
56
|
+
logs: [],
|
|
57
|
+
success: false,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (result.Payload) {
|
|
61
|
+
const tmpResult = Buffer.from(result.Payload).toString();
|
|
62
|
+
const parsedRes = JSON.parse(tmpResult);
|
|
63
|
+
|
|
64
|
+
if (parsedRes.errorMessage && parsedRes.errorMessage.includes('Task timed out')) {
|
|
65
|
+
returnVal['success'] = false;
|
|
66
|
+
returnVal['logs'] = [
|
|
67
|
+
{
|
|
68
|
+
msg: 'Task timed out',
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
} else if (parsedRes.body.includes('Unexpected end of input')) {
|
|
72
|
+
returnVal['success'] = false;
|
|
73
|
+
returnVal['logs'] = [
|
|
74
|
+
{
|
|
75
|
+
msg: 'Syntax error, your javascript code is invalid',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
} else {
|
|
79
|
+
returnVal = JSON.parse(parsedRes.body);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return returnVal;
|
|
83
|
+
}
|
package/src/main.ts
ADDED
package/tsconfig.json
ADDED
package/typedoc.json
ADDED