underpost 2.8.886 → 2.81.0

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.
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "context": "Editor && edit_prediction",
4
+ "bindings": {
5
+ "tab": "editor::AcceptEditPrediction",
6
+ "alt-tab": "editor::AcceptEditPrediction",
7
+ "alt-l": null
8
+ }
9
+ },
10
+ {
11
+ "context": "Editor && edit_prediction_conflict",
12
+ "bindings": {
13
+ "alt-l": "editor::AcceptEditPrediction",
14
+ "tab": "editor::ComposeCompletion"
15
+ }
16
+ }
17
+ ]
@@ -0,0 +1,20 @@
1
+ {
2
+ "ui_font_size": 16,
3
+ "buffer_font_size": 15,
4
+ "theme": {
5
+ "mode": "system",
6
+ "light": "One Dark",
7
+ "dark": "One Dark"
8
+ },
9
+
10
+ "features": {
11
+ "edit_prediction_provider": "copilot",
12
+ "copilot": true // https://github.com/login/device
13
+ },
14
+
15
+ "show_edit_predictions": true,
16
+
17
+ "edit_predictions": {
18
+ "mode": "eager"
19
+ }
20
+ }
package/Dockerfile CHANGED
@@ -1,7 +1,24 @@
1
1
  FROM rockylinux:9
2
2
 
3
- RUN dnf install -y --allowerasing bzip2
4
- RUN dnf clean all
3
+ # --- Update and install required packages
4
+ RUN dnf -y update && \
5
+ dnf -y install epel-release && \
6
+ dnf -y install --allowerasing \
7
+ bzip2 \
8
+ sudo \
9
+ curl \
10
+ net-tools \
11
+ openssh-server \
12
+ nano \
13
+ vim-enhanced \
14
+ less \
15
+ openssl-devel \
16
+ wget \
17
+ git \
18
+ gnupg2 \
19
+ libnsl \
20
+ perl && \
21
+ dnf clean all
5
22
 
6
23
 
7
24
  # Install Node.js
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  <!-- badges -->
20
20
 
