underpost 2.8.86 → 2.8.88

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.
Files changed (116) hide show
  1. package/.env.development +39 -2
  2. package/.env.production +42 -2
  3. package/.env.test +39 -2
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/npmpkg.ci.yml +1 -1
  6. package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -5
  7. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  8. package/.github/workflows/release.cd.yml +3 -3
  9. package/README.md +76 -2
  10. package/bin/build.js +5 -0
  11. package/bin/deploy.js +93 -27
  12. package/bin/file.js +8 -4
  13. package/bin/util.js +1 -56
  14. package/cli.md +16 -5
  15. package/conf.js +33 -7
  16. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  17. package/manifests/deployment/dd-test-development/deployment.yaml +174 -0
  18. package/manifests/deployment/dd-test-development/proxy.yaml +51 -0
  19. package/manifests/deployment/mongo-express/deployment.yaml +12 -12
  20. package/manifests/maas/nvim.sh +91 -0
  21. package/package.json +8 -15
  22. package/src/api/core/core.router.js +2 -1
  23. package/src/api/default/default.controller.js +6 -1
  24. package/src/api/default/default.router.js +6 -2
  25. package/src/api/default/default.service.js +10 -1
  26. package/src/api/document/document.controller.js +66 -0
  27. package/src/api/document/document.model.js +51 -0
  28. package/src/api/document/document.router.js +24 -0
  29. package/src/api/document/document.service.js +125 -0
  30. package/src/api/file/file.controller.js +15 -1
  31. package/src/api/file/file.router.js +2 -1
  32. package/src/api/file/file.service.js +28 -8
  33. package/src/api/test/test.router.js +1 -1
  34. package/src/api/user/postman_collection.json +216 -0
  35. package/src/api/user/user.controller.js +25 -60
  36. package/src/api/user/user.model.js +29 -7
  37. package/src/api/user/user.router.js +40 -8
  38. package/src/api/user/user.service.js +86 -35
  39. package/src/cli/baremetal.js +33 -3
  40. package/src/cli/cloud-init.js +11 -0
  41. package/src/cli/cluster.js +4 -23
  42. package/src/cli/cron.js +0 -1
  43. package/src/cli/db.js +0 -19
  44. package/src/cli/deploy.js +67 -52
  45. package/src/cli/fs.js +1 -0
  46. package/src/cli/index.js +9 -1
  47. package/src/cli/lxd.js +7 -0
  48. package/src/cli/repository.js +44 -6
  49. package/src/cli/run.js +56 -9
  50. package/src/cli/ssh.js +20 -6
  51. package/src/client/Default.index.js +42 -1
  52. package/src/client/components/core/Account.js +10 -2
  53. package/src/client/components/core/AgGrid.js +30 -8
  54. package/src/client/components/core/Auth.js +99 -56
  55. package/src/client/components/core/BtnIcon.js +3 -2
  56. package/src/client/components/core/CalendarCore.js +2 -3
  57. package/src/client/components/core/CommonJs.js +1 -2
  58. package/src/client/components/core/Content.js +15 -12
  59. package/src/client/components/core/Css.js +2 -1
  60. package/src/client/components/core/CssCore.js +18 -1
  61. package/src/client/components/core/Docs.js +5 -5
  62. package/src/client/components/core/FileExplorer.js +3 -3
  63. package/src/client/components/core/FullScreen.js +19 -28
  64. package/src/client/components/core/Input.js +22 -16
  65. package/src/client/components/core/JoyStick.js +2 -2
  66. package/src/client/components/core/LoadingAnimation.js +2 -2
  67. package/src/client/components/core/LogIn.js +16 -23
  68. package/src/client/components/core/LogOut.js +5 -1
  69. package/src/client/components/core/Logger.js +4 -1
  70. package/src/client/components/core/Modal.js +102 -87
  71. package/src/client/components/core/ObjectLayerEngine.js +229 -4
  72. package/src/client/components/core/ObjectLayerEngineModal.js +442 -0
  73. package/src/client/components/core/Pagination.js +207 -0
  74. package/src/client/components/core/Panel.js +10 -10
  75. package/src/client/components/core/PanelForm.js +130 -33
  76. package/src/client/components/core/Recover.js +2 -2
  77. package/src/client/components/core/Router.js +210 -34
  78. package/src/client/components/core/SignUp.js +1 -2
  79. package/src/client/components/core/Stream.js +1 -1
  80. package/src/client/components/core/ToggleSwitch.js +15 -1
  81. package/src/client/components/core/VanillaJs.js +3 -84
  82. package/src/client/components/core/Worker.js +2 -2
  83. package/src/client/components/default/LogInDefault.js +0 -6
  84. package/src/client/components/default/LogOutDefault.js +0 -16
  85. package/src/client/components/default/MenuDefault.js +97 -44
  86. package/src/client/components/default/RoutesDefault.js +5 -2
  87. package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
  88. package/src/client/services/core/core.service.js +8 -20
  89. package/src/client/services/default/default.management.js +115 -18
  90. package/src/client/services/default/default.service.js +13 -4
  91. package/src/client/services/document/document.service.js +97 -0
  92. package/src/client/services/file/file.service.js +2 -0
  93. package/src/client/services/test/test.service.js +3 -0
  94. package/src/client/services/user/user.management.js +6 -0
  95. package/src/client/services/user/user.service.js +15 -4
  96. package/src/client/ssr/Render.js +1 -1
  97. package/src/client/ssr/head/DefaultScripts.js +3 -0
  98. package/src/client/ssr/head/Seo.js +1 -0
  99. package/src/index.js +24 -2
  100. package/src/runtime/lampp/Lampp.js +89 -2
  101. package/src/runtime/xampp/Xampp.js +48 -1
  102. package/src/server/auth.js +519 -155
  103. package/src/server/backup.js +2 -2
  104. package/src/server/client-build-docs.js +1 -1
  105. package/src/server/client-build.js +4 -12
  106. package/src/server/client-icons.js +6 -78
  107. package/src/server/conf.js +144 -141
  108. package/src/server/process.js +2 -1
  109. package/src/server/proxy.js +1 -1
  110. package/src/server/runtime.js +136 -288
  111. package/src/server/ssl.js +1 -2
  112. package/src/server/ssr.js +85 -0
  113. package/src/server/start.js +4 -4
  114. package/src/server/valkey.js +2 -1
  115. package/test/api.test.js +3 -2
  116. package/bin/cyberia0.js +0 -78
