@geek-fun/serverlessinsight 0.3.0 → 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 -37
- package/dist/src/commands/deploy.js +2 -2
- package/dist/src/commands/destroy.js +2 -1
- package/dist/src/commands/index.js +32 -16
- package/dist/src/commands/local.js +35 -0
- package/dist/src/commands/template.js +3 -3
- package/dist/src/commands/validate.js +3 -2
- package/dist/src/common/constants.js +5 -2
- package/dist/src/common/{actionContext.js → context.js} +30 -9
- package/dist/src/common/iacHelper.js +54 -27
- package/dist/src/common/index.d.ts +1 -1
- package/dist/src/common/index.js +1 -1
- package/dist/src/common/rosAssets.js +34 -8
- package/dist/src/common/rosClient.js +6 -4
- package/dist/src/parser/index.js +2 -0
- package/dist/src/parser/tableParser.js +41 -0
- package/dist/src/stack/deploy.js +30 -13
- 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/rfsStack/index.d.ts +2 -2
- package/dist/src/stack/rfsStack/index.js +2 -1
- package/dist/src/stack/rosStack/bootstrap.js +157 -8
- package/dist/src/stack/rosStack/bucket.js +13 -12
- package/dist/src/stack/rosStack/database.js +11 -12
- package/dist/src/stack/rosStack/event.js +21 -21
- package/dist/src/stack/rosStack/function.js +66 -46
- package/dist/src/stack/rosStack/index.d.ts +2 -2
- package/dist/src/stack/rosStack/index.js +6 -3
- package/dist/src/stack/rosStack/stage.js +1 -1
- package/dist/src/stack/rosStack/table.js +95 -0
- package/dist/src/stack/rosStack/tag.js +1 -1
- package/dist/src/stack/rosStack/vars.js +3 -3
- package/dist/src/types/domains/table.js +16 -0
- package/dist/src/types/index.d.ts +5 -0
- package/dist/src/validator/functionSchema.js +1 -1
- 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 -37
- package/samples/aliyun-poc-fc-gpu.yml +23 -22
- package/samples/aliyun-poc-table.yml +48 -0
|
@@ -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
|
+
}
|
package/dist/src/stack/deploy.js
CHANGED
|
@@ -43,7 +43,8 @@ const common_1 = require("../common");
|
|
|
43
43
|
const rosStack_1 = require("./rosStack");
|
|
44
44
|
const rfsStack_1 = require("./rfsStack");
|
|
45
45
|
const lodash_1 = require("lodash");
|
|
46
|
-
const generateRosStackTemplate = (stackName, iac
|
|
46
|
+
const generateRosStackTemplate = (stackName, iac) => {
|
|
47
|
+
const context = (0, common_1.getContext)();
|
|
47
48
|
const app = new ros.App();
|
|
48
49
|
new rosStack_1.RosStack(app, iac, context);
|
|
49
50
|
const assembly = app.synth();
|
|
@@ -57,29 +58,45 @@ const generateRosStackTemplate = (stackName, iac, context) => {
|
|
|
57
58
|
return { template, assets };
|
|
58
59
|
};
|
|
59
60
|
exports.generateRosStackTemplate = generateRosStackTemplate;
|
|
60
|
-
const generateRfsStackTemplate = (stackName, iac
|
|
61
|
-
const stack = new rfsStack_1.RfsStack(iac
|
|
61
|
+
const generateRfsStackTemplate = (stackName, iac) => {
|
|
62
|
+
const stack = new rfsStack_1.RfsStack(iac);
|
|
62
63
|
const hcl = stack.toHclTerraform();
|
|
63
64
|
console.log('HCL:', hcl);
|
|
64
65
|
return { template: hcl };
|
|
65
66
|
};
|
|
66
67
|
exports.generateRfsStackTemplate = generateRfsStackTemplate;
|
|
67
|
-
const deployStack = async (stackName, iac
|
|
68
|
-
const { template, assets } = (0, exports.generateRosStackTemplate)(stackName, iac
|
|
69
|
-
await (0, rosStack_1.prepareBootstrapStack)(
|
|
68
|
+
const deployStack = async (stackName, iac) => {
|
|
69
|
+
const { template, assets } = (0, exports.generateRosStackTemplate)(stackName, iac);
|
|
70
|
+
await (0, rosStack_1.prepareBootstrapStack)();
|
|
70
71
|
common_1.logger.info(`Deploying stack, publishing assets...`);
|
|
71
|
-
await (0, common_1.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const constructedAssets = await (0, common_1.constructAssets)(assets);
|
|
73
|
+
try {
|
|
74
|
+
await (0, common_1.publishAssets)(constructedAssets);
|
|
75
|
+
common_1.logger.info(`Assets published! 🎉`);
|
|
76
|
+
await (0, common_1.rosStackDeploy)(stackName, template);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
common_1.logger.error(`Failed to deploy stack: ${e}`);
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
try {
|
|
84
|
+
common_1.logger.info(`Cleaning up temporary Assets...`);
|
|
85
|
+
await (0, common_1.cleanupAssets)(constructedAssets);
|
|
86
|
+
common_1.logger.info(`Assets cleaned up!♻️`);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
common_1.logger.error(`Failed to cleanup assets, it wont affect the deployment result, but to avoid potential cost, you can delete the temporary bucket : ${constructedAssets?.[0].bucketName}, error details:${e}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
75
92
|
};
|
|
76
93
|
exports.deployStack = deployStack;
|
|
77
|
-
const generateStackTemplate = (stackName, iac
|
|
94
|
+
const generateStackTemplate = (stackName, iac) => {
|
|
78
95
|
if (iac.provider.name === common_1.ProviderEnum.ALIYUN) {
|
|
79
|
-
return (0, exports.generateRosStackTemplate)(stackName, iac
|
|
96
|
+
return (0, exports.generateRosStackTemplate)(stackName, iac);
|
|
80
97
|
}
|
|
81
98
|
else if (iac.provider.name === common_1.ProviderEnum.HUAWEI) {
|
|
82
|
-
return (0, exports.generateRfsStackTemplate)(stackName, iac
|
|
99
|
+
return (0, exports.generateRfsStackTemplate)(stackName, iac);
|
|
83
100
|
}
|
|
84
101
|
return { template: '' };
|
|
85
102
|
};
|
|
@@ -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;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Context, ServerlessIac } from '../../types';
|
|
2
2
|
export declare class RfsStack {
|
|
3
3
|
private readonly iac;
|
|
4
4
|
private readonly context;
|
|
5
5
|
private hcl;
|
|
6
|
-
constructor(iac: ServerlessIac, context
|
|
6
|
+
constructor(iac: ServerlessIac, context?: Context);
|
|
7
7
|
toHclTerraform(): string;
|
|
8
8
|
appendHcl(hcl: string): void;
|
|
9
9
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RfsStack = void 0;
|
|
4
4
|
const function_1 = require("./function");
|
|
5
|
+
const common_1 = require("../../common");
|
|
5
6
|
const provider = (stack, context) => {
|
|
6
7
|
const hcl = `
|
|
7
8
|
terraform {
|
|
@@ -22,7 +23,7 @@ provider "huaweicloud" {
|
|
|
22
23
|
stack.appendHcl(hcl);
|
|
23
24
|
};
|
|
24
25
|
class RfsStack {
|
|
25
|
-
constructor(iac, context) {
|
|
26
|
+
constructor(iac, context = (0, common_1.getContext)()) {
|
|
26
27
|
this.iac = iac;
|
|
27
28
|
this.context = context;
|
|
28
29
|
this.hcl = '';
|
|
@@ -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 = `serverlessInsight-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: {
|
|
@@ -14,12 +13,10 @@ const getBootstrapTemplate = async (context) => {
|
|
|
14
13
|
},
|
|
15
14
|
ROSTemplateFormatVersion: '2015-09-01',
|
|
16
15
|
Resources: {
|
|
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,12 +26,164 @@ 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 };
|
|
35
183
|
};
|
|
36
|
-
const prepareBootstrapStack = async (
|
|
184
|
+
const prepareBootstrapStack = async () => {
|
|
185
|
+
const context = (0, common_1.getContext)();
|
|
37
186
|
const { stackName, template } = await getBootstrapTemplate(context);
|
|
38
|
-
await (0, common_1.rosStackDeploy)(stackName, template
|
|
187
|
+
await (0, common_1.rosStackDeploy)(stackName, template);
|
|
39
188
|
};
|
|
40
189
|
exports.prepareBootstrapStack = prepareBootstrapStack;
|
|
@@ -78,41 +78,42 @@ const resolveBuckets = (scope, buckets, context) => {
|
|
|
78
78
|
}, true);
|
|
79
79
|
}
|
|
80
80
|
buckets.forEach((bucket) => {
|
|
81
|
-
const ossBucket = new oss.Bucket(scope,
|
|
82
|
-
bucketName: (0, common_1.
|
|
83
|
-
accessControl: aclMap.get((0, common_1.
|
|
81
|
+
const ossBucket = new oss.Bucket(scope, bucket.key, {
|
|
82
|
+
bucketName: (0, common_1.calcRefs)(bucket.name, context),
|
|
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: {
|
|
87
88
|
type: '0',
|
|
88
|
-
suffix: (0, common_1.
|
|
89
|
+
suffix: (0, common_1.calcRefs)(bucket.website.index, context),
|
|
89
90
|
supportSubDir: 'true',
|
|
90
91
|
},
|
|
91
92
|
errorDocument: {
|
|
92
|
-
httpStatus: `${(0, common_1.
|
|
93
|
-
key: (0, common_1.
|
|
93
|
+
httpStatus: `${(0, common_1.calcRefs)(bucket.website.error_code, context)}`,
|
|
94
|
+
key: (0, common_1.calcRefs)(bucket.website.error_page, context),
|
|
94
95
|
},
|
|
95
96
|
}
|
|
96
97
|
: undefined,
|
|
97
98
|
});
|
|
98
99
|
if (bucket.website?.code) {
|
|
99
|
-
const filePath = node_path_1.default.resolve(process.cwd(), (0, common_1.
|
|
100
|
-
new ossDeployment.BucketDeployment(scope, `si_auto_${bucket.key}_bucket_code_deployment
|
|
100
|
+
const filePath = node_path_1.default.resolve(process.cwd(), (0, common_1.calcValue)(bucket.website.code, context));
|
|
101
|
+
new ossDeployment.BucketDeployment(scope, (0, common_1.formatRosId)(`si_auto_${bucket.key}_bucket_code_deployment`), {
|
|
101
102
|
sources: (0, common_1.getAssets)(filePath),
|
|
102
103
|
destinationBucket: ossBucket.attrName,
|
|
103
104
|
roleArn: siAutoOssDeploymentBucketRole.attrArn,
|
|
104
|
-
timeout:
|
|
105
|
+
timeout: common_1.OSS_DEPLOYMENT_TIMEOUT,
|
|
105
106
|
logMonitoring: false,
|
|
106
107
|
retainOnCreate: false,
|
|
107
108
|
}, true);
|
|
108
109
|
}
|
|
109
110
|
if (bucket.website?.domain) {
|
|
110
111
|
const { rr, domainName } = (0, common_1.splitDomain)(bucket.website.domain);
|
|
111
|
-
new oss.Domain(scope,
|
|
112
|
+
new oss.Domain(scope, (0, common_1.formatRosId)(`${bucket.key}_custom_domain`), {
|
|
112
113
|
bucketName: ossBucket.attrName,
|
|
113
|
-
domainName: (0, common_1.
|
|
114
|
+
domainName: (0, common_1.calcRefs)(bucket.website.domain, context),
|
|
114
115
|
});
|
|
115
|
-
new dns.DomainRecord(scope,
|
|
116
|
+
new dns.DomainRecord(scope, (0, common_1.formatRosId)(`${bucket.key}_custom_domain_record`), {
|
|
116
117
|
domainName: domainName,
|
|
117
118
|
rr,
|
|
118
119
|
type: 'CNAME',
|
|
@@ -212,19 +212,18 @@ const resolveDatabases = (scope, databases, context) => {
|
|
|
212
212
|
databases.forEach((db) => {
|
|
213
213
|
const { engine, version, category, dbInstanceClass, quota, storage } = rdsEngineMap.get(`${db.type}-${db.version}`) ?? {};
|
|
214
214
|
if (["ELASTICSEARCH_SERVERLESS" /* DatabaseEnum.ELASTICSEARCH_SERVERLESS */].includes(db.type)) {
|
|
215
|
-
new esServerless.App(scope,
|
|
216
|
-
appName: (0, common_1.
|
|
215
|
+
new esServerless.App(scope, db.key, {
|
|
216
|
+
appName: (0, common_1.calcRefs)(db.name, context),
|
|
217
217
|
appVersion: version,
|
|
218
218
|
authentication: {
|
|
219
219
|
basicAuth: [
|
|
220
220
|
{
|
|
221
|
-
password: (0, common_1.
|
|
221
|
+
password: (0, common_1.calcRefs)(db.security.basicAuth.password, context),
|
|
222
222
|
},
|
|
223
223
|
],
|
|
224
224
|
},
|
|
225
225
|
quotaInfo: {
|
|
226
|
-
|
|
227
|
-
storage: db.storage.min,
|
|
226
|
+
minCu: db.cu.min,
|
|
228
227
|
appType: category,
|
|
229
228
|
},
|
|
230
229
|
// network: [
|
|
@@ -246,7 +245,7 @@ const resolveDatabases = (scope, databases, context) => {
|
|
|
246
245
|
"RDS_PGSQL_SERVERLESS" /* DatabaseEnum.RDS_PGSQL_SERVERLESS */,
|
|
247
246
|
"RDS_MSSQL_SERVERLESS" /* DatabaseEnum.RDS_MSSQL_SERVERLESS */,
|
|
248
247
|
].includes(db.type)) {
|
|
249
|
-
new rds.DBInstance(scope,
|
|
248
|
+
new rds.DBInstance(scope, db.key, {
|
|
250
249
|
engine: engine,
|
|
251
250
|
/**
|
|
252
251
|
* Serverless 实例
|
|
@@ -255,7 +254,7 @@ const resolveDatabases = (scope, databases, context) => {
|
|
|
255
254
|
* PostgreSQL:14.0、15.0、16.0 - PGSQL_HA_14, PGSQL_14 PGSQL_HA_15, PGSQL_15, PGSQL_HA_16,PGSQL_16
|
|
256
255
|
*/
|
|
257
256
|
engineVersion: version,
|
|
258
|
-
dbInstanceStorage: (0, common_1.
|
|
257
|
+
dbInstanceStorage: (0, common_1.calcRefs)(db.storage.min, context),
|
|
259
258
|
/** Serverless 实例
|
|
260
259
|
* serverless_basic:Serverless 基础系列。(仅适用 MySQL 和 PostgreSQL)
|
|
261
260
|
* serverless_standard:Serverless 高可用系列。(仅适用 MySQL 和 PostgreSQL)
|
|
@@ -293,18 +292,18 @@ const resolveDatabases = (scope, databases, context) => {
|
|
|
293
292
|
*/
|
|
294
293
|
serverlessConfig: {
|
|
295
294
|
// @TODO db.cu.min should get parameter value when it refer to a parameter
|
|
296
|
-
minCapacity: (0, common_1.
|
|
297
|
-
maxCapacity: (0, common_1.
|
|
295
|
+
minCapacity: (0, common_1.calcRefs)(db.cu.min === 0 ? quota.minCapacity : db.cu.min + quota.minCapacity, context),
|
|
296
|
+
maxCapacity: (0, common_1.calcRefs)(db.cu.max + quota.minCapacity <= quota.maxCapacity
|
|
298
297
|
? db.cu.max + quota.minCapacity
|
|
299
298
|
: quota.maxCapacity, context),
|
|
300
299
|
autoPause: db.cu.min === 0,
|
|
301
300
|
switchForce: false,
|
|
302
301
|
},
|
|
303
|
-
masterUsername: (0, common_1.
|
|
304
|
-
masterUserPassword: (0, common_1.
|
|
302
|
+
masterUsername: (0, common_1.calcRefs)(db.security.basicAuth.username, context),
|
|
303
|
+
masterUserPassword: (0, common_1.calcRefs)(db.security.basicAuth.password, context),
|
|
305
304
|
masterUserType: 'Super',
|
|
306
305
|
multiAz: quota.ha,
|
|
307
|
-
securityIpList: (0, common_1.
|
|
306
|
+
securityIpList: (0, common_1.calcRefs)(db.network.ingressRules.join(','), context),
|
|
308
307
|
connectionStringType: db.network.type === 'PRIVATE' ? 'Inner' : 'Public',
|
|
309
308
|
dbInstanceNetType: db.network.type === 'PRIVATE' ? 'Intranet' : 'Internet',
|
|
310
309
|
}, true);
|
|
@@ -48,9 +48,9 @@ const resolveEvents = (scope, events, tags, context, service) => {
|
|
|
48
48
|
if (!apiGateway?.length)
|
|
49
49
|
return;
|
|
50
50
|
apiGateway.forEach((event) => {
|
|
51
|
-
const gatewayAccessRole = new ram.RosRole(scope, (0, common_1.
|
|
52
|
-
roleName: (0, common_1.
|
|
53
|
-
description: (0, common_1.
|
|
51
|
+
const gatewayAccessRole = new ram.RosRole(scope, (0, common_1.formatRosId)(`${event.key}_agw_role`), {
|
|
52
|
+
roleName: (0, common_1.calcRefs)(`${event.name}-agw-access-role`, context),
|
|
53
|
+
description: (0, common_1.calcRefs)(`${service} role`, context),
|
|
54
54
|
assumeRolePolicyDocument: {
|
|
55
55
|
version: '1',
|
|
56
56
|
statement: [
|
|
@@ -65,7 +65,7 @@ const resolveEvents = (scope, events, tags, context, service) => {
|
|
|
65
65
|
},
|
|
66
66
|
policies: [
|
|
67
67
|
{
|
|
68
|
-
policyName: (0, common_1.
|
|
68
|
+
policyName: (0, common_1.calcRefs)(`${service}-${event.name}-policy`, context),
|
|
69
69
|
policyDocument: {
|
|
70
70
|
version: '1',
|
|
71
71
|
statement: [
|
|
@@ -80,62 +80,62 @@ const resolveEvents = (scope, events, tags, context, service) => {
|
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
82
|
}, true);
|
|
83
|
-
const apiGatewayGroup = new agw.RosGroup(scope, (0, common_1.
|
|
84
|
-
groupName: (0, common_1.
|
|
85
|
-
tags: (0, common_1.
|
|
83
|
+
const apiGatewayGroup = new agw.RosGroup(scope, (0, common_1.formatRosId)(`${event.key}_agw_group`), {
|
|
84
|
+
groupName: (0, common_1.calcRefs)(`${service}-agw-group`, context),
|
|
85
|
+
tags: (0, common_1.calcRefs)(tags, context),
|
|
86
86
|
passthroughHeaders: 'host',
|
|
87
87
|
}, true);
|
|
88
88
|
if (event.domain) {
|
|
89
|
-
const
|
|
89
|
+
const dnsRecordId = (0, common_1.formatRosId)(`${event.key}_agw_custom_domain_record`);
|
|
90
90
|
const { domainName, rr } = (0, common_1.splitDomain)(event.domain?.domain_name);
|
|
91
|
-
new dns.DomainRecord(scope,
|
|
91
|
+
new dns.DomainRecord(scope, dnsRecordId, {
|
|
92
92
|
domainName,
|
|
93
93
|
rr,
|
|
94
94
|
type: 'CNAME',
|
|
95
95
|
value: apiGatewayGroup.attrSubDomain,
|
|
96
96
|
});
|
|
97
|
-
const agwCustomDomain = new agw.RosCustomDomain(scope,
|
|
97
|
+
const agwCustomDomain = new agw.RosCustomDomain(scope, (0, common_1.formatRosId)(`${event.key}_agw_custom_domain`), {
|
|
98
98
|
groupId: apiGatewayGroup.attrGroupId,
|
|
99
99
|
domainName: event.domain.domain_name,
|
|
100
100
|
certificateName: event.domain.certificate_name,
|
|
101
101
|
certificateBody: event.domain.certificate_body,
|
|
102
102
|
certificatePrivateKey: event.domain.certificate_private_key,
|
|
103
103
|
}, true);
|
|
104
|
-
agwCustomDomain.addRosDependency(
|
|
104
|
+
agwCustomDomain.addRosDependency(dnsRecordId);
|
|
105
105
|
}
|
|
106
106
|
event.triggers.forEach((trigger) => {
|
|
107
|
-
const key = (0, common_1.
|
|
108
|
-
const api = new agw.RosApi(scope, `${event.key}
|
|
109
|
-
apiName: (0, common_1.
|
|
107
|
+
const key = (0, common_1.formatRosId)((0, common_1.calcValue)(`${trigger.method}_${trigger.path}`, context));
|
|
108
|
+
const api = new agw.RosApi(scope, (0, common_1.formatRosId)(`${event.key}_agw_api_${key}`), {
|
|
109
|
+
apiName: (0, common_1.calcRefs)(`${event.name}-agw-api-${key.replace(/_/g, '-')}`, context),
|
|
110
110
|
groupId: apiGatewayGroup.attrGroupId,
|
|
111
111
|
visibility: 'PRIVATE',
|
|
112
112
|
authType: 'ANONYMOUS',
|
|
113
113
|
requestConfig: {
|
|
114
114
|
requestProtocol: 'HTTP',
|
|
115
|
-
requestHttpMethod: (0, common_1.
|
|
116
|
-
requestPath: (0, common_1.
|
|
115
|
+
requestHttpMethod: (0, common_1.calcRefs)(trigger.method, context),
|
|
116
|
+
requestPath: (0, common_1.calcRefs)(trigger.path, context),
|
|
117
117
|
requestMode: 'PASSTHROUGH',
|
|
118
118
|
},
|
|
119
119
|
serviceConfig: {
|
|
120
120
|
serviceProtocol: 'FunctionCompute',
|
|
121
121
|
functionComputeConfig: {
|
|
122
122
|
fcRegionId: context.region,
|
|
123
|
-
functionName: (0, common_1.
|
|
123
|
+
functionName: (0, common_1.calcRefs)(trigger.backend, context),
|
|
124
124
|
roleArn: gatewayAccessRole.attrArn,
|
|
125
125
|
fcVersion: '3.0',
|
|
126
|
-
method: (0, common_1.
|
|
126
|
+
method: (0, common_1.calcRefs)(trigger.method, context),
|
|
127
127
|
},
|
|
128
128
|
},
|
|
129
129
|
resultSample: 'ServerlessInsight resultSample',
|
|
130
130
|
resultType: 'PASSTHROUGH',
|
|
131
|
-
tags: (0, common_1.
|
|
131
|
+
tags: (0, common_1.calcRefs)(tags, context),
|
|
132
132
|
}, true);
|
|
133
133
|
api.addDependsOn(apiGatewayGroup);
|
|
134
|
-
new agw.Deployment(scope, `${
|
|
134
|
+
new agw.Deployment(scope, (0, common_1.formatRosId)(`${event.key}_agw_api_deployment_${key}`), {
|
|
135
135
|
apiId: api.attrApiId,
|
|
136
136
|
groupId: apiGatewayGroup.attrGroupId,
|
|
137
137
|
stageName: 'RELEASE',
|
|
138
|
-
description: `${service} Api Gateway deployment`,
|
|
138
|
+
description: (0, common_1.calcRefs)(`${service} Api Gateway deployment for api: ${trigger.method} ${trigger.path}`, context),
|
|
139
139
|
});
|
|
140
140
|
});
|
|
141
141
|
});
|