underpost 2.8.6 → 2.8.8
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/.vscode/extensions.json +36 -3
- package/.vscode/settings.json +2 -0
- package/CHANGELOG.md +24 -4
- package/Dockerfile +9 -10
- package/README.md +41 -2
- package/bin/build.js +2 -2
- package/bin/db.js +1 -0
- package/bin/deploy.js +1521 -130
- package/bin/file.js +8 -0
- package/bin/index.js +1 -218
- package/cli.md +530 -0
- package/conf.js +4 -0
- package/docker-compose.yml +1 -1
- package/jsdoc.json +1 -1
- package/manifests/deployment/adminer/deployment.yaml +32 -0
- package/manifests/deployment/adminer/kustomization.yaml +7 -0
- package/manifests/deployment/adminer/service.yaml +13 -0
- package/manifests/deployment/dd-template-development/deployment.yaml +167 -0
- package/manifests/deployment/dd-template-development/proxy.yaml +46 -0
- package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
- package/manifests/deployment/fastapi/backend-service.yml +19 -0
- package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
- package/manifests/deployment/fastapi/frontend-service.yml +15 -0
- package/manifests/deployment/fastapi/initial_data.sh +56 -0
- package/manifests/deployment/kafka/deployment.yaml +69 -0
- package/manifests/deployment/spark/spark-pi-py.yaml +21 -0
- package/manifests/envoy-service-nodeport.yaml +23 -0
- package/manifests/kubeadm-calico-config.yaml +119 -0
- package/manifests/kubelet-config.yaml +65 -0
- package/manifests/lxd/lxd-admin-profile.yaml +17 -0
- package/manifests/lxd/lxd-preseed.yaml +30 -0
- package/manifests/lxd/underpost-setup.sh +163 -0
- package/manifests/maas/lxd-preseed.yaml +32 -0
- package/manifests/maas/maas-setup.sh +82 -0
- package/manifests/mariadb/statefulset.yaml +2 -1
- package/manifests/mariadb/storage-class.yaml +10 -0
- package/manifests/mongodb/kustomization.yaml +1 -1
- package/manifests/mongodb/statefulset.yaml +12 -11
- package/manifests/mongodb/storage-class.yaml +9 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +3 -3
- package/manifests/mysql/kustomization.yaml +7 -0
- package/manifests/mysql/pv-pvc.yaml +27 -0
- package/manifests/mysql/statefulset.yaml +55 -0
- package/manifests/postgresql/configmap.yaml +9 -0
- package/manifests/postgresql/kustomization.yaml +10 -0
- package/manifests/postgresql/pv.yaml +15 -0
- package/manifests/postgresql/pvc.yaml +13 -0
- package/manifests/postgresql/service.yaml +10 -0
- package/manifests/postgresql/statefulset.yaml +37 -0
- package/manifests/valkey/service.yaml +3 -9
- package/manifests/valkey/statefulset.yaml +12 -13
- package/package.json +3 -9
- package/src/api/default/default.service.js +1 -1
- package/src/api/user/user.service.js +14 -11
- package/src/cli/baremetal.js +60 -0
- package/src/cli/cluster.js +551 -65
- package/src/cli/cron.js +39 -8
- package/src/cli/db.js +20 -10
- package/src/cli/deploy.js +288 -86
- package/src/cli/env.js +10 -4
- package/src/cli/fs.js +21 -9
- package/src/cli/image.js +116 -124
- package/src/cli/index.js +319 -0
- package/src/cli/lxd.js +395 -0
- package/src/cli/monitor.js +236 -0
- package/src/cli/repository.js +14 -8
- package/src/client/components/core/Account.js +28 -24
- package/src/client/components/core/Blockchain.js +1 -1
- package/src/client/components/core/CalendarCore.js +14 -84
- package/src/client/components/core/CommonJs.js +2 -1
- package/src/client/components/core/Css.js +0 -1
- package/src/client/components/core/CssCore.js +10 -2
- package/src/client/components/core/Docs.js +1 -1
- package/src/client/components/core/EventsUI.js +3 -3
- package/src/client/components/core/FileExplorer.js +86 -78
- package/src/client/components/core/JoyStick.js +2 -2
- package/src/client/components/core/LoadingAnimation.js +1 -17
- package/src/client/components/core/LogIn.js +3 -3
- package/src/client/components/core/LogOut.js +1 -1
- package/src/client/components/core/Modal.js +14 -8
- package/src/client/components/core/Panel.js +19 -61
- package/src/client/components/core/PanelForm.js +13 -22
- package/src/client/components/core/Recover.js +3 -3
- package/src/client/components/core/RichText.js +1 -11
- package/src/client/components/core/Router.js +3 -1
- package/src/client/components/core/SignUp.js +2 -2
- package/src/client/components/default/RoutesDefault.js +3 -2
- package/src/client/services/default/default.management.js +45 -38
- package/src/client/ssr/Render.js +2 -0
- package/src/index.js +34 -2
- package/src/mailer/MailerProvider.js +3 -0
- package/src/runtime/lampp/Dockerfile +65 -0
- package/src/server/client-build.js +13 -0
- package/src/server/conf.js +151 -1
- package/src/server/dns.js +56 -18
- package/src/server/json-schema.js +77 -0
- package/src/server/logger.js +3 -3
- package/src/server/network.js +7 -122
- package/src/server/peer.js +2 -2
- package/src/server/proxy.js +4 -4
- package/src/server/runtime.js +24 -11
- package/src/server/start.js +122 -0
- package/src/server/valkey.js +27 -13
package/src/cli/cron.js
CHANGED
|
@@ -4,20 +4,24 @@
|
|
|
4
4
|
* @namespace UnderpostCron
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
8
8
|
import BackUp from '../server/backup.js';
|
|
9
9
|
import { Cmd } from '../server/conf.js';
|
|
10
10
|
import Dns from '../server/dns.js';
|
|
11
|
-
import {
|
|
11
|
+
import { loggerFactory } from '../server/logger.js';
|
|
12
|
+
|
|
12
13
|
import { shellExec } from '../server/process.js';
|
|
13
14
|
import fs from 'fs-extra';
|
|
14
15
|
|
|
16
|
+
const logger = loggerFactory(import.meta);
|
|
17
|
+
|
|
15
18
|
/**
|
|
16
19
|
* UnderpostCron main module methods
|
|
17
20
|
* @class
|
|
18
21
|
* @memberof UnderpostCron
|
|
19
22
|
*/
|
|
20
23
|
class UnderpostCron {
|
|
24
|
+
static NETWORK = [];
|
|
21
25
|
static JOB = {
|
|
22
26
|
/**
|
|
23
27
|
* DNS cli API
|
|
@@ -46,10 +50,10 @@ class UnderpostCron {
|
|
|
46
50
|
callback: async function (
|
|
47
51
|
deployList = 'default',
|
|
48
52
|
jobList = Object.keys(UnderpostCron.JOB),
|
|
49
|
-
options = { itc: false, init: false, git: false },
|
|
53
|
+
options = { itc: false, init: false, git: false, dashboardUpdate: false },
|
|
50
54
|
) {
|
|
51
55
|
if (options.init === true) {
|
|
52
|
-
|
|
56
|
+
UnderpostCron.NETWORK = [];
|
|
53
57
|
const jobDeployId = fs.readFileSync('./engine-private/deploy/dd.cron', 'utf8').trim();
|
|
54
58
|
deployList = fs.readFileSync('./engine-private/deploy/dd.router', 'utf8').trim();
|
|
55
59
|
const confCronConfig = JSON.parse(fs.readFileSync(`./engine-private/conf/${jobDeployId}/conf.cron.json`));
|
|
@@ -57,7 +61,7 @@ class UnderpostCron {
|
|
|
57
61
|
for (const job of Object.keys(confCronConfig.jobs)) {
|
|
58
62
|
const name = `${jobDeployId}-${job}`;
|
|
59
63
|
let deployId;
|
|
60
|
-
shellExec(Cmd.delete(name));
|
|
64
|
+
if (!options.dashboardUpdate) shellExec(Cmd.delete(name));
|
|
61
65
|
switch (job) {
|
|
62
66
|
case 'dns':
|
|
63
67
|
deployId = jobDeployId;
|
|
@@ -67,15 +71,16 @@ class UnderpostCron {
|
|
|
67
71
|
deployId = deployList;
|
|
68
72
|
break;
|
|
69
73
|
}
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
if (!options.dashboardUpdate)
|
|
75
|
+
shellExec(Cmd.cron(deployId, job, name, confCronConfig.jobs[job].expression, options));
|
|
76
|
+
UnderpostCron.NETWORK.push({
|
|
72
77
|
deployId,
|
|
73
78
|
jobId: job,
|
|
74
79
|
expression: confCronConfig.jobs[job].expression,
|
|
75
80
|
});
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
|
-
await
|
|
83
|
+
if (options.dashboardUpdate === true) await UnderpostCron.API.updateDashboardData();
|
|
79
84
|
if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
|
|
80
85
|
return;
|
|
81
86
|
}
|
|
@@ -84,6 +89,32 @@ class UnderpostCron {
|
|
|
84
89
|
if (UnderpostCron.JOB[jobId]) await UnderpostCron.JOB[jobId].callback(deployList, options);
|
|
85
90
|
}
|
|
86
91
|
},
|
|
92
|
+
async updateDashboardData() {
|
|
93
|
+
try {
|
|
94
|
+
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
95
|
+
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
96
|
+
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
97
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
98
|
+
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
99
|
+
const { db } = confServer[host][path];
|
|
100
|
+
|
|
101
|
+
await DataBaseProvider.load({ apis: ['cron'], host, path, db });
|
|
102
|
+
|
|
103
|
+
/** @type {import('../api/cron/cron.model.js').CronModel} */
|
|
104
|
+
const Cron = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Cron;
|
|
105
|
+
|
|
106
|
+
await Cron.deleteMany();
|
|
107
|
+
|
|
108
|
+
for (const cronInstance of UnderpostCron.NETWORK) {
|
|
109
|
+
logger.info('save', cronInstance);
|
|
110
|
+
await new Cron(cronInstance).save();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
logger.error(error, error.stack);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
87
118
|
};
|
|
88
119
|
}
|
|
89
120
|
|
package/src/cli/db.js
CHANGED
|
@@ -15,11 +15,13 @@ class UnderpostDB {
|
|
|
15
15
|
export: false,
|
|
16
16
|
podName: false,
|
|
17
17
|
ns: false,
|
|
18
|
-
|
|
18
|
+
collections: '',
|
|
19
19
|
outPath: '',
|
|
20
20
|
drop: false,
|
|
21
21
|
preserveUUID: false,
|
|
22
22
|
git: false,
|
|
23
|
+
hosts: '',
|
|
24
|
+
paths: '',
|
|
23
25
|
},
|
|
24
26
|
) {
|
|
25
27
|
const newBackupTimestamp = new Date().getTime();
|
|
@@ -39,20 +41,28 @@ class UnderpostDB {
|
|
|
39
41
|
if (!dbs[provider]) dbs[provider] = {};
|
|
40
42
|
|
|
41
43
|
if (!(name in dbs[provider]))
|
|
42
|
-
dbs[provider][name] = { user, password, hostFolder: host + path.replaceAll('/', '-') };
|
|
44
|
+
dbs[provider][name] = { user, password, hostFolder: host + path.replaceAll('/', '-'), host, path };
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
if (options.git === true) {
|
|
50
|
+
if (!fs.existsSync(`../${repoName}`)) {
|
|
51
|
+
shellExec(`cd .. && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}`);
|
|
52
|
+
} else {
|
|
53
|
+
shellExec(`cd ../${repoName} && git checkout . && git clean -f -d`);
|
|
54
|
+
shellExec(`cd ../${repoName} && underpost pull . ${process.env.GITHUB_USERNAME}/${repoName}`);
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
for (const provider of Object.keys(dbs)) {
|
|
54
59
|
for (const dbName of Object.keys(dbs[provider])) {
|
|
55
|
-
const { hostFolder, user, password } = dbs[provider][dbName];
|
|
60
|
+
const { hostFolder, user, password, host, path } = dbs[provider][dbName];
|
|
61
|
+
if (
|
|
62
|
+
(options.hosts && !options.hosts.split(',').includes(host)) ||
|
|
63
|
+
(options.paths && !options.paths.split(',').includes(path))
|
|
64
|
+
)
|
|
65
|
+
continue;
|
|
56
66
|
if (hostFolder) {
|
|
57
67
|
logger.info('', { hostFolder, provider, dbName });
|
|
58
68
|
|
|
@@ -153,11 +163,11 @@ class UnderpostDB {
|
|
|
153
163
|
const podName = podNameData.NAME;
|
|
154
164
|
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "rm -rf /${dbName}"`);
|
|
155
165
|
if (options.collections)
|
|
156
|
-
for (const collection of options.collections)
|
|
166
|
+
for (const collection of options.collections.split(','))
|
|
157
167
|
shellExec(
|
|
158
|
-
`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} --collection ${collection} -o
|
|
168
|
+
`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} --collection ${collection} -o /"`,
|
|
159
169
|
);
|
|
160
|
-
else shellExec(`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} -o
|
|
170
|
+
else shellExec(`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} -o /"`);
|
|
161
171
|
shellExec(
|
|
162
172
|
`sudo kubectl cp ${nameSpace}/${podName}:/${dbName} ${
|
|
163
173
|
options.outPath ? options.outPath : _toNewBsonPath
|
package/src/cli/deploy.js
CHANGED
|
@@ -3,22 +3,42 @@ import {
|
|
|
3
3
|
buildPortProxyRouter,
|
|
4
4
|
buildProxyRouter,
|
|
5
5
|
Config,
|
|
6
|
+
deployRangePortFactory,
|
|
6
7
|
getDataDeploy,
|
|
7
8
|
loadReplicas,
|
|
9
|
+
pathPortAssignmentFactory,
|
|
8
10
|
} from '../server/conf.js';
|
|
9
11
|
import { loggerFactory } from '../server/logger.js';
|
|
10
12
|
import { shellExec } from '../server/process.js';
|
|
11
13
|
import fs from 'fs-extra';
|
|
12
14
|
import dotenv from 'dotenv';
|
|
15
|
+
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
16
|
+
import UnderpostRootEnv from './env.js';
|
|
17
|
+
import UnderpostCluster from './cluster.js';
|
|
13
18
|
import Underpost from '../index.js';
|
|
14
19
|
|
|
15
20
|
const logger = loggerFactory(import.meta);
|
|
16
21
|
|
|
17
22
|
class UnderpostDeploy {
|
|
23
|
+
static NETWORK = {};
|
|
18
24
|
static API = {
|
|
19
|
-
sync(deployList) {
|
|
20
|
-
const deployGroupId = 'dd.
|
|
25
|
+
sync(deployList, { versions, replicas, kubeadm = false }) {
|
|
26
|
+
const deployGroupId = 'dd.router';
|
|
21
27
|
fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
|
|
28
|
+
const totalPods = deployList.split(',').length * versions.split(',').length * parseInt(replicas);
|
|
29
|
+
const limitFactor = 0.8;
|
|
30
|
+
const reserveFactor = 0.05;
|
|
31
|
+
const resources = UnderpostCluster.API.getResourcesCapacity(kubeadm);
|
|
32
|
+
const memory = parseInt(resources.memory.value / totalPods);
|
|
33
|
+
const cpu = parseInt(resources.cpu.value / totalPods);
|
|
34
|
+
UnderpostRootEnv.API.set(
|
|
35
|
+
'resources.requests.memory',
|
|
36
|
+
`${parseInt(memory * reserveFactor)}${resources.memory.unit}`,
|
|
37
|
+
);
|
|
38
|
+
UnderpostRootEnv.API.set('resources.requests.cpu', `${parseInt(cpu * reserveFactor)}${resources.cpu.unit}`);
|
|
39
|
+
UnderpostRootEnv.API.set('resources.limits.memory', `${parseInt(memory * limitFactor)}${resources.memory.unit}`);
|
|
40
|
+
UnderpostRootEnv.API.set('resources.limits.cpu', `${parseInt(cpu * limitFactor)}${resources.cpu.unit}`);
|
|
41
|
+
UnderpostRootEnv.API.set('total-pods', totalPods);
|
|
22
42
|
return getDataDeploy({
|
|
23
43
|
buildSingleReplica: true,
|
|
24
44
|
deployGroupId,
|
|
@@ -32,75 +52,102 @@ class UnderpostDeploy {
|
|
|
32
52
|
await Config.build(undefined, 'proxy', deployList);
|
|
33
53
|
return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
|
|
34
54
|
},
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
fs.mkdirSync(`./engine-private/conf/${deployId}/build/${env}`, { recursive: true });
|
|
50
|
-
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
51
|
-
|
|
52
|
-
logger.info('port range', { deployId, fromPort, toPort });
|
|
53
|
-
|
|
54
|
-
const deploymentYamlParts = `apiVersion: apps/v1
|
|
55
|
+
deploymentYamlServiceFactory({ deployId, env, port, deploymentVersions }) {
|
|
56
|
+
return deploymentVersions
|
|
57
|
+
.map(
|
|
58
|
+
(version, i) => ` - name: ${deployId}-${env}-${version}-service
|
|
59
|
+
port: ${port}
|
|
60
|
+
weight: ${i === 0 ? 100 : 0}
|
|
61
|
+
`,
|
|
62
|
+
)
|
|
63
|
+
.join('');
|
|
64
|
+
},
|
|
65
|
+
deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas }) {
|
|
66
|
+
return `apiVersion: apps/v1
|
|
55
67
|
kind: Deployment
|
|
56
68
|
metadata:
|
|
57
|
-
name: ${deployId}-${env}
|
|
69
|
+
name: ${deployId}-${env}-${suffix}
|
|
58
70
|
labels:
|
|
59
|
-
app: ${deployId}-${env}
|
|
71
|
+
app: ${deployId}-${env}-${suffix}
|
|
60
72
|
spec:
|
|
61
|
-
replicas:
|
|
73
|
+
replicas: ${replicas}
|
|
62
74
|
selector:
|
|
63
75
|
matchLabels:
|
|
64
|
-
app: ${deployId}-${env}
|
|
76
|
+
app: ${deployId}-${env}-${suffix}
|
|
65
77
|
template:
|
|
66
78
|
metadata:
|
|
67
79
|
labels:
|
|
68
|
-
app: ${deployId}-${env}
|
|
80
|
+
app: ${deployId}-${env}-${suffix}
|
|
69
81
|
spec:
|
|
70
82
|
containers:
|
|
71
|
-
- name: ${deployId}-${env}
|
|
72
|
-
image: localhost/underpost
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
- name: ${deployId}-${env}-${suffix}
|
|
84
|
+
image: localhost/debian-underpost:${Underpost.version}
|
|
85
|
+
# resources:
|
|
86
|
+
# requests:
|
|
87
|
+
# memory: "${resources.requests.memory}"
|
|
88
|
+
# cpu: "${resources.requests.cpu}"
|
|
89
|
+
# limits:
|
|
90
|
+
# memory: "${resources.limits.memory}"
|
|
91
|
+
# cpu: "${resources.limits.cpu}"
|
|
92
|
+
command:
|
|
93
|
+
- /bin/sh
|
|
94
|
+
- -c
|
|
95
|
+
- >
|
|
96
|
+
npm install -g npm@11.2.0 &&
|
|
97
|
+
npm install -g underpost &&
|
|
98
|
+
underpost secret underpost --create-from-file /etc/config/.env.${env} &&
|
|
99
|
+
underpost start --build --run ${deployId} ${env}
|
|
100
|
+
volumeMounts:
|
|
101
|
+
- name: config-volume
|
|
102
|
+
mountPath: /etc/config
|
|
103
|
+
volumes:
|
|
104
|
+
- name: config-volume
|
|
105
|
+
configMap:
|
|
106
|
+
name: underpost-config
|
|
84
107
|
---
|
|
85
108
|
apiVersion: v1
|
|
86
109
|
kind: Service
|
|
87
110
|
metadata:
|
|
88
|
-
name: ${deployId}-${env}-service
|
|
111
|
+
name: ${deployId}-${env}-${suffix}-service
|
|
89
112
|
spec:
|
|
90
113
|
selector:
|
|
91
|
-
app: ${deployId}-${env}
|
|
114
|
+
app: ${deployId}-${env}-${suffix}
|
|
92
115
|
ports:
|
|
93
|
-
type: LoadBalancer
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
{{ports}} type: LoadBalancer`;
|
|
117
|
+
},
|
|
118
|
+
async buildManifest(deployList, env, options) {
|
|
119
|
+
const resources = UnderpostDeploy.API.resourcesFactory();
|
|
120
|
+
const replicas = options.replicas;
|
|
98
121
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
122
|
+
for (const _deployId of deployList.split(',')) {
|
|
123
|
+
const deployId = _deployId.trim();
|
|
124
|
+
if (!deployId) continue;
|
|
125
|
+
const confServer = loadReplicas(
|
|
126
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
127
|
+
'proxy',
|
|
103
128
|
);
|
|
129
|
+
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
130
|
+
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
131
|
+
const { fromPort, toPort } = deployRangePortFactory(router);
|
|
132
|
+
const deploymentVersions = options.versions.split(',');
|
|
133
|
+
fs.mkdirSync(`./engine-private/conf/${deployId}/build/${env}`, { recursive: true });
|
|
134
|
+
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
135
|
+
|
|
136
|
+
logger.info('port range', { deployId, fromPort, toPort });
|
|
137
|
+
|
|
138
|
+
let deploymentYamlParts = '';
|
|
139
|
+
for (const deploymentVersion of deploymentVersions) {
|
|
140
|
+
deploymentYamlParts += `---
|
|
141
|
+
${UnderpostDeploy.API.deploymentYamlPartsFactory({
|
|
142
|
+
deployId,
|
|
143
|
+
env,
|
|
144
|
+
suffix: deploymentVersion,
|
|
145
|
+
resources,
|
|
146
|
+
replicas,
|
|
147
|
+
}).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
|
|
148
|
+
`;
|
|
149
|
+
}
|
|
150
|
+
fs.writeFileSync(`./engine-private/conf/${deployId}/build/${env}/deployment.yaml`, deploymentYamlParts, 'utf8');
|
|
104
151
|
|
|
105
152
|
let proxyYaml = '';
|
|
106
153
|
let secretYaml = '';
|
|
@@ -122,27 +169,8 @@ spec:
|
|
|
122
169
|
kind: ClusterIssuer
|
|
123
170
|
secretName: ${host}`;
|
|
124
171
|
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
const { peer } = confServer[host][path];
|
|
128
|
-
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
129
|
-
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
130
|
-
// logger.info('', { host, port, path });
|
|
131
|
-
pathPortConditions.push({
|
|
132
|
-
port,
|
|
133
|
-
path,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
if (peer) {
|
|
137
|
-
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
138
|
-
pathPortConditions.push({
|
|
139
|
-
port: port + 1,
|
|
140
|
-
path: '/peer',
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// logger.info('', { host, pathPortConditions });
|
|
172
|
+
const pathPortAssignment = pathPortAssignmentData[host];
|
|
173
|
+
// logger.info('', { host, pathPortAssignment });
|
|
146
174
|
proxyYaml += `
|
|
147
175
|
---
|
|
148
176
|
apiVersion: projectcontour.io/v1
|
|
@@ -159,15 +187,20 @@ spec:
|
|
|
159
187
|
secretName: ${host}`
|
|
160
188
|
}
|
|
161
189
|
routes:`;
|
|
162
|
-
for (const conditionObj of
|
|
190
|
+
for (const conditionObj of pathPortAssignment) {
|
|
163
191
|
const { path, port } = conditionObj;
|
|
164
192
|
proxyYaml += `
|
|
165
193
|
- conditions:
|
|
166
194
|
- prefix: ${path}
|
|
167
195
|
enableWebsockets: true
|
|
168
196
|
services:
|
|
169
|
-
|
|
170
|
-
|
|
197
|
+
${UnderpostDeploy.API.deploymentYamlServiceFactory({
|
|
198
|
+
deployId,
|
|
199
|
+
env,
|
|
200
|
+
port,
|
|
201
|
+
deploymentVersions:
|
|
202
|
+
options.traffic && typeof options.traffic === 'string' ? options.traffic.split(',') : ['blue'],
|
|
203
|
+
})}`;
|
|
171
204
|
}
|
|
172
205
|
}
|
|
173
206
|
const yamlPath = `./engine-private/conf/${deployId}/build/${env}/proxy.yaml`;
|
|
@@ -188,6 +221,14 @@ spec:
|
|
|
188
221
|
}
|
|
189
222
|
}
|
|
190
223
|
},
|
|
224
|
+
getCurrentTraffic(deployId) {
|
|
225
|
+
// kubectl get deploy,sts,svc,configmap,secret -n default -o yaml --export > default.yaml
|
|
226
|
+
const hostTest = Object.keys(
|
|
227
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
228
|
+
)[0];
|
|
229
|
+
const info = shellExec(`sudo kubectl get HTTPProxy/${hostTest} -o yaml`, { silent: true, stdout: true });
|
|
230
|
+
return info.match('blue') ? 'blue' : info.match('green') ? 'green' : null;
|
|
231
|
+
},
|
|
191
232
|
async callback(
|
|
192
233
|
deployList = 'default',
|
|
193
234
|
env = 'development',
|
|
@@ -199,7 +240,14 @@ spec:
|
|
|
199
240
|
infoUtil: false,
|
|
200
241
|
expose: false,
|
|
201
242
|
cert: false,
|
|
202
|
-
|
|
243
|
+
versions: '',
|
|
244
|
+
traffic: '',
|
|
245
|
+
dashboardUpdate: false,
|
|
246
|
+
replicas: '',
|
|
247
|
+
restoreHosts: false,
|
|
248
|
+
disableUpdateDeployment: false,
|
|
249
|
+
infoTraffic: false,
|
|
250
|
+
rebuildClientsBundle: false,
|
|
203
251
|
},
|
|
204
252
|
) {
|
|
205
253
|
if (options.infoUtil === true)
|
|
@@ -207,18 +255,85 @@ spec:
|
|
|
207
255
|
kubectl rollout restart deployment/deployment-name
|
|
208
256
|
kubectl rollout undo deployment/deployment-name
|
|
209
257
|
kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
210
|
-
|
|
258
|
+
kubectl get pods -w
|
|
259
|
+
kubectl patch statefulset valkey-service --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"valkey/valkey:latest"}]'
|
|
260
|
+
kubectl patch statefulset valkey-service -p '{"spec":{"template":{"spec":{"containers":[{"name":"valkey-service","imagePullPolicy":"Never"}]}}}}'
|
|
261
|
+
kubectl logs -f <pod-name>
|
|
262
|
+
kubectl describe pod <pod-name>
|
|
263
|
+
kubectl exec -it <pod-name> -- bash
|
|
264
|
+
kubectl exec -it <pod-name> -- sh
|
|
265
|
+
docker exec -it kind-control-plane bash
|
|
266
|
+
curl -4 -v google.com
|
|
267
|
+
kubectl taint nodes <node-name> node-role.kubernetes.io/control-plane:NoSchedule-
|
|
268
|
+
kubectl run test-pod --image=busybox:latest --restart=Never -- /bin/sh -c "while true; do sleep 30; done;"
|
|
269
|
+
kubectl run test-pod --image=alpine/curl:latest --restart=Never -- sh -c "sleep infinity"
|
|
270
|
+
kubectl get ippools -o yaml
|
|
271
|
+
kubectl get node <node-name> -o jsonpath='{.spec.podCIDR}'
|
|
272
|
+
kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "10.244.0.0/16"}]'
|
|
273
|
+
kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "192.168.0.0/24"}]'
|
|
274
|
+
sudo podman run --rm localhost/<image-name>:<image-version> <command>
|
|
275
|
+
kubectl get configmap kubelet-config -n kube-system -o yaml > kubelet-config.yaml
|
|
276
|
+
kubectl -n kube-system rollout restart daemonset kube-proxy
|
|
277
|
+
kubectl get EndpointSlice -o wide --all-namespaces -w
|
|
278
|
+
kubectl apply -k manifests/deployment/adminer/.
|
|
279
|
+
kubectl wait --for=condition=Ready pod/busybox1
|
|
280
|
+
kubectl wait --for=jsonpath='{.status.phase}'=Running pod/busybox1
|
|
281
|
+
kubectl wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' pod/busybox1
|
|
282
|
+
kubectl wait --for=delete pod/busybox1 --timeout=60s
|
|
283
|
+
|
|
284
|
+
kubectl run --rm -it test-dns --image=busybox:latest --restart=Never -- /bin/sh -c "
|
|
285
|
+
nslookup kubernetes.default.svc.cluster.local;
|
|
286
|
+
nslookup mongodb-service.default.svc.cluster.local;
|
|
287
|
+
nslookup valkey-service.default.svc.cluster.local;
|
|
288
|
+
nc -vz mongodb-service 27017;
|
|
289
|
+
nc -vz valkey-service 6379;
|
|
290
|
+
echo exit code: \\\$?
|
|
291
|
+
"
|
|
292
|
+
|
|
293
|
+
kubectl apply -f - <<EOF
|
|
294
|
+
apiVersion: apps/v1
|
|
295
|
+
kind: StatefulSet
|
|
296
|
+
metadata:
|
|
297
|
+
name: ...
|
|
298
|
+
EOF
|
|
299
|
+
`);
|
|
211
300
|
if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
212
301
|
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
213
|
-
if (options.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
302
|
+
if (options.infoTraffic === true) {
|
|
303
|
+
for (const _deployId of deployList.split(',')) {
|
|
304
|
+
const deployId = _deployId.trim();
|
|
305
|
+
logger.info('', {
|
|
306
|
+
deployId,
|
|
307
|
+
env,
|
|
308
|
+
traffic: UnderpostDeploy.API.getCurrentTraffic(deployId),
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (options.rebuildClientsBundle === true) await UnderpostDeploy.API.rebuildClientsBundle(deployList);
|
|
314
|
+
if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
|
|
315
|
+
if (!options.replicas) options.replicas = 1;
|
|
316
|
+
if (options.sync) UnderpostDeploy.API.sync(deployList, options);
|
|
317
|
+
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
|
|
318
|
+
if (options.infoRouter === true) logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
319
|
+
if (options.dashboardUpdate === true) await UnderpostDeploy.API.updateDashboardData(deployList, env, options);
|
|
320
|
+
if (options.infoRouter === true) return;
|
|
321
|
+
shellExec(`kubectl delete configmap underpost-config`);
|
|
322
|
+
shellExec(
|
|
323
|
+
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
324
|
+
);
|
|
325
|
+
let renderHosts = '';
|
|
326
|
+
let concatHots = '';
|
|
217
327
|
const etcHost = (
|
|
218
328
|
concat,
|
|
219
329
|
) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
220
330
|
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
221
|
-
|
|
331
|
+
if (options.restoreHosts === true) {
|
|
332
|
+
renderHosts = etcHost(concatHots);
|
|
333
|
+
fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
334
|
+
logger.info(renderHosts);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
222
337
|
|
|
223
338
|
for (const _deployId of deployList.split(',')) {
|
|
224
339
|
const deployId = _deployId.trim();
|
|
@@ -233,8 +348,12 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
233
348
|
shellExec(`sudo kubectl port-forward -n default svc/${svc.NAME} ${port}:${port}`, { async: true });
|
|
234
349
|
continue;
|
|
235
350
|
}
|
|
236
|
-
|
|
237
|
-
|
|
351
|
+
|
|
352
|
+
if (!options.disableUpdateDeployment)
|
|
353
|
+
for (const version of options.versions.split(',')) {
|
|
354
|
+
shellExec(`sudo kubectl delete svc ${deployId}-${env}-${version}-service`);
|
|
355
|
+
shellExec(`sudo kubectl delete deployment ${deployId}-${env}-${version}`);
|
|
356
|
+
}
|
|
238
357
|
|
|
239
358
|
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
240
359
|
for (const host of Object.keys(confServer)) {
|
|
@@ -249,13 +368,12 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
249
368
|
: `manifests/deployment/${deployId}-${env}`;
|
|
250
369
|
|
|
251
370
|
if (!options.remove === true) {
|
|
252
|
-
shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
|
|
371
|
+
if (!options.disableUpdateDeployment) shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
|
|
253
372
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
|
|
254
373
|
if (env === 'production' && options.cert === true)
|
|
255
374
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
256
375
|
}
|
|
257
376
|
}
|
|
258
|
-
let renderHosts;
|
|
259
377
|
switch (process.platform) {
|
|
260
378
|
case 'linux':
|
|
261
379
|
{
|
|
@@ -312,6 +430,90 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
312
430
|
|
|
313
431
|
return result;
|
|
314
432
|
},
|
|
433
|
+
rebuildClientsBundle(deployList) {
|
|
434
|
+
for (const _deployId of deployList.split(',')) {
|
|
435
|
+
const deployId = _deployId.trim();
|
|
436
|
+
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
437
|
+
|
|
438
|
+
shellExec(`underpost script set ${deployId}-client-build '
|
|
439
|
+
cd /home/dd/engine &&
|
|
440
|
+
git checkout . &&
|
|
441
|
+
underpost pull . underpostnet/${repoName} &&
|
|
442
|
+
underpost pull ./engine-private underpostnet/${repoName}-private &&
|
|
443
|
+
underpost env ${deployId} production &&
|
|
444
|
+
node bin/deploy build-full-client ${deployId}
|
|
445
|
+
'`);
|
|
446
|
+
|
|
447
|
+
shellExec(`node bin script run ${deployId}-client-build --itc --pod-name ${deployId}`);
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
resourcesFactory() {
|
|
451
|
+
return {
|
|
452
|
+
requests: {
|
|
453
|
+
memory: UnderpostRootEnv.API.get('resources.requests.memory'),
|
|
454
|
+
cpu: UnderpostRootEnv.API.get('resources.requests.cpu'),
|
|
455
|
+
},
|
|
456
|
+
limits: {
|
|
457
|
+
memory: UnderpostRootEnv.API.get('resources.limits.memory'),
|
|
458
|
+
cpu: UnderpostRootEnv.API.get('resources.limits.cpu'),
|
|
459
|
+
},
|
|
460
|
+
totalPods: UnderpostRootEnv.API.get('total-pods'),
|
|
461
|
+
};
|
|
462
|
+
},
|
|
463
|
+
async updateDashboardData(deployList, env, options) {
|
|
464
|
+
try {
|
|
465
|
+
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
466
|
+
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
467
|
+
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
468
|
+
const { db } = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'))[host][
|
|
469
|
+
path
|
|
470
|
+
];
|
|
471
|
+
|
|
472
|
+
await DataBaseProvider.load({ apis: ['instance'], host, path, db });
|
|
473
|
+
|
|
474
|
+
/** @type {import('../api/instance/instance.model.js').InstanceModel} */
|
|
475
|
+
const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
|
|
476
|
+
|
|
477
|
+
await Instance.deleteMany();
|
|
478
|
+
|
|
479
|
+
for (const _deployId of deployList.split(',')) {
|
|
480
|
+
const deployId = _deployId.trim();
|
|
481
|
+
if (!deployId) continue;
|
|
482
|
+
const confServer = loadReplicas(
|
|
483
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
484
|
+
'proxy',
|
|
485
|
+
);
|
|
486
|
+
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
487
|
+
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
488
|
+
|
|
489
|
+
for (const host of Object.keys(confServer)) {
|
|
490
|
+
for (const { path, port } of pathPortAssignmentData[host]) {
|
|
491
|
+
if (!confServer[host][path]) continue;
|
|
492
|
+
|
|
493
|
+
const { client, runtime, apis } = confServer[host][path];
|
|
494
|
+
|
|
495
|
+
const body = {
|
|
496
|
+
deployId,
|
|
497
|
+
host,
|
|
498
|
+
path,
|
|
499
|
+
port,
|
|
500
|
+
client,
|
|
501
|
+
runtime,
|
|
502
|
+
apis,
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
logger.info('save', body);
|
|
506
|
+
|
|
507
|
+
await new Instance(body).save();
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
513
|
+
} catch (error) {
|
|
514
|
+
logger.error(error, error.stack);
|
|
515
|
+
}
|
|
516
|
+
},
|
|
315
517
|
};
|
|
316
518
|
}
|
|
317
519
|
|