package/src/cli/db.js CHANGED
@@ -177,25 +177,6 @@ class UnderpostDB {
177
177
  }`,
178
178
  );
179
179
  }
180
- if (false) {
181
- const containerBaseBackupPath = '/backup';
182
- let timeFolder = shellExec(
183
- `sudo kubectl exec -i ${podName} -- sh -c "cd ${containerBaseBackupPath} && ls -a"`,
184
- {
185
- stdout: true,
186
- disableLog: false,
187
- silent: true,
188
- },
189
- ).split(`\n`);
190
- timeFolder = timeFolder[timeFolder.length - 2];
191
- if (timeFolder === '..') {
192
- logger.warn(`Cannot backup available`, { timeFolder });
193
- } else {
194
- shellExec(
195
- `sudo kubectl cp ${nameSpace}/${podName}:${containerBaseBackupPath}/${timeFolder}/${dbName} ${_toNewBsonPath}`,
196
- );
197
- }
198
- }
199
180
  }
200
181
  break;
201
182
  }
package/src/cli/deploy.js CHANGED
@@ -12,7 +12,6 @@ import { loggerFactory } from '../server/logger.js';
12
12
  import { shellExec } from '../server/process.js';
13
13
  import fs from 'fs-extra';
14
14
  import dotenv from 'dotenv';
15
- import { DataBaseProvider } from '../db/DataBaseProvider.js';
16
15
  import UnderpostRootEnv from './env.js';
17
16
  import UnderpostCluster from './cluster.js';
18
17
  import Underpost from '../index.js';
@@ -22,13 +21,13 @@ const logger = loggerFactory(import.meta);
22
21
  class UnderpostDeploy {
23
22
  static NETWORK = {};
24
23
  static API = {
25
- sync(deployList, { versions, replicas, kubeadm = false }) {
24
+ sync(deployList, { versions, replicas, node }) {
26
25
  const deployGroupId = 'dd.router';
27
26
  fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
28
27
  const totalPods = deployList.split(',').length * versions.split(',').length * parseInt(replicas);
29
28
  const limitFactor = 0.8;
30
29
  const reserveFactor = 0.05;
31
- const resources = UnderpostCluster.API.getResourcesCapacity(kubeadm);
30
+ const resources = UnderpostCluster.API.getResourcesCapacity(node);
32
31
  const memory = parseInt(resources.memory.value / totalPods);
33
32
  const cpu = parseInt(resources.cpu.value / totalPods);
34
33
  UnderpostRootEnv.API.set(
@@ -49,7 +48,7 @@ class UnderpostDeploy {
49
48
  const initEnvObj = dotenv.parse(fs.readFileSync(initEnvPath, 'utf8'));
50
49
  process.env.PORT = initEnvObj.PORT;
51
50
  process.env.NODE_ENV = env;
52
- await Config.build(undefined, 'proxy', deployList);
51
+ await Config.build('proxy', deployList);
53
52
  return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
54
53
  },
55
54
  deploymentYamlServiceFactory({ deployId, env, port, deploymentVersions }) {
@@ -62,7 +61,7 @@ class UnderpostDeploy {
62
61
  )
63
62
  .join('');
64
63
  },
65
- deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas }) {
64
+ deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image }) {
66
65
  return `apiVersion: apps/v1
