@underpostnet/underpost 2.99.0 → 2.99.1

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 CHANGED
@@ -41,5 +41,6 @@ NFS_EXPORT_PATH=changethis
41
41
  NVIDIA_API_KEY=changethis
42
42
  DEFAULT_ADMIN_EMAIL=admin@default.net
43
43
  DEFAULT_ADMIN_PASSWORD=changethis
44
+ DEFAULT_SSH_PORT=22
44
45
  BASE_API=api
45
46
  DEV_PROXY_PORT_OFFSET=200
package/.env.production CHANGED
@@ -50,6 +50,7 @@ NPM_USER=changethis
50
50
  NPM_PASSWORD=changethis
51
51
  POSTMAN_EMAIL=admin@default.net
52
52
  POSTMAN_PASSWORD=changethis
53
+ DEFAULT_SSH_PORT=22
53
54
  BASE_API=api
54
55
  CERTBOT_LIVE_PATH=changethis
55
56
  CERTBOT_LIVE_PATH_WINDOWS=changethis
package/.env.test CHANGED
@@ -41,5 +41,6 @@ NFS_EXPORT_PATH=changethis
41
41
  NVIDIA_API_KEY=changethis
42
42
  DEFAULT_ADMIN_EMAIL=admin@default.net
43
43
  DEFAULT_ADMIN_PASSWORD=changethis
44
+ DEFAULT_SSH_PORT=22
44
45
  BASE_API=api
