@geek-fun/serverlessinsight 0.3.1 → 0.3.2
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/package.json +40 -38
- package/dist/src/commands/deploy.js +1 -1
- package/dist/src/commands/destroy.js +1 -1
- package/dist/src/commands/index.js +22 -7
- package/dist/src/commands/local.js +35 -0
- package/dist/src/commands/template.js +2 -2
- package/dist/src/commands/validate.js +2 -2
- package/dist/src/common/constants.js +4 -2
- package/dist/src/common/context.js +12 -6
- package/dist/src/common/iacHelper.js +1 -1
- package/dist/src/common/rosAssets.js +1 -0
- package/dist/src/common/rosClient.js +1 -1
- package/dist/src/parser/index.js +2 -0
- package/dist/src/parser/tableParser.js +41 -0
- package/dist/src/stack/localStack/event.js +38 -0
- package/dist/src/stack/localStack/index.d.ts +2 -0
- package/dist/src/stack/localStack/index.js +23 -0
- package/dist/src/stack/rosStack/bootstrap.js +153 -5
- package/dist/src/stack/rosStack/bucket.js +1 -0
- package/dist/src/stack/rosStack/database.js +1 -2
- package/dist/src/stack/rosStack/function.js +1 -2
- package/dist/src/stack/rosStack/index.js +3 -0
- package/dist/src/stack/rosStack/table.js +95 -0
- package/dist/src/types/domains/table.js +16 -0
- package/dist/src/types/index.d.ts +5 -0
- package/dist/src/validator/iacSchema.js +2 -0
- package/dist/src/validator/rootSchema.js +3 -0
- package/dist/src/validator/tableschema.js +72 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/layers/si-bootstrap-sdk/Dockerfile-aliyuncli +12 -0
- package/layers/si-bootstrap-sdk/README.md +1 -0
- package/layers/si-bootstrap-sdk/package-lock.json +875 -0
- package/layers/si-bootstrap-sdk/package.json +33 -0
- package/package.json +40 -38
- package/samples/aliyun-poc-table.yml +48 -0
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geek-fun/serverlessinsight",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Full life cycle cross providers serverless application management for your fast-growing business.",
|
|
5
5
|
"homepage": "https://serverlessinsight.geekfun.club",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -49,52 +49,54 @@
|
|
|
49
49
|
"function"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@alicloud/ims20190815": "^2.2
|
|
53
|
-
"@alicloud/openapi-client": "^0.4.
|
|
54
|
-
"@alicloud/ros-cdk-apigateway": "^1.
|
|
55
|
-
"@alicloud/ros-cdk-core": "^1.
|
|
56
|
-
"@alicloud/ros-cdk-dns": "^1.
|
|
57
|
-
"@alicloud/ros-cdk-ecs": "^1.
|
|
58
|
-
"@alicloud/ros-cdk-elasticsearchserverless": "^1.
|
|
59
|
-
"@alicloud/ros-cdk-fc3": "^1.
|
|
60
|
-
"@alicloud/ros-cdk-nas": "^1.
|
|
61
|
-
"@alicloud/ros-cdk-oss": "^1.
|
|
62
|
-
"@alicloud/ros-cdk-ossdeployment": "^1.
|
|
63
|
-
"@alicloud/ros-cdk-
|
|
64
|
-
"@alicloud/ros-cdk-
|
|
65
|
-
"@alicloud/ros-cdk-
|
|
66
|
-
"@alicloud/ros-cdk-
|
|
67
|
-
"@alicloud/
|
|
52
|
+
"@alicloud/ims20190815": "^2.3.2",
|
|
53
|
+
"@alicloud/openapi-client": "^0.4.15",
|
|
54
|
+
"@alicloud/ros-cdk-apigateway": "^1.10.0",
|
|
55
|
+
"@alicloud/ros-cdk-core": "^1.10.0",
|
|
56
|
+
"@alicloud/ros-cdk-dns": "^1.10.0",
|
|
57
|
+
"@alicloud/ros-cdk-ecs": "^1.10.0",
|
|
58
|
+
"@alicloud/ros-cdk-elasticsearchserverless": "^1.10.0",
|
|
59
|
+
"@alicloud/ros-cdk-fc3": "^1.10.0",
|
|
60
|
+
"@alicloud/ros-cdk-nas": "^1.10.0",
|
|
61
|
+
"@alicloud/ros-cdk-oss": "^1.10.0",
|
|
62
|
+
"@alicloud/ros-cdk-ossdeployment": "^1.10.0",
|
|
63
|
+
"@alicloud/ros-cdk-ots": "^1.10.0",
|
|
64
|
+
"@alicloud/ros-cdk-ram": "^1.10.0",
|
|
65
|
+
"@alicloud/ros-cdk-rds": "^1.10.0",
|
|
66
|
+
"@alicloud/ros-cdk-ros": "^1.10.0",
|
|
67
|
+
"@alicloud/ros-cdk-sls": "^1.10.0",
|
|
68
|
+
"@alicloud/ros-cdk-vpc": "^1.10.0",
|
|
69
|
+
"@alicloud/ros20190910": "^3.6.0",
|
|
68
70
|
"ajv": "^8.17.1",
|
|
69
|
-
"ali-oss": "^6.
|
|
70
|
-
"chalk": "^5.
|
|
71
|
-
"commander": "^
|
|
71
|
+
"ali-oss": "^6.23.0",
|
|
72
|
+
"chalk": "^5.6.2",
|
|
73
|
+
"commander": "^14.0.1",
|
|
72
74
|
"i": "^0.3.7",
|
|
73
|
-
"i18n": "^0.15.
|
|
75
|
+
"i18n": "^0.15.2",
|
|
74
76
|
"jszip": "^3.10.1",
|
|
75
77
|
"lodash": "^4.17.21",
|
|
76
|
-
"npm": "^11.2
|
|
77
|
-
"pino": "^9.
|
|
78
|
-
"pino-pretty": "^13.
|
|
79
|
-
"yaml": "^2.
|
|
78
|
+
"npm": "^11.5.2",
|
|
79
|
+
"pino": "^9.9.4",
|
|
80
|
+
"pino-pretty": "^13.1.1",
|
|
81
|
+
"yaml": "^2.8.1"
|
|
80
82
|
},
|
|
81
83
|
"devDependencies": {
|
|
82
84
|
"@types/ali-oss": "^6.16.11",
|
|
83
85
|
"@types/i18n": "^0.13.12",
|
|
84
|
-
"@types/jest": "^
|
|
85
|
-
"@types/lodash": "^4.17.
|
|
86
|
-
"@types/node": "^
|
|
87
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
88
|
-
"@typescript-eslint/parser": "^8.
|
|
89
|
-
"eslint": "^9.
|
|
90
|
-
"eslint-config-prettier": "^10.1.
|
|
91
|
-
"eslint-plugin-prettier": "^5.
|
|
92
|
-
"globals": "^16.
|
|
86
|
+
"@types/jest": "^30.0.0",
|
|
87
|
+
"@types/lodash": "^4.17.20",
|
|
88
|
+
"@types/node": "^24.3.0",
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "^8.39.1",
|
|
90
|
+
"@typescript-eslint/parser": "^8.39.1",
|
|
91
|
+
"eslint": "^9.33.0",
|
|
92
|
+
"eslint-config-prettier": "^10.1.8",
|
|
93
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
94
|
+
"globals": "^16.3.0",
|
|
93
95
|
"husky": "^9.1.7",
|
|
94
|
-
"jest": "^
|
|
95
|
-
"prettier": "^3.
|
|
96
|
-
"ts-jest": "^29.
|
|
96
|
+
"jest": "^30.0.5",
|
|
97
|
+
"prettier": "^3.6.2",
|
|
98
|
+
"ts-jest": "^29.4.1",
|
|
97
99
|
"ts-node": "^10.9.2",
|
|
98
|
-
"typescript": "^5.
|
|
100
|
+
"typescript": "^5.9.2"
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -8,7 +8,7 @@ const deploy = async (stackName, options) => {
|
|
|
8
8
|
common_1.logger.info('Validating yaml...');
|
|
9
9
|
const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
|
|
10
10
|
common_1.logger.info('Yaml is valid! 🎉');
|
|
11
|
-
(0, common_1.setContext)({ ...options, stackName, iacProvider: iac.provider });
|
|
11
|
+
await (0, common_1.setContext)({ ...options, stackName, iacProvider: iac.provider }, true);
|
|
12
12
|
common_1.logger.info('Deploying stack...');
|
|
13
13
|
await (0, stack_1.deployStack)(stackName, iac);
|
|
14
14
|
common_1.logger.info('Stack deployed! 🎉');
|
|
@@ -5,7 +5,7 @@ const common_1 = require("../common");
|
|
|
5
5
|
const parser_1 = require("../parser");
|
|
6
6
|
const destroyStack = async (stackName, options) => {
|
|
7
7
|
const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
|
|
8
|
-
(0, common_1.setContext)({ stackName, ...options, iacProvider: iac.provider });
|
|
8
|
+
await (0, common_1.setContext)({ stackName, ...options, iacProvider: iac.provider }, true);
|
|
9
9
|
const context = (0, common_1.getContext)();
|
|
10
10
|
common_1.logger.info(`Destroying stack: ${stackName}, provider: ${context.provider}, region: ${context.region}...`);
|
|
11
11
|
await (0, common_1.rosStackDelete)(context);
|
|
@@ -7,16 +7,16 @@ const validate_1 = require("./validate");
|
|
|
7
7
|
const deploy_1 = require("./deploy");
|
|
8
8
|
const template_1 = require("./template");
|
|
9
9
|
const destroy_1 = require("./destroy");
|
|
10
|
-
const
|
|
10
|
+
const local_1 = require("./local");
|
|
11
11
|
const program = new commander_1.Command();
|
|
12
12
|
program.name('si').description('CLI for ServerlessInsight').version((0, common_1.getVersion)());
|
|
13
13
|
program
|
|
14
14
|
.command('show')
|
|
15
15
|
.description('show string')
|
|
16
16
|
.action(async (options) => {
|
|
17
|
-
(0, common_1.setContext)({ ...options });
|
|
17
|
+
await (0, common_1.setContext)({ ...options });
|
|
18
18
|
const context = (0, common_1.getContext)();
|
|
19
|
-
const result = await (0,
|
|
19
|
+
const result = await (0, common_1.getIamInfo)(context);
|
|
20
20
|
console.log('result:', JSON.stringify(result));
|
|
21
21
|
});
|
|
22
22
|
program
|
|
@@ -24,9 +24,9 @@ program
|
|
|
24
24
|
.description('validate serverless Iac yaml')
|
|
25
25
|
.option('-f, --file <path>', 'specify the yaml file')
|
|
26
26
|
.option('-s, --stage <stage>', 'specify the stage')
|
|
27
|
-
.action((stackName, { file, stage }) => {
|
|
27
|
+
.action(async (stackName, { file, stage }) => {
|
|
28
28
|
common_1.logger.debug('log command info');
|
|
29
|
-
(0, validate_1.validate)(stackName, { stage, location: file });
|
|
29
|
+
await (0, validate_1.validate)(stackName, { stage, location: file });
|
|
30
30
|
});
|
|
31
31
|
program
|
|
32
32
|
.command('deploy <stackName>')
|
|
@@ -61,8 +61,8 @@ program
|
|
|
61
61
|
.option('-f, --file <path>', 'specify the yaml file')
|
|
62
62
|
.option('-s, --stage <stage>', 'specify the stage')
|
|
63
63
|
.option('-t, --format <type>', 'output content type (JSON or YAML)', 'JSON')
|
|
64
|
-
.action((stackName, { format, file, stage }) => {
|
|
65
|
-
(0, template_1.template)(stackName, { format, location: file, stage });
|
|
64
|
+
.action(async (stackName, { format, file, stage }) => {
|
|
65
|
+
await (0, template_1.template)(stackName, { format, location: file, stage });
|
|
66
66
|
});
|
|
67
67
|
program
|
|
68
68
|
.command('destroy <stackName>')
|
|
@@ -83,4 +83,19 @@ program
|
|
|
83
83
|
securityToken,
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
|
+
program
|
|
87
|
+
.command('local <stackName>')
|
|
88
|
+
.description('run Serverless application locally for debugging')
|
|
89
|
+
.option('-s, --stage <stage>', 'specify the stage', 'default')
|
|
90
|
+
.option('-p, --port <port>', 'specify the port', '3000')
|
|
91
|
+
.option('-d, --debug', 'enable debug mode')
|
|
92
|
+
.option('-w, --watch', 'enable file watch', true)
|
|
93
|
+
.action(async (stackName, { stage, port, debug, watch }) => {
|
|
94
|
+
await (0, local_1.runLocal)(stackName, {
|
|
95
|
+
stage,
|
|
96
|
+
port: Number(port) || 3000,
|
|
97
|
+
debug: !!debug,
|
|
98
|
+
watch: typeof watch === 'boolean' ? watch : true,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
86
101
|
program.parse();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runLocal = void 0;
|
|
4
|
+
const common_1 = require("../common");
|
|
5
|
+
const localStack_1 = require("../stack/localStack");
|
|
6
|
+
const runLocal = async (stackName, opts) => {
|
|
7
|
+
const { stage, port, debug, watch } = opts;
|
|
8
|
+
await (0, common_1.setContext)({ stage });
|
|
9
|
+
common_1.logger.info(`run-local starting: stack=${stackName} stage=${stage} port=${port} debug=${debug} watch=${watch}`);
|
|
10
|
+
await (0, localStack_1.startLocalStack)();
|
|
11
|
+
// if (watch) {
|
|
12
|
+
// const cwd = process.cwd();
|
|
13
|
+
// try {
|
|
14
|
+
// fs.watch(cwd, { recursive: true }, (eventType, filename) => {
|
|
15
|
+
// if (!filename) return;
|
|
16
|
+
// const filePath = path.join(cwd, filename);
|
|
17
|
+
// logger.info(`file change detected: ${eventType} ${filePath}`);
|
|
18
|
+
// });
|
|
19
|
+
// logger.info(`watching files under ${process.cwd()}`);
|
|
20
|
+
// } catch (err) {
|
|
21
|
+
// logger.warn(`file watch not available: ${String(err)}`);
|
|
22
|
+
// }
|
|
23
|
+
// }
|
|
24
|
+
//
|
|
25
|
+
// const shutdown = () => {
|
|
26
|
+
// logger.info('shutting down run-local server');
|
|
27
|
+
// server.close(() => process.exit(0));
|
|
28
|
+
// };
|
|
29
|
+
// process.on('SIGINT', shutdown);
|
|
30
|
+
// process.on('SIGTERM', shutdown);
|
|
31
|
+
//
|
|
32
|
+
// // return server for tests if needed
|
|
33
|
+
// return { server, port, stage, debug, watch };
|
|
34
|
+
};
|
|
35
|
+
exports.runLocal = runLocal;
|
|
@@ -9,9 +9,9 @@ const yaml_1 = __importDefault(require("yaml"));
|
|
|
9
9
|
const deploy_1 = require("../stack/deploy");
|
|
10
10
|
const common_1 = require("../common");
|
|
11
11
|
const parser_1 = require("../parser");
|
|
12
|
-
const template = (stackName, options) => {
|
|
12
|
+
const template = async (stackName, options) => {
|
|
13
13
|
const iac = (0, parser_1.parseYaml)((0, common_1.getIacLocation)(options.location));
|
|
14
|
-
(0, common_1.setContext)({ ...options, stackName, provider: iac.provider.name });
|
|
14
|
+
await (0, common_1.setContext)({ ...options, stackName, provider: iac.provider.name }, true);
|
|
15
15
|
const { template } = (0, deploy_1.generateStackTemplate)(stackName, iac);
|
|
16
16
|
if (typeof template === 'string') {
|
|
17
17
|
common_1.logger.info(`\n${template}`);
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.validate = void 0;
|
|
4
4
|
const common_1 = require("../common");
|
|
5
5
|
const parser_1 = require("../parser");
|
|
6
|
-
const validate = (stackName, options) => {
|
|
7
|
-
(0, common_1.setContext)({ stackName, ...options });
|
|
6
|
+
const validate = async (stackName, options) => {
|
|
7
|
+
await (0, common_1.setContext)({ stackName, ...options });
|
|
8
8
|
const context = (0, common_1.getContext)();
|
|
9
9
|
(0, parser_1.parseYaml)(context.iacLocation);
|
|
10
10
|
common_1.logger.info('Yaml is valid! 🎉');
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OSS_DEPLOYMENT_TIMEOUT = exports.CODE_ZIP_SIZE_LIMIT = void 0;
|
|
4
|
-
exports.CODE_ZIP_SIZE_LIMIT =
|
|
3
|
+
exports.SI_BOOTSTRAP_BUCKET_PREFIX = exports.SI_BOOTSTRAP_FC_PREFIX = exports.OSS_DEPLOYMENT_TIMEOUT = exports.CODE_ZIP_SIZE_LIMIT = void 0;
|
|
4
|
+
exports.CODE_ZIP_SIZE_LIMIT = 300 * 1000; // 300 KB ROS TemplateBody size limit 512 KB
|
|
5
5
|
exports.OSS_DEPLOYMENT_TIMEOUT = 3000; // in seconds
|
|
6
|
+
exports.SI_BOOTSTRAP_FC_PREFIX = 'si-bootstrap-api';
|
|
7
|
+
exports.SI_BOOTSTRAP_BUCKET_PREFIX = 'si-bootstrap-artifacts';
|
|
@@ -7,6 +7,7 @@ exports.getContext = exports.setContext = exports.getIacLocation = void 0;
|
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
8
|
const providerEnum_1 = require("./providerEnum");
|
|
9
9
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
10
|
+
const imsClient_1 = require("./imsClient");
|
|
10
11
|
const asyncLocalStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
11
12
|
const getIacLocation = (location) => {
|
|
12
13
|
const projectRoot = node_path_1.default.resolve(process.cwd());
|
|
@@ -18,16 +19,17 @@ const getIacLocation = (location) => {
|
|
|
18
19
|
node_path_1.default.resolve(projectRoot, 'serverless-insight.yml');
|
|
19
20
|
};
|
|
20
21
|
exports.getIacLocation = getIacLocation;
|
|
21
|
-
const setContext = (config) => {
|
|
22
|
+
const setContext = async (config, reaValToken = false) => {
|
|
23
|
+
const region = config.region ??
|
|
24
|
+
config.iacProvider?.region ??
|
|
25
|
+
process.env.ROS_REGION_ID ??
|
|
26
|
+
process.env.ALIYUN_REGION ??
|
|
27
|
+
'cn-hangzhou';
|
|
22
28
|
const context = {
|
|
23
29
|
stage: config.stage ?? 'default',
|
|
24
30
|
stackName: config.stackName ?? '',
|
|
25
31
|
provider: (config.provider ?? config.iacProvider?.name ?? providerEnum_1.ProviderEnum.ALIYUN),
|
|
26
|
-
region
|
|
27
|
-
config.iacProvider?.region ??
|
|
28
|
-
process.env.ROS_REGION_ID ??
|
|
29
|
-
process.env.ALIYUN_REGION ??
|
|
30
|
-
'cn-hangzhou',
|
|
32
|
+
region,
|
|
31
33
|
accessKeyId: config.accessKeyId ?? process.env.ALIYUN_ACCESS_KEY_ID,
|
|
32
34
|
accessKeySecret: config.accessKeySecret ?? process.env.ALIYUN_ACCESS_KEY_SECRET,
|
|
33
35
|
securityToken: config.securityToken ?? process.env.ALIYUN_SECURITY_TOKEN,
|
|
@@ -38,6 +40,10 @@ const setContext = (config) => {
|
|
|
38
40
|
[stage]: Object.entries(parameters).map(([key, value]) => ({ key, value })),
|
|
39
41
|
}), {}),
|
|
40
42
|
};
|
|
43
|
+
if (reaValToken) {
|
|
44
|
+
const iamInfo = await (0, imsClient_1.getIamInfo)(context);
|
|
45
|
+
context.accountId = iamInfo?.accountId;
|
|
46
|
+
}
|
|
41
47
|
asyncLocalStorage.enterWith(context);
|
|
42
48
|
};
|
|
43
49
|
exports.setContext = setContext;
|
|
@@ -127,7 +127,7 @@ const formatRosId = (id) => {
|
|
|
127
127
|
// Convert to lowercase
|
|
128
128
|
result = result.toLowerCase();
|
|
129
129
|
// Replace special characters with underscores
|
|
130
|
-
result = result.replace(/[
|
|
130
|
+
result = result.replace(/[/*,/#,-]/g, '_');
|
|
131
131
|
// Remove any number of underscores to single one
|
|
132
132
|
result = result.replace(/_+/g, '_');
|
|
133
133
|
// Remove leading underscores
|
|
@@ -139,6 +139,7 @@ const publishAssets = async (assets) => {
|
|
|
139
139
|
accessKeyId: context.accessKeyId,
|
|
140
140
|
accessKeySecret: context.accessKeySecret,
|
|
141
141
|
bucket: bucketName,
|
|
142
|
+
timeout: 600000, // 10 minutes
|
|
142
143
|
});
|
|
143
144
|
await ensureBucketExits(bucketName, client);
|
|
144
145
|
const headers = {
|
|
@@ -37,9 +37,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.rosStackDelete = exports.rosStackDeploy = void 0;
|
|
40
|
-
const tea_util_1 = __importDefault(require("@alicloud/tea-util"));
|
|
41
40
|
const ros20190910_1 = __importStar(require("@alicloud/ros20190910"));
|
|
42
41
|
const openapi_client_1 = require("@alicloud/openapi-client");
|
|
42
|
+
const tea_util_1 = __importDefault(require("@alicloud/tea-util"));
|
|
43
43
|
const logger_1 = require("./logger");
|
|
44
44
|
const lang_1 = require("../lang");
|
|
45
45
|
const context_1 = require("./context");
|
package/dist/src/parser/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const tagParser_1 = require("./tagParser");
|
|
|
9
9
|
const yaml_1 = require("yaml");
|
|
10
10
|
const validator_1 = require("../validator");
|
|
11
11
|
const bucketParser_1 = require("./bucketParser");
|
|
12
|
+
const tableParser_1 = require("./tableParser");
|
|
12
13
|
const validateExistence = (path) => {
|
|
13
14
|
if (!(0, node_fs_1.existsSync)(path)) {
|
|
14
15
|
throw new Error(`File does not exist at path: ${path}`);
|
|
@@ -24,6 +25,7 @@ const transformYaml = (iacJson) => {
|
|
|
24
25
|
functions: (0, functionParser_1.parseFunction)(iacJson.functions),
|
|
25
26
|
events: (0, eventParser_1.parseEvent)(iacJson.events),
|
|
26
27
|
databases: (0, databaseParser_1.parseDatabase)(iacJson.databases),
|
|
28
|
+
tables: (0, tableParser_1.parseTable)(iacJson.tables),
|
|
27
29
|
tags: (0, tagParser_1.parseTag)(iacJson.tags),
|
|
28
30
|
buckets: (0, bucketParser_1.parseBucket)(iacJson.buckets),
|
|
29
31
|
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTable = parseTable;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
function parseTable(tablesRaw) {
|
|
6
|
+
if ((0, lodash_1.isEmpty)(tablesRaw)) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
return Object.entries(tablesRaw)?.map(([key, table]) => {
|
|
10
|
+
const throughput = (0, lodash_1.omitBy)({
|
|
11
|
+
reserved: (0, lodash_1.omitBy)({
|
|
12
|
+
read: table.throughput?.reserved?.read,
|
|
13
|
+
write: table.throughput?.reserved?.write,
|
|
14
|
+
}, lodash_1.isNil),
|
|
15
|
+
onDemand: (0, lodash_1.omitBy)({
|
|
16
|
+
read: table.throughput?.on_demand?.read,
|
|
17
|
+
write: table.throughput?.on_demand?.write,
|
|
18
|
+
}, lodash_1.isNil),
|
|
19
|
+
}, lodash_1.isEmpty);
|
|
20
|
+
return {
|
|
21
|
+
key,
|
|
22
|
+
collection: table.collection,
|
|
23
|
+
name: table.name,
|
|
24
|
+
type: table.type,
|
|
25
|
+
desc: table.desc,
|
|
26
|
+
network: {
|
|
27
|
+
type: table.network?.type ?? 'PRIVATE',
|
|
28
|
+
ingressRules: table.network?.ingress_rules ?? [],
|
|
29
|
+
},
|
|
30
|
+
throughput: !(0, lodash_1.isEmpty)(throughput) ? throughput : undefined,
|
|
31
|
+
keySchema: table.key_schema?.map((keySchema) => ({
|
|
32
|
+
name: keySchema.name,
|
|
33
|
+
type: keySchema.type,
|
|
34
|
+
})) ?? [],
|
|
35
|
+
attributes: table.attributes?.map((attribute) => ({
|
|
36
|
+
name: attribute.name,
|
|
37
|
+
type: attribute.type,
|
|
38
|
+
})) ?? [],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.startEvents = void 0;
|
|
7
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
8
|
+
const common_1 = require("../../common");
|
|
9
|
+
const types_1 = require("../../types");
|
|
10
|
+
const lodash_1 = require("lodash");
|
|
11
|
+
const startApiGatewayServer = (event) => {
|
|
12
|
+
const server = node_http_1.default.createServer((req, res) => {
|
|
13
|
+
const matchedTrigger = event.triggers.find((trigger) => trigger.method === req.method && trigger.path === req.url);
|
|
14
|
+
if (!matchedTrigger) {
|
|
15
|
+
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
16
|
+
res.end('Not Found\n');
|
|
17
|
+
common_1.logger.warn(`API Gateway Event - ${req.method} ${req.url} -> Not Found`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
21
|
+
res.end(`Invoked backend: ${matchedTrigger.backend}\n`);
|
|
22
|
+
common_1.logger.info(`API Gateway Event - ${req.method} ${req.url} -> ${matchedTrigger.backend}`);
|
|
23
|
+
});
|
|
24
|
+
const port = 3000 + Math.floor(Math.random() * 1000);
|
|
25
|
+
server.listen(port, () => {
|
|
26
|
+
common_1.logger.info(`API Gateway "${event.name}" listening on http://localhost:${port}`);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
const startEvents = (events) => {
|
|
30
|
+
const apiGateways = events?.filter((event) => event.type === types_1.EventTypes.API_GATEWAY);
|
|
31
|
+
if ((0, lodash_1.isEmpty)(apiGateways)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
apiGateways.forEach((gateway) => {
|
|
35
|
+
startApiGatewayServer(gateway);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
exports.startEvents = startEvents;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.startLocalStack = void 0;
|
|
18
|
+
__exportStar(require("./event"), exports);
|
|
19
|
+
const startLocalStack = async () => {
|
|
20
|
+
// Placeholder for starting local stack logic
|
|
21
|
+
console.log('Local stack started');
|
|
22
|
+
};
|
|
23
|
+
exports.startLocalStack = startLocalStack;
|
|
@@ -3,8 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.prepareBootstrapStack = void 0;
|
|
4
4
|
const common_1 = require("../../common");
|
|
5
5
|
const getBootstrapTemplate = async (context) => {
|
|
6
|
-
const
|
|
7
|
-
const stackName = `si-bootstrap-${iamInfo?.accountId}-${context.region}`;
|
|
6
|
+
const stackName = `si-bootstrap-${context.accountId}-${context.region}`;
|
|
8
7
|
const template = {
|
|
9
8
|
Description: 'ServerlessInsight Bootstrap Stack',
|
|
10
9
|
Metadata: {
|
|
@@ -17,9 +16,7 @@ const getBootstrapTemplate = async (context) => {
|
|
|
17
16
|
si_auto_artifacts_bucket: {
|
|
18
17
|
Type: 'ALIYUN::OSS::Bucket',
|
|
19
18
|
Properties: {
|
|
20
|
-
BucketName: {
|
|
21
|
-
'Fn::Sub': 'si-bootstrap-artifacts-${ALIYUN::AccountId}-${ALIYUN::Region}',
|
|
22
|
-
},
|
|
19
|
+
BucketName: `${common_1.SI_BOOTSTRAP_BUCKET_PREFIX}-${context.accountId}-${context.region}`,
|
|
23
20
|
AccessControl: 'private',
|
|
24
21
|
DeletionForce: false,
|
|
25
22
|
EnableOssHdfsService: false,
|
|
@@ -29,6 +26,157 @@ const getBootstrapTemplate = async (context) => {
|
|
|
29
26
|
},
|
|
30
27
|
},
|
|
31
28
|
},
|
|
29
|
+
si_auto_bootstrap_api_lambda: {
|
|
30
|
+
Type: 'ALIYUN::FC3::Function',
|
|
31
|
+
Properties: {
|
|
32
|
+
FunctionName: `${common_1.SI_BOOTSTRAP_FC_PREFIX}-${context.accountId}-${context.region}`,
|
|
33
|
+
Description: 'ServerlessInsight Bootstrap API',
|
|
34
|
+
Handler: 'index.handler',
|
|
35
|
+
Runtime: 'nodejs20',
|
|
36
|
+
Layers: [
|
|
37
|
+
`acs:fc:${context.region}:${context.accountId}:layers/si-bootstrap-sdk/versions/18`,
|
|
38
|
+
],
|
|
39
|
+
Code: {
|
|
40
|
+
SourceCode: `
|
|
41
|
+
const { bootstrapHandler } = require('@geek-fun/si-bootstrap-sdk');
|
|
42
|
+
|
|
43
|
+
module.exports.handler = async (rawEvent, context) => {
|
|
44
|
+
// 处理 Buffer 类型的事件
|
|
45
|
+
const event = parseEvent(rawEvent);
|
|
46
|
+
|
|
47
|
+
const commonResponse = {
|
|
48
|
+
RequestId: event.requestId,
|
|
49
|
+
LogicalResourceId: event.logicalResourceId,
|
|
50
|
+
StackId: event.stackId
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// 处理业务逻辑
|
|
55
|
+
const result = await bootstrapHandler(event);
|
|
56
|
+
|
|
57
|
+
// 构建符合 ROS 要求的响应结构
|
|
58
|
+
const rosResponse = {
|
|
59
|
+
...commonResponse,
|
|
60
|
+
Status: result.status,
|
|
61
|
+
Reason: result.reason,
|
|
62
|
+
PhysicalResourceId: result.physicalResourceId,
|
|
63
|
+
Data: result.data || {} // 业务数据
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// 如果是删除操作,不需要返回数据
|
|
67
|
+
if (event.requestType === 'Delete') {
|
|
68
|
+
delete rosResponse.Data;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 发送响应到 ROS 服务(如果提供了 ResponseURL)
|
|
72
|
+
if (event.responseURL) {
|
|
73
|
+
await sendResponse(event.responseURL, rosResponse);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 返回成功响应
|
|
77
|
+
return {
|
|
78
|
+
statusCode: 200,
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
message: 'Request processed successfully',
|
|
81
|
+
rosResponse
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('Error:', error);
|
|
86
|
+
|
|
87
|
+
// 构建错误响应
|
|
88
|
+
const errorResponse = {
|
|
89
|
+
...commonResponse,
|
|
90
|
+
Status: 'FAILED',
|
|
91
|
+
Reason: error.message || 'Internal Server Error',
|
|
92
|
+
PhysicalResourceId: 'error-' + Date.now()
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// 发送错误响应到 ROS 服务
|
|
96
|
+
if (event.responseURL) {
|
|
97
|
+
try {
|
|
98
|
+
await sendResponse(event.responseURL, errorResponse);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error('Failed to send error response:', err);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 返回错误响应
|
|
105
|
+
return {
|
|
106
|
+
statusCode: 500,
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
error: 'Internal Server Error',
|
|
109
|
+
details: error.message,
|
|
110
|
+
rosErrorResponse: errorResponse
|
|
111
|
+
})
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// 使用原生 fetch API 发送响应
|
|
117
|
+
async function sendResponse(responseUrl, responseBody) {
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const body = JSON.stringify(responseBody);
|
|
121
|
+
|
|
122
|
+
const response = await fetch(responseUrl, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
'Content-Type': 'application/json',
|
|
126
|
+
'Content-Length': Buffer.byteLength(body).toString(),
|
|
127
|
+
'Date': new Date().toUTCString()
|
|
128
|
+
},
|
|
129
|
+
body: body
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
const errorText = await response.text();
|
|
134
|
+
throw new Error(\`Failed to send response. Status: \${response.status}, Body: \${errorText}\`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log('Response sent successfully');
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.error('Error sending response:', error);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
const parseEvent = (rawEvent) => {
|
|
146
|
+
// 处理 Buffer 类型的事件
|
|
147
|
+
let event;
|
|
148
|
+
if (Buffer.isBuffer(rawEvent)) {
|
|
149
|
+
event = JSON.parse(rawEvent.toString('utf8'));
|
|
150
|
+
} else if (typeof rawEvent === 'string') {
|
|
151
|
+
event = JSON.parse(rawEvent);
|
|
152
|
+
} else {
|
|
153
|
+
event = rawEvent;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const { credentials, ...resourceProperties } = event.ResourceProperties
|
|
157
|
+
return {
|
|
158
|
+
stackId: event.StackId,
|
|
159
|
+
responseURL: event.ResponseURL,
|
|
160
|
+
resourceOwnerId: event.ResourceOwnerId,
|
|
161
|
+
callerId: event.CallerId,
|
|
162
|
+
resourceProperties,
|
|
163
|
+
eventType: event.ResourceType,
|
|
164
|
+
requestType: event.RequestType?.toUpperCase(),
|
|
165
|
+
resourceType: resourceProperties.resource,
|
|
166
|
+
regionId: event.RegionId,
|
|
167
|
+
stackName: event.StackName,
|
|
168
|
+
requestId: event.RequestId,
|
|
169
|
+
intranetResponseURL: event.IntranetResponseURL,
|
|
170
|
+
logicalResourceId: event.LogicalResourceId,
|
|
171
|
+
physicalResourceId: event.PhysicalResourceId,
|
|
172
|
+
credentials
|
|
173
|
+
};
|
|
174
|
+
};`,
|
|
175
|
+
},
|
|
176
|
+
MemorySize: 512,
|
|
177
|
+
Timeout: 900, // 15 minutes
|
|
178
|
+
},
|
|
179
|
+
},
|
|
32
180
|
},
|
|
33
181
|
};
|
|
34
182
|
return { stackName, template };
|
|
@@ -81,6 +81,7 @@ const resolveBuckets = (scope, buckets, context) => {
|
|
|
81
81
|
const ossBucket = new oss.Bucket(scope, bucket.key, {
|
|
82
82
|
bucketName: (0, common_1.calcRefs)(bucket.name, context),
|
|
83
83
|
accessControl: aclMap.get((0, common_1.calcRefs)(bucket.security?.acl, context) ?? ''),
|
|
84
|
+
blockPublicAccess: (0, common_1.calcRefs)(bucket.security?.acl, context) === types_1.BucketAccessEnum.PRIVATE,
|
|
84
85
|
websiteConfigurationV2: bucket.website
|
|
85
86
|
? {
|
|
86
87
|
indexDocument: {
|