@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 CHANGED
@@ -1,17 +1,61 @@
1
1
  # ServerlessInsight
2
- [![Node.js CI](https://github.com/geek-fun/hostsless/actions/workflows/node.yml/badge.svg)](https://github.com/geek-fun/hostsless/actions/workflows/node.yml)
2
+
3
+ [![Node.js CI](https://github.com/geek-fun/serverlessinsight/actions/workflows/node.yml/badge.svg)](https://github.com/geek-fun/serverlessinsight/actions/workflows/node.yml)
4
+ [![release](https://github.com/geek-fun/serverlessinsight/actions/workflows/release.yml/badge.svg)](https://github.com/geek-fun/serverlessinsight/actions/workflows/release.yml)
5
+ [![npm version](https://badge.fury.io/js/@geek-fun%2Fserverlessinsight.svg)](https://badge.fury.io/js/@geek-fun%2Fserverlessinsight)
6
+ [![Known Vulnerabilities](https://snyk.io/test/github/geek-fun/serverlessinsight/badge.svg)](https://snyk.io/test/github/geek-fun/serverlessinsight)
7
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
+ [![codecov](https://codecov.io/gh/geek-fun/serverlessinsight/graph/badge.svg?token=ISW7MFuSlf)](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.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=hostsless jest --runInBand --detectOpenHandles --coverage --coverageReporters json-summary text html lcov",
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.3.3"
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 logger_1 = require("../common/logger");
7
- const getVersion_1 = require("../common/getVersion");
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, getVersion_1.getVersion)());
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
- logger_1.logger.debug({ limit, first: options.first, separator: options.separator }, 'log command info');
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,6 @@
1
+ export * from './printer';
2
+ export * from './provider';
3
+ export * from './logger';
4
+ export * from './getVersion';
5
+ export * from './rosClient';
6
+ export * from './actionContext';
@@ -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,2 @@
1
+ export * from './parse';
2
+ export * from './iacSchema';
@@ -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,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deployStack = void 0;
4
+ var deploy_1 = require("./deploy");
5
+ Object.defineProperty(exports, "deployStack", { enumerable: true, get: function () { return deploy_1.deployStack; } });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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.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=hostsless jest --runInBand --detectOpenHandles --coverage --coverageReporters json-summary text html lcov",
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.3.3"
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