underpost 2.8.85 → 2.8.86
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/.env.development +1 -1
- package/.env.production +1 -1
- package/.env.test +1 -1
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
- package/.github/workflows/release.cd.yml +37 -0
- package/README.md +7 -44
- package/bin/cyberia0.js +78 -0
- package/bin/db.js +1 -3
- package/bin/deploy.js +13 -350
- package/bin/file.js +11 -1
- package/cli.md +39 -19
- package/manifests/deployment/{dd-template-development → dd-default-development}/deployment.yaml +16 -16
- package/manifests/deployment/{dd-template-development → dd-default-development}/proxy.yaml +3 -3
- package/manifests/grafana/deployment.yaml +57 -0
- package/manifests/grafana/kustomization.yaml +7 -0
- package/manifests/grafana/pvc.yaml +12 -0
- package/manifests/grafana/service.yaml +14 -0
- package/manifests/maas/ssh-cluster-info.sh +14 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/package.json +1 -2
- package/src/api/user/user.service.js +8 -34
- package/src/cli/cluster.js +41 -2
- package/src/cli/cron.js +12 -45
- package/src/cli/db.js +149 -0
- package/src/cli/deploy.js +20 -81
- package/src/cli/index.js +20 -6
- package/src/cli/monitor.js +1 -4
- package/src/cli/repository.js +12 -5
- package/src/cli/run.js +77 -14
- package/src/client/Default.index.js +0 -2
- package/src/client/components/core/Account.js +6 -2
- package/src/client/components/core/Content.js +11 -7
- package/src/client/components/core/Css.js +5 -1
- package/src/client/components/core/Input.js +6 -1
- package/src/client/components/core/LogIn.js +3 -0
- package/src/client/components/core/LogOut.js +1 -1
- package/src/client/components/core/Modal.js +7 -4
- package/src/client/components/core/Recover.js +5 -2
- package/src/client/components/core/Scroll.js +65 -120
- package/src/client/components/core/SignUp.js +1 -0
- package/src/client/components/core/VanillaJs.js +48 -2
- package/src/client/components/default/MenuDefault.js +2 -2
- package/src/client/components/default/RoutesDefault.js +3 -3
- package/src/index.js +1 -1
- package/src/mailer/MailerProvider.js +37 -0
- package/src/server/client-build-live.js +1 -1
- package/src/server/client-dev-server.js +1 -1
- package/src/server/conf.js +2 -272
- package/src/server/proxy.js +1 -2
- package/src/server/start.js +3 -3
- package/docker-compose.yml +0 -67
- package/prometheus.yml +0 -36
package/src/cli/deploy.js
CHANGED
|
@@ -242,12 +242,10 @@ spec:
|
|
|
242
242
|
cert: false,
|
|
243
243
|
versions: '',
|
|
244
244
|
traffic: '',
|
|
245
|
-
dashboardUpdate: false,
|
|
246
245
|
replicas: '',
|
|
247
246
|
restoreHosts: false,
|
|
248
247
|
disableUpdateDeployment: false,
|
|
249
248
|
infoTraffic: false,
|
|
250
|
-
rebuildClientsBundle: false,
|
|
251
249
|
},
|
|
252
250
|
) {
|
|
253
251
|
if (options.infoUtil === true)
|
|
@@ -311,22 +309,21 @@ Password: <Your Key>
|
|
|
311
309
|
deployId,
|
|
312
310
|
env,
|
|
313
311
|
traffic: UnderpostDeploy.API.getCurrentTraffic(deployId),
|
|
312
|
+
router: await UnderpostDeploy.API.routerFactory(deployId, env),
|
|
313
|
+
pods: await UnderpostDeploy.API.get(deployId),
|
|
314
314
|
});
|
|
315
315
|
}
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
|
-
if (options.rebuildClientsBundle === true) await UnderpostDeploy.API.rebuildClientsBundle(deployList);
|
|
319
318
|
if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
|
|
320
319
|
if (!options.replicas) options.replicas = 1;
|
|
321
320
|
if (options.sync) UnderpostDeploy.API.sync(deployList, options);
|
|
322
321
|
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
|
|
323
|
-
if (options.infoRouter === true)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
329
|
-
);
|
|
322
|
+
if (options.infoRouter === true) {
|
|
323
|
+
logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
UnderpostDeploy.API.configMap(env);
|
|
330
327
|
let renderHosts = '';
|
|
331
328
|
let concatHots = '';
|
|
332
329
|
const etcHost = (
|
|
@@ -435,23 +432,6 @@ Password: <Your Key>
|
|
|
435
432
|
|
|
436
433
|
return result;
|
|
437
434
|
},
|
|
438
|
-
rebuildClientsBundle(deployList) {
|
|
439
|
-
for (const _deployId of deployList.split(',')) {
|
|
440
|
-
const deployId = _deployId.trim();
|
|
441
|
-
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
442
|
-
|
|
443
|
-
shellExec(`underpost script set ${deployId}-client-build '
|
|
444
|
-
cd /home/dd/engine &&
|
|
445
|
-
git checkout . &&
|
|
446
|
-
underpost pull . underpostnet/${repoName} &&
|
|
447
|
-
underpost pull ./engine-private underpostnet/${repoName}-private &&
|
|
448
|
-
underpost env ${deployId} production &&
|
|
449
|
-
node bin/deploy build-full-client ${deployId}
|
|
450
|
-
'`);
|
|
451
|
-
|
|
452
|
-
shellExec(`node bin script run ${deployId}-client-build --itc --pod-name ${deployId}`);
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
435
|
resourcesFactory() {
|
|
456
436
|
return {
|
|
457
437
|
requests: {
|
|
@@ -465,60 +445,6 @@ node bin/deploy build-full-client ${deployId}
|
|
|
465
445
|
totalPods: UnderpostRootEnv.API.get('total-pods'),
|
|
466
446
|
};
|
|
467
447
|
},
|
|
468
|
-
async updateDashboardData(deployList, env, options) {
|
|
469
|
-
try {
|
|
470
|
-
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
471
|
-
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
472
|
-
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
473
|
-
const { db } = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'))[host][
|
|
474
|
-
path
|
|
475
|
-
];
|
|
476
|
-
|
|
477
|
-
await DataBaseProvider.load({ apis: ['instance'], host, path, db });
|
|
478
|
-
|
|
479
|
-
/** @type {import('../api/instance/instance.model.js').InstanceModel} */
|
|
480
|
-
const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
|
|
481
|
-
|
|
482
|
-
await Instance.deleteMany();
|
|
483
|
-
|
|
484
|
-
for (const _deployId of deployList.split(',')) {
|
|
485
|
-
const deployId = _deployId.trim();
|
|
486
|
-
if (!deployId) continue;
|
|
487
|
-
const confServer = loadReplicas(
|
|
488
|
-
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
489
|
-
'proxy',
|
|
490
|
-
);
|
|
491
|
-
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
492
|
-
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
493
|
-
|
|
494
|
-
for (const host of Object.keys(confServer)) {
|
|
495
|
-
for (const { path, port } of pathPortAssignmentData[host]) {
|
|
496
|
-
if (!confServer[host][path]) continue;
|
|
497
|
-
|
|
498
|
-
const { client, runtime, apis } = confServer[host][path];
|
|
499
|
-
|
|
500
|
-
const body = {
|
|
501
|
-
deployId,
|
|
502
|
-
host,
|
|
503
|
-
path,
|
|
504
|
-
port,
|
|
505
|
-
client,
|
|
506
|
-
runtime,
|
|
507
|
-
apis,
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
logger.info('save', body);
|
|
511
|
-
|
|
512
|
-
await new Instance(body).save();
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
518
|
-
} catch (error) {
|
|
519
|
-
logger.error(error, error.stack);
|
|
520
|
-
}
|
|
521
|
-
},
|
|
522
448
|
existsContainerFile({ podName, path }) {
|
|
523
449
|
return JSON.parse(
|
|
524
450
|
shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
|
|
@@ -548,6 +474,19 @@ node bin/deploy build-full-client ${deployId}
|
|
|
548
474
|
}
|
|
549
475
|
return { ready: notReadyPods.length === 0, notReadyPods, readyPods };
|
|
550
476
|
},
|
|
477
|
+
configMap(env) {
|
|
478
|
+
shellExec(`kubectl delete configmap underpost-config`);
|
|
479
|
+
shellExec(
|
|
480
|
+
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
481
|
+
);
|
|
482
|
+
},
|
|
483
|
+
switchTraffic(deployId, env, targetTraffic, replicas = 1) {
|
|
484
|
+
UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
|
|
485
|
+
shellExec(
|
|
486
|
+
`node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} ${deployId} ${env}`,
|
|
487
|
+
);
|
|
488
|
+
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
489
|
+
},
|
|
551
490
|
};
|
|
552
491
|
}
|
|
553
492
|
|
package/src/cli/index.js
CHANGED
|
@@ -23,6 +23,7 @@ program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`
|
|
|
23
23
|
program
|
|
24
24
|
.command('new')
|
|
25
25
|
.argument('<app-name>', 'The name of the application to create.')
|
|
26
|
+
.option('--dev', 'Sets the development cli context')
|
|
26
27
|
.description('Initializes a new Underpost project with a predefined structure.')
|
|
27
28
|
.action(Underpost.repo.new);
|
|
28
29
|
|
|
@@ -123,6 +124,11 @@ program
|
|
|
123
124
|
.option('--full', 'Initializes the cluster with all available statefulsets and services.')
|
|
124
125
|
.option('--ns-use <ns-name>', 'Switches the current Kubernetes context to the specified namespace.')
|
|
125
126
|
.option('--kubeadm', 'Initializes the cluster using kubeadm for control plane management.')
|
|
127
|
+
.option('--grafana', 'Initializes the cluster with a Grafana deployment.')
|
|
128
|
+
.option(
|
|
129
|
+
'--prom [hosts]',
|
|
130
|
+
'Initializes the cluster with a Prometheus Operator deployment and monitor scrap for specified hosts.',
|
|
131
|
+
)
|
|
126
132
|
.option('--dev', 'Initializes a development-specific cluster configuration.')
|
|
127
133
|
.option('--list-pods', 'Displays detailed information about all pods.')
|
|
128
134
|
.option('--info-capacity', 'Displays the current total machine capacity information.')
|
|
@@ -155,7 +161,6 @@ program
|
|
|
155
161
|
'--build-manifest',
|
|
156
162
|
'Builds Kubernetes YAML manifests, including deployments, services, proxies, and secrets.',
|
|
157
163
|
)
|
|
158
|
-
.option('--dashboard-update', 'Updates dashboard instance data with the current router configuration.')
|
|
159
164
|
.option('--replicas <replicas>', 'Sets a custom number of replicas for deployments.')
|
|
160
165
|
.option('--versions <deployment-versions>', 'A comma-separated list of custom deployment versions.')
|
|
161
166
|
.option('--traffic <traffic-versions>', 'A comma-separated list of custom deployment traffic weights.')
|
|
@@ -163,10 +168,6 @@ program
|
|
|
163
168
|
.option('--info-traffic', 'Retrieves traffic configuration from current resource deployments.')
|
|
164
169
|
.option('--kubeadm', 'Enables the kubeadm context for deployment operations.')
|
|
165
170
|
.option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
|
|
166
|
-
.option(
|
|
167
|
-
'--rebuild-clients-bundle',
|
|
168
|
-
'Inside the container, rebuilds client bundles (only static public or storage client files).',
|
|
169
|
-
)
|
|
170
171
|
.description('Manages application deployments, defaulting to deploying development pods.')
|
|
171
172
|
.action(Underpost.deploy.callback);
|
|
172
173
|
|
|
@@ -240,6 +241,20 @@ program
|
|
|
240
241
|
.description('Manages database operations, including import, export, and collection management.')
|
|
241
242
|
.action(Underpost.db.callback);
|
|
242
243
|
|
|
244
|
+
program
|
|
245
|
+
.command('metadata')
|
|
246
|
+
.argument('[deploy-id]', 'The deployment ID to manage metadata.')
|
|
247
|
+
.argument('[host]', 'The host to manage metadata.')
|
|
248
|
+
.argument('[path]', 'The path to manage metadata.')
|
|
249
|
+
.option('--import', 'Imports from local storage.')
|
|
250
|
+
.option('--export', 'Exports to local storage.')
|
|
251
|
+
.option('--crons', 'Apply to cron data collection')
|
|
252
|
+
.option('--instances', 'Apply to instance data collection')
|
|
253
|
+
.option('--generate', 'Generate cluster metadata')
|
|
254
|
+
.option('--itc', 'Apply under container execution context')
|
|
255
|
+
.description('Manages cluster metadata operations, including import and export.')
|
|
256
|
+
.action(Underpost.db.clusterMetadataBackupCallback);
|
|
257
|
+
|
|
243
258
|
// 'script' command: Execute scripts
|
|
244
259
|
program
|
|
245
260
|
.command('script')
|
|
@@ -268,7 +283,6 @@ program
|
|
|
268
283
|
.option('--itc', 'Executes cron jobs within the container execution context.')
|
|
269
284
|
.option('--init', 'Initializes cron jobs for the default deployment ID.')
|
|
270
285
|
.option('--git', 'Uploads cron job configurations to GitHub.')
|
|
271
|
-
.option('--dashboard-update', 'Updates dashboard cron data with the current job configurations.')
|
|
272
286
|
.description('Manages cron jobs, including initialization, execution, and configuration updates.')
|
|
273
287
|
.action(Underpost.cron.callback);
|
|
274
288
|
|
package/src/cli/monitor.js
CHANGED
|
@@ -120,10 +120,7 @@ class UnderpostMonitor {
|
|
|
120
120
|
fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
|
|
121
121
|
);
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
shellExec(
|
|
125
|
-
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
126
|
-
);
|
|
123
|
+
UnderpostDeploy.API.configMap(env);
|
|
127
124
|
|
|
128
125
|
for (const host of Object.keys(confServer)) {
|
|
129
126
|
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
package/src/cli/repository.js
CHANGED
|
@@ -80,7 +80,7 @@ class UnderpostRepository {
|
|
|
80
80
|
);
|
|
81
81
|
},
|
|
82
82
|
|
|
83
|
-
new(repositoryName) {
|
|
83
|
+
new(repositoryName, options = { dev: false }) {
|
|
84
84
|
return new Promise(async (resolve, reject) => {
|
|
85
85
|
try {
|
|
86
86
|
await logger.setUpInfo();
|
|
@@ -89,15 +89,22 @@ class UnderpostRepository {
|
|
|
89
89
|
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
|
|
90
90
|
);
|
|
91
91
|
else actionInitLog();
|
|
92
|
-
const
|
|
92
|
+
const npmRoot = getNpmRootPath();
|
|
93
|
+
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
93
94
|
const destFolder = `./${repositoryName}`;
|
|
94
95
|
logger.info('Note: This process may take several minutes to complete');
|
|
95
96
|
logger.info('build app', { destFolder });
|
|
96
97
|
if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
|
|
97
98
|
fs.mkdirSync(destFolder, { recursive: true });
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
if (!options.dev) {
|
|
100
|
+
fs.copySync(underpostRoot, destFolder);
|
|
101
|
+
fs.writeFileSync(
|
|
102
|
+
`${destFolder}/.gitignore`,
|
|
103
|
+
fs.readFileSync(`${underpostRoot}/.dockerignore`, 'utf8'),
|
|
104
|
+
'utf8',
|
|
105
|
+
);
|
|
106
|
+
shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
|
|
107
|
+
}
|
|
101
108
|
shellExec(`cd ${destFolder} && npm run build`);
|
|
102
109
|
shellExec(`cd ${destFolder} && npm run dev`);
|
|
103
110
|
return resolve();
|
package/src/cli/run.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { daemonProcess, getTerminalPid, openTerminal, pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
2
2
|
import read from 'read';
|
|
3
3
|
import { getNpmRootPath } from '../server/conf.js';
|
|
4
|
-
import { loggerFactory } from '../server/logger.js';
|
|
4
|
+
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
5
5
|
import UnderpostTest from './test.js';
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
7
|
import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
@@ -54,6 +54,9 @@ class UnderpostRun {
|
|
|
54
54
|
}`,
|
|
55
55
|
);
|
|
56
56
|
},
|
|
57
|
+
'underpost-config': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
58
|
+
UnderpostDeploy.API.configMap(path ?? 'production');
|
|
59
|
+
},
|
|
57
60
|
'gpu-env': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
58
61
|
shellExec(
|
|
59
62
|
`node bin cluster --dev --reset && node bin cluster --dev --dedicated-gpu --kubeadm && kubectl get pods --all-namespaces -o wide -w`,
|
|
@@ -76,6 +79,11 @@ class UnderpostRun {
|
|
|
76
79
|
shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
|
|
77
80
|
shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
|
|
78
81
|
},
|
|
82
|
+
'ssh-cluster-info': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
83
|
+
const { underpostRoot } = options;
|
|
84
|
+
shellExec(`chmod +x ${underpostRoot}/manifests/maas/ssh-cluster-info.sh`);
|
|
85
|
+
shellExec(`${underpostRoot}/manifests/maas/ssh-cluster-info.sh`);
|
|
86
|
+
},
|
|
79
87
|
'cyberia-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
80
88
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
81
89
|
shellExec(`${baseCommand} run ide /home/dd/cyberia-server`);
|
|
@@ -93,6 +101,25 @@ class UnderpostRun {
|
|
|
93
101
|
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
94
102
|
shellExec(`${baseCommand} push . underpostnet/engine`);
|
|
95
103
|
},
|
|
104
|
+
clean: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
105
|
+
shellCd(path ?? `/home/dd/engine`);
|
|
106
|
+
shellExec(`node bin/deploy clean-core-repo`);
|
|
107
|
+
},
|
|
108
|
+
pull: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
109
|
+
shellCd(`/home/dd/engine`);
|
|
110
|
+
shellExec(`node bin/deploy clean-core-repo`);
|
|
111
|
+
shellExec(`underpost pull . underpostnet/engine`);
|
|
112
|
+
shellExec(`underpost pull engine-private underpostnet/engine-private`, { silent: true });
|
|
113
|
+
},
|
|
114
|
+
'release-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
115
|
+
actionInitLog();
|
|
116
|
+
shellExec(`underpost --version`);
|
|
117
|
+
shellCd(`/home/dd/engine`);
|
|
118
|
+
for (const _deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
119
|
+
const deployId = _deployId.trim();
|
|
120
|
+
shellExec(`underpost run deploy ${deployId}`, { async: true });
|
|
121
|
+
}
|
|
122
|
+
},
|
|
96
123
|
'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
97
124
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
98
125
|
shellCd('/home/dd/engine');
|
|
@@ -104,6 +131,16 @@ class UnderpostRun {
|
|
|
104
131
|
const { underpostRoot } = options;
|
|
105
132
|
shellExec(`node ${underpostRoot}/bin/vs ${path}`);
|
|
106
133
|
},
|
|
134
|
+
'dev-client': (_path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
135
|
+
let [deployId, hostpath, subConf, lite] = _path.split(',');
|
|
136
|
+
let [host, path] = hostpath.split('/');
|
|
137
|
+
if (!path) path = '/';
|
|
138
|
+
shellExec(`npm run dev-client ${deployId} ${host} ${path} ${subConf} static${lite === 'l' ? ' l' : ''}`);
|
|
139
|
+
},
|
|
140
|
+
'dev-api': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
141
|
+
let [deployId, subConf] = path.split(',');
|
|
142
|
+
shellExec(`npm run dev-api ${deployId} ${subConf}`);
|
|
143
|
+
},
|
|
107
144
|
monitor: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
108
145
|
const pid = getTerminalPid();
|
|
109
146
|
logger.info('monitor pid', pid);
|
|
@@ -181,6 +218,34 @@ class UnderpostRun {
|
|
|
181
218
|
const { underpostRoot } = options;
|
|
182
219
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/.`);
|
|
183
220
|
},
|
|
221
|
+
promote: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
222
|
+
let [inputDeployId, inputEnv, inputReplicas] = path.split(',');
|
|
223
|
+
if (!inputEnv) inputEnv = 'production';
|
|
224
|
+
if (!inputReplicas) inputReplicas = 1;
|
|
225
|
+
if (inputDeployId === 'dd') {
|
|
226
|
+
for (const deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
227
|
+
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
228
|
+
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
229
|
+
UnderpostDeploy.API.switchTraffic(deployId, inputEnv, targetTraffic, inputReplicas);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(inputDeployId);
|
|
233
|
+
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
234
|
+
UnderpostDeploy.API.switchTraffic(inputDeployId, inputEnv, targetTraffic, inputReplicas);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
metrics: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
239
|
+
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
240
|
+
let hosts = [];
|
|
241
|
+
for (const deployId of deployList) {
|
|
242
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
243
|
+
hosts = hosts.concat(Object.keys(confServer));
|
|
244
|
+
}
|
|
245
|
+
shellExec(`node bin cluster --prom ${hosts.join(',')}`);
|
|
246
|
+
shellExec(`node bin cluster --grafana`);
|
|
247
|
+
},
|
|
248
|
+
|
|
184
249
|
cluster: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
185
250
|
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
186
251
|
const env = 'production';
|
|
@@ -216,25 +281,23 @@ class UnderpostRun {
|
|
|
216
281
|
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
217
282
|
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
218
283
|
|
|
219
|
-
let
|
|
220
|
-
|
|
284
|
+
let checkStatusIteration = 0;
|
|
285
|
+
const checkStatusIterationMsDelay = 1000;
|
|
286
|
+
const iteratorTag = `[${deployId}-${env}-${targetTraffic}]`;
|
|
287
|
+
logger.info('Deployment init', { deployId, env, targetTraffic, checkStatusIterationMsDelay });
|
|
221
288
|
|
|
222
289
|
while (!UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready) {
|
|
223
|
-
await timer(
|
|
224
|
-
|
|
225
|
-
logger.info(
|
|
290
|
+
await timer(checkStatusIterationMsDelay);
|
|
291
|
+
checkStatusIteration++;
|
|
292
|
+
logger.info(
|
|
293
|
+
`${iteratorTag} | Deployment in progress... | Delay number check iterations: ${checkStatusIteration}`,
|
|
294
|
+
);
|
|
226
295
|
}
|
|
227
296
|
|
|
228
|
-
logger.info(
|
|
297
|
+
logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
|
|
229
298
|
|
|
230
|
-
|
|
299
|
+
UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
|
|
231
300
|
|
|
232
|
-
shellExec(
|
|
233
|
-
`node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${
|
|
234
|
-
options.replicas ? options.replicas : 1
|
|
235
|
-
} ${deployId} ${env}`,
|
|
236
|
-
);
|
|
237
|
-
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
238
301
|
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
|
|
239
302
|
},
|
|
240
303
|
'tf-vae-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
@@ -15,7 +15,6 @@ import { DefaultParams } from './components/default/CommonDefault.js';
|
|
|
15
15
|
import { SocketIo } from './components/core/SocketIo.js';
|
|
16
16
|
import { SocketIoDefault } from './components/default/SocketIoDefault.js';
|
|
17
17
|
import { ElementsDefault } from './components/default/ElementsDefault.js';
|
|
18
|
-
import { Scroll } from './components/core/Scroll.js';
|
|
19
18
|
import { CssDefaultDark, CssDefaultLight } from './components/default/CssDefault.js';
|
|
20
19
|
|
|
21
20
|
const htmlMainBody = async () => {
|
|
@@ -39,7 +38,6 @@ window.onload = () =>
|
|
|
39
38
|
await LogInDefault();
|
|
40
39
|
await LogOutDefault();
|
|
41
40
|
await SignUpDefault();
|
|
42
|
-
await Scroll.pullTopRefresh();
|
|
43
41
|
await Keyboard.Init({ callBackTime: DefaultParams.EVENT_CALLBACK_TIME });
|
|
44
42
|
},
|
|
45
43
|
});
|
|
@@ -10,7 +10,7 @@ import { Modal } from './Modal.js';
|
|
|
10
10
|
import { NotificationManager } from './NotificationManager.js';
|
|
11
11
|
import { Translate } from './Translate.js';
|
|
12
12
|
import { Validator } from './Validator.js';
|
|
13
|
-
import { append, htmls, s } from './VanillaJs.js';
|
|
13
|
+
import { append, getProxyPath, htmls, s } from './VanillaJs.js';
|
|
14
14
|
|
|
15
15
|
const Account = {
|
|
16
16
|
UpdateEvent: {},
|
|
@@ -103,7 +103,11 @@ const Account = {
|
|
|
103
103
|
e.preventDefault();
|
|
104
104
|
const result = await UserService.post({
|
|
105
105
|
id: 'mailer/verify-email',
|
|
106
|
-
body: {
|
|
106
|
+
body: {
|
|
107
|
+
email: s(`.account-email`).value,
|
|
108
|
+
hostname: `${location.hostname}`,
|
|
109
|
+
proxyPath: getProxyPath(),
|
|
110
|
+
},
|
|
107
111
|
});
|
|
108
112
|
NotificationManager.Push({
|
|
109
113
|
html: result.status === 'error' ? result.message : Translate.Render(`email send`),
|
|
@@ -7,7 +7,7 @@ import { Modal, renderViewTitle } from './Modal.js';
|
|
|
7
7
|
import { DocumentService } from '../../services/document/document.service.js';
|
|
8
8
|
import { CoreService, getApiBaseUrl } from '../../services/core/core.service.js';
|
|
9
9
|
import { loggerFactory } from './Logger.js';
|
|
10
|
-
import { imageShimmer, renderCssAttr } from './Css.js';
|
|
10
|
+
import { imageShimmer, renderChessPattern, renderCssAttr, styleFactory } from './Css.js';
|
|
11
11
|
|
|
12
12
|
const logger = loggerFactory(import.meta);
|
|
13
13
|
|
|
@@ -114,7 +114,6 @@ const Content = {
|
|
|
114
114
|
width: '100%',
|
|
115
115
|
border: 'none',
|
|
116
116
|
};
|
|
117
|
-
options.style = `style="${renderCssAttr(options)}"`;
|
|
118
117
|
if (!options.class) options.class = ``;
|
|
119
118
|
const { container, file } = options;
|
|
120
119
|
const ext = file.name.split('.')[file.name.split('.').length - 1];
|
|
@@ -126,7 +125,7 @@ const Content = {
|
|
|
126
125
|
const content = options.url
|
|
127
126
|
? await CoreService.getRaw({ url: options.url })
|
|
128
127
|
: await getRawContentFile(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
129
|
-
render += html`<div class="${options.class}" ${options.style}>${marked.parse(content)}</div>`;
|
|
128
|
+
render += html`<div class="${options.class}" ${styleFactory(options.style)}>${marked.parse(content)}</div>`;
|
|
130
129
|
}
|
|
131
130
|
|
|
132
131
|
break;
|
|
@@ -135,13 +134,18 @@ const Content = {
|
|
|
135
134
|
case 'jpeg':
|
|
136
135
|
case 'webp':
|
|
137
136
|
case 'svg':
|
|
137
|
+
case 'gif':
|
|
138
138
|
case 'png': {
|
|
139
139
|
const url = options.url
|
|
140
140
|
? options.url
|
|
141
141
|
: file._id
|
|
142
142
|
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
143
143
|
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
144
|
-
const imgRender = html`<img
|
|
144
|
+
const imgRender = html`<img
|
|
145
|
+
class="in ${options.class}"
|
|
146
|
+
${styleFactory(options.style, `${renderChessPattern(50)}`)}
|
|
147
|
+
src="${url}"
|
|
148
|
+
/>`;
|
|
145
149
|
render += imgRender;
|
|
146
150
|
break;
|
|
147
151
|
}
|
|
@@ -153,14 +157,14 @@ const Content = {
|
|
|
153
157
|
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
154
158
|
render += html`<iframe
|
|
155
159
|
class="in ${options.class} iframe-${options.idModal}"
|
|
156
|
-
${options.style}
|
|
160
|
+
${styleFactory(options.style)}
|
|
157
161
|
src="${url}"
|
|
158
162
|
></iframe>`;
|
|
159
163
|
break;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
case 'json':
|
|
163
|
-
render += html`<pre class="in ${options.class}" ${options.style}>
|
|
167
|
+
render += html`<pre class="in ${options.class}" ${styleFactory(options.style)}>
|
|
164
168
|
${JSON.stringify(
|
|
165
169
|
JSON.parse(
|
|
166
170
|
options.url
|
|
@@ -174,7 +178,7 @@ const Content = {
|
|
|
174
178
|
break;
|
|
175
179
|
|
|
176
180
|
default:
|
|
177
|
-
render += html`<div class="in ${options.class}" ${options.style}>
|
|
181
|
+
render += html`<div class="in ${options.class}" ${styleFactory(options.style)}>
|
|
178
182
|
${options.url
|
|
179
183
|
? await CoreService.getRaw({ url: options.url })
|
|
180
184
|
: await getRawContentFile(getBlobFromUint8ArrayFile(file.data.data, file.mimetype))}
|
|
@@ -1026,7 +1026,8 @@ const imageShimmer = () => html`<div
|
|
|
1026
1026
|
</div>
|
|
1027
1027
|
</div>`;
|
|
1028
1028
|
|
|
1029
|
-
const renderChessPattern = (
|
|
1029
|
+
const renderChessPattern = (patternSize = 20) =>
|
|
1030
|
+
`background: repeating-conic-gradient(#808080 0 25%, #0000 0 50%) 50% / ${patternSize}px ${patternSize}px`;
|
|
1030
1031
|
|
|
1031
1032
|
const extractBackgroundImageUrl = (element) => {
|
|
1032
1033
|
const style = window.getComputedStyle(element);
|
|
@@ -1044,6 +1045,8 @@ const simpleIconsRender = (selector) => {
|
|
|
1044
1045
|
});
|
|
1045
1046
|
};
|
|
1046
1047
|
|
|
1048
|
+
const styleFactory = (payload, plain = '') => `style="${renderCssAttr({ style: payload })} ${plain}"`;
|
|
1049
|
+
|
|
1047
1050
|
export {
|
|
1048
1051
|
Css,
|
|
1049
1052
|
Themes,
|
|
@@ -1083,4 +1086,5 @@ export {
|
|
|
1083
1086
|
lightenHex,
|
|
1084
1087
|
darkenHex,
|
|
1085
1088
|
adjustHex,
|
|
1089
|
+
styleFactory,
|
|
1086
1090
|
};
|
|
@@ -359,4 +359,9 @@ const InputFile = {
|
|
|
359
359
|
},
|
|
360
360
|
};
|
|
361
361
|
|
|
362
|
-
|
|
362
|
+
function isTextInputFocused() {
|
|
363
|
+
const active = document.activeElement;
|
|
364
|
+
return active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export { Input, InputFile, fileFormDataFactory, getSrcFromFileData, getFileFromFileData, isTextInputFocused };
|
|
@@ -8,7 +8,7 @@ import { Webhook } from './Webhook.js';
|
|
|
8
8
|
const LogOut = {
|
|
9
9
|
Event: {},
|
|
10
10
|
Trigger: async function (options) {
|
|
11
|
-
LogIn.
|
|
11
|
+
LogIn.cleanMainUser();
|
|
12
12
|
await Webhook.unregister();
|
|
13
13
|
for (const eventKey of Object.keys(this.Event)) await this.Event[eventKey](options);
|
|
14
14
|
if (s(`.session`))
|
|
@@ -28,7 +28,7 @@ import { setDocTitle, closeModalRouteChangeEvent, handleModalViewRoute } from '.
|
|
|
28
28
|
import { NotificationManager } from './NotificationManager.js';
|
|
29
29
|
import { EventsUI } from './EventsUI.js';
|
|
30
30
|
import { Translate } from './Translate.js';
|
|
31
|
-
import { Input } from './Input.js';
|
|
31
|
+
import { Input, isTextInputFocused } from './Input.js';
|
|
32
32
|
import { Validator } from './Validator.js';
|
|
33
33
|
import { DropDown } from './DropDown.js';
|
|
34
34
|
import { Keyboard } from './Keyboard.js';
|
|
@@ -186,7 +186,7 @@ const Modal = {
|
|
|
186
186
|
`.default-slide-menu-top-bar-fix-title-container`,
|
|
187
187
|
html`
|
|
188
188
|
<div class="inl default-slide-menu-top-bar-fix-title-container-text">
|
|
189
|
-
${options.RouterInstance.
|
|
189
|
+
${options.RouterInstance.BannerAppTemplate}
|
|
190
190
|
</div>
|
|
191
191
|
`,
|
|
192
192
|
);
|
|
@@ -502,7 +502,7 @@ const Modal = {
|
|
|
502
502
|
class="abs modal slide-menu-top-bar-fix"
|
|
503
503
|
style="height: ${options.heightTopBar}px; top: 0px"
|
|
504
504
|
>
|
|
505
|
-
<a class="a-link-top-banner">
|
|
505
|
+
<a class="a-link-top-banner fl">
|
|
506
506
|
<div class="inl">${await options.slideMenuTopBarBannerFix()}</div></a
|
|
507
507
|
>
|
|
508
508
|
</div>`
|
|
@@ -608,6 +608,7 @@ const Modal = {
|
|
|
608
608
|
}),
|
|
609
609
|
);
|
|
610
610
|
s(`.search-result-btn-${result.routerId}`).onclick = () => {
|
|
611
|
+
if (!s(`.html-${searchBoxHistoryId}`) || !s(`.html-${searchBoxHistoryId}`).hasChildNodes()) return;
|
|
611
612
|
s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
|
|
612
613
|
`main-btn-menu-active`,
|
|
613
614
|
);
|
|
@@ -621,6 +622,7 @@ const Modal = {
|
|
|
621
622
|
};
|
|
622
623
|
|
|
623
624
|
const getResultSearchBox = (validatorData) => {
|
|
625
|
+
if (!s(`.html-${searchBoxHistoryId}`) || !s(`.html-${searchBoxHistoryId}`).hasChildNodes()) return;
|
|
624
626
|
const { model, id } = validatorData;
|
|
625
627
|
switch (model) {
|
|
626
628
|
case 'search-box':
|
|
@@ -998,6 +1000,7 @@ const Modal = {
|
|
|
998
1000
|
['Alt', 'k'],
|
|
999
1001
|
],
|
|
1000
1002
|
eventCallBack: () => {
|
|
1003
|
+
if (isTextInputFocused()) return;
|
|
1001
1004
|
if (s(`.top-bar-search-box`)) {
|
|
1002
1005
|
if (s(`.main-body-btn-ui-close`).classList.contains('hide')) {
|
|
1003
1006
|
s(`.main-body-btn-ui-open`).click();
|
|
@@ -1157,7 +1160,7 @@ const Modal = {
|
|
|
1157
1160
|
if (s(`.slide-menu-top-bar-fix`)) {
|
|
1158
1161
|
htmls(
|
|
1159
1162
|
`.slide-menu-top-bar-fix`,
|
|
1160
|
-
html`<a class="a-link-top-banner">${await options.slideMenuTopBarBannerFix()}</a>`,
|
|
1163
|
+
html`<a class="a-link-top-banner fl">${await options.slideMenuTopBarBannerFix()}</a>`,
|
|
1161
1164
|
);
|
|
1162
1165
|
Modal.setTopBannerLink();
|
|
1163
1166
|
}
|
|
@@ -7,7 +7,7 @@ import { LogIn } from './LogIn.js';
|
|
|
7
7
|
import { NotificationManager } from './NotificationManager.js';
|
|
8
8
|
import { Translate } from './Translate.js';
|
|
9
9
|
import { Validator } from './Validator.js';
|
|
10
|
-
import { getQueryParams, s } from './VanillaJs.js';
|
|
10
|
+
import { getProxyPath, getQueryParams, s } from './VanillaJs.js';
|
|
11
11
|
|
|
12
12
|
const Recover = {
|
|
13
13
|
Event: {},
|
|
@@ -80,7 +80,10 @@ const Recover = {
|
|
|
80
80
|
}
|
|
81
81
|
switch (mode) {
|
|
82
82
|
case 'recover-verify-email': {
|
|
83
|
-
const result = await UserService.post({
|
|
83
|
+
const result = await UserService.post({
|
|
84
|
+
id: 'recover-verify-email',
|
|
85
|
+
body: { ...body, proxyPath: getProxyPath(), hostname: `${location.hostname}` },
|
|
86
|
+
});
|
|
84
87
|
NotificationManager.Push({
|
|
85
88
|
html:
|
|
86
89
|
result.status === 'error' ? result.message : Translate.Render(`${result.status}-recover-verify-email`),
|