67
66
  kind: Deployment
68
67
  metadata:
@@ -81,7 +80,7 @@ spec:
81
80
  spec:
82
81
  containers:
83
82
  - name: ${deployId}-${env}-${suffix}
84
- image: localhost/rockylinux9-underpost:${Underpost.version}
83
+ image: ${image ?? `localhost/rockylinux9-underpost:${Underpost.version}`}
85
84
  # resources:
86
85
  # requests:
87
86
  # memory: "${resources.requests.memory}"
@@ -118,6 +117,7 @@ spec:
118
117
  async buildManifest(deployList, env, options) {
119
118
  const resources = UnderpostDeploy.API.resourcesFactory();
120
119
  const replicas = options.replicas;
120
+ const image = options.image;
121
121
 
122
122
  for (const _deployId of deployList.split(',')) {
123
123
  const deployId = _deployId.trim();
@@ -144,6 +144,7 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
144
144
  suffix: deploymentVersion,
145
145
  resources,
146
146
  replicas,
147
+ image,
147
148
  }).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
148
149
  `;
149
150
  }
@@ -153,21 +154,7 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
153
154
  let secretYaml = '';
154
155
 
155
156
  for (const host of Object.keys(confServer)) {
156
- if (env === 'production')
157
- secretYaml += `
158
- ---
159
- apiVersion: cert-manager.io/v1
160
- kind: Certificate
161
- metadata:
162
- name: ${host}
163
- spec:
164
- commonName: ${host}
165
- dnsNames:
166
- - ${host}
167
- issuerRef:
168
- name: letsencrypt-prod
169
- kind: ClusterIssuer
170
- secretName: ${host}`;
157
+ if (env === 'production') secretYaml += UnderpostDeploy.API.buildCertManagerCertificate({ host });
171
158
 
172
159
  const pathPortAssignment = pathPortAssignmentData[host];
173
160
  // logger.info('', { host, pathPortAssignment });
@@ -221,6 +208,22 @@ spec:
221
208
  }
222
209
  }
223
210
  },
211
+ buildCertManagerCertificate({ host }) {
212
+ return `
213
+ ---
214
+ apiVersion: cert-manager.io/v1
215
+ kind: Certificate
216
+ metadata:
217
+ name: ${host}
218
+ spec:
219
+ commonName: ${host}
220
+ dnsNames:
221
+ - ${host}
222
+ issuerRef:
223
+ name: letsencrypt-prod
224
+ kind: ClusterIssuer
225
+ secretName: ${host}`;
226
+ },
224
227
  getCurrentTraffic(deployId) {
225
228
  // kubectl get deploy,sts,svc,configmap,secret -n default -o yaml --export > default.yaml
226
229
  const hostTest = Object.keys(
@@ -230,7 +233,7 @@ spec:
230
233
  return info.match('blue') ? 'blue' : info.match('green') ? 'green' : null;
231
234
  },
232
235
  async callback(
233
- deployList = 'default',
236
+ deployList = '',
234
237
  env = 'development',
235
238
  options = {
236
239
  remove: false,
@@ -240,12 +243,16 @@ spec:
240
243
  infoUtil: false,
241
244
  expose: false,
242
245
  cert: false,
246
+ certHosts: '',
243
247
  versions: '',
248
+ image: '',
244
249
  traffic: '',
245
250
  replicas: '',
251
+ node: '',
246
252
  restoreHosts: false,
247
253
  disableUpdateDeployment: false,
248
254
  infoTraffic: false,
255
+ etcHosts: false,
249
256
  },
250
257
  ) {
251
258
  if (options.infoUtil === true)
@@ -300,6 +307,14 @@ docker login nvcr.io
300
307
  Username: $oauthtoken
301
308
  Password: <Your Key>
302
309
  `);
