underpost 2.8.64 → 2.8.65
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/bin/deploy.js +39 -1
- package/bin/index.js +18 -11
- package/docker-compose.yml +1 -1
- package/package.json +2 -9
- package/src/api/user/user.service.js +13 -10
- package/src/cli/cluster.js +45 -2
- package/src/cli/db.js +18 -8
- package/src/cli/deploy.js +105 -53
- package/src/cli/image.js +0 -68
- package/src/cli/monitor.js +101 -11
- package/src/cli/repository.js +5 -2
- package/src/client/components/core/Account.js +3 -3
- package/src/client/components/core/CalendarCore.js +0 -1
- package/src/client/components/core/Css.js +0 -1
- package/src/client/components/core/CssCore.js +2 -0
- package/src/client/components/core/EventsUI.js +1 -1
- package/src/client/components/core/RichText.js +1 -11
- package/src/index.js +9 -8
- package/src/mailer/MailerProvider.js +3 -0
- package/src/server/conf.js +44 -0
- package/src/server/json-schema.js +77 -0
- package/src/server/peer.js +2 -2
- package/src/server/proxy.js +4 -4
- package/src/server/runtime.js +22 -9
- package/src/server/start.js +123 -0
- package/src/server/valkey.js +25 -11
package/bin/deploy.js
CHANGED
|
@@ -33,8 +33,9 @@ import { MongooseDB } from '../src/db/mongo/MongooseDB.js';
|
|
|
33
33
|
import { Lampp } from '../src/runtime/lampp/Lampp.js';
|
|
34
34
|
import { DefaultConf } from '../conf.js';
|
|
35
35
|
import { JSONweb } from '../src/server/client-formatted.js';
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
import { Xampp } from '../src/runtime/xampp/Xampp.js';
|
|
38
|
+
import { ejs } from '../src/server/json-schema.js';
|
|
38
39
|
|
|
39
40
|
const logger = loggerFactory(import.meta);
|
|
40
41
|
|
|
@@ -1048,6 +1049,43 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
|
|
|
1048
1049
|
break;
|
|
1049
1050
|
}
|
|
1050
1051
|
|
|
1052
|
+
case 'update-instances': {
|
|
1053
|
+
shellExec(`node bin deploy dd production --sync --build-manifest --info-router --dashboard-update`);
|
|
1054
|
+
shellExec(`node bin cron --dashboard-update --init`);
|
|
1055
|
+
const deployId = 'dd-core';
|
|
1056
|
+
const host = 'www.nexodev.org';
|
|
1057
|
+
const path = '/';
|
|
1058
|
+
|
|
1059
|
+
{
|
|
1060
|
+
const outputPath = './engine-private/instances';
|
|
1061
|
+
if (fs.existsSync(outputPath)) fs.mkdirSync(outputPath, { recursive: true });
|
|
1062
|
+
const collection = 'instances';
|
|
1063
|
+
if (process.argv.includes('export'))
|
|
1064
|
+
shellExec(
|
|
1065
|
+
`node bin db --export --collections ${collection} --out-path ${outputPath} --hosts ${host} --paths '${path}' ${deployId}`,
|
|
1066
|
+
);
|
|
1067
|
+
if (process.argv.includes('import'))
|
|
1068
|
+
shellExec(
|
|
1069
|
+
`node bin db --import --drop --preserveUUID --out-path ${outputPath} --hosts ${host} --paths '${path}' ${deployId}`,
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
{
|
|
1073
|
+
const outputPath = './engine-private/crons';
|
|
1074
|
+
if (fs.existsSync(outputPath)) fs.mkdirSync(outputPath, { recursive: true });
|
|
1075
|
+
const collection = 'crons';
|
|
1076
|
+
if (process.argv.includes('export'))
|
|
1077
|
+
shellExec(
|
|
1078
|
+
`node bin db --export --collections ${collection} --out-path ${outputPath} --hosts ${host} --paths '${path}' ${deployId}`,
|
|
1079
|
+
);
|
|
1080
|
+
if (process.argv.includes('import'))
|
|
1081
|
+
shellExec(
|
|
1082
|
+
`node bin db --import --drop --preserveUUID --out-path ${outputPath} --hosts ${host} --paths '${path}' ${deployId}`,
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1051
1089
|
default:
|
|
1052
1090
|
break;
|
|
1053
1091
|
}
|
package/bin/index.js
CHANGED
|
@@ -22,6 +22,15 @@ program
|
|
|
22
22
|
.description('Create a new project')
|
|
23
23
|
.action(Underpost.repo.new);
|
|
24
24
|
|
|
25
|
+
program
|
|
26
|
+
.command('start')
|
|
27
|
+
.argument('<deploy-id>', 'Deploy configuration id')
|
|
28
|
+
.argument('[env]', 'Optional environment, for default is development')
|
|
29
|
+
.option('--run', 'Run app servers and monitor health server')
|
|
30
|
+
.option('--build', 'Build app client')
|
|
31
|
+
.action(Underpost.start.callback)
|
|
32
|
+
.description('Start up server, build pipelines, or services');
|
|
33
|
+
|
|
25
34
|
program
|
|
26
35
|
.command('clone')
|
|
27
36
|
.argument(`<uri>`, 'e.g. username/repository')
|
|
@@ -91,6 +100,8 @@ program
|
|
|
91
100
|
.option('--ns-use <ns-name>', 'Switches current context to namespace')
|
|
92
101
|
.option('--dev', 'init with dev cluster')
|
|
93
102
|
.option('--list-pods', 'Display list pods information')
|
|
103
|
+
.option('--info-capacity', 'display current total machine capacity info')
|
|
104
|
+
.option('--info-capacity-pod', 'display current machine capacity pod info')
|
|
94
105
|
.action(Underpost.cluster.init)
|
|
95
106
|
.description('Manage cluster, for default initialization base kind cluster');
|
|
96
107
|
|
|
@@ -106,7 +117,9 @@ program
|
|
|
106
117
|
.option('--cert', 'Reset tls/ssl certificate secrets')
|
|
107
118
|
.option('--build-manifest', 'Build kind yaml manifests: deployments, services, proxy and secrets')
|
|
108
119
|
.option('--dashboard-update', 'Update dashboard instance data with current router config')
|
|
109
|
-
.option('--
|
|
120
|
+
.option('--replicas <replicas>', 'Set custom number of replicas')
|
|
121
|
+
.option('--versions <deployment-versions>', 'Comma separated custom deployment versions')
|
|
122
|
+
.option('--traffic <traffic-versions>', 'Comma separated custom deployment traffic')
|
|
110
123
|
.description('Manage deployment, for default deploy development pods')
|
|
111
124
|
.action(Underpost.deploy.callback);
|
|
112
125
|
|
|
@@ -125,15 +138,6 @@ program
|
|
|
125
138
|
if (args[1].init) return Underpost.secret[args[0]].init();
|
|
126
139
|
});
|
|
127
140
|
|
|
128
|
-
program
|
|
129
|
-
.command('dockerfile-node-script')
|
|
130
|
-
.argument('<deploy-id>', 'Deploy configuration id')
|
|
131
|
-
.argument('[env]', 'Optional environment, for default is development')
|
|
132
|
-
.option('--run', 'Run custom entry point script')
|
|
133
|
-
.option('--build', 'Build custom image container scripts')
|
|
134
|
-
.description('Dockerfile custom node build script')
|
|
135
|
-
.action(Underpost.image.dockerfile.script);
|
|
136
|
-
|
|
137
141
|
program
|
|
138
142
|
.command('dockerfile-image-build')
|
|
139
143
|
.option('--path [path]', 'Dockerfile path')
|
|
@@ -166,11 +170,13 @@ program
|
|
|
166
170
|
.option('--import', 'Import container backups from repositories')
|
|
167
171
|
.option('--export', 'Export container backups to repositories')
|
|
168
172
|
.option('--pod-name <pod-name>', 'Optional pod context')
|
|
169
|
-
.option('--
|
|
173
|
+
.option('--collections <collections>', 'Comma separated collections')
|
|
170
174
|
.option('--out-path <out-path>', 'Custom out path backup')
|
|
171
175
|
.option('--drop', 'Drop databases')
|
|
172
176
|
.option('--preserveUUID', 'Preserve Ids')
|
|
173
177
|
.option('--git', 'Upload to github')
|
|
178
|
+
.option('--hosts <hosts>', 'Comma separated hosts')
|
|
179
|
+
.option('--paths <paths>', 'Comma separated paths')
|
|
174
180
|
.option('--ns <ns-name>', 'Optional name space context')
|
|
175
181
|
.description('Manage databases')
|
|
176
182
|
.action(Underpost.db.callback);
|
|
@@ -231,6 +237,7 @@ program
|
|
|
231
237
|
.option('--ms-interval <ms-interval>', 'Custom ms interval delta time')
|
|
232
238
|
.option('--now', 'Exec immediately monitor script')
|
|
233
239
|
.option('--single', 'Disable recurrence')
|
|
240
|
+
.option('--type <type>', 'Set custom monitor type')
|
|
234
241
|
.description('Monitor health server management')
|
|
235
242
|
.action(Underpost.monitor.callback);
|
|
236
243
|
|
package/docker-compose.yml
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "module",
|
|
3
3
|
"main": "src/index.js",
|
|
4
4
|
"name": "underpost",
|
|
5
|
-
"version": "2.8.
|
|
5
|
+
"version": "2.8.65",
|
|
6
6
|
"description": "pwa api rest template",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
|
|
@@ -69,7 +69,6 @@
|
|
|
69
69
|
"cors": "^2.8.5",
|
|
70
70
|
"d3": "^7.9.0",
|
|
71
71
|
"dotenv": "^16.3.1",
|
|
72
|
-
"easy-json-schema": "^0.0.2-beta",
|
|
73
72
|
"easymde": "^2.18.0",
|
|
74
73
|
"env-cmd": "^10.1.0",
|
|
75
74
|
"express": "^4.18.2",
|
|
@@ -119,13 +118,7 @@
|
|
|
119
118
|
"vanilla-jsoneditor": "^2.3.2",
|
|
120
119
|
"winston": "^3.11.0"
|
|
121
120
|
},
|
|
122
|
-
"devDependencies": {
|
|
123
|
-
"clean-jsdoc-theme": "^4.3.0",
|
|
124
|
-
"easy-json-schema": "^0.0.2-beta",
|
|
125
|
-
"mocha": "^10.8.2",
|
|
126
|
-
"plantuml": "^0.0.2",
|
|
127
|
-
"swagger-autogen": "^2.23.7"
|
|
128
|
-
},
|
|
121
|
+
"devDependencies": {},
|
|
129
122
|
"publishConfig": {
|
|
130
123
|
"provenance": true,
|
|
131
124
|
"access": "public",
|
|
@@ -225,8 +225,8 @@ const UserService = {
|
|
|
225
225
|
} else throw new Error('invalid email or password');
|
|
226
226
|
|
|
227
227
|
case 'guest': {
|
|
228
|
-
const user = await ValkeyAPI.valkeyObjectFactory('user'
|
|
229
|
-
await ValkeyAPI.setValkeyObject(user.email, user);
|
|
228
|
+
const user = await ValkeyAPI.valkeyObjectFactory(options, 'user');
|
|
229
|
+
await ValkeyAPI.setValkeyObject(options, user.email, user);
|
|
230
230
|
return {
|
|
231
231
|
token: hashJWT({ user: UserDto.auth.payload(user) }),
|
|
232
232
|
user: selectDtoFactory(user, UserDto.select.get()),
|
|
@@ -325,15 +325,18 @@ const UserService = {
|
|
|
325
325
|
return await User.find().select(UserDto.select.getAll());
|
|
326
326
|
|
|
327
327
|
case 'auth': {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
328
|
+
let user;
|
|
329
|
+
if (req.auth.user._id.match('guest')) {
|
|
330
|
+
user = await ValkeyAPI.getValkeyObject(options, req.auth.user.email);
|
|
331
|
+
if (!user) throw new Error('guest user expired');
|
|
332
|
+
} else
|
|
333
|
+
user = await User.findOne({
|
|
334
|
+
_id: req.auth.user._id,
|
|
335
|
+
});
|
|
333
336
|
|
|
334
337
|
const file = await File.findOne({ _id: user.profileImageId });
|
|
335
338
|
|
|
336
|
-
if (!file && !(await ValkeyAPI.getValkeyObject(req.auth.user.email))) {
|
|
339
|
+
if (!file && !(await ValkeyAPI.getValkeyObject(options, req.auth.user.email))) {
|
|
337
340
|
await User.findByIdAndUpdate(
|
|
338
341
|
user._id,
|
|
339
342
|
{ profileImageId: await getDefaultProfileImageId(File) },
|
|
@@ -342,8 +345,8 @@ const UserService = {
|
|
|
342
345
|
},
|
|
343
346
|
);
|
|
344
347
|
}
|
|
345
|
-
return (await ValkeyAPI.getValkeyObject(req.auth.user.email))
|
|
346
|
-
? selectDtoFactory(await ValkeyAPI.getValkeyObject(req.auth.user.email), UserDto.select.get())
|
|
348
|
+
return (await ValkeyAPI.getValkeyObject(options, req.auth.user.email))
|
|
349
|
+
? selectDtoFactory(await ValkeyAPI.getValkeyObject(options, req.auth.user.email), UserDto.select.get())
|
|
347
350
|
: await User.findOne({
|
|
348
351
|
_id: req.auth.user._id,
|
|
349
352
|
}).select(UserDto.select.get());
|
package/src/cli/cluster.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cliSpinner, getNpmRootPath } from '../server/conf.js';
|
|
1
|
+
import { getNpmRootPath } from '../server/conf.js';
|
|
3
2
|
import { loggerFactory } from '../server/logger.js';
|
|
4
3
|
import { shellExec } from '../server/process.js';
|
|
5
4
|
import UnderpostDeploy from './deploy.js';
|
|
@@ -23,10 +22,14 @@ class UnderpostCluster {
|
|
|
23
22
|
reset: false,
|
|
24
23
|
dev: false,
|
|
25
24
|
nsUse: '',
|
|
25
|
+
infoCapacity: false,
|
|
26
|
+
infoCapacityPod: false,
|
|
26
27
|
},
|
|
27
28
|
) {
|
|
28
29
|
const npmRoot = getNpmRootPath();
|
|
29
30
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
31
|
+
if (options.infoCapacityPod === true) return logger.info('', UnderpostDeploy.API.resourcesFactory());
|
|
32
|
+
if (options.infoCapacity === true) return logger.info('', UnderpostCluster.API.getResourcesCapacity());
|
|
30
33
|
if (options.reset === true) return await UnderpostCluster.API.reset();
|
|
31
34
|
if (options.listPods === true) return console.table(UnderpostDeploy.API.get(podName ?? undefined));
|
|
32
35
|
|
|
@@ -197,6 +200,46 @@ class UnderpostCluster {
|
|
|
197
200
|
);
|
|
198
201
|
shellExec(`sudo podman system reset -f`);
|
|
199
202
|
},
|
|
203
|
+
getResourcesCapacity() {
|
|
204
|
+
const resources = {};
|
|
205
|
+
const info = false
|
|
206
|
+
? `Capacity:
|
|
207
|
+
cpu: 8
|
|
208
|
+
ephemeral-storage: 153131976Ki
|
|
209
|
+
hugepages-1Gi: 0
|
|
210
|
+
hugepages-2Mi: 0
|
|
211
|
+
memory: 11914720Ki
|
|
212
|
+
pods: 110
|
|
213
|
+
Allocatable:
|
|
214
|
+
cpu: 8
|
|
215
|
+
ephemeral-storage: 153131976Ki
|
|
216
|
+
hugepages-1Gi: 0
|
|
217
|
+
hugepages-2Mi: 0
|
|
218
|
+
memory: 11914720Ki
|
|
219
|
+
pods: `
|
|
220
|
+
: shellExec(`kubectl describe node kind-worker | grep -E '(Allocatable:|Capacity:)' -A 6`, {
|
|
221
|
+
stdout: true,
|
|
222
|
+
silent: true,
|
|
223
|
+
});
|
|
224
|
+
info
|
|
225
|
+
.split('Allocatable:')[1]
|
|
226
|
+
.split('\n')
|
|
227
|
+
.filter((row) => row.match('cpu') || row.match('memory'))
|
|
228
|
+
.map((row) => {
|
|
229
|
+
if (row.match('cpu'))
|
|
230
|
+
resources.cpu = {
|
|
231
|
+
value: parseInt(row.split(':')[1].trim()) * 1000,
|
|
232
|
+
unit: 'm',
|
|
233
|
+
};
|
|
234
|
+
if (row.match('memory'))
|
|
235
|
+
resources.memory = {
|
|
236
|
+
value: parseInt(row.split(':')[1].split('Ki')[0].trim()),
|
|
237
|
+
unit: 'Ki',
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return resources;
|
|
242
|
+
},
|
|
200
243
|
};
|
|
201
244
|
}
|
|
202
245
|
export default UnderpostCluster;
|
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,7 +163,7 @@ 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
168
|
`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} --collection ${collection} -o /"`,
|
|
159
169
|
);
|
package/src/cli/deploy.js
CHANGED
|
@@ -13,15 +13,31 @@ import { shellExec } from '../server/process.js';
|
|
|
13
13
|
import fs from 'fs-extra';
|
|
14
14
|
import dotenv from 'dotenv';
|
|
15
15
|
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
16
|
+
import UnderpostRootEnv from './env.js';
|
|
17
|
+
import UnderpostCluster from './cluster.js';
|
|
16
18
|
|
|
17
19
|
const logger = loggerFactory(import.meta);
|
|
18
20
|
|
|
19
21
|
class UnderpostDeploy {
|
|
20
22
|
static NETWORK = {};
|
|
21
23
|
static API = {
|
|
22
|
-
sync(deployList) {
|
|
24
|
+
sync(deployList, { versions, replicas }) {
|
|
23
25
|
const deployGroupId = 'dd.tmp';
|
|
24
26
|
fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
|
|
27
|
+
const totalPods = deployList.split(',').length * versions.split(',').length * parseInt(replicas);
|
|
28
|
+
const limitFactor = 0.95;
|
|
29
|
+
const reserveFactor = 0.35;
|
|
30
|
+
const resources = UnderpostCluster.API.getResourcesCapacity();
|
|
31
|
+
const memory = parseInt(resources.memory.value / totalPods);
|
|
32
|
+
const cpu = parseInt(resources.cpu.value / totalPods);
|
|
33
|
+
UnderpostRootEnv.API.set(
|
|
34
|
+
'resources.requests.memory',
|
|
35
|
+
`${parseInt(memory * reserveFactor)}${resources.memory.unit}`,
|
|
36
|
+
);
|
|
37
|
+
UnderpostRootEnv.API.set('resources.requests.cpu', `${parseInt(cpu * reserveFactor)}${resources.cpu.unit}`);
|
|
38
|
+
UnderpostRootEnv.API.set('resources.limits.memory', `${parseInt(memory * limitFactor)}${resources.memory.unit}`);
|
|
39
|
+
UnderpostRootEnv.API.set('resources.limits.cpu', `${parseInt(cpu * limitFactor)}${resources.cpu.unit}`);
|
|
40
|
+
UnderpostRootEnv.API.set('total-pods', totalPods);
|
|
25
41
|
return getDataDeploy({
|
|
26
42
|
buildSingleReplica: true,
|
|
27
43
|
deployGroupId,
|
|
@@ -35,52 +51,43 @@ class UnderpostDeploy {
|
|
|
35
51
|
await Config.build(undefined, 'proxy', deployList);
|
|
36
52
|
return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
|
|
37
53
|
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
fs.mkdirSync(`./engine-private/conf/${deployId}/build/${env}`, { recursive: true });
|
|
51
|
-
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
52
|
-
|
|
53
|
-
logger.info('port range', { deployId, fromPort, toPort });
|
|
54
|
-
// const customImg = `underpost-engine:${version && typeof version === 'string' ? version : '0.0.0'}`;
|
|
55
|
-
// lifecycle:
|
|
56
|
-
// postStart:
|
|
57
|
-
// exec:
|
|
58
|
-
// command:
|
|
59
|
-
// - /bin/sh
|
|
60
|
-
// - -c
|
|
61
|
-
// - >
|
|
62
|
-
// sleep 20 &&
|
|
63
|
-
// npm install -g underpost &&
|
|
64
|
-
// underpost secret underpost --create-from-file /etc/config/.env.${env}
|
|
65
|
-
const deploymentYamlParts = `apiVersion: apps/v1
|
|
54
|
+
deploymentYamlServiceFactory({ deployId, env, port, deploymentVersions }) {
|
|
55
|
+
return deploymentVersions
|
|
56
|
+
.map(
|
|
57
|
+
(version, i) => ` - name: ${deployId}-${env}-${version}-service
|
|
58
|
+
port: ${port}
|
|
59
|
+
weight: ${i === 0 ? 100 : 0}
|
|
60
|
+
`,
|
|
61
|
+
)
|
|
62
|
+
.join('');
|
|
63
|
+
},
|
|
64
|
+
deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas }) {
|
|
65
|
+
return `apiVersion: apps/v1
|
|
66
66
|
kind: Deployment
|
|
67
67
|
metadata:
|
|
68
|
-
name: ${deployId}-${env}
|
|
68
|
+
name: ${deployId}-${env}-${suffix}
|
|
69
69
|
labels:
|
|
70
|
-
app: ${deployId}-${env}
|
|
70
|
+
app: ${deployId}-${env}-${suffix}
|
|
71
71
|
spec:
|
|
72
|
-
replicas:
|
|
72
|
+
replicas: ${replicas}
|
|
73
73
|
selector:
|
|
74
74
|
matchLabels:
|
|
75
|
-
app: ${deployId}-${env}
|
|
75
|
+
app: ${deployId}-${env}-${suffix}
|
|
76
76
|
template:
|
|
77
77
|
metadata:
|
|
78
78
|
labels:
|
|
79
|
-
app: ${deployId}-${env}
|
|
79
|
+
app: ${deployId}-${env}-${suffix}
|
|
80
80
|
spec:
|
|
81
81
|
containers:
|
|
82
|
-
- name: ${deployId}-${env}
|
|
82
|
+
- name: ${deployId}-${env}-${suffix}
|
|
83
83
|
image: localhost/debian:underpost
|
|
84
|
+
resources:
|
|
85
|
+
requests:
|
|
86
|
+
memory: "${resources.requests.memory}"
|
|
87
|
+
cpu: "${resources.requests.cpu}"
|
|
88
|
+
limits:
|
|
89
|
+
memory: "${resources.limits.memory}"
|
|
90
|
+
cpu: "${resources.limits.cpu}"
|
|
84
91
|
command:
|
|
85
92
|
- /bin/sh
|
|
86
93
|
- -c
|
|
@@ -88,7 +95,7 @@ spec:
|
|
|
88
95
|
npm install -g npm@11.2.0 &&
|
|
89
96
|
npm install -g underpost &&
|
|
90
97
|
underpost secret underpost --create-from-file /etc/config/.env.${env} &&
|
|
91
|
-
underpost
|
|
98
|
+
underpost start --build --run ${deployId} ${env}
|
|
92
99
|
volumeMounts:
|
|
93
100
|
- name: config-volume
|
|
94
101
|
mountPath: /etc/config
|
|
@@ -96,27 +103,50 @@ spec:
|
|
|
96
103
|
- name: config-volume
|
|
97
104
|
configMap:
|
|
98
105
|
name: underpost-config
|
|
99
|
-
# image: localhost/${deployId}-${env}:${version && typeof version === 'string' ? version : '0.0.0'}
|
|
100
106
|
---
|
|
101
107
|
apiVersion: v1
|
|
102
108
|
kind: Service
|
|
103
109
|
metadata:
|
|
104
|
-
name: ${deployId}-${env}-service
|
|
110
|
+
name: ${deployId}-${env}-${suffix}-service
|
|
105
111
|
spec:
|
|
106
112
|
selector:
|
|
107
|
-
app: ${deployId}-${env}
|
|
113
|
+
app: ${deployId}-${env}-${suffix}
|
|
108
114
|
ports:
|
|
109
|
-
type: LoadBalancer
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
{{ports}} type: LoadBalancer`;
|
|
116
|
+
},
|
|
117
|
+
async buildManifest(deployList, env, options) {
|
|
118
|
+
const resources = UnderpostDeploy.API.resourcesFactory();
|
|
119
|
+
const replicas = options.replicas;
|
|
114
120
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
for (const _deployId of deployList.split(',')) {
|
|
122
|
+
const deployId = _deployId.trim();
|
|
123
|
+
if (!deployId) continue;
|
|
124
|
+
const confServer = loadReplicas(
|
|
125
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
126
|
+
'proxy',
|
|
119
127
|
);
|
|
128
|
+
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
129
|
+
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
130
|
+
const { fromPort, toPort } = deployRangePortFactory(router);
|
|
131
|
+
const deploymentVersions = options.versions.split(',');
|
|
132
|
+
fs.mkdirSync(`./engine-private/conf/${deployId}/build/${env}`, { recursive: true });
|
|
133
|
+
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
134
|
+
|
|
135
|
+
logger.info('port range', { deployId, fromPort, toPort });
|
|
136
|
+
|
|
137
|
+
let deploymentYamlParts = '';
|
|
138
|
+
for (const deploymentVersion of deploymentVersions) {
|
|
139
|
+
deploymentYamlParts += `---
|
|
140
|
+
${UnderpostDeploy.API.deploymentYamlPartsFactory({
|
|
141
|
+
deployId,
|
|
142
|
+
env,
|
|
143
|
+
suffix: deploymentVersion,
|
|
144
|
+
resources,
|
|
145
|
+
replicas,
|
|
146
|
+
}).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
fs.writeFileSync(`./engine-private/conf/${deployId}/build/${env}/deployment.yaml`, deploymentYamlParts, 'utf8');
|
|
120
150
|
|
|
121
151
|
let proxyYaml = '';
|
|
122
152
|
let secretYaml = '';
|
|
@@ -163,8 +193,13 @@ spec:
|
|
|
163
193
|
- prefix: ${path}
|
|
164
194
|
enableWebsockets: true
|
|
165
195
|
services:
|
|
166
|
-
|
|
167
|
-
|
|
196
|
+
${UnderpostDeploy.API.deploymentYamlServiceFactory({
|
|
197
|
+
deployId,
|
|
198
|
+
env,
|
|
199
|
+
port,
|
|
200
|
+
deploymentVersions:
|
|
201
|
+
options.traffic && typeof options.traffic === 'string' ? options.traffic.split(',') : ['blue'],
|
|
202
|
+
})}`;
|
|
168
203
|
}
|
|
169
204
|
}
|
|
170
205
|
const yamlPath = `./engine-private/conf/${deployId}/build/${env}/proxy.yaml`;
|
|
@@ -196,8 +231,10 @@ spec:
|
|
|
196
231
|
infoUtil: false,
|
|
197
232
|
expose: false,
|
|
198
233
|
cert: false,
|
|
199
|
-
|
|
234
|
+
versions: '',
|
|
235
|
+
traffic: '',
|
|
200
236
|
dashboardUpdate: false,
|
|
237
|
+
replicas: '',
|
|
201
238
|
},
|
|
202
239
|
) {
|
|
203
240
|
if (options.infoUtil === true)
|
|
@@ -208,8 +245,10 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
208
245
|
`);
|
|
209
246
|
if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
210
247
|
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
211
|
-
if (options.
|
|
212
|
-
if (options.
|
|
248
|
+
if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
|
|
249
|
+
if (!options.replicas) options.replicas = 2;
|
|
250
|
+
if (options.sync) UnderpostDeploy.API.sync(deployList, options);
|
|
251
|
+
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
|
|
213
252
|
if (options.infoRouter === true) logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
214
253
|
if (options.dashboardUpdate === true) await UnderpostDeploy.API.updateDashboardData(deployList, env, options);
|
|
215
254
|
if (options.infoRouter === true) return;
|
|
@@ -315,6 +354,19 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
315
354
|
|
|
316
355
|
return result;
|
|
317
356
|
},
|
|
357
|
+
resourcesFactory() {
|
|
358
|
+
return {
|
|
359
|
+
requests: {
|
|
360
|
+
memory: UnderpostRootEnv.API.get('resources.requests.memory'),
|
|
361
|
+
cpu: UnderpostRootEnv.API.get('resources.requests.cpu'),
|
|
362
|
+
},
|
|
363
|
+
limits: {
|
|
364
|
+
memory: UnderpostRootEnv.API.get('resources.limits.memory'),
|
|
365
|
+
cpu: UnderpostRootEnv.API.get('resources.limits.cpu'),
|
|
366
|
+
},
|
|
367
|
+
totalPods: UnderpostRootEnv.API.get('total-pods'),
|
|
368
|
+
};
|
|
369
|
+
},
|
|
318
370
|
async updateDashboardData(deployList, env, options) {
|
|
319
371
|
try {
|
|
320
372
|
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
package/src/cli/image.js
CHANGED
|
@@ -60,74 +60,6 @@ class UnderpostImage {
|
|
|
60
60
|
if (podmanSave === true) shellExec(`podman save -o ${tarFile} ${podManImg}`);
|
|
61
61
|
if (kindLoad === true) shellExec(`sudo kind load image-archive ${tarFile}`);
|
|
62
62
|
},
|
|
63
|
-
async script(deployId = 'default', env = 'development', options = { run: false, build: false }) {
|
|
64
|
-
if (options.build === true) {
|
|
65
|
-
const buildBasePath = `/home/dd`;
|
|
66
|
-
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
67
|
-
shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
|
|
68
|
-
shellExec(`cd ${buildBasePath} && sudo mv ./${repoName} ./engine`);
|
|
69
|
-
shellExec(`cd ${buildBasePath}/engine && underpost clone underpostnet/${repoName}-private`);
|
|
70
|
-
shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
|
|
71
|
-
shellCd(`${buildBasePath}/engine`);
|
|
72
|
-
shellExec(`npm install`);
|
|
73
|
-
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
74
|
-
if (fs.existsSync('./engine-private/itc-scripts')) {
|
|
75
|
-
const itcScripts = await fs.readdir('./engine-private/itc-scripts');
|
|
76
|
-
for (const itcScript of itcScripts)
|
|
77
|
-
if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
|
|
78
|
-
}
|
|
79
|
-
switch (deployId) {
|
|
80
|
-
default:
|
|
81
|
-
{
|
|
82
|
-
{
|
|
83
|
-
const originPath = `./src/db/mongo/MongooseDB.js`;
|
|
84
|
-
fs.writeFileSync(
|
|
85
|
-
originPath,
|
|
86
|
-
fs.readFileSync(originPath, 'utf8').replaceAll(
|
|
87
|
-
`connect: async (host, name) => {`,
|
|
88
|
-
`connect: async (host, name) => {
|
|
89
|
-
host = 'mongodb://mongodb-0.mongodb-service:27017';
|
|
90
|
-
`,
|
|
91
|
-
),
|
|
92
|
-
'utf8',
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
{
|
|
97
|
-
const originPath = `./src/server/valkey.js`;
|
|
98
|
-
fs.writeFileSync(
|
|
99
|
-
originPath,
|
|
100
|
-
fs.readFileSync(originPath, 'utf8').replaceAll(
|
|
101
|
-
` // port: 6379,
|
|
102
|
-
// host: 'service-valkey.default.svc.cluster.local',`,
|
|
103
|
-
` port: 6379,
|
|
104
|
-
host: 'service-valkey.default.svc.cluster.local',`,
|
|
105
|
-
),
|
|
106
|
-
'utf8',
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
113
|
-
}
|
|
114
|
-
if (options.run === true) {
|
|
115
|
-
const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
|
|
116
|
-
if (fs.existsSync(`./engine-private/replica`)) {
|
|
117
|
-
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
118
|
-
for (const replica of replicas) {
|
|
119
|
-
if (!replica.match(deployId)) continue;
|
|
120
|
-
shellExec(`node bin/deploy conf ${replica} ${env}`);
|
|
121
|
-
shellExec(`npm ${runCmd} deploy deploy-id:${replica}`, { async: true });
|
|
122
|
-
await awaitDeployMonitor(true);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
126
|
-
shellExec(`npm ${runCmd} deploy deploy-id:${deployId}`, { async: true });
|
|
127
|
-
await awaitDeployMonitor(true);
|
|
128
|
-
await UnderpostMonitor.API.callback(deployId, env, { itc: true });
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
63
|
},
|
|
132
64
|
};
|
|
133
65
|
}
|