underpost 2.89.0 → 2.89.2
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/.github/workflows/release.cd.yml +2 -0
- package/README.md +2 -2
- package/bin/index.js +8 -1
- package/cli.md +53 -45
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -0
- package/manifests/grafana/deployment.yaml +7 -0
- package/manifests/grafana/kustomization.yaml +1 -1
- package/manifests/grafana/pvc.yaml +1 -1
- package/manifests/grafana/storage-class.yaml +9 -0
- package/package.json +1 -1
- package/scripts/rpmfusion-ffmpeg-setup.sh +55 -0
- package/src/cli/cluster.js +10 -0
- package/src/cli/deploy.js +84 -70
- package/src/cli/index.js +7 -1
- package/src/cli/run.js +139 -37
- package/src/client/components/core/Pagination.js +42 -7
- package/src/client/components/core/Router.js +32 -0
- package/src/index.js +1 -1
- package/src/server/client-build.js +2 -2
|
@@ -30,7 +30,9 @@ jobs:
|
|
|
30
30
|
echo "Starting remote release deploy"
|
|
31
31
|
underpost run pull
|
|
32
32
|
underpost run secret
|
|
33
|
+
npm install -g underpost
|
|
33
34
|
cd /home/dd/engine
|
|
35
|
+
underpost run secret
|
|
34
36
|
node bin run --dev git-conf
|
|
35
37
|
node bin run --dev template-deploy-image
|
|
36
38
|
node bin run --dev ssh-deploy sync-engine-test
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<!-- badges -->
|
|
20
20
|
|
|
21
|
-
[](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [](https://www.npmjs.com/package/underpost) [](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [](https://www.npmjs.com/package/underpost) [](https://socket.dev/npm/package/underpost/overview/2.89.2) [](https://coveralls.io/github/underpostnet/engine?branch=master) [](https://www.npmjs.org/package/underpost) [](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.89.
|
|
69
|
+
## underpost ci/cd cli v2.89.2
|
|
70
70
|
|
|
71
71
|
### Usage: `underpost [options] [command]`
|
|
72
72
|
```
|
package/bin/index.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { program } from '../src/cli/index.js';
|
|
4
|
+
import { loggerFactory } from '../src/server/logger.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const logger = loggerFactory(import.meta);
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
program.parse();
|
|
10
|
+
} catch (error) {
|
|
11
|
+
logger.error(error);
|
|
12
|
+
}
|
package/cli.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v2.89.
|
|
1
|
+
## underpost ci/cd cli v2.89.2
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -277,6 +277,8 @@ Options:
|
|
|
277
277
|
kubeconfig files.
|
|
278
278
|
--k3s Initializes the cluster using K3s (Lightweight
|
|
279
279
|
Kubernetes).
|
|
280
|
+
--hosts <hosts> A comma-separated list of cluster hostnames or IP
|
|
281
|
+
addresses.
|
|
280
282
|
-h, --help display help for command
|
|
281
283
|
|
|
282
284
|
```
|
|
@@ -289,50 +291,53 @@ Options:
|
|
|
289
291
|
Manages application deployments, defaulting to deploying development pods.
|
|
290
292
|
|
|
291
293
|
Arguments:
|
|
292
|
-
deploy-list
|
|
293
|
-
|
|
294
|
-
env
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
deploy-list A comma-separated list of deployment IDs
|
|
295
|
+
(e.g., "default-a,default-b").
|
|
296
|
+
env Optional: The environment for deployment
|
|
297
|
+
(e.g., "development", "production").
|
|
298
|
+
Defaults to "development".
|
|
297
299
|
|
|
298
300
|
Options:
|
|
299
|
-
--remove
|
|
300
|
-
|
|
301
|
-
--sync
|
|
302
|
-
|
|
303
|
-
--info-router
|
|
304
|
-
|
|
305
|
-
--expose
|
|
306
|
-
|
|
307
|
-
--info-util
|
|
308
|
-
|
|
309
|
-
--cert
|
|
310
|
-
|
|
311
|
-
--cert-hosts <hosts>
|
|
312
|
-
|
|
313
|
-
--node <node>
|
|
314
|
-
|
|
315
|
-
--build-manifest
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
--replicas <replicas>
|
|
319
|
-
|
|
320
|
-
--image <image>
|
|
321
|
-
--versions <deployment-versions>
|
|
322
|
-
|
|
323
|
-
--traffic <traffic-versions>
|
|
324
|
-
|
|
325
|
-
--disable-update-deployment
|
|
326
|
-
--disable-update-proxy
|
|
327
|
-
--
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
-
|
|
301
|
+
--remove Deletes specified deployments and their
|
|
302
|
+
associated services.
|
|
303
|
+
--sync Synchronizes deployment environment
|
|
304
|
+
variables, ports, and replica counts.
|
|
305
|
+
--info-router Displays the current router structure and
|
|
306
|
+
configuration.
|
|
307
|
+
--expose Exposes services matching the provided
|
|
308
|
+
deployment ID list.
|
|
309
|
+
--info-util Displays useful `kubectl` utility
|
|
310
|
+
management commands.
|
|
311
|
+
--cert Resets TLS/SSL certificate secrets for
|
|
312
|
+
deployments.
|
|
313
|
+
--cert-hosts <hosts> Resets TLS/SSL certificate secrets for
|
|
314
|
+
specified hosts.
|
|
315
|
+
--node <node> Sets optional node for deployment
|
|
316
|
+
operations.
|
|
317
|
+
--build-manifest Builds Kubernetes YAML manifests,
|
|
318
|
+
including deployments, services, proxies,
|
|
319
|
+
and secrets.
|
|
320
|
+
--replicas <replicas> Sets a custom number of replicas for
|
|
321
|
+
deployments.
|
|
322
|
+
--image <image> Sets a custom image for deployments.
|
|
323
|
+
--versions <deployment-versions> A comma-separated list of custom
|
|
324
|
+
deployment versions.
|
|
325
|
+
--traffic <traffic-versions> A comma-separated list of custom
|
|
326
|
+
deployment traffic weights.
|
|
327
|
+
--disable-update-deployment Disables updates to deployments.
|
|
328
|
+
--disable-update-proxy Disables updates to proxies.
|
|
329
|
+
--disable-deployment-proxy Disables proxies of deployments.
|
|
330
|
+
--status Retrieves current network traffic data
|
|
331
|
+
from resource deployments and the host
|
|
332
|
+
machine network configuration.
|
|
333
|
+
--kubeadm Enables the kubeadm context for deployment
|
|
334
|
+
operations.
|
|
335
|
+
--etc-hosts Enables the etc-hosts context for
|
|
336
|
+
deployment operations.
|
|
337
|
+
--restore-hosts Restores default `/etc/hosts` entries.
|
|
338
|
+
--disable-update-underpost-config Disables updates to Underpost
|
|
339
|
+
configuration during deployment.
|
|
340
|
+
-h, --help display help for command
|
|
336
341
|
|
|
337
342
|
```
|
|
338
343
|
|
|
@@ -623,7 +628,7 @@ Options:
|
|
|
623
628
|
Runs a script from the specified path.
|
|
624
629
|
|
|
625
630
|
Arguments:
|
|
626
|
-
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, cluster-build, template-deploy, template-deploy-image, clean, pull, release-deploy, ssh-deploy, ide, sync, tz, cron, ls-deployments, ls-images, host-update, dev-container, monitor, db-client, git-conf, promote, metrics, cluster, deploy, dev, service, sh, log, release-cmt, sync-replica, tf-vae-test, deploy-job.
|
|
631
|
+
runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, 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, sync, tz, cron, ls-deployments, ls-images, host-update, dev-container, monitor, db-client, git-conf, promote, metrics, cluster, deploy, dev, service, sh, log, release-cmt, sync-replica, tf-vae-test, deploy-job.
|
|
627
632
|
path The absolute or relative directory path where the script is located.
|
|
628
633
|
|
|
629
634
|
Options:
|
|
@@ -632,7 +637,10 @@ Options:
|
|
|
632
637
|
--dev Sets the development context environment for the script.
|
|
633
638
|
--build Set builder context runner
|
|
634
639
|
--replicas <replicas> Sets a custom number of replicas for deployment.
|
|
635
|
-
--pod-name <pod-name> Optional: Specifies the pod name for
|
|
640
|
+
--pod-name <pod-name> Optional: Specifies the pod name for execution.
|
|
641
|
+
--node-name <node-name> Optional: Specifies the node name for execution.
|
|
642
|
+
--port <port> Optional: Specifies the port for execution.
|
|
643
|
+
--etc-hosts Enables etc-hosts context for the runner execution.
|
|
636
644
|
--volume-host-path <volume-host-path> Optional: Specifies the volume host path for test execution.
|
|
637
645
|
--volume-mount-path <volume-mount-path> Optional: Specifies the volume mount path for test execution.
|
|
638
646
|
--volume-type <volume-type> Optional: Specifies the volume type for test execution.
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-default-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.89.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.89.2
|
|
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.89.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v2.89.2
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-test-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.89.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.89.2
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "96294Ki"
|
|
@@ -104,7 +104,7 @@ spec:
|
|
|
104
104
|
spec:
|
|
105
105
|
containers:
|
|
106
106
|
- name: dd-test-development-green
|
|
107
|
-
image: localhost/rockylinux9-underpost:v2.89.
|
|
107
|
+
image: localhost/rockylinux9-underpost:v2.89.2
|
|
108
108
|
# resources:
|
|
109
109
|
# requests:
|
|
110
110
|
# memory: "96294Ki"
|
|
@@ -10,6 +10,7 @@ spec:
|
|
|
10
10
|
routes:
|
|
11
11
|
- conditions:
|
|
12
12
|
- prefix: /
|
|
13
|
+
|
|
13
14
|
enableWebsockets: true
|
|
14
15
|
services:
|
|
15
16
|
- name: dd-test-development-blue-service
|
|
@@ -18,6 +19,7 @@ spec:
|
|
|
18
19
|
|
|
19
20
|
- conditions:
|
|
20
21
|
- prefix: /peer
|
|
22
|
+
|
|
21
23
|
enableWebsockets: true
|
|
22
24
|
services:
|
|
23
25
|
- name: dd-test-development-blue-service
|
|
@@ -35,6 +37,7 @@ spec:
|
|
|
35
37
|
routes:
|
|
36
38
|
- conditions:
|
|
37
39
|
- prefix: /
|
|
40
|
+
|
|
38
41
|
enableWebsockets: true
|
|
39
42
|
services:
|
|
40
43
|
- name: dd-test-development-blue-service
|
|
@@ -43,6 +46,7 @@ spec:
|
|
|
43
46
|
|
|
44
47
|
- conditions:
|
|
45
48
|
- prefix: /peer
|
|
49
|
+
|
|
46
50
|
enableWebsockets: true
|
|
47
51
|
services:
|
|
48
52
|
- name: dd-test-development-blue-service
|
|
@@ -21,6 +21,13 @@ spec:
|
|
|
21
21
|
containers:
|
|
22
22
|
- name: grafana
|
|
23
23
|
image: grafana/grafana:latest
|
|
24
|
+
env:
|
|
25
|
+
# - name: GF_SERVER_ROOT_URL
|
|
26
|
+
# value: '{{GF_SERVER_ROOT_URL}}'
|
|
27
|
+
- name: GF_SERVER_ROOT_URL
|
|
28
|
+
value: '/grafana'
|
|
29
|
+
- name: GF_SERVER_SERVE_FROM_SUB_PATH
|
|
30
|
+
value: 'true'
|
|
24
31
|
imagePullPolicy: IfNotPresent
|
|
25
32
|
ports:
|
|
26
33
|
- containerPort: 3000
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
apiVersion: storage.k8s.io/v1
|
|
2
|
+
kind: StorageClass
|
|
3
|
+
metadata:
|
|
4
|
+
name: grafana-storage-class
|
|
5
|
+
annotations:
|
|
6
|
+
storageclass.kubernetes.io/is-default-class: 'false'
|
|
7
|
+
provisioner: rancher.io/local-path
|
|
8
|
+
reclaimPolicy: Retain
|
|
9
|
+
volumeBindingMode: WaitForFirstConsumer
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Purpose: enable required repos (CRB, EPEL, RPM Fusion) and attempt to install ffmpeg on Rocky/Alma/RHEL-9 compatible systems.
|
|
5
|
+
|
|
6
|
+
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
|
|
7
|
+
echo "This script must be run as root or with sudo. Exiting."
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
echo "1) Ensure dnf-plugins-core is available (for config-manager)"
|
|
12
|
+
dnf -y install dnf-plugins-core || true
|
|
13
|
+
|
|
14
|
+
echo "2) Enable CodeReady / CRB (needed for some deps, e.g. ladspa)"
|
|
15
|
+
# On RHEL you'd use subscription-manager; on CentOS/Rocky/Alma use config-manager
|
|
16
|
+
dnf config-manager --set-enabled crb || true
|
|
17
|
+
|
|
18
|
+
echo "3) Install EPEL release (required by some ffmpeg deps)"
|
|
19
|
+
dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm || true
|
|
20
|
+
|
|
21
|
+
echo "4) Add RPM Fusion (free + nonfree) repositories"
|
|
22
|
+
# Using mirrors.rpmfusion.org recommended links
|
|
23
|
+
dnf -y install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm \
|
|
24
|
+
https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm || true
|
|
25
|
+
|
|
26
|
+
echo "5) Refresh metadata and update system"
|
|
27
|
+
dnf -y makecache
|
|
28
|
+
# Optional: update system packages (comment out if you don't want a full update)
|
|
29
|
+
# dnf -y update
|
|
30
|
+
|
|
31
|
+
echo "6) Try to install audio helper packages that sometimes block ffmpeg (ladspa, rubberband)"
|
|
32
|
+
# These may be provided by CRB/EPEL or other compatible repos
|
|
33
|
+
dnf -y install ladspa || echo "ladspa not available from enabled repos (will try later)"
|
|
34
|
+
dnf -y install rubberband || echo "rubberband not available from enabled repos (will try later)"
|
|
35
|
+
|
|
36
|
+
echo "7) Try installing ffmpeg (several fallbacks tried)"
|
|
37
|
+
if dnf -y install ffmpeg ffmpeg-devel --allowerasing; then
|
|
38
|
+
echo "ffmpeg installed successfully (used --allowerasing)."
|
|
39
|
+
elif dnf -y install ffmpeg ffmpeg-devel --nobest; then
|
|
40
|
+
echo "ffmpeg installed successfully (used --nobest)."
|
|
41
|
+
elif dnf -y install ffmpeg ffmpeg-devel --skip-broken; then
|
|
42
|
+
echo "ffmpeg installed (skip-broken). Some optional packages may have been skipped."
|
|
43
|
+
else
|
|
44
|
+
echo "Automatic install failed."
|
|
45
|
+
echo "Helpful troubleshooting steps:"
|
|
46
|
+
echo " - Check which repo provides ladspa: dnf repoquery --whatprovides 'ladspa'"
|
|
47
|
+
echo " - Check which package provides librubberband: dnf repoquery --whatprovides 'librubberband.so.2'"
|
|
48
|
+
echo " - Try enabling CRB and EPEL (we already attempted that). If ladspa/rubberband are still missing you can fetch their EL9 rpm from a trusted mirror or build them."
|
|
49
|
+
echo " - Example manual install (ONLY if you trust the source): sudo dnf install /path/to/ladspa-*.el9.rpm /path/to/rubberband-*.el9.rpm"
|
|
50
|
+
echo " - After satisfying ladspa/rubberband, rerun: sudo dnf install ffmpeg ffmpeg-devel"
|
|
51
|
+
exit 2
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "\nInstallation finished. Verify with: ffmpeg -version"
|
|
55
|
+
exit 0
|
package/src/cli/cluster.js
CHANGED
|
@@ -58,6 +58,7 @@ class UnderpostCluster {
|
|
|
58
58
|
* @param {boolean} [options.config=false] - Apply general host configuration (SELinux, containerd, sysctl, firewalld).
|
|
59
59
|
* @param {boolean} [options.worker=false] - Configure as a worker node (for Kubeadm or K3s join).
|
|
60
60
|
* @param {boolean} [options.chown=false] - Set up kubectl configuration for the current user.
|
|
61
|
+
* @param {string} [options.hosts] - Set custom hosts entries.
|
|
61
62
|
* @memberof UnderpostCluster
|
|
62
63
|
*/
|
|
63
64
|
async init(
|
|
@@ -90,6 +91,7 @@ class UnderpostCluster {
|
|
|
90
91
|
config: false,
|
|
91
92
|
worker: false,
|
|
92
93
|
chown: false,
|
|
94
|
+
hosts: '',
|
|
93
95
|
},
|
|
94
96
|
) {
|
|
95
97
|
// Handles initial host setup (installing docker, podman, kind, kubeadm, helm)
|
|
@@ -280,6 +282,14 @@ class UnderpostCluster {
|
|
|
280
282
|
if (options.grafana === true) {
|
|
281
283
|
shellExec(`kubectl delete deployment grafana --ignore-not-found`);
|
|
282
284
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/grafana`);
|
|
285
|
+
const yaml = `${fs
|
|
286
|
+
.readFileSync(`${underpostRoot}/manifests/grafana/deployment.yaml`, 'utf8')
|
|
287
|
+
.replace('{{GF_SERVER_ROOT_URL}}', options.hosts.split(',')[0])}`;
|
|
288
|
+
console.log(yaml);
|
|
289
|
+
shellExec(`kubectl apply -f - <<EOF
|
|
290
|
+
${yaml}
|
|
291
|
+
EOF
|
|
292
|
+
`);
|
|
283
293
|
}
|
|
284
294
|
|
|
285
295
|
if (options.prom && typeof options.prom === 'string') {
|
package/src/cli/deploy.js
CHANGED
|
@@ -91,12 +91,25 @@ class UnderpostDeploy {
|
|
|
91
91
|
* @param {Array<string>} deploymentVersions - List of deployment versions.
|
|
92
92
|
* @returns {string} - YAML service configuration for the specified deployment.
|
|
93
93
|
* @param {string} [serviceId] - Custom service name (optional).
|
|
94
|
+
* @param {Array} [pathRewritePolicy] - Path rewrite policy (optional).
|
|
94
95
|
* @memberof UnderpostDeploy
|
|
95
96
|
*/
|
|
96
|
-
deploymentYamlServiceFactory({ deployId, path, env, port, deploymentVersions, serviceId }) {
|
|
97
|
+
deploymentYamlServiceFactory({ deployId, path, env, port, deploymentVersions, serviceId, pathRewritePolicy }) {
|
|
97
98
|
return `
|
|
98
99
|
- conditions:
|
|
99
100
|
- prefix: ${path}
|
|
101
|
+
${
|
|
102
|
+
pathRewritePolicy
|
|
103
|
+
? `pathRewritePolicy:
|
|
104
|
+
replacePrefix:
|
|
105
|
+
${pathRewritePolicy.map(
|
|
106
|
+
(rd) => `- prefix: ${rd.prefix}
|
|
107
|
+
replacement: ${rd.replacement}
|
|
108
|
+
`,
|
|
109
|
+
).join(`
|
|
110
|
+
`)}`
|
|
111
|
+
: ''
|
|
112
|
+
}
|
|
100
113
|
enableWebsockets: true
|
|
101
114
|
services:
|
|
102
115
|
${deploymentVersions
|
|
@@ -230,7 +243,7 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
|
|
|
230
243
|
|
|
231
244
|
const pathPortAssignment = pathPortAssignmentData[host];
|
|
232
245
|
// logger.info('', { host, pathPortAssignment });
|
|
233
|
-
|
|
246
|
+
let _proxyYaml = `
|
|
234
247
|
---
|
|
235
248
|
apiVersion: projectcontour.io/v1
|
|
236
249
|
kind: HTTPProxy
|
|
@@ -248,32 +261,31 @@ spec:
|
|
|
248
261
|
routes:`;
|
|
249
262
|
const deploymentVersions =
|
|
250
263
|
options.traffic && typeof options.traffic === 'string' ? options.traffic.split(',') : ['blue'];
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
path,
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
264
|
+
let proxyRoutes = '';
|
|
265
|
+
if (!options.disableDeploymentProxy)
|
|
266
|
+
for (const conditionObj of pathPortAssignment) {
|
|
267
|
+
const { path, port } = conditionObj;
|
|
268
|
+
proxyRoutes += UnderpostDeploy.API.deploymentYamlServiceFactory({
|
|
269
|
+
path,
|
|
270
|
+
deployId,
|
|
271
|
+
env,
|
|
272
|
+
port,
|
|
273
|
+
deploymentVersions,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
261
276
|
for (const customService of customServices) {
|
|
262
|
-
const { path: _path, port, serviceId, host: _host } = customService;
|
|
277
|
+
const { path: _path, port, serviceId, host: _host, pathRewritePolicy } = customService;
|
|
263
278
|
if (host === _host) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
});
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
279
|
+
proxyRoutes += UnderpostDeploy.API.deploymentYamlServiceFactory({
|
|
280
|
+
path: _path,
|
|
281
|
+
port,
|
|
282
|
+
serviceId,
|
|
283
|
+
deploymentVersions,
|
|
284
|
+
pathRewritePolicy,
|
|
285
|
+
});
|
|
275
286
|
}
|
|
276
287
|
}
|
|
288
|
+
if (proxyRoutes) proxyYaml += _proxyYaml + proxyRoutes;
|
|
277
289
|
}
|
|
278
290
|
const yamlPath = `./engine-private/conf/${deployId}/build/${env}/proxy.yaml`;
|
|
279
291
|
fs.writeFileSync(yamlPath, proxyYaml, 'utf8');
|
|
@@ -332,28 +344,30 @@ spec:
|
|
|
332
344
|
|
|
333
345
|
/**
|
|
334
346
|
* Callback function for handling deployment options.
|
|
335
|
-
* @param {string} deployList - List of deployment IDs to
|
|
336
|
-
* @param {string} env - Environment for which the
|
|
337
|
-
* @param {object} options - Options for the
|
|
338
|
-
* @param {
|
|
339
|
-
* @param {
|
|
340
|
-
* @param {
|
|
341
|
-
* @param {
|
|
342
|
-
* @param {
|
|
343
|
-
* @param {
|
|
344
|
-
* @param {
|
|
345
|
-
* @param {string} options.certHosts -
|
|
347
|
+
* @param {string} deployList - List of deployment IDs to process.
|
|
348
|
+
* @param {string} env - Environment for which the deployment is being processed.
|
|
349
|
+
* @param {object} options - Options for the deployment process.
|
|
350
|
+
* @param {boolean} options.remove - Whether to remove the deployment.
|
|
351
|
+
* @param {boolean} options.infoRouter - Whether to display router information.
|
|
352
|
+
* @param {boolean} options.sync - Whether to synchronize deployment configurations.
|
|
353
|
+
* @param {boolean} options.buildManifest - Whether to build the deployment manifest.
|
|
354
|
+
* @param {boolean} options.infoUtil - Whether to display utility information.
|
|
355
|
+
* @param {boolean} options.expose - Whether to expose the deployment.
|
|
356
|
+
* @param {boolean} options.cert - Whether to create certificates for the deployment.
|
|
357
|
+
* @param {string} options.certHosts - Comma-separated list of hosts for which to create certificates.
|
|
346
358
|
* @param {string} options.versions - Comma-separated list of versions to deploy.
|
|
347
359
|
* @param {string} options.image - Docker image for the deployment.
|
|
348
|
-
* @param {string} options.traffic -
|
|
360
|
+
* @param {string} options.traffic - Traffic status for the deployment.
|
|
349
361
|
* @param {string} options.replicas - Number of replicas for the deployment.
|
|
350
362
|
* @param {string} options.node - Node name for resource allocation.
|
|
351
|
-
* @param {
|
|
352
|
-
* @param {
|
|
353
|
-
* @param {
|
|
354
|
-
* @param {
|
|
355
|
-
* @param {
|
|
356
|
-
* @
|
|
363
|
+
* @param {boolean} options.restoreHosts - Whether to restore the hosts file.
|
|
364
|
+
* @param {boolean} options.disableUpdateDeployment - Whether to disable deployment updates.
|
|
365
|
+
* @param {boolean} options.disableUpdateProxy - Whether to disable proxy updates.
|
|
366
|
+
* @param {boolean} options.disableDeploymentProxy - Whether to disable deployment proxy.
|
|
367
|
+
* @param {boolean} options.status - Whether to display deployment status.
|
|
368
|
+
* @param {boolean} options.etcHosts - Whether to display the /etc/hosts file.
|
|
369
|
+
* @param {boolean} options.disableUpdateUnderpostConfig - Whether to disable Underpost config updates.
|
|
370
|
+
* @returns {Promise<void>} - Promise that resolves when the deployment process is complete.
|
|
357
371
|
* @memberof UnderpostDeploy
|
|
358
372
|
*/
|
|
359
373
|
async callback(
|
|
@@ -376,8 +390,10 @@ spec:
|
|
|
376
390
|
restoreHosts: false,
|
|
377
391
|
disableUpdateDeployment: false,
|
|
378
392
|
disableUpdateProxy: false,
|
|
393
|
+
disableDeploymentProxy: false,
|
|
379
394
|
status: false,
|
|
380
395
|
etcHosts: false,
|
|
396
|
+
disableUpdateUnderpostConfig: false,
|
|
381
397
|
},
|
|
382
398
|
) {
|
|
383
399
|
if (options.infoUtil === true)
|
|
@@ -473,7 +489,7 @@ EOF`);
|
|
|
473
489
|
logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
474
490
|
return;
|
|
475
491
|
}
|
|
476
|
-
UnderpostDeploy.API.configMap(env);
|
|
492
|
+
if (!options.disableUpdateUnderpostConfig) UnderpostDeploy.API.configMap(env);
|
|
477
493
|
let renderHosts = '';
|
|
478
494
|
let etcHosts = [];
|
|
479
495
|
if (options.restoreHosts === true) {
|
|
@@ -789,37 +805,35 @@ ${renderHosts}`,
|
|
|
789
805
|
}))
|
|
790
806
|
.filter((o) => o.image);
|
|
791
807
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
808
|
+
const raw = shellExec(node === 'kind-worker' ? `docker exec -i ${node} crictl images` : `crictl images`, {
|
|
809
|
+
stdout: true,
|
|
810
|
+
silent: true,
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
const heads = raw
|
|
814
|
+
.split(`\n`)[0]
|
|
815
|
+
.split(' ')
|
|
816
|
+
.filter((_r) => _r.trim());
|
|
817
|
+
|
|
818
|
+
const pods = raw
|
|
819
|
+
.split(`\n`)
|
|
820
|
+
.filter((r) => !r.match('IMAGE'))
|
|
821
|
+
.map((r) => r.split(' ').filter((_r) => _r.trim()));
|
|
797
822
|
|
|
798
|
-
|
|
799
|
-
.split(`\n`)[0]
|
|
800
|
-
.split(' ')
|
|
801
|
-
.filter((_r) => _r.trim());
|
|
823
|
+
const result = [];
|
|
802
824
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
if (row.length === 0) continue;
|
|
812
|
-
const pod = {};
|
|
813
|
-
let index = -1;
|
|
814
|
-
for (const head of heads) {
|
|
815
|
-
if (head in pod) continue;
|
|
816
|
-
index++;
|
|
817
|
-
pod[head] = row[index];
|
|
818
|
-
}
|
|
819
|
-
result.push(pod);
|
|
825
|
+
for (const row of pods) {
|
|
826
|
+
if (row.length === 0) continue;
|
|
827
|
+
const pod = {};
|
|
828
|
+
let index = -1;
|
|
829
|
+
for (const head of heads) {
|
|
830
|
+
if (head in pod) continue;
|
|
831
|
+
index++;
|
|
832
|
+
pod[head] = row[index];
|
|
820
833
|
}
|
|
821
|
-
|
|
834
|
+
result.push(pod);
|
|
822
835
|
}
|
|
836
|
+
return result;
|
|
823
837
|
},
|
|
824
838
|
};
|
|
825
839
|
}
|
package/src/cli/index.js
CHANGED
|
@@ -162,6 +162,7 @@ program
|
|
|
162
162
|
.option('--worker', 'Sets the context for a worker node.')
|
|
163
163
|
.option('--chown', 'Sets the appropriate ownership for Kubernetes kubeconfig files.')
|
|
164
164
|
.option('--k3s', 'Initializes the cluster using K3s (Lightweight Kubernetes).')
|
|
165
|
+
.option('--hosts <hosts>', 'A comma-separated list of cluster hostnames or IP addresses.')
|
|
165
166
|
.action(Underpost.cluster.init)
|
|
166
167
|
.description('Manages Kubernetes clusters, defaulting to Kind cluster initialization.');
|
|
167
168
|
|
|
@@ -191,6 +192,7 @@ program
|
|
|
191
192
|
.option('--traffic <traffic-versions>', 'A comma-separated list of custom deployment traffic weights.')
|
|
192
193
|
.option('--disable-update-deployment', 'Disables updates to deployments.')
|
|
193
194
|
.option('--disable-update-proxy', 'Disables updates to proxies.')
|
|
195
|
+
.option('--disable-deployment-proxy', 'Disables proxies of deployments.')
|
|
194
196
|
.option(
|
|
195
197
|
'--status',
|
|
196
198
|
'Retrieves current network traffic data from resource deployments and the host machine network configuration.',
|
|
@@ -198,6 +200,7 @@ program
|
|
|
198
200
|
.option('--kubeadm', 'Enables the kubeadm context for deployment operations.')
|
|
199
201
|
.option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
|
|
200
202
|
.option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
|
|
203
|
+
.option('--disable-update-underpost-config', 'Disables updates to Underpost configuration during deployment.')
|
|
201
204
|
.description('Manages application deployments, defaulting to deploying development pods.')
|
|
202
205
|
.action(Underpost.deploy.callback);
|
|
203
206
|
|
|
@@ -379,7 +382,10 @@ program
|
|
|
379
382
|
.option('--dev', 'Sets the development context environment for the script.')
|
|
380
383
|
.option('--build', 'Set builder context runner')
|
|
381
384
|
.option('--replicas <replicas>', 'Sets a custom number of replicas for deployment.')
|
|
382
|
-
.option('--pod-name <pod-name>', 'Optional: Specifies the pod name for
|
|
385
|
+
.option('--pod-name <pod-name>', 'Optional: Specifies the pod name for execution.')
|
|
386
|
+
.option('--node-name <node-name>', 'Optional: Specifies the node name for execution.')
|
|
387
|
+
.option('--port <port>', 'Optional: Specifies the port for execution.')
|
|
388
|
+
.option('--etc-hosts', 'Enables etc-hosts context for the runner execution.')
|
|
383
389
|
.option('--volume-host-path <volume-host-path>', 'Optional: Specifies the volume host path for test execution.')
|
|
384
390
|
.option('--volume-mount-path <volume-mount-path>', 'Optional: Specifies the volume mount path for test execution.')
|
|
385
391
|
.option('--volume-type <volume-type>', 'Optional: Specifies the volume type for test execution.')
|
package/src/cli/run.js
CHANGED
|
@@ -42,6 +42,9 @@ class UnderpostRun {
|
|
|
42
42
|
* @type {Object}
|
|
43
43
|
* @property {boolean} dev - Whether to run in development mode.
|
|
44
44
|
* @property {string} podName - The name of the pod to run.
|
|
45
|
+
* @property {string} nodeName - The name of the node to run.
|
|
46
|
+
* @property {number} port - Custom port to use.
|
|
47
|
+
* @property {boolean} etcHosts - Whether to modify /etc/hosts.
|
|
45
48
|
* @property {string} volumeHostPath - The host path for the volume.
|
|
46
49
|
* @property {string} volumeMountPath - The mount path for the volume.
|
|
47
50
|
* @property {string} imageName - The name of the image to run.
|
|
@@ -65,6 +68,8 @@ class UnderpostRun {
|
|
|
65
68
|
static DEFAULT_OPTION = {
|
|
66
69
|
dev: false,
|
|
67
70
|
podName: '',
|
|
71
|
+
nodeName: '',
|
|
72
|
+
port: 0,
|
|
68
73
|
volumeHostPath: '',
|
|
69
74
|
volumeMountPath: '',
|
|
70
75
|
imageName: '',
|
|
@@ -216,13 +221,66 @@ class UnderpostRun {
|
|
|
216
221
|
);
|
|
217
222
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
|
|
218
223
|
}
|
|
219
|
-
shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
|
|
220
|
-
shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
|
|
224
|
+
shellExec(`${baseCommand} deploy --expose --disable-update-underpost-config mongo`, { async: true });
|
|
225
|
+
shellExec(`${baseCommand} deploy --expose --disable-update-underpost-config valkey`, { async: true });
|
|
221
226
|
{
|
|
222
227
|
const hostListenResult = UnderpostDeploy.API.etcHostFactory(mongoHosts);
|
|
223
228
|
logger.info(hostListenResult.renderHosts);
|
|
224
229
|
}
|
|
225
230
|
},
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @method metadata
|
|
234
|
+
* @description Generates metadata for the specified path after exposing the development cluster.
|
|
235
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
236
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
237
|
+
* @memberof UnderpostRun
|
|
238
|
+
*/
|
|
239
|
+
metadata: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
240
|
+
const ports = '6379,27017';
|
|
241
|
+
shellExec(`node bin run kill '${ports}'`);
|
|
242
|
+
shellExec(`node bin run dev-cluster --dev expose`, { async: true });
|
|
243
|
+
console.log('Loading fordward services...');
|
|
244
|
+
await timer(5000);
|
|
245
|
+
shellExec(`node bin metadata --generate ${path}`);
|
|
246
|
+
shellExec(`node bin run kill '${ports}'`);
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @method svc-ls
|
|
251
|
+
* @description Lists systemd services and installed packages, optionally filtering by the provided path.
|
|
252
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional filter for services and packages).
|
|
253
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
254
|
+
* @memberof UnderpostRun
|
|
255
|
+
*/
|
|
256
|
+
'svc-ls': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
257
|
+
const log = shellExec(`systemctl list-units --type=service${path ? ` | grep ${path}` : ''}`, {
|
|
258
|
+
silent: true,
|
|
259
|
+
stdout: true,
|
|
260
|
+
});
|
|
261
|
+
console.log(path ? log.replaceAll(path, path.red) : log);
|
|
262
|
+
const log0 = shellExec(`sudo dnf list installed${path ? ` | grep ${path}` : ''}`, {
|
|
263
|
+
silent: true,
|
|
264
|
+
stdout: true,
|
|
265
|
+
});
|
|
266
|
+
console.log(path ? log0.replaceAll(path, path.red) : log0);
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @method svc-rm
|
|
271
|
+
* @description Removes a systemd service by stopping it, disabling it, uninstalling the package, and deleting related files.
|
|
272
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the service name).
|
|
273
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
274
|
+
* @memberof UnderpostRun
|
|
275
|
+
*/
|
|
276
|
+
'svc-rm': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
277
|
+
shellExec(`sudo systemctl stop ${path}`);
|
|
278
|
+
shellExec(`sudo systemctl disable --now ${path}`);
|
|
279
|
+
shellExec(`sudo dnf remove -y ${path}*`);
|
|
280
|
+
shellExec(`sudo rm -f /usr/lib/systemd/system/${path}.service`);
|
|
281
|
+
shellExec(`sudo rm -f /etc/yum.repos.d/${path}*.repo`);
|
|
282
|
+
},
|
|
283
|
+
|
|
226
284
|
/**
|
|
227
285
|
* @method ssh-cluster-info
|
|
228
286
|
* @description Executes the `ssh-cluster-info.sh` script to display cluster connection information.
|
|
@@ -498,7 +556,12 @@ class UnderpostRun {
|
|
|
498
556
|
* @memberof UnderpostRun
|
|
499
557
|
*/
|
|
500
558
|
'ls-images': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
501
|
-
console.table(
|
|
559
|
+
console.table(
|
|
560
|
+
UnderpostDeploy.API.getCurrentLoadedImages(
|
|
561
|
+
options.nodeName ? options.nodeName : 'kind-worker',
|
|
562
|
+
path === 'spec' ? true : false,
|
|
563
|
+
),
|
|
564
|
+
);
|
|
502
565
|
},
|
|
503
566
|
|
|
504
567
|
/**
|
|
@@ -883,52 +946,84 @@ class UnderpostRun {
|
|
|
883
946
|
service: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
884
947
|
const env = options.dev ? 'development' : 'production';
|
|
885
948
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
886
|
-
|
|
949
|
+
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
887
950
|
shellCd(`/home/dd/engine`);
|
|
888
951
|
let [deployId, serviceId, host, _path, replicas, image, node] = path.split(',');
|
|
952
|
+
// const confClient = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
|
|
953
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
954
|
+
// const confSSR = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
|
|
955
|
+
// const packageData = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
|
|
889
956
|
const services = fs.existsSync(`./engine-private/deploy/${deployId}/conf.services.json`)
|
|
890
957
|
? JSON.parse(fs.readFileSync(`./engine-private/deploy/${deployId}/conf.services.json`, 'utf8'))
|
|
891
958
|
: [];
|
|
959
|
+
let serviceData = services.findIndex((s) => s.serviceId === serviceId);
|
|
960
|
+
const payload = {
|
|
961
|
+
serviceId,
|
|
962
|
+
path: _path,
|
|
963
|
+
port: options.port,
|
|
964
|
+
host,
|
|
965
|
+
};
|
|
966
|
+
let podToMonitor;
|
|
967
|
+
if (!payload.port)
|
|
968
|
+
switch (serviceId) {
|
|
969
|
+
case 'mongo-express-service': {
|
|
970
|
+
payload.port = 8081;
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
case 'grafana': {
|
|
974
|
+
payload.port = 3000;
|
|
975
|
+
// payload.pathRewritePolicy = [
|
|
976
|
+
// {
|
|
977
|
+
// prefix: '/grafana',
|
|
978
|
+
// replacement: '/',
|
|
979
|
+
// },
|
|
980
|
+
// ];
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
if (serviceData == -1) {
|
|
985
|
+
services.push(payload);
|
|
986
|
+
} else {
|
|
987
|
+
services[serviceData] = payload;
|
|
988
|
+
}
|
|
989
|
+
fs.writeFileSync(
|
|
990
|
+
`./engine-private/conf/${deployId}/conf.services.json`,
|
|
991
|
+
JSON.stringify(services, null, 4),
|
|
992
|
+
'utf8',
|
|
993
|
+
);
|
|
892
994
|
switch (serviceId) {
|
|
893
995
|
case 'mongo-express-service': {
|
|
894
|
-
let serviceData = services.findIndex((s) => s.serviceId === serviceId);
|
|
895
|
-
const payload = {
|
|
896
|
-
serviceId,
|
|
897
|
-
path: _path,
|
|
898
|
-
port: 8081,
|
|
899
|
-
host,
|
|
900
|
-
};
|
|
901
|
-
if (serviceData == -1) {
|
|
902
|
-
services.push(payload);
|
|
903
|
-
} else {
|
|
904
|
-
services[serviceData] = payload;
|
|
905
|
-
}
|
|
906
|
-
fs.writeFileSync(
|
|
907
|
-
`./engine-private/conf/${deployId}/conf.services.json`,
|
|
908
|
-
JSON.stringify(services, null, 4),
|
|
909
|
-
'utf8',
|
|
910
|
-
);
|
|
911
996
|
shellExec(`kubectl delete svc mongo-express-service --ignore-not-found`);
|
|
912
997
|
shellExec(`kubectl delete deployment mongo-express --ignore-not-found`);
|
|
913
998
|
shellExec(`kubectl apply -f manifests/deployment/mongo-express/deployment.yaml`);
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
replicas ? replicas : 1
|
|
923
|
-
} --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
|
|
924
|
-
);
|
|
925
|
-
shellExec(
|
|
926
|
-
`${baseCommand} deploy --kubeadm --disable-update-deployment ${deployId} ${env} --versions ${versions}`,
|
|
927
|
-
);
|
|
928
|
-
} else logger.error('Mongo Express deployment failed');
|
|
999
|
+
podToMonitor = 'mongo-express';
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
case 'grafana': {
|
|
1003
|
+
shellExec(
|
|
1004
|
+
`node bin cluster${baseClusterCommand} --grafana --hosts '${host}' --prom '${Object.keys(confServer)}'`,
|
|
1005
|
+
);
|
|
1006
|
+
podToMonitor = 'grafana';
|
|
929
1007
|
break;
|
|
930
1008
|
}
|
|
931
1009
|
}
|
|
1010
|
+
const success = await UnderpostTest.API.statusMonitor(podToMonitor);
|
|
1011
|
+
if (success) {
|
|
1012
|
+
const versions = UnderpostDeploy.API.getCurrentTraffic(deployId) || 'blue';
|
|
1013
|
+
if (!node) node = os.hostname();
|
|
1014
|
+
shellExec(
|
|
1015
|
+
`${baseCommand} deploy${options.dev ? '' : ' --kubeadm'}${options.devProxyPortOffset ? ' --disable-deployment-proxy' : ''} --build-manifest --sync --info-router --replicas ${
|
|
1016
|
+
replicas ? replicas : 1
|
|
1017
|
+
} --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
|
|
1018
|
+
);
|
|
1019
|
+
shellExec(
|
|
1020
|
+
`${baseCommand} deploy${options.dev ? '' : ' --kubeadm'}${options.devProxyPortOffset ? ' --disable-deployment-proxy' : ''} --disable-update-deployment ${deployId} ${env} --versions ${versions}`,
|
|
1021
|
+
);
|
|
1022
|
+
} else logger.error('Mongo Express deployment failed');
|
|
1023
|
+
if (options.etcHosts === true) {
|
|
1024
|
+
const hostListenResult = UnderpostDeploy.API.etcHostFactory([host]);
|
|
1025
|
+
logger.info(hostListenResult.renderHosts);
|
|
1026
|
+
}
|
|
932
1027
|
},
|
|
933
1028
|
|
|
934
1029
|
/**
|
|
@@ -938,7 +1033,14 @@ class UnderpostRun {
|
|
|
938
1033
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
939
1034
|
* @memberof UnderpostRun
|
|
940
1035
|
*/
|
|
941
|
-
sh: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
1036
|
+
sh: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
1037
|
+
let [operator, arg0, arg1] = path.split(',');
|
|
1038
|
+
if (operator == 'copy') {
|
|
1039
|
+
shellExec(
|
|
1040
|
+
`kitty @ get-text ${arg0 === 'all' ? '--match all' : '--self'} --extent all${arg1 === 'ansi' ? ' --ansi yes' : ''} | kitty +kitten clipboard`,
|
|
1041
|
+
);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
942
1044
|
shellExec(`kitty -o allow_remote_control=yes`);
|
|
943
1045
|
},
|
|
944
1046
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { getQueryParams, setQueryParams } from './Router.js';
|
|
1
|
+
import { getQueryParams, setQueryParams, listenQueryParamsChange } from './Router.js';
|
|
2
2
|
|
|
3
3
|
class AgPagination extends HTMLElement {
|
|
4
4
|
constructor() {
|
|
5
5
|
super();
|
|
6
6
|
this.attachShadow({ mode: 'open' });
|
|
7
7
|
this._gridId = null;
|
|
8
|
-
|
|
8
|
+
let queryParams = getQueryParams();
|
|
9
9
|
this._currentPage = parseInt(queryParams.page, 10) || 1;
|
|
10
10
|
this._limit = parseInt(queryParams.limit, 10) || 10;
|
|
11
11
|
this._totalPages = 1;
|
|
@@ -13,6 +13,8 @@ class AgPagination extends HTMLElement {
|
|
|
13
13
|
this._limitOptions = [10, 20, 50, 100]; // Default options
|
|
14
14
|
this.handlePageChange = this.handlePageChange.bind(this);
|
|
15
15
|
this.handleLimitChange = this.handleLimitChange.bind(this);
|
|
16
|
+
|
|
17
|
+
this.handleQueryParamsChange = this.handleQueryParamsChange.bind(this);
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
static get observedAttributes() {
|
|
@@ -53,11 +55,43 @@ class AgPagination extends HTMLElement {
|
|
|
53
55
|
connectedCallback() {
|
|
54
56
|
this.render();
|
|
55
57
|
this.addEventListeners();
|
|
56
|
-
|
|
58
|
+
// Subscribe to query parameter changes once the component is connected and _gridId is potentially set.
|
|
59
|
+
listenQueryParamsChange({
|
|
60
|
+
id: `ag-pagination-${this._gridId || 'default'}`, // Use _gridId for a unique listener ID
|
|
61
|
+
event: this.handleQueryParamsChange,
|
|
62
|
+
});
|
|
63
|
+
// The initial state is already set in the constructor from getQueryParams().
|
|
64
|
+
// The `listenQueryParamsChange` in `Router.js` will trigger an immediate (setTimeout) call
|
|
65
|
+
// to `handleQueryParamsChange`, which will re-sync the state if needed and update the component.
|
|
66
|
+
this.update(); // Keep the initial update for rendering based on constructor's initial state.
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
disconnectedCallback() {
|
|
60
|
-
//
|
|
70
|
+
// If Router.js held strong references to queryParamsChangeListeners, you might need to unsubscribe here.
|
|
71
|
+
// However, for this example, we'll assume the component's lifecycle or weak references handle cleanup.
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
handleQueryParamsChange(queryParams) {
|
|
75
|
+
const newPage = parseInt(queryParams.page, 10) || 1;
|
|
76
|
+
const newLimit = parseInt(queryParams.limit, 10) || 10;
|
|
77
|
+
|
|
78
|
+
let shouldUpdate = false;
|
|
79
|
+
|
|
80
|
+
if (newPage !== this._currentPage) {
|
|
81
|
+
this._currentPage = newPage;
|
|
82
|
+
shouldUpdate = true;
|
|
83
|
+
}
|
|
84
|
+
if (newLimit !== this._limit) {
|
|
85
|
+
this._limit = newLimit;
|
|
86
|
+
shouldUpdate = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (shouldUpdate) {
|
|
90
|
+
this.update();
|
|
91
|
+
this.dispatchEvent(
|
|
92
|
+
new CustomEvent('pagination-query-params-change', { detail: { page: this._currentPage, limit: this._limit } }),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
61
95
|
}
|
|
62
96
|
|
|
63
97
|
handlePageChange(newPage) {
|
|
@@ -65,7 +99,7 @@ class AgPagination extends HTMLElement {
|
|
|
65
99
|
return;
|
|
66
100
|
}
|
|
67
101
|
this._currentPage = newPage;
|
|
68
|
-
setQueryParams({ page: newPage, limit: this._limit });
|
|
102
|
+
setQueryParams({ page: newPage, limit: this._limit }, { replace: false }); // Use pushState
|
|
69
103
|
this.dispatchEvent(new CustomEvent('page-change', { detail: { page: newPage } }));
|
|
70
104
|
}
|
|
71
105
|
|
|
@@ -76,7 +110,7 @@ class AgPagination extends HTMLElement {
|
|
|
76
110
|
}
|
|
77
111
|
this._limit = newLimit;
|
|
78
112
|
this._currentPage = 1; // Reset to first page on limit change
|
|
79
|
-
setQueryParams({ page: 1, limit: newLimit });
|
|
113
|
+
setQueryParams({ page: 1, limit: newLimit }, { replace: false }); // Use pushState
|
|
80
114
|
this.dispatchEvent(new CustomEvent('limit-change', { detail: { limit: newLimit } }));
|
|
81
115
|
}
|
|
82
116
|
|
|
@@ -98,7 +132,8 @@ class AgPagination extends HTMLElement {
|
|
|
98
132
|
this.shadowRoot.querySelector('#page-info').textContent = `Page ${this._currentPage} of ${this._totalPages}`;
|
|
99
133
|
|
|
100
134
|
const limitSelector = this.shadowRoot.querySelector('#limit-selector');
|
|
101
|
-
if (limitSelector.value != this._limit) {
|
|
135
|
+
if (limitSelector && limitSelector.value != this._limit) {
|
|
136
|
+
// Added null check for limitSelector
|
|
102
137
|
limitSelector.value = this._limit;
|
|
103
138
|
}
|
|
104
139
|
|
|
@@ -19,6 +19,13 @@ const logger = loggerFactory(import.meta, { trace: true });
|
|
|
19
19
|
*/
|
|
20
20
|
const RouterEvents = {};
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* @type {Object.<string, function>}\n
|
|
24
|
+
* @description Holds event listeners for query parameter changes.\n
|
|
25
|
+
* @memberof PwaRouter
|
|
26
|
+
*/
|
|
27
|
+
const queryParamsChangeListeners = {};
|
|
28
|
+
|
|
22
29
|
/**
|
|
23
30
|
* @type {string[]}
|
|
24
31
|
* @description Array of core UI component IDs that should not trigger modal close route changes.
|
|
@@ -227,6 +234,22 @@ const listenQueryPathInstance = ({ id, routeId, event }, queryKey = 'cid') => {
|
|
|
227
234
|
});
|
|
228
235
|
};
|
|
229
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Registers a listener for changes to query parameters.\n
|
|
239
|
+
* The provided event callback is triggered with the current query parameters object.\n
|
|
240
|
+
* @param {object} options - The listener options.\n
|
|
241
|
+
* @param {string} options.id - A unique ID for the listener.\n
|
|
242
|
+
* @param {function(Object.<string, string>): void} options.event - The callback function to execute with the new query parameters.\n
|
|
243
|
+
* @memberof PwaRouter
|
|
244
|
+
*/
|
|
245
|
+
const listenQueryParamsChange = ({ id, event }) => {
|
|
246
|
+
queryParamsChangeListeners[id] = event;
|
|
247
|
+
// Immediately call with current query params for initial state
|
|
248
|
+
setTimeout(() => {
|
|
249
|
+
event(getQueryParams());
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
|
|
230
253
|
/**
|
|
231
254
|
* Handles the logic for changing the route when a modal is closed. It determines the next URL
|
|
232
255
|
* based on the remaining open modals or falls back to a home URL.
|
|
@@ -305,6 +328,13 @@ const setQueryParams = (newParams, options = { replace: true }) => {
|
|
|
305
328
|
} else {
|
|
306
329
|
history.pushState(history.state, '', newPath);
|
|
307
330
|
}
|
|
331
|
+
|
|
332
|
+
const updatedParams = getQueryParams();
|
|
333
|
+
for (const listenerId in queryParamsChangeListeners) {
|
|
334
|
+
if (Object.hasOwnProperty.call(queryParamsChangeListeners, listenerId)) {
|
|
335
|
+
queryParamsChangeListeners[listenerId](updatedParams);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
308
338
|
};
|
|
309
339
|
|
|
310
340
|
export {
|
|
@@ -323,4 +353,6 @@ export {
|
|
|
323
353
|
setPath,
|
|
324
354
|
setQueryParams,
|
|
325
355
|
sanitizeRoute,
|
|
356
|
+
queryParamsChangeListeners,
|
|
357
|
+
listenQueryParamsChange,
|
|
326
358
|
};
|
package/src/index.js
CHANGED
|
@@ -573,7 +573,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
573
573
|
apiBaseHost,
|
|
574
574
|
apiBasePath: process.env.BASE_API,
|
|
575
575
|
version: Underpost.version,
|
|
576
|
-
dev:
|
|
576
|
+
...(isDevelopment ? { dev: true } : undefined),
|
|
577
577
|
},
|
|
578
578
|
renderApi: {
|
|
579
579
|
JSONweb,
|
|
@@ -667,7 +667,7 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
667
667
|
apiBaseHost,
|
|
668
668
|
apiBasePath: process.env.BASE_API,
|
|
669
669
|
version: Underpost.version,
|
|
670
|
-
dev:
|
|
670
|
+
...(isDevelopment ? { dev: true } : undefined),
|
|
671
671
|
},
|
|
672
672
|
renderApi: {
|
|
673
673
|
JSONweb,
|