underpost 2.8.85 → 2.8.87
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 +7 -2
- package/.env.production +7 -2
- package/.env.test +7 -2
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
- package/.github/workflows/release.cd.yml +37 -0
- package/README.md +7 -24
- package/bin/build.js +1 -0
- package/bin/db.js +1 -3
- package/bin/deploy.js +43 -368
- package/bin/file.js +16 -3
- package/bin/util.js +1 -56
- package/cli.md +46 -21
- package/conf.js +3 -3
- 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/deployment/mongo-express/deployment.yaml +12 -12
- 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/nvim.sh +91 -0
- package/manifests/maas/ssh-cluster-info.sh +14 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/package.json +3 -12
- package/src/api/file/file.service.js +28 -8
- package/src/api/user/user.router.js +31 -5
- package/src/api/user/user.service.js +11 -38
- package/src/cli/cluster.js +45 -25
- package/src/cli/cron.js +12 -45
- package/src/cli/db.js +149 -19
- package/src/cli/deploy.js +41 -110
- package/src/cli/fs.js +1 -0
- package/src/cli/index.js +24 -7
- package/src/cli/monitor.js +1 -4
- package/src/cli/repository.js +15 -6
- package/src/cli/run.js +94 -16
- 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/CssCore.js +12 -0
- package/src/client/components/core/FullScreen.js +19 -28
- package/src/client/components/core/Input.js +7 -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 +32 -43
- package/src/client/components/core/ObjectLayerEngine.js +229 -4
- package/src/client/components/core/ObjectLayerEngineModal.js +441 -0
- 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/ToggleSwitch.js +15 -1
- 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/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
- package/src/index.js +1 -1
- package/src/mailer/MailerProvider.js +37 -0
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build-live.js +1 -1
- package/src/server/client-build.js +4 -12
- package/src/server/client-dev-server.js +1 -1
- package/src/server/client-icons.js +6 -78
- package/src/server/conf.js +83 -408
- package/src/server/proxy.js +2 -3
- package/src/server/runtime.js +1 -2
- package/src/server/start.js +5 -5
- package/test/api.test.js +3 -2
- package/docker-compose.yml +0 -67
- package/prometheus.yml +0 -36
package/src/cli/deploy.js
CHANGED
|
@@ -22,13 +22,13 @@ const logger = loggerFactory(import.meta);
|
|
|
22
22
|
class UnderpostDeploy {
|
|
23
23
|
static NETWORK = {};
|
|
24
24
|
static API = {
|
|
25
|
-
sync(deployList, { versions, replicas,
|
|
25
|
+
sync(deployList, { versions, replicas, node }) {
|
|
26
26
|
const deployGroupId = 'dd.router';
|
|
27
27
|
fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
|
|
28
28
|
const totalPods = deployList.split(',').length * versions.split(',').length * parseInt(replicas);
|
|
29
29
|
const limitFactor = 0.8;
|
|
30
30
|
const reserveFactor = 0.05;
|
|
31
|
-
const resources = UnderpostCluster.API.getResourcesCapacity(
|
|
31
|
+
const resources = UnderpostCluster.API.getResourcesCapacity(node);
|
|
32
32
|
const memory = parseInt(resources.memory.value / totalPods);
|
|
33
33
|
const cpu = parseInt(resources.cpu.value / totalPods);
|
|
34
34
|
UnderpostRootEnv.API.set(
|
|
@@ -49,7 +49,7 @@ class UnderpostDeploy {
|
|
|
49
49
|
const initEnvObj = dotenv.parse(fs.readFileSync(initEnvPath, 'utf8'));
|
|
50
50
|
process.env.PORT = initEnvObj.PORT;
|
|
51
51
|
process.env.NODE_ENV = env;
|
|
52
|
-
await Config.build(
|
|
52
|
+
await Config.build('proxy', deployList);
|
|
53
53
|
return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
|
|
54
54
|
},
|
|
55
55
|
deploymentYamlServiceFactory({ deployId, env, port, deploymentVersions }) {
|
|
@@ -242,12 +242,12 @@ spec:
|
|
|
242
242
|
cert: false,
|
|
243
243
|
versions: '',
|
|
244
244
|
traffic: '',
|
|
245
|
-
dashboardUpdate: false,
|
|
246
245
|
replicas: '',
|
|
246
|
+
node: '',
|
|
247
247
|
restoreHosts: false,
|
|
248
248
|
disableUpdateDeployment: false,
|
|
249
249
|
infoTraffic: false,
|
|
250
|
-
|
|
250
|
+
etcHosts: false,
|
|
251
251
|
},
|
|
252
252
|
) {
|
|
253
253
|
if (options.infoUtil === true)
|
|
@@ -311,31 +311,26 @@ Password: <Your Key>
|
|
|
311
311
|
deployId,
|
|
312
312
|
env,
|
|
313
313
|
traffic: UnderpostDeploy.API.getCurrentTraffic(deployId),
|
|
314
|
+
router: await UnderpostDeploy.API.routerFactory(deployId, env),
|
|
315
|
+
pods: await UnderpostDeploy.API.get(deployId),
|
|
314
316
|
});
|
|
315
317
|
}
|
|
316
318
|
return;
|
|
317
319
|
}
|
|
318
|
-
if (options.rebuildClientsBundle === true) await UnderpostDeploy.API.rebuildClientsBundle(deployList);
|
|
319
320
|
if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
|
|
320
321
|
if (!options.replicas) options.replicas = 1;
|
|
321
322
|
if (options.sync) UnderpostDeploy.API.sync(deployList, options);
|
|
322
323
|
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
|
-
);
|
|
324
|
+
if (options.infoRouter === true) {
|
|
325
|
+
logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
UnderpostDeploy.API.configMap(env);
|
|
330
329
|
let renderHosts = '';
|
|
331
|
-
let
|
|
332
|
-
const etcHost = (
|
|
333
|
-
concat,
|
|
334
|
-
) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
335
|
-
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
330
|
+
let etcHosts = [];
|
|
336
331
|
if (options.restoreHosts === true) {
|
|
337
|
-
|
|
338
|
-
|
|
332
|
+
const factoryResult = UnderpostDeploy.API.etcHostFactory(etcHosts);
|
|
333
|
+
renderHosts = factoryResult.renderHosts;
|
|
339
334
|
logger.info(renderHosts);
|
|
340
335
|
return;
|
|
341
336
|
}
|
|
@@ -364,7 +359,7 @@ Password: <Your Key>
|
|
|
364
359
|
for (const host of Object.keys(confServer)) {
|
|
365
360
|
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
366
361
|
if (env === 'production' && options.cert === true) shellExec(`sudo kubectl delete Certificate ${host}`);
|
|
367
|
-
if (!options.remove === true && env === 'development')
|
|
362
|
+
if (!options.remove === true && env === 'development') etcHosts.push(host);
|
|
368
363
|
}
|
|
369
364
|
|
|
370
365
|
const manifestsPath =
|
|
@@ -379,24 +374,9 @@ Password: <Your Key>
|
|
|
379
374
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
380
375
|
}
|
|
381
376
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
switch (env) {
|
|
386
|
-
case 'development':
|
|
387
|
-
renderHosts = etcHost(concatHots);
|
|
388
|
-
fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
389
|
-
|
|
390
|
-
break;
|
|
391
|
-
|
|
392
|
-
default:
|
|
393
|
-
break;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
break;
|
|
397
|
-
|
|
398
|
-
default:
|
|
399
|
-
break;
|
|
377
|
+
if (options.etcHosts === true) {
|
|
378
|
+
const factoryResult = UnderpostDeploy.API.etcHostFactory(etcHosts);
|
|
379
|
+
renderHosts = factoryResult.renderHosts;
|
|
400
380
|
}
|
|
401
381
|
if (renderHosts)
|
|
402
382
|
logger.info(
|
|
@@ -435,23 +415,6 @@ Password: <Your Key>
|
|
|
435
415
|
|
|
436
416
|
return result;
|
|
437
417
|
},
|
|
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
418
|
resourcesFactory() {
|
|
456
419
|
return {
|
|
457
420
|
requests: {
|
|
@@ -465,60 +428,6 @@ node bin/deploy build-full-client ${deployId}
|
|
|
465
428
|
totalPods: UnderpostRootEnv.API.get('total-pods'),
|
|
466
429
|
};
|
|
467
430
|
},
|
|
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
431
|
existsContainerFile({ podName, path }) {
|
|
523
432
|
return JSON.parse(
|
|
524
433
|
shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
|
|
@@ -548,6 +457,28 @@ node bin/deploy build-full-client ${deployId}
|
|
|
548
457
|
}
|
|
549
458
|
return { ready: notReadyPods.length === 0, notReadyPods, readyPods };
|
|
550
459
|
},
|
|
460
|
+
configMap(env) {
|
|
461
|
+
shellExec(`kubectl delete configmap underpost-config`);
|
|
462
|
+
shellExec(
|
|
463
|
+
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
464
|
+
);
|
|
465
|
+
},
|
|
466
|
+
switchTraffic(deployId, env, targetTraffic, replicas = 1) {
|
|
467
|
+
UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
|
|
468
|
+
shellExec(
|
|
469
|
+
`node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} ${deployId} ${env}`,
|
|
470
|
+
);
|
|
471
|
+
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
472
|
+
},
|
|
473
|
+
etcHostFactory(hosts = []) {
|
|
474
|
+
const renderHosts = `127.0.0.1 ${hosts.join(
|
|
475
|
+
' ',
|
|
476
|
+
)} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
477
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
478
|
+
|
|
479
|
+
fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
480
|
+
return { renderHosts };
|
|
481
|
+
},
|
|
551
482
|
};
|
|
552
483
|
}
|
|
553
484
|
|
package/src/cli/fs.js
CHANGED
|
@@ -61,6 +61,7 @@ class UnderpostFileStorage {
|
|
|
61
61
|
await UnderpostFileStorage.API.pull(_path, options);
|
|
62
62
|
} else logger.warn(`Pull path already exists`, _path);
|
|
63
63
|
}
|
|
64
|
+
shellExec(`cd ${path} && git init && git add . && git commit -m "Base pull state"`);
|
|
64
65
|
} else {
|
|
65
66
|
const files =
|
|
66
67
|
options.git === true
|
package/src/cli/index.js
CHANGED
|
@@ -22,7 +22,9 @@ program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`
|
|
|
22
22
|
// 'new' command: Create a new project
|
|
23
23
|
program
|
|
24
24
|
.command('new')
|
|
25
|
-
.argument('<app-name>', 'The name of the application to create.')
|
|
25
|
+
.argument('<app-name>', 'The name or deploy-id of the application to create.')
|
|
26
|
+
.option('--deploy-id', 'Crete deploy ID conf env files')
|
|
27
|
+
.option('--dev', 'Sets the development cli context')
|
|
26
28
|
.description('Initializes a new Underpost project with a predefined structure.')
|
|
27
29
|
.action(Underpost.repo.new);
|
|
28
30
|
|
|
@@ -123,6 +125,11 @@ program
|
|
|
123
125
|
.option('--full', 'Initializes the cluster with all available statefulsets and services.')
|
|
124
126
|
.option('--ns-use <ns-name>', 'Switches the current Kubernetes context to the specified namespace.')
|
|
125
127
|
.option('--kubeadm', 'Initializes the cluster using kubeadm for control plane management.')
|
|
128
|
+
.option('--grafana', 'Initializes the cluster with a Grafana deployment.')
|
|
129
|
+
.option(
|
|
130
|
+
'--prom [hosts]',
|
|
131
|
+
'Initializes the cluster with a Prometheus Operator deployment and monitor scrap for specified hosts.',
|
|
132
|
+
)
|
|
126
133
|
.option('--dev', 'Initializes a development-specific cluster configuration.')
|
|
127
134
|
.option('--list-pods', 'Displays detailed information about all pods.')
|
|
128
135
|
.option('--info-capacity', 'Displays the current total machine capacity information.')
|
|
@@ -151,22 +158,19 @@ program
|
|
|
151
158
|
.option('--expose', 'Exposes services matching the provided deployment ID list.')
|
|
152
159
|
.option('--info-util', 'Displays useful `kubectl` utility management commands.')
|
|
153
160
|
.option('--cert', 'Resets TLS/SSL certificate secrets for deployments.')
|
|
161
|
+
.option('--node <node>', 'Sets optional node for deployment operations.')
|
|
154
162
|
.option(
|
|
155
163
|
'--build-manifest',
|
|
156
164
|
'Builds Kubernetes YAML manifests, including deployments, services, proxies, and secrets.',
|
|
157
165
|
)
|
|
158
|
-
.option('--dashboard-update', 'Updates dashboard instance data with the current router configuration.')
|
|
159
166
|
.option('--replicas <replicas>', 'Sets a custom number of replicas for deployments.')
|
|
160
167
|
.option('--versions <deployment-versions>', 'A comma-separated list of custom deployment versions.')
|
|
161
168
|
.option('--traffic <traffic-versions>', 'A comma-separated list of custom deployment traffic weights.')
|
|
162
169
|
.option('--disable-update-deployment', 'Disables updates to deployments.')
|
|
163
170
|
.option('--info-traffic', 'Retrieves traffic configuration from current resource deployments.')
|
|
164
171
|
.option('--kubeadm', 'Enables the kubeadm context for deployment operations.')
|
|
172
|
+
.option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
|
|
165
173
|
.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
174
|
.description('Manages application deployments, defaulting to deploying development pods.')
|
|
171
175
|
.action(Underpost.deploy.callback);
|
|
172
176
|
|
|
@@ -240,6 +244,20 @@ program
|
|
|
240
244
|
.description('Manages database operations, including import, export, and collection management.')
|
|
241
245
|
.action(Underpost.db.callback);
|
|
242
246
|
|
|
247
|
+
program
|
|
248
|
+
.command('metadata')
|
|
249
|
+
.argument('[deploy-id]', 'The deployment ID to manage metadata.')
|
|
250
|
+
.argument('[host]', 'The host to manage metadata.')
|
|
251
|
+
.argument('[path]', 'The path to manage metadata.')
|
|
252
|
+
.option('--import', 'Imports from local storage.')
|
|
253
|
+
.option('--export', 'Exports to local storage.')
|
|
254
|
+
.option('--crons', 'Apply to cron data collection')
|
|
255
|
+
.option('--instances', 'Apply to instance data collection')
|
|
256
|
+
.option('--generate', 'Generate cluster metadata')
|
|
257
|
+
.option('--itc', 'Apply under container execution context')
|
|
258
|
+
.description('Manages cluster metadata operations, including import and export.')
|
|
259
|
+
.action(Underpost.db.clusterMetadataBackupCallback);
|
|
260
|
+
|
|
243
261
|
// 'script' command: Execute scripts
|
|
244
262
|
program
|
|
245
263
|
.command('script')
|
|
@@ -268,7 +286,6 @@ program
|
|
|
268
286
|
.option('--itc', 'Executes cron jobs within the container execution context.')
|
|
269
287
|
.option('--init', 'Initializes cron jobs for the default deployment ID.')
|
|
270
288
|
.option('--git', 'Uploads cron job configurations to GitHub.')
|
|
271
|
-
.option('--dashboard-update', 'Updates dashboard cron data with the current job configurations.')
|
|
272
289
|
.description('Manages cron jobs, including initialization, execution, and configuration updates.')
|
|
273
290
|
.action(Underpost.cron.callback);
|
|
274
291
|
|
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
|
@@ -5,6 +5,7 @@ import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
6
|
import { getNpmRootPath } from '../server/conf.js';
|
|
7
7
|
import UnderpostStartUp from '../server/start.js';
|
|
8
|
+
import { Config } from '../server/conf.js';
|
|
8
9
|
|
|
9
10
|
dotenv.config();
|
|
10
11
|
|
|
@@ -80,24 +81,32 @@ class UnderpostRepository {
|
|
|
80
81
|
);
|
|
81
82
|
},
|
|
82
83
|
|
|
83
|
-
new(repositoryName) {
|
|
84
|
+
new(repositoryName, options = { dev: false, deployId: false }) {
|
|
84
85
|
return new Promise(async (resolve, reject) => {
|
|
85
86
|
try {
|
|
86
87
|
await logger.setUpInfo();
|
|
88
|
+
actionInitLog();
|
|
87
89
|
if (repositoryName === 'service')
|
|
88
90
|
return resolve(
|
|
89
91
|
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
|
|
90
92
|
);
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
+
if (options.deployId === true) return Config.deployIdFactory(repositoryName);
|
|
94
|
+
const npmRoot = getNpmRootPath();
|
|
95
|
+
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
93
96
|
const destFolder = `./${repositoryName}`;
|
|
94
97
|
logger.info('Note: This process may take several minutes to complete');
|
|
95
98
|
logger.info('build app', { destFolder });
|
|
96
99
|
if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
|
|
97
100
|
fs.mkdirSync(destFolder, { recursive: true });
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
if (!options.dev) {
|
|
102
|
+
fs.copySync(underpostRoot, destFolder);
|
|
103
|
+
fs.writeFileSync(
|
|
104
|
+
`${destFolder}/.gitignore`,
|
|
105
|
+
fs.readFileSync(`${underpostRoot}/.dockerignore`, 'utf8'),
|
|
106
|
+
'utf8',
|
|
107
|
+
);
|
|
108
|
+
shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
|
|
109
|
+
}
|
|
101
110
|
shellExec(`cd ${destFolder} && npm run build`);
|
|
102
111
|
shellExec(`cd ${destFolder} && npm run dev`);
|
|
103
112
|
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`,
|
|
@@ -69,12 +72,24 @@ class UnderpostRun {
|
|
|
69
72
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
70
73
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
|
|
71
74
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
|
|
75
|
+
const mongoHosts = ['mongodb-0.mongodb-service'];
|
|
72
76
|
shellExec(
|
|
73
|
-
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${
|
|
77
|
+
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${mongoHosts.join(
|
|
78
|
+
',',
|
|
79
|
+
)} --pull-image`,
|
|
74
80
|
);
|
|
75
81
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
|
|
76
82
|
shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
|
|
77
83
|
shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
|
|
84
|
+
{
|
|
85
|
+
const hostListenResult = UnderpostDeploy.API.etcHostFactory(mongoHosts);
|
|
86
|
+
logger.info(hostListenResult.renderHosts);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
'ssh-cluster-info': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
90
|
+
const { underpostRoot } = options;
|
|
91
|
+
shellExec(`chmod +x ${underpostRoot}/manifests/maas/ssh-cluster-info.sh`);
|
|
92
|
+
shellExec(`${underpostRoot}/manifests/maas/ssh-cluster-info.sh`);
|
|
78
93
|
},
|
|
79
94
|
'cyberia-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
80
95
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
@@ -93,6 +108,25 @@ class UnderpostRun {
|
|
|
93
108
|
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
94
109
|
shellExec(`${baseCommand} push . underpostnet/engine`);
|
|
95
110
|
},
|
|
111
|
+
clean: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
112
|
+
shellCd(path ?? `/home/dd/engine`);
|
|
113
|
+
shellExec(`node bin/deploy clean-core-repo`);
|
|
114
|
+
},
|
|
115
|
+
pull: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
116
|
+
shellCd(`/home/dd/engine`);
|
|
117
|
+
shellExec(`node bin/deploy clean-core-repo`);
|
|
118
|
+
shellExec(`underpost pull . underpostnet/engine`);
|
|
119
|
+
shellExec(`underpost pull engine-private underpostnet/engine-private`, { silent: true });
|
|
120
|
+
},
|
|
121
|
+
'release-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
122
|
+
actionInitLog();
|
|
123
|
+
shellExec(`underpost --version`);
|
|
124
|
+
shellCd(`/home/dd/engine`);
|
|
125
|
+
for (const _deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
126
|
+
const deployId = _deployId.trim();
|
|
127
|
+
shellExec(`underpost run deploy ${deployId}`, { async: true });
|
|
128
|
+
}
|
|
129
|
+
},
|
|
96
130
|
'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
97
131
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
98
132
|
shellCd('/home/dd/engine');
|
|
@@ -104,6 +138,24 @@ class UnderpostRun {
|
|
|
104
138
|
const { underpostRoot } = options;
|
|
105
139
|
shellExec(`node ${underpostRoot}/bin/vs ${path}`);
|
|
106
140
|
},
|
|
141
|
+
'dev-client': (_path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
142
|
+
let [deployId, hostpath, subConf, lite] = _path.split(',');
|
|
143
|
+
let [host, path] = hostpath.split('/');
|
|
144
|
+
if (!path) path = '/';
|
|
145
|
+
shellExec(`npm run dev-client ${deployId} ${host} ${path} ${subConf} static${lite === 'l' ? ' l' : ''}`);
|
|
146
|
+
},
|
|
147
|
+
'dev-api': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
148
|
+
let [deployId, subConf] = path.split(',');
|
|
149
|
+
shellExec(`npm run dev-api ${deployId} ${subConf}`);
|
|
150
|
+
},
|
|
151
|
+
'router-sync': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
152
|
+
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
153
|
+
const defaultPaht = ['dd', 'kind-control-plane'];
|
|
154
|
+
let [deployId, node] = path ? path.split(',') : defaultPaht;
|
|
155
|
+
deployId = deployId ?? defaultPaht[0];
|
|
156
|
+
node = node ?? defaultPaht[1];
|
|
157
|
+
shellExec(`${baseCommand} deploy --sync --node ${node} --build-manifest --info-router ${deployId} production`);
|
|
158
|
+
},
|
|
107
159
|
monitor: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
108
160
|
const pid = getTerminalPid();
|
|
109
161
|
logger.info('monitor pid', pid);
|
|
@@ -181,6 +233,34 @@ class UnderpostRun {
|
|
|
181
233
|
const { underpostRoot } = options;
|
|
182
234
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/.`);
|
|
183
235
|
},
|
|
236
|
+
promote: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
237
|
+
let [inputDeployId, inputEnv, inputReplicas] = path.split(',');
|
|
238
|
+
if (!inputEnv) inputEnv = 'production';
|
|
239
|
+
if (!inputReplicas) inputReplicas = 1;
|
|
240
|
+
if (inputDeployId === 'dd') {
|
|
241
|
+
for (const deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
242
|
+
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
243
|
+
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
244
|
+
UnderpostDeploy.API.switchTraffic(deployId, inputEnv, targetTraffic, inputReplicas);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(inputDeployId);
|
|
248
|
+
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
249
|
+
UnderpostDeploy.API.switchTraffic(inputDeployId, inputEnv, targetTraffic, inputReplicas);
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
metrics: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
254
|
+
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
255
|
+
let hosts = [];
|
|
256
|
+
for (const deployId of deployList) {
|
|
257
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
258
|
+
hosts = hosts.concat(Object.keys(confServer));
|
|
259
|
+
}
|
|
260
|
+
shellExec(`node bin cluster --prom ${hosts.join(',')}`);
|
|
261
|
+
shellExec(`node bin cluster --grafana`);
|
|
262
|
+
},
|
|
263
|
+
|
|
184
264
|
cluster: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
185
265
|
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
186
266
|
const env = 'production';
|
|
@@ -216,26 +296,24 @@ class UnderpostRun {
|
|
|
216
296
|
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
217
297
|
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
218
298
|
|
|
219
|
-
let
|
|
220
|
-
|
|
299
|
+
let checkStatusIteration = 0;
|
|
300
|
+
const checkStatusIterationMsDelay = 1000;
|
|
301
|
+
const iteratorTag = `[${deployId}-${env}-${targetTraffic}]`;
|
|
302
|
+
logger.info('Deployment init', { deployId, env, targetTraffic, checkStatusIterationMsDelay });
|
|
221
303
|
|
|
222
304
|
while (!UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready) {
|
|
223
|
-
await timer(
|
|
224
|
-
|
|
225
|
-
logger.info(
|
|
305
|
+
await timer(checkStatusIterationMsDelay);
|
|
306
|
+
checkStatusIteration++;
|
|
307
|
+
logger.info(
|
|
308
|
+
`${iteratorTag} | Deployment in progress... | Delay number check iterations: ${checkStatusIteration}`,
|
|
309
|
+
);
|
|
226
310
|
}
|
|
227
311
|
|
|
228
|
-
logger.info(
|
|
312
|
+
logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
|
|
229
313
|
|
|
230
|
-
|
|
314
|
+
UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
|
|
231
315
|
|
|
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
|
-
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
|
|
316
|
+
// shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
|
|
239
317
|
},
|
|
240
318
|
'tf-vae-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
241
319
|
const { underpostRoot } = options;
|
|
@@ -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))}
|