@geek-fun/serverlessinsight 0.0.0 → 0.0.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/README.md +45 -1
- package/dist/package.json +37 -5
- package/dist/src/commands/deploy.js +18 -0
- package/dist/src/commands/index.js +21 -4
- package/dist/src/commands/validate.js +12 -0
- package/dist/src/common/actionContext.js +22 -0
- package/dist/src/common/index.d.ts +6 -0
- package/dist/src/common/index.js +22 -0
- package/dist/src/common/printer.js +12 -0
- package/dist/src/common/rosClient.js +102 -0
- package/dist/src/iac/iacSchema.js +126 -0
- package/dist/src/iac/index.d.ts +2 -0
- package/dist/src/iac/index.js +18 -0
- package/dist/src/iac/parse.js +34 -0
- package/dist/src/stack/deploy.js +83 -0
- package/dist/src/stack/index.d.ts +1 -0
- package/dist/src/stack/index.js +5 -0
- package/dist/src/types.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +37 -5
- package/Dockerfile +0 -19
- package/docs/hls.drawio +0 -88
- package/docs/index.md +0 -25
package/README.md
CHANGED
|
@@ -1,17 +1,61 @@
|
|
|
1
1
|
# ServerlessInsight
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
[](https://github.com/geek-fun/serverlessinsight/actions/workflows/node.yml)
|
|
4
|
+
[](https://github.com/geek-fun/serverlessinsight/actions/workflows/release.yml)
|
|
5
|
+
[](https://badge.fury.io/js/@geek-fun%2Fserverlessinsight)
|
|
6
|
+
[](https://snyk.io/test/github/geek-fun/serverlessinsight)
|
|
7
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
|
+
[](https://codecov.io/gh/geek-fun/serverlessinsight)
|
|
3
9
|
|
|
4
10
|
Full life cycle cross providers serverless application management for your fast-growing business.
|
|
5
11
|
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
### prerequisites
|
|
15
|
+
|
|
16
|
+
- Node.js 16.x
|
|
17
|
+
|
|
18
|
+
### Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @geek-fun/serverlessinsight
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Usage
|
|
6
25
|
|
|
26
|
+
```bash
|
|
27
|
+
si -h
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
#### Initialize a new project
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
si init
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Deploy the application
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
si deploy
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Remove the application
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
si remove
|
|
46
|
+
```
|
|
7
47
|
|
|
8
48
|
## Development
|
|
49
|
+
|
|
9
50
|
Link ServerlessInsight globally to use the CLI tool.
|
|
51
|
+
|
|
10
52
|
```bash
|
|
11
53
|
npm run build
|
|
12
54
|
npm link
|
|
13
55
|
```
|
|
56
|
+
|
|
14
57
|
run the command then:
|
|
58
|
+
|
|
15
59
|
```bash
|
|
16
60
|
si -h
|
|
17
61
|
```
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geek-fun/serverlessinsight",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.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",
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
"si": "dist/src/commands/index.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"test": "DEBUG=
|
|
12
|
+
"test": "DEBUG=ServerlessInsight jest --runInBand --detectOpenHandles --coverage --coverageReporters json-summary text html lcov",
|
|
13
13
|
"test:ci": "jest --runInBand --ci --coverage --coverageReporters json-summary text html lcov",
|
|
14
14
|
"build": "tsc --build",
|
|
15
15
|
"lint:fix": "eslint --fix ./",
|
|
16
|
-
"lint:check": "eslint ./"
|
|
16
|
+
"lint:check": "eslint ./",
|
|
17
|
+
"prepare": "husky"
|
|
17
18
|
},
|
|
18
19
|
"repository": {
|
|
19
20
|
"type": "git",
|
|
@@ -24,10 +25,40 @@
|
|
|
24
25
|
"bugs": {
|
|
25
26
|
"url": "https://github.com/geek-fun/serverlessinsight/issues"
|
|
26
27
|
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"serverless",
|
|
30
|
+
"serverless-insight",
|
|
31
|
+
"lambda",
|
|
32
|
+
"aws-lambda",
|
|
33
|
+
"azure-functions",
|
|
34
|
+
"google-cloud-functions",
|
|
35
|
+
"tencent-cloud-functions",
|
|
36
|
+
"alibaba-cloud-functions",
|
|
37
|
+
"huawei-cloud-functions",
|
|
38
|
+
"serverless-framework",
|
|
39
|
+
"serverless-management",
|
|
40
|
+
"serverless-automation",
|
|
41
|
+
"serverless-observability",
|
|
42
|
+
"serverless-tracing",
|
|
43
|
+
"serverless-offline",
|
|
44
|
+
"alibaba",
|
|
45
|
+
"tencent",
|
|
46
|
+
"azure",
|
|
47
|
+
"huawei",
|
|
48
|
+
"google",
|
|
49
|
+
"function"
|
|
50
|
+
],
|
|
27
51
|
"dependencies": {
|
|
52
|
+
"@alicloud/openapi-client": "^0.4.11",
|
|
53
|
+
"@alicloud/ros-cdk-core": "^1.2.0",
|
|
54
|
+
"@alicloud/ros-cdk-fc": "^1.2.0",
|
|
55
|
+
"@alicloud/ros20190910": "^3.4.3",
|
|
56
|
+
"ajv": "^8.17.1",
|
|
57
|
+
"chalk": "^4.1.2",
|
|
28
58
|
"commander": "^11.1.0",
|
|
29
59
|
"i18n": "^0.15.1",
|
|
30
|
-
"pino": "^8.17.2"
|
|
60
|
+
"pino": "^8.17.2",
|
|
61
|
+
"yaml": "^2.5.1"
|
|
31
62
|
},
|
|
32
63
|
"devDependencies": {
|
|
33
64
|
"@types/i18n": "^0.13.10",
|
|
@@ -38,10 +69,11 @@
|
|
|
38
69
|
"eslint": "^8.56.0",
|
|
39
70
|
"eslint-config-prettier": "^9.1.0",
|
|
40
71
|
"eslint-plugin-prettier": "^5.1.3",
|
|
72
|
+
"husky": "^9.1.6",
|
|
41
73
|
"jest": "^29.7.0",
|
|
42
74
|
"prettier": "^3.2.4",
|
|
43
75
|
"ts-jest": "^29.1.1",
|
|
44
76
|
"ts-node": "^10.9.2",
|
|
45
|
-
"typescript": "^5.
|
|
77
|
+
"typescript": "^5.6.2"
|
|
46
78
|
}
|
|
47
79
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deploy = void 0;
|
|
4
|
+
const stack_1 = require("../stack");
|
|
5
|
+
const common_1 = require("../common");
|
|
6
|
+
const iac_1 = require("../iac");
|
|
7
|
+
const actionContext_1 = require("../common/actionContext");
|
|
8
|
+
const deploy = async (stackName, options) => {
|
|
9
|
+
const context = (0, actionContext_1.constructActionContext)({ location: options.location });
|
|
10
|
+
common_1.printer.info(`Deploying stack context: ${JSON.stringify(context)}...`);
|
|
11
|
+
common_1.printer.info('Validating yaml...');
|
|
12
|
+
const iac = (0, iac_1.parseYaml)(context.iacLocation);
|
|
13
|
+
common_1.printer.success('Yaml is valid! 🎉');
|
|
14
|
+
common_1.printer.info('Deploying stack...');
|
|
15
|
+
await (0, stack_1.deployStack)(stackName, iac, context);
|
|
16
|
+
common_1.printer.success('Stack deployed! 🎉');
|
|
17
|
+
};
|
|
18
|
+
exports.deploy = deploy;
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const lang_1 = require("../lang");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const common_1 = require("../common");
|
|
7
|
+
const validate_1 = require("./validate");
|
|
8
|
+
const deploy_1 = require("./deploy");
|
|
8
9
|
const program = new commander_1.Command();
|
|
9
|
-
program.name('si').description('CLI for ServerlessInsight').version((0,
|
|
10
|
+
program.name('si').description('CLI for ServerlessInsight').version((0, common_1.getVersion)());
|
|
10
11
|
program
|
|
11
12
|
.command('show')
|
|
12
13
|
.description('show string')
|
|
@@ -15,7 +16,23 @@ program
|
|
|
15
16
|
.option('-s, --separator <char>', 'separator character', ',')
|
|
16
17
|
.action((str, options) => {
|
|
17
18
|
const limit = options.first ? 1 : undefined;
|
|
18
|
-
|
|
19
|
+
common_1.logger.debug({ limit, first: options.first, separator: options.separator }, 'log command info');
|
|
19
20
|
console.log(`${str} ${options.first} ${options.separator} ${lang_1.lang.__('hello')}`);
|
|
20
21
|
});
|
|
22
|
+
program
|
|
23
|
+
.command('validate [stackName]')
|
|
24
|
+
.description('validate serverless Iac yaml')
|
|
25
|
+
.option('-f, --file <path>', 'specify the yaml file')
|
|
26
|
+
.action((stackName, options) => {
|
|
27
|
+
common_1.logger.debug('log command info');
|
|
28
|
+
(0, validate_1.validate)(options.file);
|
|
29
|
+
});
|
|
30
|
+
program
|
|
31
|
+
.command('deploy <stackName>')
|
|
32
|
+
.description('deploy serverless Iac yaml')
|
|
33
|
+
.option('-f, --file <path>', 'specify the yaml file')
|
|
34
|
+
.action(async (stackName, options) => {
|
|
35
|
+
common_1.logger.debug('log command info');
|
|
36
|
+
await (0, deploy_1.deploy)(stackName, { location: options.file });
|
|
37
|
+
});
|
|
21
38
|
program.parse();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validate = void 0;
|
|
4
|
+
const iac_1 = require("../iac");
|
|
5
|
+
const common_1 = require("../common");
|
|
6
|
+
const actionContext_1 = require("../common/actionContext");
|
|
7
|
+
const validate = (location) => {
|
|
8
|
+
const context = (0, actionContext_1.constructActionContext)({ location });
|
|
9
|
+
(0, iac_1.parseYaml)(context.iacLocation);
|
|
10
|
+
common_1.printer.success('Yaml is valid! 🎉');
|
|
11
|
+
};
|
|
12
|
+
exports.validate = validate;
|
|
@@ -0,0 +1,22 @@
|
|
|
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.constructActionContext = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const constructActionContext = (config) => {
|
|
9
|
+
return {
|
|
10
|
+
region: config?.region ?? process.env.ROS_REGION_ID ?? process.env.ALIYUN_REGION ?? 'cn-hangzhou',
|
|
11
|
+
accessKeyId: config?.accessKeyId ?? process.env.ALIYUN_ACCESS_KEY_ID,
|
|
12
|
+
accessKeySecret: config?.accessKeySecret ?? process.env.ALIYUN_ACCESS_KEY_SECRET,
|
|
13
|
+
securityToken: config?.securityToken ?? process.env.ALIYUN_SECURITY_TOKEN,
|
|
14
|
+
iacLocation: (() => {
|
|
15
|
+
const projectRoot = node_path_1.default.resolve(process.cwd());
|
|
16
|
+
return config?.location
|
|
17
|
+
? node_path_1.default.resolve(projectRoot, config?.location)
|
|
18
|
+
: node_path_1.default.resolve(projectRoot, 'serverless-insight.yml');
|
|
19
|
+
})(),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.constructActionContext = constructActionContext;
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
__exportStar(require("./printer"), exports);
|
|
18
|
+
__exportStar(require("./provider"), exports);
|
|
19
|
+
__exportStar(require("./logger"), exports);
|
|
20
|
+
__exportStar(require("./getVersion"), exports);
|
|
21
|
+
__exportStar(require("./rosClient"), exports);
|
|
22
|
+
__exportStar(require("./actionContext"), exports);
|
|
@@ -0,0 +1,12 @@
|
|
|
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.printer = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
exports.printer = {
|
|
9
|
+
success: (message) => console.log(`${chalk_1.default.blue('ServerlessInsight')}: ${chalk_1.default.green(message)}`),
|
|
10
|
+
info: (message) => console.log(`${chalk_1.default.blue('ServerlessInsight')}: ${message}`),
|
|
11
|
+
error: (message) => console.log(`${chalk_1.default.bgRed(chalk_1.default.black('ServerlessInsight'))}: ${chalk_1.default.red(message)}`),
|
|
12
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.rosStackDeploy = void 0;
|
|
30
|
+
const tea_util_1 = __importDefault(require("@alicloud/tea-util"));
|
|
31
|
+
const ros20190910_1 = __importStar(require("@alicloud/ros20190910"));
|
|
32
|
+
const openapi_client_1 = require("@alicloud/openapi-client");
|
|
33
|
+
const printer_1 = require("./printer");
|
|
34
|
+
const client = new ros20190910_1.default(new openapi_client_1.Config({
|
|
35
|
+
accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID,
|
|
36
|
+
accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET,
|
|
37
|
+
regionId: process.env.ALIYUN_REGION,
|
|
38
|
+
disableRollback: false,
|
|
39
|
+
}));
|
|
40
|
+
const createStack = async (stackName, templateBody, context) => {
|
|
41
|
+
const parameters = context.parameters?.map((parameter) => new ros20190910_1.CreateStackRequestParameters({
|
|
42
|
+
parameterKey: tea_util_1.default.assertAsString(parameter.key),
|
|
43
|
+
parameterValue: tea_util_1.default.assertAsString(parameter.value),
|
|
44
|
+
}));
|
|
45
|
+
const createStackRequest = new ros20190910_1.CreateStackRequest({
|
|
46
|
+
regionId: context.region,
|
|
47
|
+
stackName,
|
|
48
|
+
templateBody: JSON.stringify(templateBody),
|
|
49
|
+
parameters,
|
|
50
|
+
tags: context.tags?.map((tag) => new ros20190910_1.CreateStackRequestTags(tag)),
|
|
51
|
+
});
|
|
52
|
+
console.log('createStackRequest:', createStackRequest);
|
|
53
|
+
const response = await client.createStack(createStackRequest);
|
|
54
|
+
console.log(`创建中,资源栈ID:${response.body?.stackId}`);
|
|
55
|
+
return response.body?.stackId;
|
|
56
|
+
};
|
|
57
|
+
const updateStack = async (stackName, templateBody, context) => {
|
|
58
|
+
const parameters = context.parameters?.map((parameter) => new ros20190910_1.CreateStackRequestParameters({
|
|
59
|
+
parameterKey: tea_util_1.default.assertAsString(parameter.key),
|
|
60
|
+
parameterValue: tea_util_1.default.assertAsString(parameter.value),
|
|
61
|
+
}));
|
|
62
|
+
const createStackRequest = new ros20190910_1.CreateStackRequest({
|
|
63
|
+
stackName,
|
|
64
|
+
templateBody,
|
|
65
|
+
parameters,
|
|
66
|
+
});
|
|
67
|
+
const response = await client.updateStack(createStackRequest);
|
|
68
|
+
console.log(`更新中,资源栈ID:${response.body?.stackId}`);
|
|
69
|
+
return response.body?.stackId;
|
|
70
|
+
};
|
|
71
|
+
const getStackByName = async (stackName, region) => {
|
|
72
|
+
const result = await client.listStacks(new ros20190910_1.ListStacksRequest({
|
|
73
|
+
regionId: region,
|
|
74
|
+
pageSize: 10,
|
|
75
|
+
pageNumber: 1,
|
|
76
|
+
stackName: [stackName],
|
|
77
|
+
}));
|
|
78
|
+
if (result.statusCode === 200) {
|
|
79
|
+
return result.body?.stacks?.[0];
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const rosStackDeploy = async (stackName, templateBody, context) => {
|
|
86
|
+
const stackInfo = await getStackByName(stackName, context.region);
|
|
87
|
+
if (stackInfo) {
|
|
88
|
+
const { Status: stackStatus } = stackInfo;
|
|
89
|
+
if (stackStatus?.indexOf('IN_PROGRESS') >= 0) {
|
|
90
|
+
printer_1.printer.error(`fail to update stack, because stack status is ${stackStatus}`);
|
|
91
|
+
throw new Error(`fail to update stack, because stack status is ${stackStatus}`);
|
|
92
|
+
}
|
|
93
|
+
printer_1.printer.info(`Update stack: ${stackName} deploying... `);
|
|
94
|
+
return await updateStack(stackName, templateBody, context);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// create stack
|
|
98
|
+
printer_1.printer.info(`Create stack: ${stackName} deploying... `);
|
|
99
|
+
return await createStack(stackName, templateBody, context);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
exports.rosStackDeploy = rosStackDeploy;
|
|
@@ -0,0 +1,126 @@
|
|
|
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.validateYaml = void 0;
|
|
7
|
+
const ajv_1 = __importDefault(require("ajv"));
|
|
8
|
+
const ajv = new ajv_1.default({ allowUnionTypes: true, strict: false, allErrors: true });
|
|
9
|
+
const schema = {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
version: { type: 'string', enum: ['0.0.0', '0.0.1'] },
|
|
13
|
+
provider: { type: 'string', enum: ['aliyun', 'huawei'] },
|
|
14
|
+
service: { type: 'string' },
|
|
15
|
+
vars: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
additionalProperties: {
|
|
18
|
+
type: ['string', 'number', 'boolean'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
stages: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
patternProperties: {
|
|
24
|
+
'.*': {
|
|
25
|
+
type: 'object',
|
|
26
|
+
additionalProperties: {
|
|
27
|
+
type: ['string', 'number', 'boolean'],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
tags: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
additionalProperties: {
|
|
35
|
+
type: ['string', 'number', 'boolean'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
functions: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
patternProperties: {
|
|
41
|
+
'.*': {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
name: { type: 'string' },
|
|
45
|
+
runtime: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
enum: [
|
|
48
|
+
'nodejs20',
|
|
49
|
+
'nodejs18',
|
|
50
|
+
'nodejs16',
|
|
51
|
+
'nodejs14',
|
|
52
|
+
'nodejs12',
|
|
53
|
+
'nodejs10',
|
|
54
|
+
'nodejs8',
|
|
55
|
+
'python3.10',
|
|
56
|
+
'python3.9',
|
|
57
|
+
'python3',
|
|
58
|
+
'PHP 7.2',
|
|
59
|
+
'Java 11',
|
|
60
|
+
'.NET Core 3.1',
|
|
61
|
+
'Go 1.x',
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
handler: { type: 'string' },
|
|
65
|
+
code: { type: 'string' },
|
|
66
|
+
memory: { type: 'number' },
|
|
67
|
+
timeout: { type: 'number' },
|
|
68
|
+
environment: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
additionalProperties: {
|
|
71
|
+
type: ['string', 'number', 'boolean'],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
additionalProperties: false,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
events: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
patternProperties: {
|
|
82
|
+
'.*': {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
type: { type: 'string', enum: ['API_GATEWAY'] },
|
|
86
|
+
triggers: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
items: {
|
|
89
|
+
method: { type: 'string', enum: ['GET', 'POST', 'PUT', 'DELETE', 'ANY'] },
|
|
90
|
+
path: { type: 'string' },
|
|
91
|
+
backend: { type: 'string' },
|
|
92
|
+
required: ['method', 'path', 'backend'],
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: ['type', 'triggers'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
required: ['version', 'provider', 'service'],
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
};
|
|
104
|
+
class IacSchemaErrors extends Error {
|
|
105
|
+
constructor(errors) {
|
|
106
|
+
super(`Invalid yaml`);
|
|
107
|
+
this.schemaErrors = errors.map((error) => ({
|
|
108
|
+
instancePath: error.instancePath,
|
|
109
|
+
schemaPath: error.schemaPath,
|
|
110
|
+
message: error.message,
|
|
111
|
+
allowedValues: error.params?.allowedValues,
|
|
112
|
+
type: error.keyword,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
get errors() {
|
|
116
|
+
return this.schemaErrors;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const validateYaml = (iacJson) => {
|
|
120
|
+
const validate = ajv.compile(schema);
|
|
121
|
+
const valid = validate(iacJson);
|
|
122
|
+
if (!valid)
|
|
123
|
+
throw new IacSchemaErrors(validate.errors);
|
|
124
|
+
return true;
|
|
125
|
+
};
|
|
126
|
+
exports.validateYaml = validateYaml;
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
__exportStar(require("./parse"), exports);
|
|
18
|
+
__exportStar(require("./iacSchema"), exports);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseYaml = void 0;
|
|
4
|
+
const yaml_1 = require("yaml");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const iacSchema_1 = require("./iacSchema");
|
|
7
|
+
const mapToArr = (obj) => {
|
|
8
|
+
return Object.entries(obj).map(([key, value]) => typeof value === 'string' ? { [key]: value } : { key, ...value });
|
|
9
|
+
};
|
|
10
|
+
const validateExistence = (path) => {
|
|
11
|
+
if (!(0, node_fs_1.existsSync)(path)) {
|
|
12
|
+
throw new Error(`File does not exist at path: ${path}`);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const transformYaml = (iacJson) => {
|
|
16
|
+
return {
|
|
17
|
+
service: iacJson.service,
|
|
18
|
+
version: iacJson.version,
|
|
19
|
+
provider: iacJson.provider,
|
|
20
|
+
vars: iacJson.vars,
|
|
21
|
+
stages: iacJson.stages,
|
|
22
|
+
functions: mapToArr(iacJson.functions),
|
|
23
|
+
events: mapToArr(iacJson.events),
|
|
24
|
+
tags: mapToArr(iacJson.tags),
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const parseYaml = (yamlPath) => {
|
|
28
|
+
validateExistence(yamlPath);
|
|
29
|
+
const yamlContent = (0, node_fs_1.readFileSync)(yamlPath, 'utf8');
|
|
30
|
+
const iacJson = (0, yaml_1.parse)(yamlContent);
|
|
31
|
+
(0, iacSchema_1.validateYaml)(iacJson);
|
|
32
|
+
return transformYaml(iacJson);
|
|
33
|
+
};
|
|
34
|
+
exports.parseYaml = parseYaml;
|
|
@@ -0,0 +1,83 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.deployStack = exports.IacStack = void 0;
|
|
30
|
+
const ros = __importStar(require("@alicloud/ros-cdk-core"));
|
|
31
|
+
const fc = __importStar(require("@alicloud/ros-cdk-fc"));
|
|
32
|
+
const common_1 = require("../common");
|
|
33
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
34
|
+
const fs = __importStar(require("node:fs"));
|
|
35
|
+
const resolveCode = (location) => {
|
|
36
|
+
const filePath = node_path_1.default.resolve(process.cwd(), location);
|
|
37
|
+
const fileContent = fs.readFileSync(filePath);
|
|
38
|
+
return fileContent.toString('base64');
|
|
39
|
+
};
|
|
40
|
+
class IacStack extends ros.Stack {
|
|
41
|
+
constructor(scope, iac, props) {
|
|
42
|
+
super(scope, iac.service, props);
|
|
43
|
+
new ros.RosInfo(this, ros.RosInfo.description, 'This is the simple ros cdk app example.');
|
|
44
|
+
const service = new fc.RosService(this, `${iac.service}-service`, {
|
|
45
|
+
serviceName: `${iac.service}-service`,
|
|
46
|
+
}, true);
|
|
47
|
+
iac.functions.forEach((fnc) => {
|
|
48
|
+
const func = new fc.RosFunction(this, fnc.key, {
|
|
49
|
+
functionName: fnc.name,
|
|
50
|
+
serviceName: service.serviceName,
|
|
51
|
+
handler: fnc.handler,
|
|
52
|
+
runtime: fnc.runtime,
|
|
53
|
+
memorySize: fnc.memory,
|
|
54
|
+
timeout: fnc.timeout,
|
|
55
|
+
environmentVariables: fnc.environment,
|
|
56
|
+
code: {
|
|
57
|
+
zipFile: resolveCode(fnc.code),
|
|
58
|
+
},
|
|
59
|
+
}, true);
|
|
60
|
+
func.addDependsOn(service);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.IacStack = IacStack;
|
|
65
|
+
const generateStackTemplate = (stackName, iac) => {
|
|
66
|
+
const app = new ros.App();
|
|
67
|
+
new IacStack(app, iac);
|
|
68
|
+
const assembly = app.synth();
|
|
69
|
+
const stackArtifact = assembly.getStackByName(stackName);
|
|
70
|
+
const parameters = Object.entries(stackArtifact.parameters).map(([key, value]) => ({
|
|
71
|
+
key,
|
|
72
|
+
value,
|
|
73
|
+
}));
|
|
74
|
+
return { template: stackArtifact.template, parameters };
|
|
75
|
+
};
|
|
76
|
+
const deployStack = async (stackName, iac, context) => {
|
|
77
|
+
common_1.printer.info(`Deploying stack... ${JSON.stringify(iac)}`);
|
|
78
|
+
const { template, parameters } = generateStackTemplate(stackName, iac);
|
|
79
|
+
console.log('Generated ROS YAML:', JSON.stringify({ template, parameters }));
|
|
80
|
+
await (0, common_1.rosStackDeploy)(stackName, template, { ...context, parameters });
|
|
81
|
+
common_1.printer.info(`Stack deployed! 🎉`);
|
|
82
|
+
};
|
|
83
|
+
exports.deployStack = deployStack;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { deployStack } from './deploy';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../src/index.ts","../src/types.ts","../src/commands/deploy.ts","../src/commands/index.ts","../src/commands/validate.ts","../src/common/actionContext.ts","../src/common/getVersion.ts","../src/common/index.ts","../src/common/logger.ts","../src/common/printer.ts","../src/common/provider.ts","../src/common/rosClient.ts","../src/iac/iacSchema.ts","../src/iac/index.ts","../src/iac/parse.ts","../src/lang/index.ts","../src/stack/deploy.ts","../src/stack/index.ts"],"version":"5.6.2"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geek-fun/serverlessinsight",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.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",
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
"si": "dist/src/commands/index.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"test": "DEBUG=
|
|
12
|
+
"test": "DEBUG=ServerlessInsight jest --runInBand --detectOpenHandles --coverage --coverageReporters json-summary text html lcov",
|
|
13
13
|
"test:ci": "jest --runInBand --ci --coverage --coverageReporters json-summary text html lcov",
|
|
14
14
|
"build": "tsc --build",
|
|
15
15
|
"lint:fix": "eslint --fix ./",
|
|
16
|
-
"lint:check": "eslint ./"
|
|
16
|
+
"lint:check": "eslint ./",
|
|
17
|
+
"prepare": "husky"
|
|
17
18
|
},
|
|
18
19
|
"repository": {
|
|
19
20
|
"type": "git",
|
|
@@ -24,10 +25,40 @@
|
|
|
24
25
|
"bugs": {
|
|
25
26
|
"url": "https://github.com/geek-fun/serverlessinsight/issues"
|
|
26
27
|
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"serverless",
|
|
30
|
+
"serverless-insight",
|
|
31
|
+
"lambda",
|
|
32
|
+
"aws-lambda",
|
|
33
|
+
"azure-functions",
|
|
34
|
+
"google-cloud-functions",
|
|
35
|
+
"tencent-cloud-functions",
|
|
36
|
+
"alibaba-cloud-functions",
|
|
37
|
+
"huawei-cloud-functions",
|
|
38
|
+
"serverless-framework",
|
|
39
|
+
"serverless-management",
|
|
40
|
+
"serverless-automation",
|
|
41
|
+
"serverless-observability",
|
|
42
|
+
"serverless-tracing",
|
|
43
|
+
"serverless-offline",
|
|
44
|
+
"alibaba",
|
|
45
|
+
"tencent",
|
|
46
|
+
"azure",
|
|
47
|
+
"huawei",
|
|
48
|
+
"google",
|
|
49
|
+
"function"
|
|
50
|
+
],
|
|
27
51
|
"dependencies": {
|
|
52
|
+
"@alicloud/openapi-client": "^0.4.11",
|
|
53
|
+
"@alicloud/ros-cdk-core": "^1.2.0",
|
|
54
|
+
"@alicloud/ros-cdk-fc": "^1.2.0",
|
|
55
|
+
"@alicloud/ros20190910": "^3.4.3",
|
|
56
|
+
"ajv": "^8.17.1",
|
|
57
|
+
"chalk": "^4.1.2",
|
|
28
58
|
"commander": "^11.1.0",
|
|
29
59
|
"i18n": "^0.15.1",
|
|
30
|
-
"pino": "^8.17.2"
|
|
60
|
+
"pino": "^8.17.2",
|
|
61
|
+
"yaml": "^2.5.1"
|
|
31
62
|
},
|
|
32
63
|
"devDependencies": {
|
|
33
64
|
"@types/i18n": "^0.13.10",
|
|
@@ -38,10 +69,11 @@
|
|
|
38
69
|
"eslint": "^8.56.0",
|
|
39
70
|
"eslint-config-prettier": "^9.1.0",
|
|
40
71
|
"eslint-plugin-prettier": "^5.1.3",
|
|
72
|
+
"husky": "^9.1.6",
|
|
41
73
|
"jest": "^29.7.0",
|
|
42
74
|
"prettier": "^3.2.4",
|
|
43
75
|
"ts-jest": "^29.1.1",
|
|
44
76
|
"ts-node": "^10.9.2",
|
|
45
|
-
"typescript": "^5.
|
|
77
|
+
"typescript": "^5.6.2"
|
|
46
78
|
}
|
|
47
79
|
}
|
package/Dockerfile
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
FROM node:16.17.1-alpine@sha256:4e36c3dee7c32cef5bfce5bc1b5013d1c3cc542cfdefde2a545ec641e7c94243 AS builder
|
|
2
|
-
WORKDIR /app
|
|
3
|
-
|
|
4
|
-
ENV NODE_ENV=development
|
|
5
|
-
COPY ./package.json .
|
|
6
|
-
COPY ./package-lock.json .
|
|
7
|
-
RUN npm install
|
|
8
|
-
COPY ./tsconfig.json .
|
|
9
|
-
COPY ./src ./src
|
|
10
|
-
RUN npm run build
|
|
11
|
-
|
|
12
|
-
FROM node:16.17.1-alpine@sha256:4e36c3dee7c32cef5bfce5bc1b5013d1c3cc542cfdefde2a545ec641e7c94243
|
|
13
|
-
WORKDIR /app
|
|
14
|
-
|
|
15
|
-
ENV NODE_ENV=production
|
|
16
|
-
COPY --from=builder /app/dist .
|
|
17
|
-
COPY ./package.json .
|
|
18
|
-
COPY ./package-lock.json .
|
|
19
|
-
RUN npm install
|
package/docs/hls.drawio
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
<mxfile host="Electron" modified="2024-01-22T09:48:55.568Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.16 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="gWoh4gj2v1h36HgFtq0S" version="22.1.16" type="device">
|
|
2
|
-
<diagram name="c4m" id="Lr6ONU7xbmqIyIEAW1Wm">
|
|
3
|
-
<mxGraphModel dx="1570" dy="1084" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
|
4
|
-
<root>
|
|
5
|
-
<mxCell id="0" />
|
|
6
|
-
<mxCell id="1" parent="0" />
|
|
7
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-37" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=#E6E6E6;" parent="1" vertex="1">
|
|
8
|
-
<mxGeometry x="10" y="240" width="1070" height="790" as="geometry" />
|
|
9
|
-
</mxCell>
|
|
10
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-12" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=#A3A3A3;opacity=50;" parent="1" vertex="1">
|
|
11
|
-
<mxGeometry x="550" y="270" width="480" height="270" as="geometry" />
|
|
12
|
-
</mxCell>
|
|
13
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-11" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=#A3A3A3;opacity=50;" parent="1" vertex="1">
|
|
14
|
-
<mxGeometry x="49.5" y="590" width="980.5" height="140" as="geometry" />
|
|
15
|
-
</mxCell>
|
|
16
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-9" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=#A3A3A3;opacity=50;" parent="1" vertex="1">
|
|
17
|
-
<mxGeometry x="50" y="270" width="480" height="270" as="geometry" />
|
|
18
|
-
</mxCell>
|
|
19
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-3" value="cli" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.command_line_interface;" parent="1" vertex="1">
|
|
20
|
-
<mxGeometry x="80" y="300" width="80" height="80" as="geometry" />
|
|
21
|
-
</mxCell>
|
|
22
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-4" value="schema" style="image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/Image_Definitions.svg;" parent="1" vertex="1">
|
|
23
|
-
<mxGeometry x="230" y="300" width="102.56" height="80" as="geometry" />
|
|
24
|
-
</mxCell>
|
|
25
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-6" value="resource" style="image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/general/Resource_Group_List.svg;" parent="1" vertex="1">
|
|
26
|
-
<mxGeometry x="230" y="429.85" width="81.34" height="80.15" as="geometry" />
|
|
27
|
-
</mxCell>
|
|
28
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-8" value="observibility" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.opensearch_observability;" parent="1" vertex="1">
|
|
29
|
-
<mxGeometry x="580" y="300" width="80" height="80" as="geometry" />
|
|
30
|
-
</mxCell>
|
|
31
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-10" value="state" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.state_manager;fillColor=#759C3E;gradientColor=none;" parent="1" vertex="1">
|
|
32
|
-
<mxGeometry x="90" y="610" width="79.5" height="82.5" as="geometry" />
|
|
33
|
-
</mxCell>
|
|
34
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-13" value="CI/CD" style="image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/Azure_Pipelines.svg;" parent="1" vertex="1">
|
|
35
|
-
<mxGeometry x="720" y="310" width="70" height="70" as="geometry" />
|
|
36
|
-
</mxCell>
|
|
37
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-15" value="localstack" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.toolkit_for_windows_powershell;fillColor=#737373;gradientColor=none;" parent="1" vertex="1">
|
|
38
|
-
<mxGeometry x="400" y="297.5" width="80" height="82.5" as="geometry" />
|
|
39
|
-
</mxCell>
|
|
40
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-16" value="credenticals" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#DD344C;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.identity_and_access_management;" parent="1" vertex="1">
|
|
41
|
-
<mxGeometry x="81" y="429.85" width="78" height="78" as="geometry" />
|
|
42
|
-
</mxCell>
|
|
43
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-17" value="logs" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#E7157B;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.cloudwatch_logs;" parent="1" vertex="1">
|
|
44
|
-
<mxGeometry x="230.00000000000003" y="622.46" width="78" height="58" as="geometry" />
|
|
45
|
-
</mxCell>
|
|
46
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-18" value="metrics" style="image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/management_governance/Metrics.svg;" parent="1" vertex="1">
|
|
47
|
-
<mxGeometry x="370" y="616.25" width="65" height="70.42" as="geometry" />
|
|
48
|
-
</mxCell>
|
|
49
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-19" value="trace" style="sketch=0;html=1;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;align=center;spacingTop=-6;fontSize=11;fontStyle=1;fontColor=#999999;shape=image;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB2aWV3Qm94PSIwIDAgMjAgMjAiPiYjeGE7CTxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+JiN4YTsJLnN0MHtmaWxsOiM0Mjg1ZjQ7fSYjeGE7CS5zdDF7ZmlsbDojNjY5ZGY2O30mI3hhOwk8L3N0eWxlPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMCA4SDEwdjRoMTB6bTAgOEgxMHY0aDEweiIgZmlsbD0iIzQyODVmNCIvPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xMCAxNkg2djRoNHpNMCAwaDZ2NEgwem0wIDhoMTB2NEgweiIgZmlsbD0iIzY2OWRmNiIvPiYjeGE7PC9zdmc+;" parent="1" vertex="1">
|
|
50
|
-
<mxGeometry x="500" y="616.25" width="70" height="70" as="geometry" />
|
|
51
|
-
</mxCell>
|
|
52
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-20" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=#A3A3A3;opacity=50;" parent="1" vertex="1">
|
|
53
|
-
<mxGeometry x="49.5" y="790" width="980.5" height="140" as="geometry" />
|
|
54
|
-
</mxCell>
|
|
55
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-21" value="audit" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#DD344C;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.audit_manager;" parent="1" vertex="1">
|
|
56
|
-
<mxGeometry x="880" y="310" width="78" height="78" as="geometry" />
|
|
57
|
-
</mxCell>
|
|
58
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-22" value="time-series audit" style="image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/iot/Time_Series_Insights_Event_Sources.svg;" parent="1" vertex="1">
|
|
59
|
-
<mxGeometry x="645.61" y="610.75" width="74.39" height="75.5" as="geometry" />
|
|
60
|
-
</mxCell>
|
|
61
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-23" value="org/account manage" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#E7157B;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.organizations_management_account;" parent="1" vertex="1">
|
|
62
|
-
<mxGeometry x="580" y="429.85" width="74" height="78" as="geometry" />
|
|
63
|
-
</mxCell>
|
|
64
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-25" value="dashboard" style="image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/other/Dashboard_Hub.svg;" parent="1" vertex="1">
|
|
65
|
-
<mxGeometry x="712.19" y="439.1" width="79.64" height="60.9" as="geometry" />
|
|
66
|
-
</mxCell>
|
|
67
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-26" value="cost manage" style="sketch=0;html=1;aspect=fixed;strokeColor=none;shadow=0;fillColor=#3B8DF1;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;shape=mxgraph.gcp2.cost_savings" parent="1" vertex="1">
|
|
68
|
-
<mxGeometry x="886" y="427.77000000000004" width="52.85" height="80.08" as="geometry" />
|
|
69
|
-
</mxCell>
|
|
70
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-27" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=https://a0.awsstatic.com/libra-css/images/logos/aws_logo_smile_1200x630.png;" parent="1" vertex="1">
|
|
71
|
-
<mxGeometry x="560" y="817.8" width="185.14" height="97.2" as="geometry" />
|
|
72
|
-
</mxCell>
|
|
73
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-28" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=https://www.vaisulweb.com/wp-content/uploads/2019/02/azure_logo_794_new.png;" parent="1" vertex="1">
|
|
74
|
-
<mxGeometry x="790" y="817.8" width="90" height="90" as="geometry" />
|
|
75
|
-
</mxCell>
|
|
76
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-29" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=https://assets-global.website-files.com/63c6b9bb4a1e0a0f0dc1b957/63c6b9bb4a1e0ae488c1b962_941070.png;" parent="1" vertex="1">
|
|
77
|
-
<mxGeometry x="74.75" y="805" width="110" height="110" as="geometry" />
|
|
78
|
-
</mxCell>
|
|
79
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-35" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/jpeg,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoICAgICQkJCAgLDgoIDQgICQgBAwQEBgUGCAYGCAoICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICP/AABEIAS0CAAMBEQACEQEDEQH/xAAdAAEAAQQDAQAAAAAAAAAAAAAABwECBggDBQkE/8QAVRAAAgIBAgMFBAQHCgkKBwAAAQIAAwQFEQYSIQcIEzFBCSJRYRQycfAYI0JUgZKhFVJicnWCkbG00yQmM3SiwcLR4SU2Q1NVY5Sjs7UWGSdzdpPx/8QAHAEBAAICAwEAAAAAAAAAAAAAAAEHAgYEBQgD/8QAQhEBAAECAwUEBgcIAgIBBQAAAAECEQMEIQUGMUFREmFxkRMigaGx0QcXU8HS4fAUFiMyQlJikjNDJPFyc6KywuL/2gAMAwEAAhEDEQA/APVOAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUJkChaJmI4hzReOFw8SInut4ombcjnkl4OeEnNAqDMbinNMhdAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA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GCNPFddrGj6OPC3Jrbdnuc0q9l7u1llhd2ZmcmBlPbj3c9H4jxhi6viJk1oS1T7tXfQ523ai+srZWW5V5gDyuBswYdIGueieyZ4Xrtra5tSzKKnDV4l+Y5oXbb3WCBWKEDYgFdx0326QJ07Ie6ho2hZ+bqOmY7Y12fXXVdUjAYqV1EGtKKFVVqC7AbL6b77k7wJigVgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUIgNoFYFNoFYCBTaA2gCIDlgVgICBTaAAgVgU2gOWA2gVgIFOWA2gVgU2gIFYFNoFYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB//9k=;clipPath=inset(17.05% 25.67% 20.45% 22.33%);" parent="1" vertex="1">
|
|
80
|
-
<mxGeometry x="390" y="817.8" width="124.99" height="88.13" as="geometry" />
|
|
81
|
-
</mxCell>
|
|
82
|
-
<mxCell id="gF1gTNd6t_6eibbaIrRp-36" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/jpeg,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;" parent="1" vertex="1">
|
|
83
|
-
<mxGeometry x="221.27999999999997" y="801.86" width="120" height="120" as="geometry" />
|
|
84
|
-
</mxCell>
|
|
85
|
-
</root>
|
|
86
|
-
</mxGraphModel>
|
|
87
|
-
</diagram>
|
|
88
|
-
</mxfile>
|
package/docs/index.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
a CI/CD service considerations:
|
|
2
|
-
|
|
3
|
-
- Zero downtime
|
|
4
|
-
|
|
5
|
-
- health check
|
|
6
|
-
|
|
7
|
-
- **Startup probes**
|
|
8
|
-
|
|
9
|
-
- **Readiness probes**
|
|
10
|
-
|
|
11
|
-
- **Liveness probes**
|
|
12
|
-
|
|
13
|
-
> https://www.fairwinds.com/blog/a-guide-to-understanding-kubernetes-liveness-probes-best-practices
|
|
14
|
-
|
|
15
|
-
- Blue/green deployment
|
|
16
|
-
|
|
17
|
-
- canary deployment
|
|
18
|
-
|
|
19
|
-
- service access control(private/public/geo-blocker)
|
|
20
|
-
|
|
21
|
-
- Authentication/autorization
|
|
22
|
-
|
|
23
|
-
- Fast fail and rollback
|
|
24
|
-
|
|
25
|
-
- full stack local setup
|