45
46
  DEV_PROXY_PORT_OFFSET=200
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.ci.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.99.0)](https://socket.dev/npm/package/underpost/overview/2.99.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)
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.ci.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.99.1)](https://socket.dev/npm/package/underpost/overview/2.99.1) [![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.99.0
69
+ ## underpost ci/cd cli v2.99.1
70
70
 
71
71
  ### Usage: `underpost [options] [command]`
72
72
  ```
package/cli.md CHANGED
@@ -1,4 +1,4 @@
1
- ## underpost ci/cd cli v2.99.0
1
+ ## underpost ci/cd cli v2.99.1
2
2
 
3
3
  ### Usage: `underpost [options] [command]`
4
4
  ```
@@ -742,6 +742,10 @@ Options:
742
742
  (e.g., "150ms").
743
743
  --disable-private-conf-update Disables updates to private configuration
744
744
  during execution.
745
+ --versions <deployment-versions> Specifies the deployment versions to
746
+ monitor. eg. "blue,green", "green"
747
+ --ready-deployment Run in ready deployment monitor mode.
748
+ --promote Promotes the deployment after monitoring.
745
749
  -h, --help display help for command
746
750
 
747
751
  ```
@@ -796,7 +800,7 @@ Options:
796
800
  Runs specified scripts using various runners.
797
801
 
798
802
  Arguments:
799
- runner-id The runner ID to run. Options: dev-cluster,metadata,svc-ls,svc-rm,ssh-cluster-info,dev-hosts-expose,dev-hosts-restore,cluster-build,template-deploy,template-deploy-image,clean,pull,release-deploy,ssh-deploy,ide,crypto-policy,sync,stop,ssh-deploy-stop,tz,cron,get-proxy,instance-promote,instance,ls-deployments,host-update,dd-container,ip-info,monitor,db-client,git-conf,promote,metrics,cluster,deploy,disk-clean,disk-usage,dev,service,etc-hosts,sh,log,ps,ptls,release-cmt,deploy-test,sync-replica,tf-vae-test,spark-template,rmi,kill,secret,underpost-config,gpu-env,tf-gpu-test,deploy-job.
803
+ runner-id The runner ID to run. Options: dev-cluster,metadata,svc-ls,svc-rm,ssh-deploy-info,dev-hosts-expose,dev-hosts-restore,cluster-build,template-deploy,template-deploy-image,clean,pull,release-deploy,ssh-deploy,ide,crypto-policy,sync,stop,ssh-deploy-stop,ssh-deploy-db-rollback,ssh-deploy-db,ssh-deploy-db-status,tz,cron,get-proxy,instance-promote,instance,ls-deployments,host-update,dd-container,ip-info,monitor,db-client,git-conf,promote,metrics,cluster,deploy,disk-clean,disk-usage,dev,service,etc-hosts,sh,log,ps,ptls,release-cmt,deploy-test,sync-replica,tf-vae-test,spark-template,rmi,kill,secret,underpost-config,gpu-env,tf-gpu-test,deploy-job.
800
804
  path The input value, identifier, or path for the operation.
801
805
 
802
806
  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.99.0
20
+ image: localhost/rockylinux9-underpost:v2.99.1
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.99.0
103
+ image: localhost/rockylinux9-underpost:v2.99.1
104
104
  # resources:
105
105
  # requests:
106
106
  # memory: "124Ki"
@@ -18,7 +18,7 @@ spec:
18
18
  spec:
19
19
  containers:
20
20
  - name: dd-test-development-blue
21
- image: localhost/rockylinux9-underpost:v2.99.0
21
+ image: localhost/rockylinux9-underpost:v2.99.1
22
22
 
23
23
  command:
24
24
  - /bin/sh
@@ -103,7 +103,7 @@ spec:
103
103
  spec:
104
104
  containers:
105
105
  - name: dd-test-development-green
106
- image: localhost/rockylinux9-underpost:v2.99.0
106
+ image: localhost/rockylinux9-underpost:v2.99.1
107
107
 
108
108
  command:
109
109
  - /bin/sh
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "@underpostnet/underpost",
5
- "version": "2.99.0",
5
+ "version": "2.99.1",
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",
package/src/cli/deploy.js CHANGED
@@ -166,7 +166,7 @@ spec:
166
166
  spec:
167
167
  containers:
168
168
  - name: ${deployId}-${env}-${suffix}
169
- image: ${image ?? `localhost/rockylinux9-underpost:v${packageJson.version}`}
169
+ image: ${image ? image : `localhost/rockylinux9-underpost:v${packageJson.version}`}
170
170
  ${
171
171
  resources
172
172
  ? ` resources:
package/src/cli/env.js CHANGED
@@ -27,7 +27,7 @@ class UnderpostRootEnv {
27
27
  * @param {string} value - The value of the environment variable to set.
28
28
  * @param {object} options - Options for setting the environment variable.
29
29
  * @param {string} [options.deployId=''] - Deployment ID associated with the environment variable.
30
- * @param {boolean} [options.build=false] - If true, triggers a build after setting the environment variable.
30
+ * @param {boolean} [options.build=false] - If true, sets the environment variable using custom --deploy-id or all dd.router deploy ids configured.
31
31
  * @memberof UnderpostEnv
32
32
  */
33
33
  set(key, value, options = { deployId: '', build: false }) {
package/src/cli/index.js CHANGED
@@ -456,6 +456,9 @@ program
456
456
  .option('--retry-count <count>', 'Sets HTTPProxy per-route retry count (e.g., 3).')
457
457
  .option('--retry-per-try-timeout <duration>', 'Sets HTTPProxy retry per-try timeout (e.g., "150ms").')
458
458
  .option('--disable-private-conf-update', 'Disables updates to private configuration during execution.')
459
+ .option('--versions <deployment-versions>', 'Specifies the deployment versions to monitor. eg. "blue,green", "green"')
460
+ .option('--ready-deployment', 'Run in ready deployment monitor mode.')
461
+ .option('--promote', 'Promotes the deployment after monitoring.')
459
462
  .description('Manages health server monitoring for specified deployments.')
460
463
  .action(Underpost.monitor.callback);
461
464
 
@@ -42,6 +42,9 @@ class UnderpostMonitor {
42
42
  * @param {string} [options.timeoutIdle=''] - Timeout for idle connections.
43
43
  * @param {string} [options.retryCount=''] - Number of retry attempts for health checks.
44
44
  * @param {string} [options.retryPerTryTimeout=''] - Timeout per retry attempt.
45
+ * @param {boolean} [options.promote=false] - Promote the deployment after monitoring.
46
+ * @param {boolean} [options.readyDeployment=false] - Monitor until the deployment is ready.
47
+ * @param {string} [options.versions=''] - Specific version of the deployment to monitor.
45
48
  * @param {object} [commanderOptions] - Options passed from the command line interface.
46
49
  * @param {object} [auxRouter] - Optional router configuration for the deployment.
47
50
  * @memberof UnderpostMonitor
@@ -61,6 +64,9 @@ class UnderpostMonitor {
61
64
  timeoutIdle: '',
62
65
  retryCount: '',
63
66
  retryPerTryTimeout: '',
67
+ promote: false,
68
+ readyDeployment: false,
69
+ versions: '',
64
70
  },
65
71
  commanderOptions,
66
72
  auxRouter,
@@ -79,6 +85,17 @@ class UnderpostMonitor {
79
85
  return;
80
86
  }
81
87
 
88
+ if (options.readyDeployment) {
89
+ for (const version of options.versions.split(',')) {
90
+ (async () => {
91
+ await Underpost.deploy.monitorReadyRunner(deployId, env, version, [], options.namespace, 'underpost');
92
+ if (options.promote)
93
+ Underpost.deploy.switchTraffic(deployId, env, version, options.replicas, options.namespace, options);
94
+ })();
95
+ }
96
+ return;
97
+ }
98
+
82
99
  const router = auxRouter ?? (await Underpost.deploy.routerFactory(deployId, env));
83
100
 
84
101
  const confServer = loadReplicas(
package/src/cli/run.js CHANGED
@@ -255,17 +255,25 @@ class UnderpostRun {
255
255
  },
256
256
 
257
257
  /**
258
- * @method ssh-cluster-info
259
- * @description Executes the `ssh-cluster-info.sh` script to display cluster connection information.
258
+ * @method ssh-deploy-info
259
+ * @description Retrieves deployment status and pod information from a remote server via SSH.
260
260
  * @param {string} path - The input value, identifier, or path for the operation.
261
261
  * @param {Object} options - The default underpost runner options for customizing workflow
262
262
  * @memberof UnderpostRun
263
263
  */
264
- 'ssh-cluster-info': async (path, options = DEFAULT_OPTION) => {
265
- const { underpostRoot } = options;
266
- if (options.deployId && options.user) await Underpost.ssh.setDefautlSshCredentials(options);
267
- shellExec(`chmod +x ${underpostRoot}/scripts/ssh-cluster-info.sh`);
268
- shellExec(`${underpostRoot}/scripts/ssh-cluster-info.sh`);
264
+ 'ssh-deploy-info': async (path = '', options = DEFAULT_OPTION) => {
265
+ const env = options.dev ? 'development' : 'production';
266
+ await Underpost.ssh.sshRemoteRunner(
267
+ `node bin deploy ${path ? path : 'dd'} ${env} --status && kubectl get pods -A`,
268
+ {
269
+ deployId: options.deployId,
270
+ user: options.user,
271
+ dev: options.dev,
272
+ remote: true,
273
+ useSudo: true,
274
+ cd: '/home/dd/engine',
275
+ },
276
+ );
269
277
  },
270
278
 
271
279
  /**
@@ -494,19 +502,19 @@ class UnderpostRun {
494
502
  if (targetTraffic) versions = versions ? versions : targetTraffic;
495
503
 
496
504
  const timeoutFlags = Underpost.deploy.timeoutFlagsFactory(options);
505
+ const cmdString = options.cmd
506
+ ? ' --cmd ' + (options.cmd.find((c) => c.match('"')) ? '"' + options.cmd + '"' : "'" + options.cmd + "'")
507
+ : '';
497
508
 
498
509
  shellExec(
499
510
  `${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${replicas} --node ${node}${
500
511
  image ? ` --image ${image}` : ''
501
512
  }${versions ? ` --versions ${versions}` : ''}${
502
513
  options.namespace ? ` --namespace ${options.namespace}` : ''
503
- }${timeoutFlags} dd ${env}`,
514
+ }${timeoutFlags}${cmdString} dd ${env}`,
504
515
  );
505
516
 
506
517
  if (isDeployRunnerContext(path, options)) {
507
- const cmdString = options.cmd
508
- ? ` --cmd ${options.cmd.find((c) => c.match('"')) ? `"${options.cmd}"` : `'${options.cmd}'`}`
509
- : '';
510
518
  shellExec(
511
519
  `${baseCommand} deploy --kubeadm${cmdString} --replicas ${replicas} --disable-update-proxy ${deployId} ${env} --versions ${versions}${
512
520
  options.namespace ? ` --namespace ${options.namespace}` : ''
@@ -552,29 +560,121 @@ class UnderpostRun {
552
560
  * @memberof UnderpostRun
553
561
  */
554
562
  'ssh-deploy-stop': async (path, options = DEFAULT_OPTION) => {
555
- const env = options.dev ? 'development' : 'production';
556
563
  const baseCommand = options.dev ? 'node bin' : 'underpost';
557
564
  const baseClusterCommand = options.dev ? ' --dev' : '';
558
- await Underpost.ssh.setDefautlSshCredentials(options);
559
- shellExec(`#!/usr/bin/env bash
560
- set -euo pipefail
561
-
562
- REMOTE_USER=$(node bin config get --plain DEFAULT_SSH_USER)
563
- REMOTE_HOST=$(node bin config get --plain DEFAULT_SSH_HOST)
564
- REMOTE_PORT=$(node bin config get --plain DEFAULT_SSH_PORT)
565
- SSH_KEY=$(node bin config get --plain DEFAULT_SSH_KEY_PATH)
566
-
567
- chmod 600 "$SSH_KEY"
568
565
 
569
- ssh -i "$SSH_KEY" -o BatchMode=yes "$REMOTE_USER@$REMOTE_HOST" -p $REMOTE_PORT sh <<EOF
570
- cd /home/dd/engine
571
- sudo -n -- /bin/bash -lc "${[
566
+ const remoteCommand = [
572
567
  `${baseCommand} run${baseClusterCommand} stop${path ? ` ${path}` : ''}`,
573
568
  ` --deploy-id ${options.deployId}${options.instanceId ? ` --instance-id ${options.instanceId}` : ''}`,
574
569
  ` --namespace ${options.namespace}${options.hosts ? ` --hosts ${options.hosts}` : ''}`,
575
- ].join('')}"
576
- EOF
577
- `);
570
+ ].join('');
571
+
572
+ await Underpost.ssh.sshRemoteRunner(remoteCommand, {
573
+ deployId: options.deployId,
574
+ user: options.user,
575
+ dev: options.dev,
576
+ remote: true,
577
+ useSudo: true,
578
+ cd: '/home/dd/engine',
579
+ });
580
+ },
581
+
582
+ /**
583
+ * @method ssh-deploy-db-rollback
584
+ * @description Performs a database rollback on remote deployment via SSH.
585
+ * @param {string} path - Comma-separated deployId and optional number of commits to reset (format: "deployId,nCommits")
586
+ * @param {Object} options - The default underpost runner options for customizing workflow
587
+ * @param {string} options.deployId - The deployment identifier
588
+ * @param {string} options.user - The SSH user for credential lookup
589
+ * @param {boolean} options.dev - Development mode flag
590
+ * @memberof UnderpostRun
591
+ */
592
+ 'ssh-deploy-db-rollback': async (path = '', options = DEFAULT_OPTION) => {
593
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
594
+ let [deployId, nCommitsReset] = path.split(',');
595
+ if (!nCommitsReset) nCommitsReset = 1;
596
+
597
+ const remoteCommand = `${baseCommand} db ${deployId} --git --kubeadm --primary-pod --force-clone --macro-rollback-export ${nCommitsReset}${options.namespace ? ` --ns ${options.namespace}` : ''}`;
598
+
599
+ await Underpost.ssh.sshRemoteRunner(remoteCommand, {
600
+ deployId: options.deployId,
601
+ user: options.user,
602
+ dev: options.dev,
603
+ remote: true,
604
+ useSudo: true,
605
+ cd: '/home/dd/engine',
606
+ });
607
+ },
608
+
609
+ /**
610
+ * @method ssh-deploy-db
611
+ * @description Imports/restores a database on remote deployment via SSH.
612
+ * @param {string} path - The deployment ID for database import
613
+ * @param {Object} options - The default underpost runner options for customizing workflow
614
+ * @param {string} options.deployId - The deployment identifier
615
+ * @param {string} options.user - The SSH user for credential lookup
616
+ * @param {boolean} options.dev - Development mode flag
617
+ * @memberof UnderpostRun
618
+ */
619
+ 'ssh-deploy-db': async (path, options = DEFAULT_OPTION) => {
620
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
621
+
622
+ const remoteCommand = `${baseCommand} db ${path} --import --drop --preserveUUID --git --kubeadm --primary-pod --force-clone${options.namespace ? ` --ns ${options.namespace}` : ''}`;
623
+
624
+ await Underpost.ssh.sshRemoteRunner(remoteCommand, {
625
+ deployId: options.deployId,
626
+ user: options.user,
627
+ dev: options.dev,
628
+ remote: true,
629
+ useSudo: true,
630
+ cd: '/home/dd/engine',
631
+ });
632
+ },
633
+
634
+ /**
635
+ * @method ssh-deploy-db-status
636
+ * @description Retrieves database status/stats for a deployment (or all deployments from dd.router) via SSH.
637
+ * @param {string} path - Comma-separated deployId(s) or 'dd' to use the dd.router list.
638
+ * @param {Object} options - Runner options (uses options.deployId for SSH host lookup).
639
+ * @param {string} options.deployId - Deployment identifier used for SSH config lookup.
640
+ * @param {string} options.user - SSH user for credential lookup.
641
+ * @param {boolean} options.dev - Development mode flag.
642
+ * @param {string} [options.namespace] - Kubernetes namespace to pass to the db check.
643
+ * @memberof UnderpostRun
644
+ */
645
+ 'ssh-deploy-db-status': async (path = '', options = DEFAULT_OPTION) => {
646
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
647
+
648
+ let deployList = [];
649
+ if (!path || path === 'dd') {
650
+ if (!fs.existsSync('./engine-private/deploy/dd.router')) {
651
+ logger.warn('dd.router not found; nothing to run');
652
+ return;
653
+ }
654
+ deployList = fs
655
+ .readFileSync('./engine-private/deploy/dd.router', 'utf8')
656
+ .split(',')
657
+ .map((d) => d.trim())
658
+ .filter(Boolean);
659
+ } else {
660
+ deployList = path
661
+ .split(',')
662
+ .map((d) => d.trim())
663
+ .filter(Boolean);
664
+ }
665
+
666
+ for (const deployId of deployList) {
667
+ const remoteCommand = `${baseCommand} db ${deployId} --stats --kubeadm --primary-pod${options.namespace ? ` --ns ${options.namespace}` : ''}`;
668
+
669
+ await Underpost.ssh.sshRemoteRunner(remoteCommand, {
670
+ deployId: options.deployId,
671
+ user: options.user,
672
+ dev: options.dev,
673
+ remote: true,
674
+ useSudo: true,
675
+ cd: '/home/dd/engine',
676
+ });
677
+ }
578
678
  },
579
679
 
580
680
  /**
@@ -1134,7 +1234,9 @@ EOF
1134
1234
  }
1135
1235
  await timer(5000);
1136
1236
  for (const deployId of deployList) {
1137
- shellExec(`${baseCommand} db ${deployId} --import --git --drop --preserveUUID --primary-pod`);
1237
+ shellExec(
1238
+ `${baseCommand} db ${deployId} --import --git --drop --preserveUUID --primary-pod${options.namespace ? ` --ns ${options.namespace}` : ''}`,
1239
+ );
1138
1240
  }
1139
1241
  await timer(5000);
1140
1242
  shellExec(`${baseCommand} cluster${baseClusterCommand} --${clusterType} --pull-image --valkey`);
@@ -1148,7 +1250,7 @@ EOF
1148
1250
  shellExec(
1149
1251
  `${baseCommand} deploy ${deployId} ${env} --${clusterType}${env === 'production' ? ' --cert' : ''}${
1150
1252
  env === 'development' ? ' --etc-hosts' : ''
1151
- }`,
1253
+ }${options.namespace ? ` --namespace ${options.namespace}` : ''}`,
1152
1254
  );
1153
1255
  }
1154
1256
  },
@@ -1165,7 +1267,7 @@ EOF
1165
1267
  if (!validVersion) throw new Error('Version mismatch');
1166
1268
  const currentTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace });
1167
1269
  const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
1168
- const env = 'production';
1270
+ const env = options.dev ? 'development' : 'production';
1169
1271
  const ignorePods = Underpost.deploy
1170
1272
  .get(`${deployId}-${env}-${targetTraffic}`, 'pods', options.namespace)
1171
1273
  .map((p) => p.NAME);
package/src/cli/ssh.js CHANGED
@@ -496,6 +496,55 @@ EOF`);
496
496
  if (options.status) shellExec('service sshd status');
497
497
  },
498
498
 
499
+ /**
500
+ * Generic SSH remote command runner that centralizes SSH execution logic.
501
+ * Executes arbitrary shell commands on a remote server via SSH with proper credential handling.
502
+ * @async
503
+ * @function sshRemoteRunner
504
+ * @param {string} remoteCommand - The command to execute on the remote server
505
+ * @param {Object} options - Configuration options for SSH execution
506
+ * @param {string} [options.deployId] - Deployment ID for credential lookup
507
+ * @param {string} [options.user] - SSH user for credential lookup
508
+ * @param {boolean} [options.dev=false] - Development mode flag
509
+ * @param {string} [options.cd='/home/dd/engine'] - Working directory on remote server
510
+ * @param {boolean} [options.useSudo=true] - Whether to use sudo for command execution
511
+ * @param {boolean} [options.remote=true] - Whether to execute as remote command (if false, runs locally)
512
+ * @returns {Promise<string>} Output from the shell execution
513
+ * @memberof UnderpostSSH
514
+ */
515
+ sshRemoteRunner: async (remoteCommand, options = {}) => {
516
+ const { deployId = '', user = '', dev = false, cd = '/home/dd/engine', useSudo = true, remote = true } = options;
517
+
518
+ // If not executing remotely, just run locally
519
+ if (!remote) {
520
+ return shellExec(remoteCommand);
521
+ }
522
+
523
+ // Set up SSH credentials from config
524
+ if (deployId && user) {
525
+ await Underpost.ssh.setDefautlSshCredentials({ deployId, user });
526
+ }
527
+
528
+ // Build the complete SSH command
529
+ const sshScript = `#!/usr/bin/env bash
530
+ set -euo pipefail
531
+
532
+ REMOTE_USER=$(node bin config get --plain DEFAULT_SSH_USER)
533
+ REMOTE_HOST=$(node bin config get --plain DEFAULT_SSH_HOST)
534
+ REMOTE_PORT=$(node bin config get --plain DEFAULT_SSH_PORT)
535
+ SSH_KEY=$(node bin config get --plain DEFAULT_SSH_KEY_PATH)
536
+
537
+ chmod 600 "$SSH_KEY"
538
+
539
+ ssh -i "$SSH_KEY" -o BatchMode=yes "$REMOTE_USER@$REMOTE_HOST" -p $REMOTE_PORT sh <<EOF
540
+ ${cd ? `cd ${cd}` : ''}
541
+ ${useSudo ? `sudo -n -- /bin/bash -lc "${remoteCommand}"` : remoteCommand}
542
+ EOF
543
+ `;
544
+
545
+ return shellExec(sshScript, { stdout: true });
546
+ },
547
+
499
548
  /**
500
549
  * Loads saved SSH credentials from config and sets them in the UnderpostRootEnv API.
501
550
  * @async
package/src/index.js CHANGED
@@ -38,7 +38,7 @@ class Underpost {
38
38
  * @type {String}
39
39
  * @memberof Underpost
40
40
  */
41
- static version = 'v2.99.0';
41
+ static version = 'v2.99.1';
42
42
  /**
43
43
  * Repository cli API
44
44
  * @static
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- REMOTE_USER=$(node bin config get --plain DEFAULT_SSH_USER)
5
- REMOTE_HOST=$(node bin config get --plain DEFAULT_SSH_HOST)
6
- REMOTE_PORT=$(node bin config get --plain DEFAULT_SSH_PORT)
7
- SSH_KEY=$(node bin config get --plain DEFAULT_SSH_KEY_PATH)
8
-
9
- chmod 600 "$SSH_KEY"
10
-
11
- ssh -i "$SSH_KEY" -o BatchMode=yes "${REMOTE_USER}@${REMOTE_HOST}" -p ${REMOTE_PORT} sh <<EOF
12
- cd /home/dd/engine
13
- sudo -n -- /bin/bash -lc "node bin deploy dd production --status"
14
- sudo -n -- /bin/bash -lc "kubectl get pods -A"
15
- EOF