310
+ if (!deployList && options.certHosts) {
311
+ for (const host of options.certHosts.split(',')) {
312
+ shellExec(`sudo kubectl apply -f - <<EOF
313
+ ${UnderpostDeploy.API.buildCertManagerCertificate({ host })}
314
+ EOF`);
315
+ }
316
+ return;
317
+ } else if (!deployList) deployList = 'dd-default';
303
318
  if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
304
319
  deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
305
320
  if (options.infoTraffic === true) {
@@ -319,20 +334,16 @@ Password: <Your Key>
319
334
  if (!options.replicas) options.replicas = 1;
320
335
  if (options.sync) UnderpostDeploy.API.sync(deployList, options);
321
336
  if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
322
- if (options.infoRouter === true) {
337
+ if (options.infoRouter === true || options.buildManifest === true) {
323
338
  logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
324
339
  return;
325
340
  }
326
341
  UnderpostDeploy.API.configMap(env);
327
342
  let renderHosts = '';
328
- let concatHots = '';
329
- const etcHost = (
330
- concat,
331
- ) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
332
- ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
343
+ let etcHosts = [];
333
344
  if (options.restoreHosts === true) {
334
- renderHosts = etcHost(concatHots);
335
- fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
345
+ const factoryResult = UnderpostDeploy.API.etcHostFactory(etcHosts);
346
+ renderHosts = factoryResult.renderHosts;
336
347
  logger.info(renderHosts);
337
348
  return;
338
349
  }
@@ -360,8 +371,9 @@ Password: <Your Key>
360
371
  const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
361
372
  for (const host of Object.keys(confServer)) {
362
373
  shellExec(`sudo kubectl delete HTTPProxy ${host}`);
363
- if (env === 'production' && options.cert === true) shellExec(`sudo kubectl delete Certificate ${host}`);
364
- if (!options.remove === true && env === 'development') concatHots += ` ${host}`;
374
+ if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
375
+ shellExec(`sudo kubectl delete Certificate ${host}`);
376
+ if (!options.remove === true && env === 'development') etcHosts.push(host);
365
377
  }
366
378
 
367
379
  const manifestsPath =
@@ -372,28 +384,14 @@ Password: <Your Key>
372
384
  if (!options.remove === true) {
373
385
  if (!options.disableUpdateDeployment) shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
374
386
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
375
- if (env === 'production' && options.cert === true)
387
+
388
+ if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
376
389
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
377
390
  }
378
391
  }
379
- switch (process.platform) {
380
- case 'linux':
381
- {
382
- switch (env) {
383
- case 'development':
384
- renderHosts = etcHost(concatHots);
385
- fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
386
-
387
- break;
388
-
389
- default:
390
- break;
391
- }
392
- }
393
- break;
394
-
395
- default:
396
- break;
392
+ if (options.etcHosts === true) {
393
+ const factoryResult = UnderpostDeploy.API.etcHostFactory(etcHosts);
394
+ renderHosts = factoryResult.renderHosts;
397
395
  }
398
396
  if (renderHosts)
399
397
  logger.info(
@@ -472,7 +470,11 @@ Password: <Your Key>
472
470
  notReadyPods.push(pod);
473
471
  }
474
472
  }
475
- return { ready: notReadyPods.length === 0, notReadyPods, readyPods };
473
+ return {
474
+ ready: pods.length > 0 && notReadyPods.length === 0,
475
+ notReadyPods,
476
+ readyPods,
477
+ };
476
478
  },
477
479
  configMap(env) {
478
480
  shellExec(`kubectl delete configmap underpost-config`);
@@ -487,6 +489,19 @@ Password: <Your Key>
487
489
  );
488
490
  shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
489
491
  },