21
- [![Node.js CI](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [![Test](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [![Downloads](https://img.shields.io/npm/dm/underpost.svg)](https://www.npmjs.com/package/underpost) [![Socket Badge](https://socket.dev/api/badge/npm/package/underpost/2.8.886)](https://socket.dev/npm/package/underpost/overview/2.8.886) [![Coverage Status](https://coveralls.io/repos/github/underpostnet/engine/badge.svg?branch=master)](https://coveralls.io/github/underpostnet/engine?branch=master) [![Version](https://img.shields.io/npm/v/underpost.svg)](https://www.npmjs.org/package/underpost) [![License](https://img.shields.io/npm/l/underpost.svg)](https://www.npmjs.com/package/underpost)
21
+ [![Node.js CI](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [![Test](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [![Downloads](https://img.shields.io/npm/dm/underpost.svg)](https://www.npmjs.com/package/underpost) [![Socket Badge](https://socket.dev/api/badge/npm/package/underpost/2.81.0)](https://socket.dev/npm/package/underpost/overview/2.81.0) [![Coverage Status](https://coveralls.io/repos/github/underpostnet/engine/badge.svg?branch=master)](https://coveralls.io/github/underpostnet/engine?branch=master) [![Version](https://img.shields.io/npm/v/underpost.svg)](https://www.npmjs.org/package/underpost) [![License](https://img.shields.io/npm/l/underpost.svg)](https://www.npmjs.com/package/underpost)
22
22
 
23
23
  <!-- end-badges -->
24
24
 
@@ -66,7 +66,7 @@ Run dev client server
66
66
  npm run dev
67
67
  ```
68
68
  <!-- -->
69
- ## underpost ci/cd cli v2.8.886
69
+ ## underpost ci/cd cli v2.81.0
70
70
 
71
71
  ### Usage: `underpost [options] [command]`
72
72
  ```
@@ -79,7 +79,7 @@ Commands:
79
79
  start [options] <deploy-id> [env] Initiates application servers, build pipelines, or other defined services based on the deployment ID.
80
80
  clone [options] <uri> Clones a specified GitHub repository into the current directory.
81
81
  pull [options] <path> <uri> Pulls the latest changes from a specified GitHub repository.
82
- cmt [options] <path> <commit-type> [module-tag] [message] Manages commits to a GitHub repository, supporting various commit types and options.
82
+ cmt [options] [path] [commit-type] [module-tag] [message] Manages commits to a GitHub repository, supporting various commit types and options.
83
83
  push [options] <path> <uri> Pushes committed changes from a local repository to a remote GitHub repository.
84
84
  env [deploy-id] [env] [subConf] Sets environment variables and configurations related to a specific deployment ID.
85
85
  config [options] <operator> [key] [value] Manages Underpost configurations using various operators.
@@ -104,6 +104,6 @@ Commands:
104
104
  help [command] display help for command
105
105
 
106
106
  ```
107
-
107
+
108
108
  <a target="_top" href="https://github.com/underpostnet/pwa-microservices-template/blob/master/cli.md">See complete CLI Docs here.</a>
109
-
109
+
package/bin/deploy.js CHANGED
@@ -27,7 +27,7 @@ import { buildClient } from '../src/server/client-build.js';
27
27
  import { DefaultConf } from '../conf.js';
28
28
  import colors from 'colors';
29
29
  import { program } from '../src/cli/index.js';
30
- import { getLocalIPv4Address, ip } from '../src/server/dns.js';
30
+ import Dns, { getLocalIPv4Address } from '../src/server/dns.js';
31
31
  import { timer } from '../src/client/components/core/CommonJs.js';
32
32
 
33
33
  colors.enable();
@@ -124,8 +124,12 @@ try {
124
124
  case 'conf': {
125
125
  let subConf = process.argv[5] ?? '';
126
126
 
127
- if (!['current', 'clean'].includes(process.argv[3]))
128
- dotenv.config({ path: `./engine-private/conf/${process.argv[3]}/.env.${process.argv[4]}`, override: true });
127
+ if (!['current', 'clean', 'root'].includes(process.argv[3])) {
128
+ const path = fs.existsSync(`./engine-private/replica/${process.argv[3]}`)
129
+ ? `./engine-private/replica/${process.argv[3]}/.env.${process.argv[4]}`
130
+ : `./engine-private/conf/${process.argv[3]}/.env.${process.argv[4]}`;
131
+ dotenv.config({ path, override: true });
132
+ }
129
133
 
130
134
  loadConf(process.argv[3], subConf);
131
135
  break;
@@ -267,6 +271,7 @@ try {
267
271
  writeEnv(envPath, envObj);
268
272
  }
269
273
  const serverConf = loadReplicas(
274
+ deployId,
270
275
  JSON.parse(fs.readFileSync(`${baseConfPath}/${deployId}/conf.server.json`, 'utf8')),
271
276
  );
272
277
  for (const host of Object.keys(serverConf)) {
@@ -287,6 +292,7 @@ try {
287
292
  const host = process.argv[4];
288
293
  const path = process.argv[5];
289
294
  const serverConf = loadReplicas(
295
+ deployId,
290
296
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
291
297
  );
292
298
 
@@ -479,10 +485,19 @@ try {
479
485
  break;
480
486
  }
481
487
 
488
+ case 'private': {
489
+ shellExec(`node bin/deploy sync-deploy-envs`);
490
+ shellExec(`node bin/build dd conf`);
491
+ shellExec(`cd ./engine-private && git add . && node ../bin cmt . build`);
492
+ shellExec(`cd ./engine-private && node ../bin push . ${process.env.GITHUB_USERNAME}/engine-private`);
493
+ break;
494
+ }
495
+
482
496
  case 'version-deploy': {
483
497
  shellExec(
484
498
  `underpost secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
485
499
  );
500
+ shellExec(`node bin/deploy sync-deploy-envs`);
486
501
  shellExec(`node bin/build dd conf`);
487
502
  shellExec(`git add . && cd ./engine-private && git add .`);
488
503
  shellExec(`node bin cmt . ci package-pwa-microservices-template`);
@@ -564,10 +579,10 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
564
579
  `${key}`.toUpperCase().match('MAC')
565
580
  ? 'changethis'
566
581
  : isNaN(parseFloat(privateEnv[key]))
567
- ? `${privateEnv[key]}`.match(`@`)
568
- ? 'admin@default.net'
569
- : 'changethis'
570
- : privateEnv[key];
582
+ ? `${privateEnv[key]}`.match(`@`)
583
+ ? 'admin@default.net'
584
+ : 'changethis'
585
+ : privateEnv[key];
571
586
  }
572
587
  return env;
573
588
  };
@@ -654,7 +669,7 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
654
669
  // generate + import + start
655
670
  // node bin/deploy ssh root@<host> <password>
656
671
 
657
- const host = process.argv[3] ?? `root@${await ip.public.ipv4()}`;
672
+ const host = process.argv[3] ?? `root@${await Dns.getPublicIp()}`;
658
673
  const domain = host.split('@')[1];
659
674
  const user = 'root'; // host.split('@')[0];
660
675
  const password = process.argv[4] ?? '';
@@ -1294,6 +1309,20 @@ nvidia/gpu-operator \
1294
1309
  shellExec(`./scripts/ssl.sh ${targetDir} "${domains.join(' ')}"`);
1295
1310
  break;
1296
1311
  }
1312
+
1313
+ case 'sync-deploy-envs': {
1314
+ const envObj = dotenv.parse(fs.readFileSync(`./engine-private/conf/dd-cron/.env.production`));
1315
+ for (const deployId of ['dd-cron'].concat(
1316
+ fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(','),
1317
+ )) {
1318
+ for (const env of ['production', 'development', 'test']) {
1319
+ const _envObj = dotenv.parse(fs.readFileSync(`./engine-private/conf/${deployId}/.env.${env}`, 'utf8'));
1320
+ _envObj.GITHUB_TOKEN = envObj.GITHUB_TOKEN;
1321
+ writeEnv(`./engine-private/conf/${deployId}/.env.${env}`, _envObj);
1322
+ }
1323
+ }
1324
+ break;
1325
+ }
1297
1326
  }
1298
1327
  } catch (error) {
1299
1328
  logger.error(error, error.stack);
package/bin/zed.js ADDED
@@ -0,0 +1,20 @@
1
+ import { shellExec } from '../src/server/process.js';
2
+ import fs from 'fs-extra';
3
+ import { loggerFactory } from '../src/server/logger.js';
4
+
5
+ const logger = loggerFactory(import.meta);
6
+
7
+ fs.copyFileSync(`./.vscode/zed.settings.json`, `/root/.config/zed/settings.json`);
8
+ fs.copyFileSync(`./.vscode/zed.keymap.json`, `/root/.config/zed/keymap.json`);
9
+
10
+ shellExec(`ZED_ALLOW_ROOT=true zed ${process.argv[2] ? process.argv[2] : '.'}`);
11
+
12
+ logger.info('Connect copilot device', 'https://github.com/login/device');
13
+ logger.info('Comments', 'Ctrl shift 7');
14
+ logger.info('Unfold', 'Ctrl K + Ctrl J');
15
+ logger.info('Fold', 'Ctrl K + Ctrl 0');
16
+ logger.info('Command Palette', 'Ctrl Shift P');
17
+ logger.info('Open File', 'Ctrl P');
18
+ logger.info('Find in Files', 'Ctrl Shift F');
19
+ logger.info('Go to Line', 'Ctrl G');
20
+ logger.info('New file', 'Ctrl N');
package/cli.md CHANGED
@@ -1,4 +1,4 @@
1
- ## underpost ci/cd cli v2.8.886
1
+ ## underpost ci/cd cli v2.81.0
2
2
 
3
3
  ### Usage: `underpost [options] [command]`
4
4
  ```
@@ -11,7 +11,7 @@ Commands:
11
11
  start [options] <deploy-id> [env] Initiates application servers, build pipelines, or other defined services based on the deployment ID.
12
12
  clone [options] <uri> Clones a specified GitHub repository into the current directory.
13
13
  pull [options] <path> <uri> Pulls the latest changes from a specified GitHub repository.
14
- cmt [options] <path> <commit-type> [module-tag] [message] Manages commits to a GitHub repository, supporting various commit types and options.
14
+ cmt [options] [path] [commit-type] [module-tag] [message] Manages commits to a GitHub repository, supporting various commit types and options.
15
15
  push [options] <path> <uri> Pushes committed changes from a local repository to a remote GitHub repository.
16
16
  env [deploy-id] [env] [subConf] Sets environment variables and configurations related to a specific deployment ID.
17
17
  config [options] <operator> [key] [value] Manages Underpost configurations using various operators.
@@ -117,7 +117,7 @@ Options:
117
117
 
118
118
  ### `cmt` :
119
119
  ```
120
- Usage: underpost cmt [options] <path> <commit-type> [module-tag] [message]
120
+ Usage: underpost cmt [options] [path] [commit-type] [module-tag] [message]
121
121
 
122
122
  Manages commits to a GitHub repository, supporting various commit types and
123
123
  options.
@@ -131,6 +131,8 @@ Arguments:
131
131
  message Optional: Provides an additional custom message for the commit.
132
132
 
133
133
  Options:
134
+ --log Shows commit history from the specified number of latest n path
135
+ commits.
134
136
  --empty Allows committing with empty files.
135
137
  --copy Copies the generated commit message to the clipboard.
136
138
  --info Displays information about available commit types.
@@ -166,7 +168,7 @@ ID.
166
168
 
167
169
  Arguments:
168
170
  deploy-id The deployment configuration ID. Use 'clean' to restore default
169
- environment settings. User 'root' to load root env. User
171
+ environment settings. Use 'root' to load underpost root env. Use
170
172
  'current' to get plain current deploy Id.
171
173
  env Optional: The environment to set (e.g., "production",
172
174
  "development"). Defaults to "production".
@@ -311,8 +313,10 @@ Options:
311
313
  --traffic <traffic-versions> A comma-separated list of custom deployment
312
314
  traffic weights.
313
315
  --disable-update-deployment Disables updates to deployments.
314
- --info-traffic Retrieves traffic configuration from
315
- current resource deployments.
316
+ --disable-update-proxy Disables updates to proxies.
317
+ --status Retrieves current network traffic data from
318
+ resource deployments and the host machine
319
+ network configuration.
316
320
  --kubeadm Enables the kubeadm context for deployment
317
321
  operations.
318
322
  --etc-hosts Enables the etc-hosts context for
@@ -370,6 +374,7 @@ Options:
370
374
  environment secrets.
371
375
  --reset Performs a build without using the
372
376
  cache.
377
+ --dev Use development mode.
373
378
  --k3s-load Loads the image into a K3s cluster.
374
379
  -h, --help display help for command
375
380
 
@@ -389,6 +394,7 @@ Options:
389
394
  --kubeadm-load Imports the pulled image into a Kubeadm cluster.
390
395
  --version Sets a custom version for the base images.
391
396
  --k3s-load Loads the image into a K3s cluster.
397
+ --dev Use development mode.
392
398
  -h, --help display help for command
393
399
 
394
400
  ```
@@ -607,7 +613,7 @@ Options:
607
613
  Runs a script from the specified path.
608
614
 
609
615
  Arguments:
610
- runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, dev-cluster, ssh-cluster-info, cyberia-ide, engine-ide, cluster-build, template-deploy, clean, pull, release-deploy, ssh-deploy, ide, sync, ls-deployments, monitor, db-client, promote, metrics, cluster, deploy, sync-replica, tf-vae-test, deploy-job.
616
+ runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, dev-cluster, ssh-cluster-info, dev-hosts-expose, dev-hosts-restore, cyberia-ide, engine-ide, cluster-build, template-deploy, clean, pull, release-deploy, ssh-deploy, ide, sync, ls-deployments, monitor, db-client, promote, metrics, cluster, deploy, sync-replica, tf-vae-test, deploy-job.
611
617
  path The absolute or relative directory path where the script is located.
612
618
 
613
619
  Options:
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-default-development-blue
20
- image: localhost/rockylinux9-underpost:v2.8.886
20
+ image: localhost/rockylinux9-underpost:v2.81.0
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "124Ki"
@@ -100,7 +100,7 @@ spec:
100
100
  spec:
101
101
  containers:
102
102
  - name: dd-default-development-green
103
- image: localhost/rockylinux9-underpost:v2.8.886
103
+ image: localhost/rockylinux9-underpost:v2.81.0
104
104
  # resources:
105
105
  # requests:
106
106
  # memory: "124Ki"
@@ -17,13 +17,13 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-test-development-blue
20
- image: localhost/rockylinux9-underpost:v2.8.886
20
+ image: localhost/rockylinux9-underpost:v2.81.0
21
21
  # resources:
22
22
  # requests:
23
- # memory: "94Ki"
23
+ # memory: "96294Ki"
24
24
  # cpu: "75m"
25
25
  # limits:
26
- # memory: "1504Ki"
26
+ # memory: "1540709Ki"
27
27
  # cpu: "1200m"
28
28
  command:
29
29
  - /bin/sh
@@ -104,13 +104,13 @@ spec:
104
104
  spec:
105
105
  containers:
106
106
  - name: dd-test-development-green
107
- image: localhost/rockylinux9-underpost:v2.8.886
107
+ image: localhost/rockylinux9-underpost:v2.81.0
108
108
  # resources:
109
109
  # requests:
110
- # memory: "94Ki"
110
+ # memory: "96294Ki"
111
111
  # cpu: "75m"
112
112
  # limits:
113
- # memory: "1504Ki"
113
+ # memory: "1540709Ki"
114
114
  # cpu: "1200m"
115
115
  command:
116
116
  - /bin/sh
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "underpost",
5
- "version": "2.8.886",
5
+ "version": "2.81.0",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
@@ -93,7 +93,6 @@
93
93
  "peer": "^1.0.2",
94
94
  "peerjs": "^1.5.2",
95
95
  "prom-client": "^15.1.2",
96
- "public-ip": "^6.0.1",
97
96
  "read": "^2.1.0",
98
97
  "rrule": "^2.8.1",
99
98
  "sharp": "^0.32.5",
@@ -9,6 +9,6 @@ chmod 600 "$SSH_KEY"
9
9
 
10
10
  ssh -i "$SSH_KEY" -o BatchMode=yes "${REMOTE_USER}@${REMOTE_HOST}" sh <<EOF
11
11
  cd /home/dd/engine
12
- node bin deploy dd production --info-traffic
12
+ node bin deploy dd production --status
13
13
  kubectl get pods -A
14
14
  EOF
@@ -952,7 +952,7 @@ EOF`);
952
952
  */
953
953
  getHostArch() {
954
954
  // `uname -m` returns e.g. 'x86_64' or 'aarch64'
955
- const machine = shellExec('uname -m', { stdout: true }).trim();
955
+ const machine = shellExec('uname -m', { stdout: true, silent: true }).trim();
956
956
  if (machine === 'x86_64') return { alias: 'amd64', name: 'x86_64' };
957
957
  if (machine === 'aarch64') return { alias: 'arm64', name: 'aarch64' };
958
958
  throw new Error(`Unsupported host architecture: ${machine}`);
@@ -698,7 +698,11 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
698
698
  */
699
699
  getResourcesCapacity(node) {
700
700
  const resources = {};
701
- const nodeName = node ?? os.hostname();
701
+ const nodeName = node
702
+ ? node
703
+ : UnderpostDeploy.API.get('kind-control-plane', 'node').length > 0
704
+ ? 'kind-control-plane'
705
+ : os.hostname();
702
706
  const info = shellExec(`kubectl describe node ${nodeName} | grep -E '(Allocatable:|Capacity:)' -A 6`, {
703
707
  stdout: true,
704
708
  silent: true,
package/src/cli/db.js CHANGED
@@ -271,6 +271,7 @@ class UnderpostDB {
271
271
  const deployId = _deployId.trim();
272
272
  if (!deployId) continue;
273
273
  const confServer = loadReplicas(
274
+ deployId,
274
275
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
275
276
  );
276
277
  const router = await UnderpostDeploy.API.routerFactory(deployId, env);
package/src/cli/deploy.js CHANGED
@@ -21,6 +21,9 @@ import dotenv from 'dotenv';
21
21
  import UnderpostRootEnv from './env.js';
22
22
  import UnderpostCluster from './cluster.js';
23
23
  import { timer } from '../client/components/core/CommonJs.js';
24
+ import os from 'node:os';
25
+ import Dns, { getLocalIPv4Address } from '../server/dns.js';
26
+ import UnderpostBaremetal from './baremetal.js';
24
27
 
25
28
  const logger = loggerFactory(import.meta);
26
29
 
@@ -184,6 +187,7 @@ spec:
184
187
  const deployId = _deployId.trim();
185
188
  if (!deployId) continue;
186
189
  const confServer = loadReplicas(
190
+ deployId,
187
191
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
188
192
  );
189
193
  const router = await UnderpostDeploy.API.routerFactory(deployId, env);
@@ -227,12 +231,12 @@ metadata:
227
231
  spec:
228
232
  virtualhost:
229
233
  fqdn: ${host}${
230
- env === 'development'
231
- ? ''
232
- : `
234
+ env === 'development'
235
+ ? ''
236
+ : `
233
237
  tls:
234
238
  secretName: ${host}`
235
- }
239
+ }
236
240
  routes:`;
237
241
  for (const conditionObj of pathPortAssignment) {
238
242
  const { path, port } = conditionObj;
@@ -325,7 +329,8 @@ spec:
325
329
  * @param {string} options.node - Node name for resource allocation.
326
330
  * @param {string} options.restoreHosts - Whether to restore hosts.
327
331
  * @param {string} options.disableUpdateDeployment - Whether to disable updating the deployment.
328
- * @param {string} options.infoTraffic - Whether to display traffic information.
332
+ * @param {string} options.disableUpdateProxy - Whether to disable updating the proxy.
333
+ * @param {string} options.status - Whether to display status host machine server and traffic information.
329
334
  * @param {string} options.etcHosts - Whether to update /etc/hosts.
330
335
  * @returns {Promise<void>} - Promise that resolves when the callback is complete.
331
336
  * @memberof UnderpostDeploy
@@ -349,7 +354,8 @@ spec:
349
354
  node: '',
350
355
  restoreHosts: false,
351
356
  disableUpdateDeployment: false,
352
- infoTraffic: false,
357
+ disableUpdateProxy: false,
358
+ status: false,
353
359
  etcHosts: false,
354
360
  },
355
361
  ) {
@@ -415,7 +421,7 @@ EOF`);
415
421
  } else if (!deployList) deployList = 'dd-default';
416
422
  if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
417
423
  deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
418
- if (options.infoTraffic === true) {
424
+ if (options.status === true) {
419
425
  for (const _deployId of deployList.split(',')) {
420
426
  const deployId = _deployId.trim();
421
427
  logger.info('', {
@@ -426,6 +432,16 @@ EOF`);
426
432
  pods: await UnderpostDeploy.API.get(deployId),
427
433
  });
428
434
  }
435
+ const interfaceName = Dns.getDefaultNetworkInterface();
436
+ logger.info('Machine', {
437
+ node: os.hostname(),
438
+ arch: UnderpostBaremetal.API.getHostArch(),
439
+ ipv4Public: await Dns.getPublicIp(),
440
+ ipv4Local: getLocalIPv4Address(),
441
+ resources: UnderpostCluster.API.getResourcesCapacity(),
442
+ defaultInterfaceName: interfaceName,
443
+ defaultInterfaceInfo: os.networkInterfaces()[interfaceName],
444
+ });
429
445
  return;
430
446
  }
431
447
  if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
@@ -467,11 +483,14 @@ EOF`);
467
483
  }
468
484
 
469
485
  const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
486
+
470
487
  for (const host of Object.keys(confServer)) {
471
- shellExec(`sudo kubectl delete HTTPProxy ${host}`);
472
- if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
473
- shellExec(`sudo kubectl delete Certificate ${host}`);
474
- if (!options.remove === true && env === 'development') etcHosts.push(host);
488
+ if (!options.disableUpdateProxy) {
489
+ shellExec(`sudo kubectl delete HTTPProxy ${host}`);
490
+ if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
491
+ shellExec(`sudo kubectl delete Certificate ${host}`);
492
+ }
493
+ if (!options.remove) etcHosts.push(host);
475
494
  }
476
495
 
477
496
  const manifestsPath =
@@ -479,9 +498,9 @@ EOF`);
479
498
  ? `engine-private/conf/${deployId}/build/production`
480
499
  : `manifests/deployment/${deployId}-${env}`;
481
500
 
482
- if (!options.remove === true) {
501
+ if (!options.remove) {
483
502
  if (!options.disableUpdateDeployment) shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
484
- shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
503
+ if (!options.disableUpdateProxy) shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
485
504
 
486
505
  if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
487
506
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
package/src/cli/image.js CHANGED
@@ -34,6 +34,7 @@ class UnderpostImage {
34
34
  * @param {boolean} [options.kubeadmLoad=false] - If true, load image into Kubeadm cluster.
35
35
  * @param {boolean} [options.k3sLoad=false] - If true, load image into K3s cluster.
36
36
  * @param {string} [options.path=false] - Path to the Dockerfile context.
37
+ * @param {boolean} [options.dev=false] - If true, use development mode.
37
38
  * @param {string} [options.version=''] - Version tag for the image.
38
39
  * @memberof UnderpostImage
39
40
  */
@@ -43,11 +44,14 @@ class UnderpostImage {
43
44
  kubeadmLoad: false,
44
45
  k3sLoad: false,
45
46
  path: false,
47
+ dev: false,
46
48
  version: '',
47
49
  },
48
50
  ) {
49
51
  // shellExec(`sudo podman pull docker.io/library/debian:buster`);
50
52
  shellExec(`sudo podman pull docker.io/library/rockylinux:9`);
53
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
54
+ const baseCommandOption = options.dev ? ' --dev' : '';
51
55
  const IMAGE_NAME = `rockylinux9-underpost`;
52
56
  const IMAGE_NAME_FULL = `${IMAGE_NAME}:${options.version ?? Underpost.version}`;
53
57
  let LOAD_TYPE = '';
@@ -61,7 +65,7 @@ class UnderpostImage {
61
65
  }
62
66
 
63
67
  shellExec(
64
- `underpost dockerfile-image-build --podman-save --reset --image-path=. --path ${
68
+ `${baseCommand} dockerfile-image-build${baseCommandOption} --podman-save --reset --image-path=. --path ${
65
69
  options.path ?? getUnderpostRootPath()
66
70
  } --image-name=${IMAGE_NAME_FULL} ${LOAD_TYPE}`,
67
71
  );
@@ -82,6 +86,7 @@ class UnderpostImage {
82
86
  * @param {boolean} [options.secrets=false] - If true, load secrets from the .env file for the build.
83
87
  * @param {string} [options.secretsPath=''] - Custom path to the .env file for secrets.
84
88
  * @param {boolean} [options.reset=false] - If true, perform a no-cache build.
89
+ * @param {boolean} [options.dev=false] - If true, use development mode.
85
90
  * @memberof UnderpostImage
86
91
  */
87
92
  build(
@@ -97,6 +102,7 @@ class UnderpostImage {
97
102
  secrets: false,
98
103
  secretsPath: '',
99
104
  reset: false,
105
+ dev: false,
100
106
  },
101
107
  ) {
102
108
  const {
@@ -111,6 +117,7 @@ class UnderpostImage {
111
117
  kubeadmLoad,
112
118
  k3sLoad,
113
119
  reset,
120
+ dev,
114
121
  } = options;
115
122
  const podManImg = `localhost/${imageName}`;
116
123
  if (imagePath && typeof imagePath === 'string' && !fs.existsSync(imagePath))
@@ -139,7 +146,10 @@ class UnderpostImage {
139
146
  } -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache}${secretDockerInput} --network host`,
140
147
  );
141
148
 
142
- if (podmanSave === true) shellExec(`podman save -o ${tarFile} ${podManImg}`);
149
+ if (podmanSave === true) {
150
+ if (fs.existsSync(tarFile)) fs.removeSync(tarFile);
151
+ shellExec(`podman save -o ${tarFile} ${podManImg}`);
152
+ }
143
153
  if (kindLoad === true) shellExec(`sudo kind load image-archive ${tarFile}`);
144
154
  if (kubeadmLoad === true) {
145
155
  // Use 'ctr' for Kubeadm
package/src/cli/index.js CHANGED
@@ -64,10 +64,11 @@ program
64
64
  // 'cmt' command: Commit changes to a GitHub repository
65
65
  program
66
66
  .command('cmt')
67
- .argument('<path>', 'The absolute or relative directory path of the repository.')
68
- .argument(`<commit-type>`, `The type of commit to perform. Options: ${Object.keys(commitData).join(', ')}.`)
67
+ .argument('[path]', 'The absolute or relative directory path of the repository.')
68
+ .argument(`[commit-type]`, `The type of commit to perform. Options: ${Object.keys(commitData).join(', ')}.`)
69
69
  .argument(`[module-tag]`, 'Optional: Sets a specific module tag for the commit.')
70
70
  .argument(`[message]`, 'Optional: Provides an additional custom message for the commit.')
71
+ .option(`--log`, 'Shows commit history from the specified number of latest n path commits.')
71
72
  .option('--empty', 'Allows committing with empty files.')
72
73
  .option('--copy', 'Copies the generated commit message to the clipboard.')
73
74
  .option('--info', 'Displays information about available commit types.')
@@ -89,7 +90,7 @@ program
89
90
  .command('env')
90
91
  .argument(
91
92
  '[deploy-id]',
92
- `The deployment configuration ID. Use 'clean' to restore default environment settings. User 'root' to load root env. User 'current' to get plain current deploy Id.`,
93
+ `The deployment configuration ID. Use 'clean' to restore default environment settings. Use 'root' to load underpost root env. Use 'current' to get plain current deploy Id.`,
93
94
  )
94
95
  .argument('[env]', 'Optional: The environment to set (e.g., "production", "development"). Defaults to "production".')
95
96
  .argument('[subConf]', 'Optional: The sub configuration to set.')
@@ -183,7 +184,11 @@ program
183
184
  .option('--versions <deployment-versions>', 'A comma-separated list of custom deployment versions.')
184
185
  .option('--traffic <traffic-versions>', 'A comma-separated list of custom deployment traffic weights.')
185
186
  .option('--disable-update-deployment', 'Disables updates to deployments.')
186
- .option('--info-traffic', 'Retrieves traffic configuration from current resource deployments.')
187
+ .option('--disable-update-proxy', 'Disables updates to proxies.')
188
+ .option(
189
+ '--status',
190
+ 'Retrieves current network traffic data from resource deployments and the host machine network configuration.',
191
+ )
187
192
  .option('--kubeadm', 'Enables the kubeadm context for deployment operations.')
188
193
  .option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
189
194
  .option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
@@ -217,6 +222,7 @@ program
217
222
  .option('--secrets', 'Includes Dockerfile environment secrets during the build.')
218
223
  .option('--secrets-path [secrets-path]', 'Specifies a custom path for Dockerfile environment secrets.')
219
224
  .option('--reset', 'Performs a build without using the cache.')
225
+ .option('--dev', 'Use development mode.')
220
226
  .option('--k3s-load', 'Loads the image into a K3s cluster.')
221
227
  .description(
222
228
  'Builds a Docker image from a specified Dockerfile with various options for naming, saving, and loading.',
@@ -231,6 +237,7 @@ program
231
237
  .option('--kubeadm-load', 'Imports the pulled image into a Kubeadm cluster.')
232
238
  .option('--version', 'Sets a custom version for the base images.')
233
239
  .option('--k3s-load', 'Loads the image into a K3s cluster.')
240
+ .option('--dev', 'Use development mode.')
234
241
  .description('Pulls required Underpost Dockerfile base images and optionally loads them into clusters.')
235
242
  .action(Underpost.image.dockerfile.pullBaseImages);
236
243
 
@@ -65,6 +65,7 @@ class UnderpostMonitor {
65
65
  const router = auxRouter ?? (await UnderpostDeploy.API.routerFactory(deployId, env));
66
66
 
67
67
  const confServer = loadReplicas(
68
+ deployId,
68
69
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
69
70
  );
70
71
 
@@ -83,7 +83,7 @@ class UnderpostRepository {
83
83
  * @memberof UnderpostRepository
84
84
  */
85
85
  commit(
86
- repoPath = './',
86
+ repoPath = undefined,
87
87
  commitType = 'feat',
88
88
  subModule = '',
89
89
  message = '',
@@ -91,8 +91,31 @@ class UnderpostRepository {
91
91
  copy: false,
92
92
  info: false,
93
93
  empty: false,
94
+ log: false,
94
95
  },
95
96
  ) {
97
+ if (options.log) {
98
+ const history = UnderpostRepository.API.getHistory(repoPath);
99
+ if (history[0]) {
100
+ pbcopy(
101
+ history
102
+ .reverse()
103
+ .map((commitData, i) => `${i === 0 ? '' : ' && '}git --no-pager show ${commitData.hash}`)
104
+ .join(''),
105
+ );
106
+ for (const commit of history) {
107
+ console.log(commit.hash.yellow, commit.message);
108
+ console.log(
109
+ shellExec(`git show --name-status --pretty="" ${commit.hash}`, {
110
+ stdout: true,
111
+ silent: true,
112
+ disableLog: true,
113
+ }).red,
114
+ );
115
+ }
116
+ } else logger.warn('No commits found');
117
+ return;
118
+ }
96
119
  if (commitType === 'reset') {
97
120
  if (options.copy) pbcopy(shellExec(`git --no-pager log -1 --pretty=%B`, { stdout: true }));
98
121
  shellExec(`cd ${repoPath} && git reset --soft HEAD~${isNaN(parseInt(subModule)) ? 1 : parseInt(subModule)}`);
@@ -268,6 +291,24 @@ Prevent build private config repo.`,
268
291
  deployVersion: packageJsonDeploy.version,
269
292
  };
270
293
  },
294
+ getHistory(sinceCommit = 5) {
295
+ return shellExec(`git log --oneline --graph --decorate -n ${sinceCommit}`, { stdout: true, silent: true })
296
+ .split(`\n`)
297
+ .map((line) => {
298
+ return {
299
+ hash: line.slice(2, 10),
300
+ message: line.slice(11),
301
+ };
302
+ })
303
+ .filter((line) => line.hash)
304
+ .map((line) => {
305
+ line.files = shellExec(`git show --name-status --pretty="" ${line.hash}`, {
306
+ stdout: true,
307
+ silent: true,
308
+ });
309
+ return line;
310
+ });
311
+ },
271
312
  };
272
313
  }
273
314
 
package/src/cli/run.js CHANGED
@@ -169,15 +169,18 @@ class UnderpostRun {
169
169
  */
170
170
  'dev-cluster': (path, options = UnderpostRun.DEFAULT_OPTION) => {
171
171
  const baseCommand = options.dev ? 'node bin' : 'underpost';
172
- shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
173
- shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
174
172
  const mongoHosts = ['mongodb-0.mongodb-service'];
175
- shellExec(
176
- `${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${mongoHosts.join(
177
- ',',
178
- )} --pull-image`,
179
- );
180
- shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
173
+ if (path !== 'expose') {
174
+ shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
175
+ shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
176
+
177
+ shellExec(
178
+ `${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${mongoHosts.join(
179
+ ',',
180
+ )} --pull-image`,
181
+ );
182
+ shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
183
+ }
181
184
  shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
182
185
  shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
183
186
  {
@@ -197,6 +200,31 @@ class UnderpostRun {
197
200
  shellExec(`chmod +x ${underpostRoot}/scripts/ssh-cluster-info.sh`);
198
201
  shellExec(`${underpostRoot}/scripts/ssh-cluster-info.sh`);
199
202
  },
203
+
204
+ /**
205
+ * @method dev-hosts-expose
206
+ * @description Deploys a specified service in development mode with `/etc/hosts` modification for local access.
207
+ * @param {string} path - The input value, identifier, or path for the operation (used as the deployment ID to deploy).
208
+ * @param {Object} options - The default underpost runner options for customizing workflow
209
+ * @memberof UnderpostRun
210
+ */
211
+ 'dev-hosts-expose': (path, options = UnderpostRun.DEFAULT_OPTION) => {
212
+ shellExec(
213
+ `node bin deploy ${path} development --disable-update-deployment --disable-update-proxy --kubeadm --etc-hosts`,
214
+ );
215
+ },
216
+
217
+ /**
218
+ * @method dev-hosts-restore
219
+ * @description Restores the `/etc/hosts` file to its original state after modifications made during development deployments.
220
+ * @param {string} path - The input value, identifier, or path for the operation.
221
+ * @param {Object} options - The default underpost runner options for customizing workflow
222
+ * @memberof UnderpostRun
223
+ */
224
+ 'dev-hosts-restore': (path, options = UnderpostRun.DEFAULT_OPTION) => {
225
+ shellExec(`node bin deploy --restore-hosts`);
226
+ },
227
+
200
228
  /**
201
229
  * @method cyberia-ide
202
230
  * @description Starts the development environment (IDE) for both `cyberia-server` and `cyberia-client` repositories.
@@ -244,7 +272,7 @@ class UnderpostRun {
244
272
  * @memberof UnderpostRun
245
273
  */
246
274
  'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
247
- const baseCommand = options.dev || true ? 'node bin' : 'underpost';
275
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
248
276
  shellExec(`${baseCommand} run clean`);
249
277
  shellExec(`${baseCommand} push ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
250
278
  shellCd('/home/dd/engine');
@@ -301,7 +329,7 @@ class UnderpostRun {
301
329
  */
302
330
  'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
303
331
  actionInitLog();
304
- const baseCommand = options.dev || true ? 'node bin' : 'underpost';
332
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
305
333
  shellCd('/home/dd/engine');
306
334
  shellExec(`git reset`);
307
335
  shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
@@ -309,14 +337,14 @@ class UnderpostRun {
309
337
  },
310
338
  /**
311
339
  * @method ide
312
- * @description Opens a Visual Studio Code (VS Code) session for the specified path using `node ${underpostRoot}/bin/vs ${path}`.
340
+ * @description Opens a Visual Studio Code (VS Code) session for the specified path using `node ${underpostRoot}/bin/zed ${path}`.
313
341
  * @param {string} path - The input value, identifier, or path for the operation (used as the path to the directory to open in the IDE).
314
342
  * @param {Object} options - The default underpost runner options for customizing workflow
315
343
  * @memberof UnderpostRun
316
344
  */
317
345
  ide: (path, options = UnderpostRun.DEFAULT_OPTION) => {
318
346
  const { underpostRoot } = options;
319
- shellExec(`node ${underpostRoot}/bin/vs ${path}`);
347
+ shellExec(`node ${underpostRoot}/bin/zed ${path}`);
320
348
  },
321
349
  /**
322
350
  * @method sync
@@ -328,7 +356,7 @@ class UnderpostRun {
328
356
  sync: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
329
357
  // Dev usage: node bin run --dev --build sync dd-default
330
358
  const env = options.dev ? 'development' : 'production';
331
- const baseCommand = options.dev || true ? 'node bin' : 'underpost';
359
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
332
360
  const defaultPath = [
333
361
  'dd-default',
334
362
  1,
@@ -337,11 +365,11 @@ class UnderpostRun {
337
365
  options.dev || !isDeployRunnerContext(path, options) ? 'kind-control-plane' : os.hostname(),
338
366
  ];
339
367
  let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
340
- deployId = deployId ?? defaultPath[0];
341
- replicas = replicas ?? defaultPath[1];
342
- versions = versions ?? defaultPath[2];
343
- image = image ?? defaultPath[3];
344
- node = node ?? defaultPath[4];
368
+ deployId = deployId ? deployId : defaultPath[0];
369
+ replicas = replicas ? replicas : defaultPath[1];
370
+ versions = versions ? versions.replaceAll('+', ',') : defaultPath[2];
371
+ image = image ? image : defaultPath[3];
372
+ node = node ? node : defaultPath[4];
345
373
 
346
374
  if (isDeployRunnerContext(path, options)) {
347
375
  const { validVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
@@ -357,13 +385,11 @@ class UnderpostRun {
357
385
  shellExec(
358
386
  `${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
359
387
  replicas ?? 1
360
- } --node ${node}${image ? ` --image ${image}` : ''}${
361
- versions ? ` --versions ${versions.replaceAll('+', ',')}` : ''
362
- } dd ${env}`,
388
+ } --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
363
389
  );
364
390
 
365
391
  if (isDeployRunnerContext(path, options)) {
366
- shellExec(`${baseCommand} deploy --kubeadm ${deployId} ${env}`);
392
+ shellExec(`${baseCommand} deploy --kubeadm --disable-update-proxy ${deployId} ${env} --versions ${versions}`);
367
393
  if (!targetTraffic) targetTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
368
394
  await UnderpostDeploy.API.monitorReadyRunner(deployId, env, targetTraffic);
369
395
  UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
@@ -529,36 +555,56 @@ class UnderpostRun {
529
555
  },
530
556
  /**
531
557
  * @method cluster
532
- * @description Deploys a full production-ready Kubernetes cluster environment including MongoDB, MariaDB, Valkey, Contour (Ingress), and Cert-Manager, and deploys all services.
558
+ * @description Deploys a full production/development ready Kubernetes cluster environment including MongoDB, MariaDB, Valkey, Contour (Ingress), and Cert-Manager, and deploys all services.
533
559
  * @param {string} path - The input value, identifier, or path for the operation.
534
560
  * @param {Object} options - The default underpost runner options for customizing workflow
535
561
  * @memberof UnderpostRun
536
562
  */
537
- cluster: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
538
- const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
539
- const env = 'production';
563
+ cluster: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
564
+ const env = options.dev ? 'development' : 'production';
565
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
566
+ const baseClusterCommand = options.dev ? ' --dev' : '';
540
567
  shellCd(`/home/dd/engine`);
541
- shellExec(`underpost cluster --reset`);
542
- await timer(5000);
543
- shellExec(`underpost cluster --kubeadm`);
568
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --reset`);
544
569
  await timer(5000);
545
- shellExec(`underpost dockerfile-pull-base-images --path /home/dd/engine/src/runtime/lampp --kubeadm-load`);
570
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --kubeadm`);
546
571
  await timer(5000);
547
- shellExec(`underpost cluster --kubeadm --pull-image --mongodb`);
572
+ let [runtimeImage, deployList] = path.split(',')
573
+ ? path.split(',')
574
+ : ['lampp', fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').replaceAll(',', '+')];
575
+ shellExec(
576
+ `${baseCommand} dockerfile-pull-base-images${baseClusterCommand}${
577
+ runtimeImage ? ` --path /home/dd/engine/src/runtime/${runtimeImage}` : ''
578
+ } --kubeadm-load`,
579
+ );
580
+ if (!deployList) {
581
+ deployList = [];
582
+ logger.warn('No deploy list provided');
583
+ } else deployList = deployList.split('+');
548
584
  await timer(5000);
549
- shellExec(`underpost cluster --kubeadm --pull-image --mariadb`);
585
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --kubeadm --pull-image --mongodb`);
586
+ if (runtimeImage === 'lampp') {
587
+ await timer(5000);
588
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --kubeadm --pull-image --mariadb`);
589
+ }
550
590
  await timer(5000);
551
591
  for (const deployId of deployList) {
552
- shellExec(`underpost db ${deployId} --import --git`);
592
+ shellExec(`${baseCommand} db ${deployId} --import --git`);
553
593
  }
554
594
  await timer(5000);
555
- shellExec(`underpost cluster --kubeadm --pull-image --valkey`);
556
- await timer(5000);
557
- shellExec(`underpost cluster --kubeadm --contour`);
595
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --kubeadm --pull-image --valkey`);
558
596
  await timer(5000);
559
- shellExec(`underpost cluster --kubeadm --cert-manager`);
597
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --kubeadm --contour`);
598
+ if (env === 'production') {
599
+ await timer(5000);
600
+ shellExec(`${baseCommand} cluster${baseClusterCommand} --kubeadm --cert-manager`);
601
+ }
560
602
  for (const deployId of deployList) {
561
- shellExec(`underpost deploy ${deployId} ${env} --kubeadm --cert`);
603
+ shellExec(
604
+ `${baseCommand} deploy ${deployId} ${env} --kubeadm${env === 'production' ? ' --cert' : ''}${
605
+ env === 'development' ? ' --etc-hosts' : ''
606
+ }`,
607
+ );
562
608
  }
563
609
  },
564
610
  /**
@@ -593,7 +639,7 @@ class UnderpostRun {
593
639
  */
594
640
  'sync-replica': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
595
641
  const env = options.dev ? 'development' : 'production';
596
- const baseCommand = options.dev || true ? 'node bin' : 'underpost';
642
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
597
643
 
598
644
  for (let deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
599
645
  deployId = deployId.trim();
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ class Underpost {
35
35
  * @type {String}
36
36
  * @memberof Underpost
37
37
  */
38
- static version = 'v2.8.886';
38
+ static version = 'v2.81.0';
39
39
  /**
40
40
  * Repository cli API
41
41
  * @static
@@ -0,0 +1,41 @@
1
+ FROM rockylinux:9
2
+
3
+ # --- Update and install required packages
4
+ RUN dnf -y update && \
5
+ dnf -y install epel-release && \
6
+ dnf -y install --allowerasing \
7
+ bzip2 \
8
+ sudo \
9
+ curl \
10
+ net-tools \
11
+ openssh-server \
12
+ nano \
13
+ vim-enhanced \
14
+ less \
15
+ openssl-devel \
16
+ wget \
17
+ git \
18
+ gnupg2 \
19
+ libnsl \
20
+ perl && \
21
+ dnf clean all
22
+
23
+
24
+ # Install Node.js
25
+ RUN curl -fsSL https://rpm.nodesource.com/setup_24.x | bash -
26
+ RUN dnf install nodejs -y
27
+ RUN dnf clean all
28
+
29
+ # Verify Node.js and npm versions
30
+ RUN node --version
31
+ RUN npm --version
32
+
33
+ # Set working directory
34
+ WORKDIR /home/dd
35
+
36
+ # Expose necessary ports
37
+ EXPOSE 22
38
+ EXPOSE 80
39
+ EXPOSE 443
40
+ EXPOSE 3000-3100
41
+ EXPOSE 4000-4100
@@ -11,6 +11,7 @@ import {
11
11
  capFirst,
12
12
  getCapVariableName,
13
13
  newInstance,
14
+ orderAbc,
14
15
  orderArrayFromAttrInt,
15
16
  range,
16
17
  timer,
@@ -154,18 +155,20 @@ const Config = {
154
155
  * @memberof ServerConfBuilder
155
156
  */
156
157
  buildProxyByDeployId: function (deployId = 'dd-default', subConf = '') {
157
- let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
158
- const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
158
+ let confPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
159
159
  ? `./engine-private/replica/${deployId}/conf.server.json`
160
- : `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
161
- const confDevPath = fs.existsSync(privateConfDevPath)
162
- ? privateConfDevPath
163
- : `./engine-private/conf/${deployId}/conf.server.dev.json`;
160
+ : `./engine-private/conf/${deployId}/conf.server.json`;
161
+
162
+ if (
163
+ process.env.NODE_ENV === 'development' &&
164
+ subConf &&
165
+ fs.existsSync(`./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`)
166
+ )
167
+ confPath = `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
164
168
 
165
- if (fs.existsSync(confDevPath)) confPath = confDevPath;
166
169
  const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
167
170
 
168
- for (const host of Object.keys(loadReplicas(serverConf)))
171
+ for (const host of Object.keys(loadReplicas(deployId, serverConf)))
169
172
  this.default.server[host] = {
170
173
  ...this.default.server[host],
171
174
  ...serverConf[host],
@@ -231,7 +234,7 @@ const loadConf = (deployId = 'dd-default', subConf) => {
231
234
  const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
232
235
  if (fs.existsSync(devConfPath)) srcConf = fs.readFileSync(devConfPath, 'utf8');
233
236
  }
234
- if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(JSON.parse(srcConf)), null, 4);
237
+ if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(deployId, JSON.parse(srcConf)), null, 4);
235
238
  fs.writeFileSync(`./conf/conf.${typeConf}.json`, srcConf, 'utf8');
236
239
  }
237
240
  fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
@@ -263,19 +266,30 @@ const loadConf = (deployId = 'dd-default', subConf) => {
263
266
  * @param {object} confServer - The server configuration.
264
267
  * @memberof ServerConfBuilder
265
268
  */
266
- const loadReplicas = (confServer) => {
269
+ const loadReplicas = (deployId, confServer) => {
270
+ const confServerOrigin = newInstance(confServer);
267
271
  for (const host of Object.keys(confServer)) {
268
272
  for (const path of Object.keys(confServer[host])) {
269
273
  const { replicas, singleReplica } = confServer[host][path];
270
- if (replicas && !singleReplica)
271
- for (const replicaPath of replicas) {
272
- {
273
- confServer[host][replicaPath] = newInstance(confServer[host][path]);
274
- delete confServer[host][replicaPath].replicas;
274
+ if (replicas) {
275
+ if (!singleReplica)
276
+ for (const replicaPath of replicas) {
277
+ {
278
+ confServer[host][replicaPath] = newInstance(confServer[host][path]);
279
+ delete confServer[host][replicaPath].replicas;
280
+ }
275
281
  }
282
+ else {
283
+ const orderReplica = orderAbc(confServerOrigin[host][path].replicas);
284
+ confServerOrigin[host][path].replicas = orderReplica;
285
+ confServer[host][path].replicas = orderReplica;
276
286
  }
287
+ }
277
288
  }
278
289
  }
290
+ const serverPath = `./engine-private/conf/${deployId}/conf.server${process.env.NODE_ENV === 'production' ? '' : '.dev'}.json`;
291
+ if (fs.existsSync(serverPath)) fs.writeFileSync(serverPath, JSON.stringify(confServerOrigin, null, 4), 'utf8');
292
+
279
293
  return confServer;
280
294
  };
281
295
 
@@ -866,6 +880,7 @@ const getDataDeploy = (
866
880
  let buildDataDeploy = [];
867
881
  for (const deployObj of dataDeploy) {
868
882
  const serverConf = loadReplicas(
883
+ deployObj.deployId,
869
884
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployObj.deployId}/conf.server.json`, 'utf8')),
870
885
  );
871
886
  let replicaDataDeploy = [];
@@ -1039,6 +1054,7 @@ const mergeFile = async (parts = [], outputFilePath) => {
1039
1054
  */
1040
1055
  const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
1041
1056
  const confServer = loadReplicas(
1057
+ deployId,
1042
1058
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
1043
1059
  );
1044
1060
  const hosts = {};
@@ -1306,9 +1322,9 @@ const buildCliDoc = (program, oldVersion, newVersion) => {
1306
1322
  ` +
1307
1323
  baseOptions +
1308
1324
  `
1309
-
1325
+
1310
1326
  <a target="_top" href="https://github.com/${process.env.GITHUB_USERNAME}/pwa-microservices-template/blob/master/cli.md">See complete CLI Docs here.</a>
1311
-
1327
+
1312
1328
  `
1313
1329
  ).replaceAll(oldVersion, newVersion),
1314
1330
  'utf8',
package/src/server/dns.js CHANGED
@@ -8,7 +8,6 @@ import axios from 'axios';
8
8
  import dotenv from 'dotenv';
9
9
  import fs from 'fs';
10
10
  import validator from 'validator';
11
- import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
12
11
  import { loggerFactory } from './logger.js';
13
12
  import UnderpostRootEnv from '../cli/env.js';
14
13
  import dns from 'node:dns';
@@ -35,40 +34,41 @@ class Dns {
35
34
  * @returns {Promise<string>} The public IP address.
36
35
  */
37
36
  static async getPublicIp() {
38
- return await publicIp();
37
+ return await new Promise(async (resolve) => {
38
+ try {
39
+ return axios.get('https://api.ipify.org').then((response) => resolve(response.data));
40
+ } catch (error) {
41
+ logger.error('Error fetching public IP:', { error: error.message, stack: error.stack });
42
+ return resolve(null);
43
+ }
44
+ });
39
45
  }
40
46
 
41
47
  /**
42
- * Retrieves the current public IPv4 address.
43
- * @async
48
+ * Checks for active internet connection by performing a DNS lookup on a specified domain.
44
49
  * @static
45
50
  * @memberof DnsManager
46
- * @returns {Promise<string>} The public IPv4 address.
51
+ * @param {string} [domain='google.com'] The domain to check the connection against.
52
+ * @returns {Promise<boolean>} True if connected, false otherwise.
47
53
  */
48
- static async getPublicIpv4() {
49
- return await publicIpv4();
54
+ static isInternetConnection(domain = 'google.com') {
55
+ return new Promise((resolve) => dns.lookup(domain, {}, (err) => resolve(err ? false : true)));
50
56
  }
51
57
 
52
58
  /**
53
- * Retrieves the current public IPv6 address.
54
- * @async
59
+ * Determines the default network interface name using shell command.
60
+ * This method is primarily intended for Linux environments.
55
61
  * @static
56
62
  * @memberof DnsManager
57
- * @returns {Promise<string>} The public IPv6 address.
58
- */
59
- static async getPublicIpv6() {
60
- return await publicIpv6();
61
- }
62
-
63
- /**
64
- * Checks for active internet connection by performing a DNS lookup on a specified domain.
65
- * @static
63
+ * @returns {string} The default network interface name.
66
64
  * @memberof DnsManager
67
- * @param {string} [domain='google.com'] The domain to check the connection against.
68
- * @returns {Promise<boolean>} True if connected, false otherwise.
69
65
  */
70
- static isInternetConnection(domain = 'google.com') {
71
- return new Promise((resolve) => dns.lookup(domain, {}, (err) => resolve(err ? false : true)));
66
+ static getDefaultNetworkInterface() {
67
+ return shellExec(`ip route | grep default | cut -d ' ' -f 5`, {
68
+ stdout: true,
69
+ silent: true,
70
+ disableLog: true,
71
+ }).trim();
72
72
  }
73
73
 
74
74
  /**
@@ -80,11 +80,7 @@ class Dns {
80
80
  */
81
81
  static getLocalIPv4Address() {
82
82
  // Determine the default network interface name using shell command
83
- const interfaceName = shellExec(`ip route | grep default | cut -d ' ' -f 5`, {
84
- stdout: true,
85
- silent: true,
86
- disableLog: true,
87
- }).trim();
83
+ const interfaceName = Dns.getDefaultNetworkInterface();
88
84
 
89
85
  // Find the IPv4 address associated with the determined interface
90
86
  const networkInfo = os.networkInterfaces()[interfaceName];
@@ -121,7 +117,7 @@ class Dns {
121
117
  let testIp;
122
118
 
123
119
  try {
124
- testIp = await Dns.getPublicIpv4();
120
+ testIp = await Dns.getPublicIp();
125
121
  } catch (error) {
126
122
  logger.error(error, { testIp, stack: error.stack });
127
123
  }
@@ -238,21 +234,6 @@ class Dns {
238
234
  };
239
235
  }
240
236
 
241
- /**
242
- * @namespace Dns
243
- * @description Exported IP object for backward compatibility, mapping to Dns static methods.
244
- */
245
- const ip = {
246
- public: {
247
- /** @type {function(): Promise<string>} */
248
- get: Dns.getPublicIp,
249
- /** @type {function(): Promise<string>} */
250
- ipv4: Dns.getPublicIpv4,
251
- /** @type {function(): Promise<string>} */
252
- ipv6: Dns.getPublicIpv6,
253
- },
254
- };
255
-
256
237
  /**
257
238
  * @function isInternetConnection
258
239
  * @memberof DnsManager
@@ -273,4 +254,4 @@ const getLocalIPv4Address = Dns.getLocalIPv4Address;
273
254
  // Export the class as default and all original identifiers for backward compatibility.
274
255
  export default Dns;
275
256
 
276
- export { Dns, ip, isInternetConnection, getLocalIPv4Address };
257
+ export { Dns, isInternetConnection, getLocalIPv4Address };