underpost 2.8.65 → 2.8.71
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 +3 -2
- package/.vscode/settings.json +2 -0
- package/CHANGELOG.md +24 -4
- package/README.md +39 -2
- package/bin/deploy.js +1351 -145
- package/bin/file.js +8 -0
- package/bin/index.js +1 -240
- package/cli.md +451 -0
- package/docker-compose.yml +1 -1
- package/jsdoc.json +1 -1
- package/manifests/calico-custom-resources.yaml +25 -0
- 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/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/kubeadm-calico-config.yaml +119 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +1 -1
- 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/statefulset.yaml +6 -4
- package/package.json +2 -1
- package/src/cli/cluster.js +163 -18
- package/src/cli/deploy.js +68 -8
- package/src/cli/fs.js +14 -3
- package/src/cli/image.js +1 -1
- package/src/cli/index.js +312 -0
- package/src/cli/monitor.js +93 -39
- package/src/client/components/core/JoyStick.js +2 -2
- package/src/client/components/core/Modal.js +1 -0
- package/src/index.js +1 -1
- package/src/server/client-build.js +13 -0
- package/src/server/conf.js +5 -1
- package/src/server/dns.js +47 -17
- package/src/server/runtime.js +2 -0
- package/src/server/start.js +0 -1
package/src/cli/index.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import Underpost from '../index.js';
|
|
4
|
+
import { getUnderpostRootPath, loadConf } from '../server/conf.js';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import { commitData } from '../client/components/core/CommonJs.js';
|
|
7
|
+
import { shellExec } from '../server/process.js';
|
|
8
|
+
|
|
9
|
+
const underpostRootPath = getUnderpostRootPath();
|
|
10
|
+
fs.existsSync(`${underpostRootPath}/.env`)
|
|
11
|
+
? dotenv.config({ path: `${underpostRootPath}/.env`, override: true })
|
|
12
|
+
: dotenv.config();
|
|
13
|
+
|
|
14
|
+
const program = new Command();
|
|
15
|
+
|
|
16
|
+
program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`).version(Underpost.version);
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.command('new')
|
|
20
|
+
.argument('<app-name>', 'Application name')
|
|
21
|
+
.description('Create a new project')
|
|
22
|
+
.action(Underpost.repo.new);
|
|
23
|
+
|
|
24
|
+
program
|
|
25
|
+
.command('start')
|
|
26
|
+
.argument('<deploy-id>', 'Deploy configuration id')
|
|
27
|
+
.argument('[env]', 'Optional environment, for default is development')
|
|
28
|
+
.option('--run', 'Run app servers and monitor health server')
|
|
29
|
+
.option('--build', 'Build app client')
|
|
30
|
+
.action(Underpost.start.callback)
|
|
31
|
+
.description('Start up server, build pipelines, or services');
|
|
32
|
+
|
|
33
|
+
program
|
|
34
|
+
.command('clone')
|
|
35
|
+
.argument(`<uri>`, 'e.g. username/repository')
|
|
36
|
+
.option('--bare', 'Clone only .git files')
|
|
37
|
+
.description('Clone github repository')
|
|
38
|
+
.action(Underpost.repo.clone);
|
|
39
|
+
|
|
40
|
+
program
|
|
41
|
+
.command('pull')
|
|
42
|
+
.argument('<path>', 'Absolute or relative directory')
|
|
43
|
+
.argument(`<uri>`, 'e.g. username/repository')
|
|
44
|
+
.description('Pull github repository')
|
|
45
|
+
.action(Underpost.repo.pull);
|
|
46
|
+
|
|
47
|
+
program
|
|
48
|
+
.command('cmt')
|
|
49
|
+
.argument('<path>', 'Absolute or relative directory')
|
|
50
|
+
.argument(`<commit-type>`, `Options: ${Object.keys(commitData)}`)
|
|
51
|
+
.argument(`[module-tag]`, 'Optional set module tag')
|
|
52
|
+
.argument(`[message]`, 'Optional set additional message')
|
|
53
|
+
.option('--empty', 'Allow empty files')
|
|
54
|
+
.option('--copy', 'Copy to clipboard message')
|
|
55
|
+
.option('--info', 'Info commit types')
|
|
56
|
+
.description('Commit github repository')
|
|
57
|
+
.action(Underpost.repo.commit);
|
|
58
|
+
|
|
59
|
+
program
|
|
60
|
+
.command('push')
|
|
61
|
+
.argument('<path>', 'Absolute or relative directory')
|
|
62
|
+
.argument(`<uri>`, 'e.g. username/repository')
|
|
63
|
+
.option('-f', 'Force push overwriting repository')
|
|
64
|
+
.description('Push github repository')
|
|
65
|
+
.action(Underpost.repo.push);
|
|
66
|
+
|
|
67
|
+
program
|
|
68
|
+
.command('env')
|
|
69
|
+
.argument('<deploy-id>', `deploy configuration id, if 'clean' restore default`)
|
|
70
|
+
.argument('[env]', 'Optional environment, for default is production')
|
|
71
|
+
.description('Set environment variables files and conf related to <deploy-id>')
|
|
72
|
+
.action(loadConf);
|
|
73
|
+
|
|
74
|
+
program
|
|
75
|
+
.command('config')
|
|
76
|
+
.argument('operator', `Options: ${Object.keys(Underpost.env)}`)
|
|
77
|
+
.argument('[key]', 'Config key')
|
|
78
|
+
.argument('[value]', 'Config value')
|
|
79
|
+
.description(`Manage configuration, operators`)
|
|
80
|
+
.action((...args) => Underpost.env[args[0]](args[1], args[2]));
|
|
81
|
+
|
|
82
|
+
program
|
|
83
|
+
.command('root')
|
|
84
|
+
.description('Get npm root path')
|
|
85
|
+
.action(() => console.log(getNpmRootPath()));
|
|
86
|
+
|
|
87
|
+
program
|
|
88
|
+
.command('cluster')
|
|
89
|
+
.argument('[pod-name]', 'Optional pod name filter')
|
|
90
|
+
.option('--reset', `Delete all clusters and prune all data and caches`)
|
|
91
|
+
.option('--mariadb', 'Init with mariadb statefulset')
|
|
92
|
+
.option('--mongodb', 'Init with mongodb statefulset')
|
|
93
|
+
.option('--postgresql', 'Init with postgresql statefulset')
|
|
94
|
+
.option('--mongodb4', 'Init with mongodb 4.4 service')
|
|
95
|
+
.option('--istio', 'Init base istio cluster')
|
|
96
|
+
.option('--valkey', 'Init with valkey service')
|
|
97
|
+
.option('--contour', 'Init with project contour base HTTPProxy and envoy')
|
|
98
|
+
.option('--cert-manager', 'Init with letsencrypt-prod ClusterIssuer')
|
|
99
|
+
.option('--info', 'Get all kinds objects deployed')
|
|
100
|
+
.option('--full', 'Init with all statefulsets and services available')
|
|
101
|
+
.option('--ns-use <ns-name>', 'Switches current context to namespace')
|
|
102
|
+
.option('--dev', 'init with dev cluster')
|
|
103
|
+
.option('--list-pods', 'Display list pods information')
|
|
104
|
+
.option('--info-capacity', 'display current total machine capacity info')
|
|
105
|
+
.option('--info-capacity-pod', 'display current machine capacity pod info')
|
|
106
|
+
.option('--pull-image', 'Set optional pull associated image')
|
|
107
|
+
.action(Underpost.cluster.init)
|
|
108
|
+
.description('Manage cluster, for default initialization base kind cluster');
|
|
109
|
+
|
|
110
|
+
program
|
|
111
|
+
.command('deploy')
|
|
112
|
+
.argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
|
|
113
|
+
.argument('[env]', 'Optional environment, for default is development')
|
|
114
|
+
.option('--remove', 'Delete deployments and services')
|
|
115
|
+
.option('--sync', 'Sync deployments env, ports, and replicas')
|
|
116
|
+
.option('--info-router', 'Display router structure')
|
|
117
|
+
.option('--expose', 'Expose service match deploy-list')
|
|
118
|
+
.option('--info-util', 'Display kubectl util management commands')
|
|
119
|
+
.option('--cert', 'Reset tls/ssl certificate secrets')
|
|
120
|
+
.option('--build-manifest', 'Build kind yaml manifests: deployments, services, proxy and secrets')
|
|
121
|
+
.option('--dashboard-update', 'Update dashboard instance data with current router config')
|
|
122
|
+
.option('--replicas <replicas>', 'Set custom number of replicas')
|
|
123
|
+
.option('--versions <deployment-versions>', 'Comma separated custom deployment versions')
|
|
124
|
+
.option('--traffic <traffic-versions>', 'Comma separated custom deployment traffic')
|
|
125
|
+
.option('--disable-update-deployment', 'Disable update deployments')
|
|
126
|
+
.option('--info-traffic', 'get traffic conf form current resources deployments')
|
|
127
|
+
.option(
|
|
128
|
+
'--rebuild-clients-bundle',
|
|
129
|
+
'Inside container, rebuild clients bundle, only static public or storage client files',
|
|
130
|
+
)
|
|
131
|
+
.description('Manage deployment, for default deploy development pods')
|
|
132
|
+
.action(Underpost.deploy.callback);
|
|
133
|
+
|
|
134
|
+
program
|
|
135
|
+
.command('secret')
|
|
136
|
+
.argument('<platform>', `Options: ${Object.keys(Underpost.secret)}`)
|
|
137
|
+
.option('--init', 'Init secrets platform environment')
|
|
138
|
+
.option('--create-from-file <path-env-file>', 'Create secret from env file')
|
|
139
|
+
.option('--list', 'Lists secrets')
|
|
140
|
+
// .option('--delete [secret-key]', 'Delete key secret, if not set, are default delete all')
|
|
141
|
+
// .option('--create [secret-key] [secret-value]', 'Create secret key, with secret value')
|
|
142
|
+
.description(`Manage secrets`)
|
|
143
|
+
.action((...args) => {
|
|
144
|
+
if (args[1].createFromFile) return Underpost.secret[args[0]].createFromEnvFile(args[1].createFromFile);
|
|
145
|
+
if (args[1].list) return Underpost.secret[args[0]].list();
|
|
146
|
+
if (args[1].init) return Underpost.secret[args[0]].init();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
program
|
|
150
|
+
.command('dockerfile-image-build')
|
|
151
|
+
.option('--path [path]', 'Dockerfile path')
|
|
152
|
+
.option('--image-name [image-name]', 'Set image name')
|
|
153
|
+
.option('--image-path [image-path]', 'Set tar image path')
|
|
154
|
+
.option('--dockerfile-name [dockerfile-name]', 'set Dockerfile name')
|
|
155
|
+
.option('--podman-save', 'Export tar file from podman')
|
|
156
|
+
.option('--kind-load', 'Import tar image to Kind cluster')
|
|
157
|
+
.option('--secrets', 'Dockerfile env secrets')
|
|
158
|
+
.option('--secrets-path [secrets-path]', 'Dockerfile custom path env secrets')
|
|
159
|
+
.option('--no-cache', 'Build without using cache')
|
|
160
|
+
.description('Build image from Dockerfile')
|
|
161
|
+
.action(Underpost.image.dockerfile.build);
|
|
162
|
+
|
|
163
|
+
program
|
|
164
|
+
.command('dockerfile-pull-base-images')
|
|
165
|
+
.description('Pull underpost dockerfile images requirements')
|
|
166
|
+
.action(Underpost.image.dockerfile.pullBaseImages);
|
|
167
|
+
|
|
168
|
+
program
|
|
169
|
+
.command('install')
|
|
170
|
+
.description('Fast import underpost npm dependencies')
|
|
171
|
+
.action(() => {
|
|
172
|
+
fs.copySync(`${underpostRootPath}/node_modules`, './node_modules');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
program
|
|
176
|
+
.command('db')
|
|
177
|
+
.argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
|
|
178
|
+
.option('--import', 'Import container backups from repositories')
|
|
179
|
+
.option('--export', 'Export container backups to repositories')
|
|
180
|
+
.option('--pod-name <pod-name>', 'Optional pod context')
|
|
181
|
+
.option('--collections <collections>', 'Comma separated collections')
|
|
182
|
+
.option('--out-path <out-path>', 'Custom out path backup')
|
|
183
|
+
.option('--drop', 'Drop databases')
|
|
184
|
+
.option('--preserveUUID', 'Preserve Ids')
|
|
185
|
+
.option('--git', 'Upload to github')
|
|
186
|
+
.option('--hosts <hosts>', 'Comma separated hosts')
|
|
187
|
+
.option('--paths <paths>', 'Comma separated paths')
|
|
188
|
+
.option('--ns <ns-name>', 'Optional name space context')
|
|
189
|
+
.description('Manage databases')
|
|
190
|
+
.action(Underpost.db.callback);
|
|
191
|
+
|
|
192
|
+
program
|
|
193
|
+
.command('script')
|
|
194
|
+
.argument('operator', `Options: ${Object.keys(Underpost.script)}`)
|
|
195
|
+
.argument('<script-name>', 'Script name')
|
|
196
|
+
.argument('[script-value]', 'Literal command, or path')
|
|
197
|
+
.option('--itc', 'Inside container execution context')
|
|
198
|
+
.option('--itc-path', 'Inside container path options')
|
|
199
|
+
.option('--ns <ns-name>', 'Options name space context')
|
|
200
|
+
.option('--pod-name <pod-name>')
|
|
201
|
+
.description(
|
|
202
|
+
'Supports a number of built-in underpost global scripts and their preset life cycle events as well as arbitrary scripts',
|
|
203
|
+
)
|
|
204
|
+
.action((...args) => Underpost.script[args[0]](args[1], args[2], args[3]));
|
|
205
|
+
|
|
206
|
+
program
|
|
207
|
+
.command('cron')
|
|
208
|
+
.argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
|
|
209
|
+
.argument('[job-list]', `Deploy id list, e.g. ${Object.keys(Underpost.cron)}, for default all available jobs`)
|
|
210
|
+
.option('--itc', 'Inside container execution context')
|
|
211
|
+
.option('--init', 'Init cron jobs for cron job default deploy id')
|
|
212
|
+
.option('--git', 'Upload to github')
|
|
213
|
+
.option('--dashboard-update', 'Update dashboard cron data with current jobs config')
|
|
214
|
+
.description('Cron jobs management')
|
|
215
|
+
.action(Underpost.cron.callback);
|
|
216
|
+
|
|
217
|
+
program
|
|
218
|
+
.command('fs')
|
|
219
|
+
.argument('[path]', 'Absolute or relative directory')
|
|
220
|
+
.option('--rm', 'Remove file')
|
|
221
|
+
.option('--git', 'Current git changes')
|
|
222
|
+
.option('--recursive', 'Upload files recursively')
|
|
223
|
+
.option('--deploy-id <deploy-id>', 'Deploy configuration id')
|
|
224
|
+
.option('--pull', 'Download file')
|
|
225
|
+
.option('--force', 'Force action')
|
|
226
|
+
.option('--storage-file-path <storage-file-path>', 'custom file storage path')
|
|
227
|
+
.description('File storage management, for default upload file')
|
|
228
|
+
.action(Underpost.fs.callback);
|
|
229
|
+
|
|
230
|
+
program
|
|
231
|
+
.command('test')
|
|
232
|
+
.argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
|
|
233
|
+
.description('Manage Test, for default run current underpost default test')
|
|
234
|
+
.option('--itc', 'Inside container execution context')
|
|
235
|
+
.option('--sh', 'Copy to clipboard, container entrypoint shell command')
|
|
236
|
+
.option('--logs', 'Display container logs')
|
|
237
|
+
.option('--pod-name <pod-name>')
|
|
238
|
+
.option('--pod-status <pod-status>')
|
|
239
|
+
.option('--kind-type <kind-type>')
|
|
240
|
+
.action(Underpost.test.callback);
|
|
241
|
+
|
|
242
|
+
program
|
|
243
|
+
.command('monitor')
|
|
244
|
+
.argument('<deploy-id>', 'Deploy configuration id')
|
|
245
|
+
.argument('[env]', 'Optional environment, for default is development')
|
|
246
|
+
.option('--ms-interval <ms-interval>', 'Custom ms interval delta time')
|
|
247
|
+
.option('--now', 'Exec immediately monitor script')
|
|
248
|
+
.option('--single', 'Disable recurrence')
|
|
249
|
+
.option('--replicas <replicas>', 'Set custom number of replicas')
|
|
250
|
+
.option('--type <type>', 'Set custom monitor type')
|
|
251
|
+
.option('--sync', 'Sync with current proxy deployments proxy traffic')
|
|
252
|
+
.description('Monitor health server management')
|
|
253
|
+
.action(Underpost.monitor.callback);
|
|
254
|
+
|
|
255
|
+
const buildCliDoc = () => {
|
|
256
|
+
let md = shellExec(`node bin help`, { silent: true, stdout: true }).split('Options:');
|
|
257
|
+
const baseOptions =
|
|
258
|
+
`## ${md[0].split(`\n`)[2]}
|
|
259
|
+
|
|
260
|
+
### Usage: ` +
|
|
261
|
+
'`' +
|
|
262
|
+
md[0].split(`\n`)[0].split('Usage: ')[1] +
|
|
263
|
+
'`' +
|
|
264
|
+
`
|
|
265
|
+
` +
|
|
266
|
+
'```\n Options:' +
|
|
267
|
+
md[1] +
|
|
268
|
+
' \n```';
|
|
269
|
+
md =
|
|
270
|
+
baseOptions +
|
|
271
|
+
`
|
|
272
|
+
|
|
273
|
+
## Commands:
|
|
274
|
+
`;
|
|
275
|
+
program.commands.map((o) => {
|
|
276
|
+
md +=
|
|
277
|
+
`
|
|
278
|
+
|
|
279
|
+
` +
|
|
280
|
+
'### `' +
|
|
281
|
+
o._name +
|
|
282
|
+
'` :' +
|
|
283
|
+
`
|
|
284
|
+
` +
|
|
285
|
+
'```\n ' +
|
|
286
|
+
shellExec(`node bin help ${o._name}`, { silent: true, stdout: true }) +
|
|
287
|
+
' \n```' +
|
|
288
|
+
`
|
|
289
|
+
`;
|
|
290
|
+
});
|
|
291
|
+
fs.writeFileSync(`./src/client/public/nexodev/docs/references/Command Line Interface.md`, md, 'utf8');
|
|
292
|
+
fs.writeFileSync(`./cli.md`, md, 'utf8');
|
|
293
|
+
const readmeSplit = `pwa-microservices-template</a>`;
|
|
294
|
+
const readme = fs.readFileSync(`./README.md`, 'utf8').split(readmeSplit);
|
|
295
|
+
fs.writeFileSync(
|
|
296
|
+
'./README.md',
|
|
297
|
+
readme[0] +
|
|
298
|
+
readmeSplit +
|
|
299
|
+
`
|
|
300
|
+
|
|
301
|
+
` +
|
|
302
|
+
baseOptions +
|
|
303
|
+
`
|
|
304
|
+
|
|
305
|
+
<a target="_top" href="https://github.com/underpostnet/pwa-microservices-template/blob/master/cli.md">See complete CLI Docs here.</a>
|
|
306
|
+
|
|
307
|
+
`,
|
|
308
|
+
'utf8',
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export { program, buildCliDoc };
|
package/src/cli/monitor.js
CHANGED
|
@@ -5,6 +5,7 @@ import axios from 'axios';
|
|
|
5
5
|
import UnderpostRootEnv from './env.js';
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
7
|
import { shellExec } from '../server/process.js';
|
|
8
|
+
import { isInternetConnection } from '../server/dns.js';
|
|
8
9
|
|
|
9
10
|
const logger = loggerFactory(import.meta);
|
|
10
11
|
|
|
@@ -13,7 +14,8 @@ class UnderpostMonitor {
|
|
|
13
14
|
async callback(
|
|
14
15
|
deployId,
|
|
15
16
|
env = 'development',
|
|
16
|
-
options = { now: false, single: false, msInterval: '', type: '' },
|
|
17
|
+
options = { now: false, single: false, msInterval: '', type: '', replicas: '', sync: false },
|
|
18
|
+
commanderOptions,
|
|
17
19
|
auxRouter,
|
|
18
20
|
) {
|
|
19
21
|
if (deployId === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`)) {
|
|
@@ -22,6 +24,7 @@ class UnderpostMonitor {
|
|
|
22
24
|
_deployId.trim(),
|
|
23
25
|
env,
|
|
24
26
|
options,
|
|
27
|
+
commanderOptions,
|
|
25
28
|
await UnderpostDeploy.API.routerFactory(_deployId, env),
|
|
26
29
|
);
|
|
27
30
|
return;
|
|
@@ -36,15 +39,43 @@ class UnderpostMonitor {
|
|
|
36
39
|
|
|
37
40
|
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
38
41
|
|
|
39
|
-
logger.info(`${deployId} ${env}`, pathPortAssignmentData);
|
|
40
|
-
|
|
41
42
|
let errorPayloads = [];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
if (options.sync === true) {
|
|
44
|
+
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
45
|
+
if (currentTraffic) UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, currentTraffic);
|
|
46
|
+
}
|
|
47
|
+
let traffic = UnderpostRootEnv.API.get(`${deployId}-${env}-traffic`) ?? 'blue';
|
|
48
|
+
const maxAttempts = parseInt(
|
|
49
|
+
Object.keys(pathPortAssignmentData)
|
|
50
|
+
.map((host) => pathPortAssignmentData[host].length)
|
|
51
|
+
.reduce((accumulator, value) => accumulator + value, 0) * 2.5,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
logger.info(`Init deploy monitor`, {
|
|
55
|
+
pathPortAssignmentData,
|
|
56
|
+
maxAttempts,
|
|
57
|
+
deployId,
|
|
58
|
+
env,
|
|
59
|
+
traffic,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const switchTraffic = () => {
|
|
63
|
+
if (traffic === 'blue') traffic = 'green';
|
|
64
|
+
else traffic = 'blue';
|
|
65
|
+
UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, traffic);
|
|
66
|
+
shellExec(
|
|
67
|
+
`node bin deploy --info-router --build-manifest --traffic ${traffic} --replicas ${
|
|
68
|
+
options.replicas ? options.replicas : 1
|
|
69
|
+
} ${deployId} ${env}`,
|
|
70
|
+
);
|
|
71
|
+
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
72
|
+
};
|
|
46
73
|
|
|
47
74
|
const monitor = async (reject) => {
|
|
75
|
+
if (UnderpostRootEnv.API.get(`monitor-init-callback-script`))
|
|
76
|
+
shellExec(UnderpostRootEnv.API.get(`monitor-init-callback-script`));
|
|
77
|
+
const currentTimestamp = new Date().getTime();
|
|
78
|
+
errorPayloads = errorPayloads.filter((e) => currentTimestamp - e.timestamp < 60 * 1000 * 5);
|
|
48
79
|
logger.info(`[${deployId}-${env}] Check server health`);
|
|
49
80
|
for (const host of Object.keys(pathPortAssignmentData)) {
|
|
50
81
|
for (const instance of pathPortAssignmentData[host]) {
|
|
@@ -52,6 +83,7 @@ class UnderpostMonitor {
|
|
|
52
83
|
if (path.match('peer') || path.match('socket')) continue;
|
|
53
84
|
let urlTest = `http://localhost:${port}${path}`;
|
|
54
85
|
switch (options.type) {
|
|
86
|
+
case 'remote':
|
|
55
87
|
case 'blue-green':
|
|
56
88
|
urlTest = `https://${host}${path}`;
|
|
57
89
|
break;
|
|
@@ -71,6 +103,7 @@ class UnderpostMonitor {
|
|
|
71
103
|
status: error.status,
|
|
72
104
|
code: error.code,
|
|
73
105
|
errors: error.errors,
|
|
106
|
+
timestamp: new Date().getTime(),
|
|
74
107
|
};
|
|
75
108
|
if (errorPayload.status !== 404) {
|
|
76
109
|
errorPayloads.push(errorPayload);
|
|
@@ -87,30 +120,31 @@ class UnderpostMonitor {
|
|
|
87
120
|
fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
|
|
88
121
|
);
|
|
89
122
|
|
|
123
|
+
shellExec(`kubectl delete configmap underpost-config`);
|
|
124
|
+
shellExec(
|
|
125
|
+
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
126
|
+
);
|
|
127
|
+
|
|
90
128
|
for (const host of Object.keys(confServer)) {
|
|
91
129
|
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
92
130
|
}
|
|
93
131
|
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${traffic}`);
|
|
94
132
|
|
|
95
|
-
|
|
96
|
-
else traffic = 'blue';
|
|
97
|
-
|
|
98
|
-
shellExec(
|
|
99
|
-
`node bin deploy --info-router --build-manifest --traffic ${traffic} ${deployId} ${env}`,
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
103
|
-
errorPayloads = [];
|
|
133
|
+
switchTraffic();
|
|
104
134
|
}
|
|
105
135
|
|
|
106
136
|
break;
|
|
107
137
|
|
|
138
|
+
case 'remote':
|
|
139
|
+
break;
|
|
140
|
+
|
|
108
141
|
default:
|
|
109
142
|
if (reject) reject(message);
|
|
110
143
|
else throw new Error(message);
|
|
111
144
|
}
|
|
145
|
+
errorPayloads = [];
|
|
112
146
|
}
|
|
113
|
-
logger.error(
|
|
147
|
+
logger.error(`Error accumulator ${deployId}-${env}-${traffic}`, errorPayloads.length);
|
|
114
148
|
}
|
|
115
149
|
});
|
|
116
150
|
}
|
|
@@ -119,13 +153,19 @@ class UnderpostMonitor {
|
|
|
119
153
|
if (options.now === true) await monitor();
|
|
120
154
|
if (options.single === true) return;
|
|
121
155
|
let optionsMsTimeout = parseInt(options.msInterval);
|
|
122
|
-
if (isNaN(optionsMsTimeout)) optionsMsTimeout =
|
|
156
|
+
if (isNaN(optionsMsTimeout)) optionsMsTimeout = 60250; // 60.25 seconds
|
|
123
157
|
let monitorTrafficName;
|
|
124
158
|
let monitorPodName;
|
|
125
159
|
const monitorCallBack = (resolve, reject) => {
|
|
126
160
|
const envMsTimeout = UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-ms`);
|
|
127
161
|
setTimeout(
|
|
128
162
|
async () => {
|
|
163
|
+
const isOnline = await isInternetConnection();
|
|
164
|
+
if (!isOnline) {
|
|
165
|
+
logger.warn('No internet connection');
|
|
166
|
+
monitorCallBack(resolve, reject);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
129
169
|
switch (options.type) {
|
|
130
170
|
case 'blue-green':
|
|
131
171
|
{
|
|
@@ -135,14 +175,17 @@ class UnderpostMonitor {
|
|
|
135
175
|
}
|
|
136
176
|
const cmd = `underpost config get container-status`;
|
|
137
177
|
const checkDeploymentReadyStatus = () => {
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
178
|
+
const pods = UnderpostDeploy.API.get(`${deployId}-${env}-${traffic}`);
|
|
179
|
+
if (pods && pods[0]) {
|
|
180
|
+
const { NAME } = pods[0];
|
|
181
|
+
if (
|
|
182
|
+
shellExec(`sudo kubectl exec -i ${NAME} -- sh -c "${cmd}"`, { stdout: true }).match(
|
|
183
|
+
`${deployId}-${env}-running-deployment`,
|
|
184
|
+
)
|
|
185
|
+
) {
|
|
186
|
+
monitorPodName = NAME;
|
|
187
|
+
monitorTrafficName = `${traffic}`;
|
|
188
|
+
}
|
|
146
189
|
}
|
|
147
190
|
};
|
|
148
191
|
if (!monitorPodName) {
|
|
@@ -157,19 +200,30 @@ class UnderpostMonitor {
|
|
|
157
200
|
default:
|
|
158
201
|
break;
|
|
159
202
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
for (const monitorStatus of [
|
|
204
|
+
{ key: `monitor-input`, value: UnderpostRootEnv.API.get(`monitor-input`) },
|
|
205
|
+
{
|
|
206
|
+
key: `${deployId}-${env}-monitor-input`,
|
|
207
|
+
value: UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-input`),
|
|
208
|
+
},
|
|
209
|
+
])
|
|
210
|
+
switch (monitorStatus.value) {
|
|
211
|
+
case 'pause':
|
|
212
|
+
monitorCallBack(resolve, reject);
|
|
213
|
+
return;
|
|
214
|
+
case 'restart':
|
|
215
|
+
UnderpostRootEnv.API.delete(monitorStatus.key);
|
|
216
|
+
return reject();
|
|
217
|
+
case 'stop':
|
|
218
|
+
UnderpostRootEnv.API.delete(monitorStatus.key);
|
|
219
|
+
return resolve();
|
|
220
|
+
case 'blue-green-switch':
|
|
221
|
+
UnderpostRootEnv.API.delete(monitorStatus.key);
|
|
222
|
+
switchTraffic();
|
|
223
|
+
}
|
|
224
|
+
await monitor(reject);
|
|
225
|
+
monitorCallBack(resolve, reject);
|
|
226
|
+
return;
|
|
173
227
|
},
|
|
174
228
|
!isNaN(envMsTimeout) ? envMsTimeout : optionsMsTimeout,
|
|
175
229
|
);
|
|
@@ -1629,6 +1629,7 @@ const Modal = {
|
|
|
1629
1629
|
currentTopModalId: '',
|
|
1630
1630
|
zIndexSync: function ({ idModal }) {
|
|
1631
1631
|
setTimeout(() => {
|
|
1632
|
+
if (!this.Data[idModal]) return;
|
|
1632
1633
|
const cleanTopModal = () => {
|
|
1633
1634
|
Object.keys(this.Data).map((_idModal) => {
|
|
1634
1635
|
if (this.Data[_idModal].options.zIndexSync && s(`.${_idModal}`)) s(`.${_idModal}`).style.zIndex = '3';
|
package/src/index.js
CHANGED
|
@@ -683,6 +683,19 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
683
683
|
root file where the route starts, such as index.js, app.js, routes.js, etc ... */
|
|
684
684
|
|
|
685
685
|
await swaggerAutoGen({ openapi: '3.0.0' })(outputFile, routes, doc);
|
|
686
|
+
|
|
687
|
+
const htmlFiles = await fs.readdir(`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}`);
|
|
688
|
+
for (const htmlFile of htmlFiles) {
|
|
689
|
+
if (htmlFile.match('.html')) {
|
|
690
|
+
fs.writeFileSync(
|
|
691
|
+
`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}/${htmlFile}`,
|
|
692
|
+
fs
|
|
693
|
+
.readFileSync(`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}/${htmlFile}`, 'utf8')
|
|
694
|
+
.replaceAll('Tutorials', 'References'),
|
|
695
|
+
'utf8',
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
686
699
|
}
|
|
687
700
|
|
|
688
701
|
if (client) {
|
package/src/server/conf.js
CHANGED
|
@@ -927,7 +927,9 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
|
927
927
|
const confServer = loadReplicas(
|
|
928
928
|
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
929
929
|
);
|
|
930
|
+
const hosts = {};
|
|
930
931
|
for (const host of Object.keys(confServer)) {
|
|
932
|
+
hosts[host] = {};
|
|
931
933
|
for (const path of Object.keys(confServer[host])) {
|
|
932
934
|
if (!confServer[host][path].db) continue;
|
|
933
935
|
const { singleReplica, replicas, db } = confServer[host][path];
|
|
@@ -940,6 +942,7 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
|
940
942
|
);
|
|
941
943
|
for (const _host of Object.keys(confServerReplica)) {
|
|
942
944
|
for (const _path of Object.keys(confServerReplica[_host])) {
|
|
945
|
+
hosts[host][_path] = { replica: { host, path } };
|
|
943
946
|
confServerReplica[_host][_path].valkey = valkey;
|
|
944
947
|
switch (provider) {
|
|
945
948
|
case 'mongoose':
|
|
@@ -954,7 +957,7 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
|
954
957
|
'utf8',
|
|
955
958
|
);
|
|
956
959
|
}
|
|
957
|
-
}
|
|
960
|
+
} else hosts[host][path] = {};
|
|
958
961
|
confServer[host][path].valkey = valkey;
|
|
959
962
|
switch (provider) {
|
|
960
963
|
case 'mongoose':
|
|
@@ -964,6 +967,7 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
|
964
967
|
}
|
|
965
968
|
}
|
|
966
969
|
fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
970
|
+
return { hosts };
|
|
967
971
|
};
|
|
968
972
|
|
|
969
973
|
const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
|