492
+ etcHostFactory(hosts = []) {
493
+ const renderHosts = `127.0.0.1 ${hosts.join(
494
+ ' ',
495
+ )} localhost localhost.localdomain localhost4 localhost4.localdomain4
496
+ ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
497
+
498
+ fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
499
+ return { renderHosts };
500
+ },
501
+ isValidTLSContext: ({ host, env, options }) =>
502
+ env === 'production' &&
503
+ options.cert === true &&
504
+ (!options.certHosts || options.certHosts.split(',').includes(host)),
490
505
  };
491
506
  }
492
507
 
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('--cluster', 'Create deploy ID cluster files and sync to current cluster')
26
28
  .option('--dev', 'Sets the development cli context')
27
29
  .description('Initializes a new Underpost project with a predefined structure.')
28
30
  .action(Underpost.repo.new);
@@ -157,16 +159,20 @@ program
157
159
  .option('--expose', 'Exposes services matching the provided deployment ID list.')
158
160
  .option('--info-util', 'Displays useful `kubectl` utility management commands.')
159
161
  .option('--cert', 'Resets TLS/SSL certificate secrets for deployments.')
162
+ .option('--cert-hosts <hosts>', 'Resets TLS/SSL certificate secrets for specified hosts.')
163
+ .option('--node <node>', 'Sets optional node for deployment operations.')
160
164
  .option(
161
165
  '--build-manifest',
162
166
  'Builds Kubernetes YAML manifests, including deployments, services, proxies, and secrets.',
163
167
  )
164
168
  .option('--replicas <replicas>', 'Sets a custom number of replicas for deployments.')
169
+ .option('--image <image>', 'Sets a custom image for deployments.')
165
170
  .option('--versions <deployment-versions>', 'A comma-separated list of custom deployment versions.')
166
171
  .option('--traffic <traffic-versions>', 'A comma-separated list of custom deployment traffic weights.')
167
172
  .option('--disable-update-deployment', 'Disables updates to deployments.')
168
173
  .option('--info-traffic', 'Retrieves traffic configuration from current resource deployments.')
169
174
  .option('--kubeadm', 'Enables the kubeadm context for deployment operations.')
175
+ .option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
170
176
  .option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
171
177
  .description('Manages application deployments, defaulting to deploying development pods.')
172
178
  .action(Underpost.deploy.callback);
@@ -345,6 +351,8 @@ program
345
351
  .option('--command <command-array>', 'Array of commands to run.')
346
352
  .option('--args <args-array>', 'Array of arguments to pass to the command.')
347
353
  .option('--dev', 'Sets the development context environment for the script.')
354
+ .option('--build', 'Set builder context runner')
355
+ .option('--replicas <replicas>', 'Sets a custom number of replicas for deployment.')
348
356
  .option('--pod-name <pod-name>', 'Optional: Specifies the pod name for test execution.')
349
357
  .option('--volume-host-path <volume-host-path>', 'Optional: Specifies the volume host path for test execution.')
350
358
  .option('--volume-mount-path <volume-mount-path>', 'Optional: Specifies the volume mount path for test execution.')
package/src/cli/lxd.js CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * LXD module for managing LXD virtual machines and networks.
3
+ * @module src/cli/lxd.js
4
+ * @namespace UnderpostLxd
5
+ */
6
+
1
7
  import { getNpmRootPath } from '../server/conf.js';
2
8
  import { getLocalIPv4Address } from '../server/dns.js';
3
9
  import { pbcopy, shellExec } from '../server/process.js';
@@ -32,6 +38,7 @@ class UnderpostLxd {
32
38
  * @param {string} [options.deleteExpose=''] - Delete exposed ports from a VM (format: 'vmName:port1,port2').
33
39
  * @param {string} [options.test=''] - Test health, status and network connectivity for a VM.
34
40
  * @param {string} [options.autoExposeK8sPorts=''] - Automatically expose common Kubernetes ports for the VM.
41
+ * @memberof UnderpostLxd
35
42
  */
36
43
  async callback(
37
44
  options = {
@@ -1,10 +1,11 @@
1
1
  import { commitData } from '../client/components/core/CommonJs.js';
2
2
  import dotenv from 'dotenv';
3
- import { pbcopy, shellExec } from '../server/process.js';
3
+ import { pbcopy, shellCd, shellExec } from '../server/process.js';
4
4
  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
 
@@ -12,7 +13,7 @@ const logger = loggerFactory(import.meta);
12
13
 
13
14
  class UnderpostRepository {
14
15
  static API = {
15
- clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false, g8: false }) {
16
+ clone(gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`, options = { bare: false, g8: false }) {
16
17
  const gExtension = options.g8 === true ? '.g8' : '.git';
17
18
  const repoName = gitUri.split('/').pop();
18
19
  if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
@@ -25,7 +26,11 @@ class UnderpostRepository {
25
26
  },
26
27
  );
27
28
  },
28
- pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { g8: false }) {
29
+ pull(
30
+ repoPath = './',
31
+ gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`,
32
+ options = { g8: false },
33
+ ) {
29
34
  const gExtension = options.g8 === true ? '.g8' : '.git';
30
35
  shellExec(
31
36
  `cd ${repoPath} && git pull https://${
@@ -48,6 +53,7 @@ class UnderpostRepository {
48
53
  },
49
54
  ) {
50
55
  if (commitType === 'reset') {
56
+ if (options.copy) pbcopy(shellExec(`git --no-pager log -1 --pretty=%B`, { stdout: true }));
51
57
  shellExec(`cd ${repoPath} && git reset --soft HEAD~${isNaN(parseInt(subModule)) ? 1 : parseInt(subModule)}`);
52
58
  return;
53
59
  }
@@ -59,7 +65,11 @@ class UnderpostRepository {
59
65
  shellExec(`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}-m "${_message}"`);
60
66
  },
61
67
 
62
- push(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { f: false, g8: false }) {
68
+ push(
69
+ repoPath = './',
70
+ gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template}`,
71
+ options = { f: false, g8: false },
72
+ ) {
63
73
  const gExtension = options.g8 === true || options.G8 === true ? '.g8' : '.git';
64
74
  shellExec(
65
75
  `cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}${gExtension}${
@@ -80,15 +90,16 @@ class UnderpostRepository {
80
90
  );
81
91
  },
82
92
 
83
- new(repositoryName, options = { dev: false }) {
93
+ new(repositoryName, options = { dev: false, deployId: false, cluster: false }) {
84
94
  return new Promise(async (resolve, reject) => {
85
95
  try {
86
96
  await logger.setUpInfo();
97
+ actionInitLog();
87
98
  if (repositoryName === 'service')
88
99
  return resolve(
89
100
  await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
90
101
  );
91
- else actionInitLog();
102
+ if (options.deployId === true) return Config.deployIdFactory(repositoryName, options);
92
103
  const npmRoot = getNpmRootPath();
93
104
  const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
94
105
  const destFolder = `./${repositoryName}`;
@@ -135,6 +146,33 @@ class UnderpostRepository {
135
146
  .concat(diffUntrackOutput.toString().split('\n').filter(Boolean))
136
147
  .filter((f) => !deleteFiles.includes(f));
137
148
  },
149
+ privateConfUpdate(deployId) {
150
+ shellCd(`/home/dd/engine`);
151
+ const privateRepoName = `engine-${deployId.split('dd-')[1]}-private`;
152
+ const privateRepoPath = `../${privateRepoName}`;
153
+ if (fs.existsSync(privateRepoPath)) fs.removeSync(privateRepoPath);
154
+ shellExec(`cd .. && underpost clone ${process.env.GITHUB_USERNAME}/${privateRepoName}`);
155
+ shellExec(`cd ${privateRepoPath} && underpost pull . ${process.env.GITHUB_USERNAME}/${privateRepoName}`);
156
+ const packageJsonDeploy = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
157
+ const packageJsonEngine = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
158
+ if (packageJsonDeploy.version !== packageJsonEngine.version) {
159
+ logger.warn(
160
+ `Version mismatch: deploy-version:${packageJsonDeploy.version} !== engine-version:${packageJsonEngine.version},
161
+ Prevent build private config repo.`,
162
+ );
163
+ return {
164
+ validVersion: false,
165
+ engineVersion: packageJsonEngine.version,
166
+ deployVersion: packageJsonDeploy.version,
167
+ };
168
+ }
169
+ shellExec(`node bin/build ${deployId} conf`);
170
+ return {
171
+ validVersion: true,
172
+ engineVersion: packageJsonEngine.version,
173
+ deployVersion: packageJsonDeploy.version,
174
+ };
175
+ },
138
176
  };
139
177
  }
140
178
 
package/src/cli/run.js CHANGED
@@ -7,6 +7,8 @@ import fs from 'fs-extra';
7
7
  import { range, setPad, timer } from '../client/components/core/CommonJs.js';
8
8
  import UnderpostDeploy from './deploy.js';
9
9
  import UnderpostRootEnv from './env.js';
10
+ import UnderpostRepository from './repository.js';
11
+ import os from 'os';
10
12
 
11
13
  const logger = loggerFactory(import.meta);
12
14
 
@@ -19,6 +21,8 @@ class UnderpostRun {
19
21
  imageName: '',
20
22
  containerName: '',
21
23
  namespace: '',
24
+ build: false,
25
+ replicas: 1,
22
26
  };
23
27
  static RUNNERS = {
24
28
  'spark-template': (path, options = UnderpostRun.DEFAULT_OPTION) => {
@@ -26,9 +30,9 @@ class UnderpostRun {
26
30
  shellExec(`sudo rm -rf ${dir}`);
27
31
  shellCd('/home/dd');
28
32
 
29
- // pbcopy(`cd /home/dd && sbt new underpostnet/spark-template.g8`);
33
+ // pbcopy(`cd /home/dd && sbt new ${process.env.GITHUB_USERNAME}/spark-template.g8`);
30
34
  // await read({ prompt: 'Command copy to clipboard, press enter to continue.\n' });
31
- shellExec(`cd /home/dd && sbt new underpostnet/spark-template.g8 '--name=spark-template'`);
35
+ shellExec(`cd /home/dd && sbt new ${process.env.GITHUB_USERNAME}/spark-template.g8 '--name=spark-template'`);
32
36
 
33
37
  shellCd(dir);
34
38
 
@@ -72,12 +76,19 @@ class UnderpostRun {
72
76
  const baseCommand = options.dev ? 'node bin' : 'underpost';
73
77
  shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
74
78
  shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
79
+ const mongoHosts = ['mongodb-0.mongodb-service'];
75
80
  shellExec(
76
- `${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${'127.0.0.1'} --pull-image`,
81
+ `${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${mongoHosts.join(
82
+ ',',
83
+ )} --pull-image`,
77
84
  );
78
85
  shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
79
86
  shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
80
87
  shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
88
+ {
89
+ const hostListenResult = UnderpostDeploy.API.etcHostFactory(mongoHosts);
90
+ logger.info(hostListenResult.renderHosts);
91
+ }
81
92
  },
82
93
  'ssh-cluster-info': (path, options = UnderpostRun.DEFAULT_OPTION) => {
83
94
  const { underpostRoot } = options;
@@ -96,10 +107,12 @@ class UnderpostRun {
96
107
  },
97
108
  'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
98
109
  const baseCommand = options.dev || true ? 'node bin' : 'underpost';
110
+ shellExec(`${baseCommand} run clean`);
111
+ shellExec(`${baseCommand} push ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
99
112
  shellCd('/home/dd/engine');
100
113
  shellExec(`git reset`);
101
114
  shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
102
- shellExec(`${baseCommand} push . underpostnet/engine`);
115
+ shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
103
116
  },
104
117
  clean: (path, options = UnderpostRun.DEFAULT_OPTION) => {
105
118
  shellCd(path ?? `/home/dd/engine`);
@@ -108,8 +121,8 @@ class UnderpostRun {
108
121
  pull: (path, options = UnderpostRun.DEFAULT_OPTION) => {
109
122
  shellCd(`/home/dd/engine`);
110
123
  shellExec(`node bin/deploy clean-core-repo`);
111
- shellExec(`underpost pull . underpostnet/engine`);
112
- shellExec(`underpost pull engine-private underpostnet/engine-private`, { silent: true });
124
+ shellExec(`underpost pull . ${process.env.GITHUB_USERNAME}/engine`);
125
+ shellExec(`underpost pull ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
113
126
  },
114
127
  'release-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
115
128
  actionInitLog();
@@ -121,11 +134,12 @@ class UnderpostRun {
121
134
  }
122
135
  },
123
136
  'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
137
+ actionInitLog();
124
138
  const baseCommand = options.dev || true ? 'node bin' : 'underpost';
125
139
  shellCd('/home/dd/engine');
126
140
  shellExec(`git reset`);
127
141
  shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
128
- shellExec(`${baseCommand} push . underpostnet/engine`);
142
+ shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
129
143
  },
130
144
  ide: (path, options = UnderpostRun.DEFAULT_OPTION) => {
131
145
  const { underpostRoot } = options;
@@ -141,6 +155,29 @@ class UnderpostRun {
141
155
  let [deployId, subConf] = path.split(',');
142
156
  shellExec(`npm run dev-api ${deployId} ${subConf}`);
143
157
  },
158
+ sync: (path, options = UnderpostRun.DEFAULT_OPTION) => {
159
+ const env = options.dev ? 'development' : 'production';
160
+ const baseCommand = options.dev || true ? 'node bin' : 'underpost';
161
+ shellExec(`${baseCommand} run clean`);
162
+ const defaultPath = ['dd-default', 1, ``, ``, 'kind-control-plane'];
163
+ let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
164
+ deployId = deployId ?? defaultPath[0];
165
+ replicas = replicas ?? defaultPath[1];
166
+ versions = versions ?? defaultPath[2];
167
+ image = image ?? defaultPath[3];
168
+ node = node ?? defaultPath[4];
169
+ shellExec(
170
+ `${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
171
+ replicas ?? 1
172
+ } --node ${node}${image ? ` --image ${image}` : ''}${
173
+ versions ? ` --versions ${versions.replaceAll('+', ',')}` : ''
174
+ } dd ${env}`,
175
+ );
176
+ if (!options.build) shellExec(`${baseCommand} deploy --kubeadm ${deployId} ${env}`);
177
+ },
178
+ 'ls-deployments': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
179
+ console.table(await UnderpostDeploy.API.get(path, 'deployments'));
180
+ },
144
181
  monitor: (path, options = UnderpostRun.DEFAULT_OPTION) => {
145
182
  const pid = getTerminalPid();
146
183
  logger.info('monitor pid', pid);
@@ -275,11 +312,21 @@ class UnderpostRun {
275
312
  },
276
313
  deploy: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
277
314
  const deployId = path;
315
+ const { validVersion, deployVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
316
+ if (!validVersion) throw new Error('Version mismatch');
278
317
  const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
279
318
  const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
280
319
  const env = 'production';
281
320
  const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
282
- shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
321
+
322
+ if (options.build === true) {
323
+ // deployId, replicas, versions, image, node
324
+ shellExec(
325
+ `node bin run sync ${deployId},${options.replicas ?? 1},${targetTraffic},${
326
+ options.imageName ?? `localhost/rockylinux9-underpost:${deployVersion}`
327
+ },${os.hostname()}`,
328
+ );
329
+ } else shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
283
330
 
284
331
  let checkStatusIteration = 0;
285
332
  const checkStatusIterationMsDelay = 1000;
@@ -298,7 +345,7 @@ class UnderpostRun {
298
345
 
299
346
  UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
300
347
 
301
- shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
348
+ // shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
302
349
  },
303
350
  'tf-vae-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
304
351
  const { underpostRoot } = options;
package/src/cli/ssh.js CHANGED
@@ -1,23 +1,37 @@
1
- import { getNpmRootPath } from '../server/conf.js';
1
+ /**
2
+ * SSH module for managing SSH key generation and connection setup.
3
+ * @module src/cli/ssh.js
4
+ * @namespace UnderpostSSH
5
+ */
6
+
2
7
  import { shellExec } from '../server/process.js';
3
8
 
9
+ /**
10
+ * @class UnderpostSSH
11
+ * @description Manages SSH key generation and connection setup.
12
+ * @memberof UnderpostSSH
13
+ */
4
14
  class UnderpostSSH {
5
15
  static API = {
6
16
  /**
7
17
  * @method callback
8
- * @param {object} options
9
- * @param {boolean} options.generate - Generates new ssh credential and stores it in current private keys file storage.
10
- * @description Import and start ssh server and client based on current default deployment ID.
18
+ * @description Manages SSH key generation and connection setup based on the default deployment ID.
19
+ * This function will either generate a new SSH key pair or import an existing one,
20
+ * then initiate the SSH connection process.
21
+ * @param {object} [options={ generate: false }] - Options for the SSH callback.
22
+ * @param {boolean} [options.generate=false] - If true, generates a new SSH key pair. Otherwise, it imports the existing one.
23
+ * @memberof UnderpostSSH
24
+ * @returns {Promise<void>}
11
25
  */
12
26
  callback: async (
13
27
  options = {
14
28
  generate: false,
15
29
  },
16
30
  ) => {
17
- // only import + start
31
+ // Example usage for importing an existing key:
18
32
  // node bin/deploy ssh root@<host> <password> import
19
33
 
20
- // generate + import + start
34
+ // Example usage for generating a new key:
21
35
  // node bin/deploy ssh root@<host> <password>
22
36
 
23
37
  shellExec(