underpost 2.89.2 → 2.89.21
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 +2 -0
- package/.env.production +2 -0
- package/.env.test +2 -0
- package/.github/workflows/release.cd.yml +2 -0
- package/README.md +2 -3
- package/cli.md +74 -53
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +10 -2
- package/manifests/pv-pvc-dd.yaml +34 -0
- package/package.json +1 -1
- package/src/cli/cluster.js +30 -18
- package/src/cli/deploy.js +109 -7
- package/src/cli/index.js +13 -0
- package/src/cli/repository.js +12 -0
- package/src/cli/run.js +54 -32
- package/src/client/components/core/ObjectLayerEngineModal.js +4 -3
- package/src/client/components/core/ObjectLayerEngineViewer.js +83 -31
- package/src/index.js +1 -1
- package/src/server/start.js +2 -1
package/.env.development
CHANGED
|
@@ -22,6 +22,8 @@ ROUTER=changethis
|
|
|
22
22
|
CLOUDINARY_CLOUD_NAME=changethis
|
|
23
23
|
CLOUDINARY_API_KEY=changethis
|
|
24
24
|
CLOUDINARY_API_SECRET=changethis
|
|
25
|
+
CLOUDINARY_PASSWORD=changethis
|
|
26
|
+
CLOUDINARY_EMAIL=admin@default.net
|
|
25
27
|
DB_PG_MAAS_NAME=changethis
|
|
26
28
|
DB_PG_MAAS_PASS=changethis
|
|
27
29
|
DB_PG_MAAS_USER=changethis
|
package/.env.production
CHANGED
|
@@ -23,6 +23,8 @@ ROUTER=changethis
|
|
|
23
23
|
CLOUDINARY_CLOUD_NAME=changethis
|
|
24
24
|
CLOUDINARY_API_KEY=changethis
|
|
25
25
|
CLOUDINARY_API_SECRET=changethis
|
|
26
|
+
CLOUDINARY_PASSWORD=changethis
|
|
27
|
+
CLOUDINARY_EMAIL=admin@default.net
|
|
26
28
|
DB_PG_MAAS_NAME=changethis
|
|
27
29
|
DB_PG_MAAS_PASS=changethis
|
|
28
30
|
DB_PG_MAAS_USER=changethis
|
package/.env.test
CHANGED
|
@@ -22,6 +22,8 @@ ROUTER=changethis
|
|
|
22
22
|
CLOUDINARY_CLOUD_NAME=changethis
|
|
23
23
|
CLOUDINARY_API_KEY=changethis
|
|
24
24
|
CLOUDINARY_API_SECRET=changethis
|
|
25
|
+
CLOUDINARY_PASSWORD=changethis
|
|
26
|
+
CLOUDINARY_EMAIL=admin@default.net
|
|
25
27
|
DB_PG_MAAS_NAME=changethis
|
|
26
28
|
DB_PG_MAAS_PASS=changethis
|
|
27
29
|
DB_PG_MAAS_USER=changethis
|
|
@@ -22,6 +22,8 @@ jobs:
|
|
|
22
22
|
key: ${{ secrets.SSH_PRIV_KEY }}
|
|
23
23
|
# Remote port (optional)
|
|
24
24
|
port: ${{ secrets.SSH_PORT }}
|
|
25
|
+
# Optional: increase timeout for long-running commands
|
|
26
|
+
command_timeout: 60m
|
|
25
27
|
# Optional: if your private key has a passphrase, add:
|
|
26
28
|
# passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
|
|
27
29
|
# Commands to run on the remote VM
|
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.21) [](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.21
|
|
70
70
|
|
|
71
71
|
### Usage: `underpost [options] [command]`
|
|
72
72
|
```
|
|
@@ -106,4 +106,3 @@ Commands:
|
|
|
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
|
-
|
package/cli.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v2.89.
|
|
1
|
+
## underpost ci/cd cli v2.89.21
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -146,6 +146,9 @@ Options:
|
|
|
146
146
|
--deploy-id <deploy-id> Sets the deployment configuration ID for the commit
|
|
147
147
|
context.
|
|
148
148
|
--cached Commit staged changes only or context.
|
|
149
|
+
--hashes <hashes> Comma-separated list of specific file hashes of
|
|
150
|
+
commits.
|
|
151
|
+
--extension <extension> specific file extensions of commits.
|
|
149
152
|
-h, --help display help for command
|
|
150
153
|
|
|
151
154
|
```
|
|
@@ -228,58 +231,66 @@ Options:
|
|
|
228
231
|
Manages Kubernetes clusters, defaulting to Kind cluster initialization.
|
|
229
232
|
|
|
230
233
|
Arguments:
|
|
231
|
-
pod-name
|
|
234
|
+
pod-name Optional: Filters information by a specific pod
|
|
235
|
+
name.
|
|
232
236
|
|
|
233
237
|
Options:
|
|
234
|
-
--reset
|
|
235
|
-
|
|
236
|
-
--mariadb
|
|
237
|
-
|
|
238
|
-
--
|
|
239
|
-
--
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
--
|
|
243
|
-
|
|
244
|
-
--
|
|
245
|
-
|
|
246
|
-
--
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
--
|
|
260
|
-
|
|
261
|
-
--
|
|
262
|
-
|
|
263
|
-
--
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
--
|
|
267
|
-
|
|
268
|
-
--
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
--
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
--
|
|
281
|
-
|
|
282
|
-
|
|
238
|
+
--reset Deletes all clusters and prunes all related data
|
|
239
|
+
and caches.
|
|
240
|
+
--mariadb Initializes the cluster with a MariaDB
|
|
241
|
+
statefulset.
|
|
242
|
+
--mysql Initializes the cluster with a MySQL statefulset.
|
|
243
|
+
--mongodb Initializes the cluster with a MongoDB
|
|
244
|
+
statefulset.
|
|
245
|
+
--mongo-db-host <host> Set custom mongo db host
|
|
246
|
+
--postgresql Initializes the cluster with a PostgreSQL
|
|
247
|
+
statefulset.
|
|
248
|
+
--mongodb4 Initializes the cluster with a MongoDB 4.4
|
|
249
|
+
service.
|
|
250
|
+
--valkey Initializes the cluster with a Valkey service.
|
|
251
|
+
--contour Initializes the cluster with Project Contour base
|
|
252
|
+
HTTPProxy and Envoy.
|
|
253
|
+
--cert-manager Initializes the cluster with a Let's Encrypt
|
|
254
|
+
production ClusterIssuer.
|
|
255
|
+
--dedicated-gpu Initializes the cluster with dedicated GPU base
|
|
256
|
+
resources and environment settings.
|
|
257
|
+
--info Retrieves information about all deployed
|
|
258
|
+
Kubernetes objects.
|
|
259
|
+
--full Initializes the cluster with all available
|
|
260
|
+
statefulsets and services.
|
|
261
|
+
--ns-use <ns-name> Switches the current Kubernetes context to the
|
|
262
|
+
specified namespace.
|
|
263
|
+
--kubeadm Initializes the cluster using kubeadm for control
|
|
264
|
+
plane management.
|
|
265
|
+
--grafana Initializes the cluster with a Grafana
|
|
266
|
+
deployment.
|
|
267
|
+
--prom [hosts] Initializes the cluster with a Prometheus
|
|
268
|
+
Operator deployment and monitor scrap for
|
|
269
|
+
specified hosts.
|
|
270
|
+
--dev Initializes a development-specific cluster
|
|
271
|
+
configuration.
|
|
272
|
+
--list-pods Displays detailed information about all pods.
|
|
273
|
+
--info-capacity Displays the current total machine capacity
|
|
274
|
+
information.
|
|
275
|
+
--info-capacity-pod Displays the current machine capacity information
|
|
276
|
+
per pod.
|
|
277
|
+
--pull-image Sets an optional associated image to pull during
|
|
278
|
+
initialization.
|
|
279
|
+
--init-host Installs necessary Kubernetes node CLI tools
|
|
280
|
+
(e.g., kind, kubeadm, docker, podman, helm).
|
|
281
|
+
--uninstall-host Uninstalls all host components installed by
|
|
282
|
+
init-host.
|
|
283
|
+
--config Sets the base Kubernetes node configuration.
|
|
284
|
+
--worker Sets the context for a worker node.
|
|
285
|
+
--chown Sets the appropriate ownership for Kubernetes
|
|
286
|
+
kubeconfig files.
|
|
287
|
+
--k3s Initializes the cluster using K3s (Lightweight
|
|
288
|
+
Kubernetes).
|
|
289
|
+
--hosts <hosts> A comma-separated list of cluster hostnames or IP
|
|
290
|
+
addresses.
|
|
291
|
+
--remove-volume-host-paths Removes specified volume host paths after
|
|
292
|
+
execution.
|
|
293
|
+
-h, --help display help for command
|
|
283
294
|
|
|
284
295
|
```
|
|
285
296
|
|
|
@@ -327,6 +338,8 @@ Options:
|
|
|
327
338
|
--disable-update-deployment Disables updates to deployments.
|
|
328
339
|
--disable-update-proxy Disables updates to proxies.
|
|
329
340
|
--disable-deployment-proxy Disables proxies of deployments.
|
|
341
|
+
--disable-update-volume Disables updates to volume mounts during
|
|
342
|
+
deployment.
|
|
330
343
|
--status Retrieves current network traffic data
|
|
331
344
|
from resource deployments and the host
|
|
332
345
|
machine network configuration.
|
|
@@ -628,7 +641,7 @@ Options:
|
|
|
628
641
|
Runs a script from the specified path.
|
|
629
642
|
|
|
630
643
|
Arguments:
|
|
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,
|
|
644
|
+
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, dd-container, monitor, db-client, git-conf, promote, metrics, cluster, deploy, dev, service, sh, log, release-cmt, sync-replica, tf-vae-test, deploy-job.
|
|
632
645
|
path The absolute or relative directory path where the script is located.
|
|
633
646
|
|
|
634
647
|
Options:
|
|
@@ -647,6 +660,14 @@ Options:
|
|
|
647
660
|
--image-name <image-name> Optional: Specifies the image name for test execution.
|
|
648
661
|
--container-name <container-name> Optional: Specifies the container name for test execution.
|
|
649
662
|
--namespace <namespace> Optional: Specifies the namespace for test execution.
|
|
663
|
+
--tty Enables TTY for the container in deploy-job.
|
|
664
|
+
--stdin Keeps STDIN open for the container in deploy-job.
|
|
665
|
+
--restart-policy <policy> Sets the restart policy for the job in deploy-job.
|
|
666
|
+
--runtime-class-name <name> Sets the runtime class name for the job in deploy-job.
|
|
667
|
+
--image-pull-policy <policy> Sets the image pull policy for the job in deploy-job.
|
|
668
|
+
--api-version <version> Sets the API version for the job manifest in deploy-job.
|
|
669
|
+
--claim-name <name> Optional: Specifies the claim name for volume mounting in deploy-job.
|
|
670
|
+
--kind <kind-type> Specifies the kind of Kubernetes resource (e.g., Job, Deployment) for deploy-job.
|
|
650
671
|
--kubeadm Flag to indicate Kubeadm cluster type context
|
|
651
672
|
--k3s Flag to indicate K3s cluster type context
|
|
652
673
|
--force Forces operation, overriding any warnings or conflicts.
|
|
@@ -655,6 +676,7 @@ Options:
|
|
|
655
676
|
--terminal Enables terminal mode for interactive script execution.
|
|
656
677
|
--dev-proxy-port-offset <port-offset> Sets a custom port offset for development proxy.
|
|
657
678
|
--conf-server-path <conf-server-path> Sets a custom configuration server path.
|
|
679
|
+
--underpost-root <underpost-root> Sets a custom Underpost root path.
|
|
658
680
|
-h, --help display help for command
|
|
659
681
|
|
|
660
682
|
```
|
|
@@ -741,4 +763,3 @@ Options:
|
|
|
741
763
|
-h, --help display help for command
|
|
742
764
|
|
|
743
765
|
```
|
|
744
|
-
|
|
@@ -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.21
|
|
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.21
|
|
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.21
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "96294Ki"
|
|
@@ -33,13 +33,17 @@ spec:
|
|
|
33
33
|
npm install -g underpost &&
|
|
34
34
|
underpost secret underpost --create-from-file /etc/config/.env.development &&
|
|
35
35
|
underpost start --build --run dd-test development
|
|
36
|
+
|
|
36
37
|
volumeMounts:
|
|
37
38
|
- name: config-volume
|
|
38
39
|
mountPath: /etc/config
|
|
40
|
+
|
|
39
41
|
volumes:
|
|
40
42
|
- name: config-volume
|
|
41
43
|
configMap:
|
|
42
44
|
name: underpost-config
|
|
45
|
+
|
|
46
|
+
|
|
43
47
|
---
|
|
44
48
|
apiVersion: v1
|
|
45
49
|
kind: Service
|
|
@@ -104,7 +108,7 @@ spec:
|
|
|
104
108
|
spec:
|
|
105
109
|
containers:
|
|
106
110
|
- name: dd-test-development-green
|
|
107
|
-
image: localhost/rockylinux9-underpost:v2.89.
|
|
111
|
+
image: localhost/rockylinux9-underpost:v2.89.21
|
|
108
112
|
# resources:
|
|
109
113
|
# requests:
|
|
110
114
|
# memory: "96294Ki"
|
|
@@ -120,13 +124,17 @@ spec:
|
|
|
120
124
|
npm install -g underpost &&
|
|
121
125
|
underpost secret underpost --create-from-file /etc/config/.env.development &&
|
|
122
126
|
underpost start --build --run dd-test development
|
|
127
|
+
|
|
123
128
|
volumeMounts:
|
|
124
129
|
- name: config-volume
|
|
125
130
|
mountPath: /etc/config
|
|
131
|
+
|
|
126
132
|
volumes:
|
|
127
133
|
- name: config-volume
|
|
128
134
|
configMap:
|
|
129
135
|
name: underpost-config
|
|
136
|
+
|
|
137
|
+
|
|
130
138
|
---
|
|
131
139
|
apiVersion: v1
|
|
132
140
|
kind: Service
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
apiVersion: v1
|
|
2
|
+
kind: PersistentVolume
|
|
3
|
+
metadata:
|
|
4
|
+
name: pv-dd
|
|
5
|
+
spec:
|
|
6
|
+
capacity:
|
|
7
|
+
storage: 5Gi
|
|
8
|
+
accessModes:
|
|
9
|
+
- ReadWriteOnce
|
|
10
|
+
persistentVolumeReclaimPolicy: Retain
|
|
11
|
+
storageClassName: manual
|
|
12
|
+
hostPath:
|
|
13
|
+
path: /home/dd
|
|
14
|
+
type: DirectoryOrCreate
|
|
15
|
+
nodeAffinity:
|
|
16
|
+
required:
|
|
17
|
+
nodeSelectorTerms:
|
|
18
|
+
- matchExpressions:
|
|
19
|
+
- key: kubernetes.io/hostname
|
|
20
|
+
operator: In
|
|
21
|
+
values:
|
|
22
|
+
- localhost
|
|
23
|
+
---
|
|
24
|
+
apiVersion: v1
|
|
25
|
+
kind: PersistentVolumeClaim
|
|
26
|
+
metadata:
|
|
27
|
+
name: pvc-dd
|
|
28
|
+
spec:
|
|
29
|
+
accessModes:
|
|
30
|
+
- ReadWriteOnce
|
|
31
|
+
storageClassName: manual
|
|
32
|
+
resources:
|
|
33
|
+
requests:
|
|
34
|
+
storage: 1Gi
|
package/package.json
CHANGED
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 {boolean} [options.removeVolumeHostPaths=false] - Remove data from host paths used by Persistent Volumes.
|
|
61
62
|
* @param {string} [options.hosts] - Set custom hosts entries.
|
|
62
63
|
* @memberof UnderpostCluster
|
|
63
64
|
*/
|
|
@@ -91,6 +92,7 @@ class UnderpostCluster {
|
|
|
91
92
|
config: false,
|
|
92
93
|
worker: false,
|
|
93
94
|
chown: false,
|
|
95
|
+
removeVolumeHostPaths: false,
|
|
94
96
|
hosts: '',
|
|
95
97
|
},
|
|
96
98
|
) {
|
|
@@ -153,7 +155,11 @@ class UnderpostCluster {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
// Reset Kubernetes cluster components (Kind/Kubeadm/K3s) and container runtimes
|
|
156
|
-
if (options.reset === true)
|
|
158
|
+
if (options.reset === true)
|
|
159
|
+
return await UnderpostCluster.API.safeReset({
|
|
160
|
+
underpostRoot,
|
|
161
|
+
removeVolumeHostPaths: options.removeVolumeHostPaths,
|
|
162
|
+
});
|
|
157
163
|
|
|
158
164
|
// Check if a cluster (Kind, Kubeadm, or K3s) is already initialized
|
|
159
165
|
const alreadyKubeadmCluster = UnderpostDeploy.API.get('calico-kube-controllers')[0];
|
|
@@ -585,9 +591,10 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
585
591
|
* in coredns) by restoring SELinux security contexts and safely cleaning up cluster artifacts.
|
|
586
592
|
* @param {object} [options] - Configuration options for the reset.
|
|
587
593
|
* @param {string} [options.underpostRoot] - The root path of the underpost project.
|
|
594
|
+
* @param {boolean} [options.removeVolumeHostPaths=false] - Whether to remove data from host paths used by Persistent Volumes.
|
|
588
595
|
* @memberof UnderpostCluster
|
|
589
596
|
*/
|
|
590
|
-
async safeReset(options = { underpostRoot: '.' }) {
|
|
597
|
+
async safeReset(options = { underpostRoot: '.', removeVolumeHostPaths: false }) {
|
|
591
598
|
logger.info('Starting a safe and comprehensive reset of Kubernetes and container environments...');
|
|
592
599
|
|
|
593
600
|
try {
|
|
@@ -614,25 +621,30 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
614
621
|
// Phase 1: Clean up Persistent Volumes with hostPath
|
|
615
622
|
// This targets data created by Kubernetes Persistent Volumes that use hostPath.
|
|
616
623
|
logger.info('Phase 1/7: Cleaning Kubernetes hostPath volumes...');
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
624
|
+
if (options.removeVolumeHostPaths)
|
|
625
|
+
try {
|
|
626
|
+
const pvListJson = shellExec(`kubectl get pv -o json || echo '{"items":[]}'`, {
|
|
627
|
+
stdout: true,
|
|
628
|
+
silent: true,
|
|
629
|
+
});
|
|
630
|
+
const pvList = JSON.parse(pvListJson);
|
|
631
|
+
|
|
632
|
+
if (pvList.items && pvList.items.length > 0) {
|
|
633
|
+
for (const pv of pvList.items) {
|
|
634
|
+
// Check if the PV uses hostPath and delete its contents
|
|
635
|
+
if (pv.spec.hostPath && pv.spec.hostPath.path) {
|
|
636
|
+
const hostPath = pv.spec.hostPath.path;
|
|
637
|
+
logger.info(`Removing data from host path for PV '${pv.metadata.name}': ${hostPath}`);
|
|
638
|
+
shellExec(`sudo rm -rf ${hostPath}/* || true`);
|
|
639
|
+
}
|
|
628
640
|
}
|
|
641
|
+
} else {
|
|
642
|
+
logger.info('No Persistent Volumes found with hostPath to clean up.');
|
|
629
643
|
}
|
|
630
|
-
}
|
|
631
|
-
logger.
|
|
644
|
+
} catch (error) {
|
|
645
|
+
logger.error('Failed to clean up Persistent Volumes:', error);
|
|
632
646
|
}
|
|
633
|
-
|
|
634
|
-
logger.error('Failed to clean up Persistent Volumes:', error);
|
|
635
|
-
}
|
|
647
|
+
else logger.info(' -> Skipping hostPath volume cleanup as per configuration.');
|
|
636
648
|
// Phase 2: Restore SELinux and stop services
|
|
637
649
|
// This is critical for fixing the 'permission denied' error you experienced.
|
|
638
650
|
// Enable SELinux permissive mode and restore file contexts.
|
package/src/cli/deploy.js
CHANGED
|
@@ -134,6 +134,17 @@ class UnderpostDeploy {
|
|
|
134
134
|
*/
|
|
135
135
|
deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image }) {
|
|
136
136
|
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
137
|
+
let volumes = [
|
|
138
|
+
{
|
|
139
|
+
volumeMountPath: '/etc/config',
|
|
140
|
+
volumeName: 'config-volume',
|
|
141
|
+
configMap: 'underpost-config',
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
|
|
145
|
+
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
|
|
146
|
+
: [];
|
|
147
|
+
volumes = volumes.concat(confVolume);
|
|
137
148
|
return `apiVersion: apps/v1
|
|
138
149
|
kind: Deployment
|
|
139
150
|
metadata:
|
|
@@ -168,13 +179,10 @@ spec:
|
|
|
168
179
|
npm install -g underpost &&
|
|
169
180
|
underpost secret underpost --create-from-file /etc/config/.env.${env} &&
|
|
170
181
|
underpost start --build --run ${deployId} ${env}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- name: config-volume
|
|
176
|
-
configMap:
|
|
177
|
-
name: underpost-config
|
|
182
|
+
${UnderpostDeploy.API.volumeFactory(volumes)
|
|
183
|
+
.render.split(`\n`)
|
|
184
|
+
.map((l) => ' ' + l)
|
|
185
|
+
.join(`\n`)}
|
|
178
186
|
---
|
|
179
187
|
apiVersion: v1
|
|
180
188
|
kind: Service
|
|
@@ -364,6 +372,7 @@ spec:
|
|
|
364
372
|
* @param {boolean} options.disableUpdateDeployment - Whether to disable deployment updates.
|
|
365
373
|
* @param {boolean} options.disableUpdateProxy - Whether to disable proxy updates.
|
|
366
374
|
* @param {boolean} options.disableDeploymentProxy - Whether to disable deployment proxy.
|
|
375
|
+
* @param {boolean} options.disableUpdateVolume - Whether to disable volume updates.
|
|
367
376
|
* @param {boolean} options.status - Whether to display deployment status.
|
|
368
377
|
* @param {boolean} options.etcHosts - Whether to display the /etc/hosts file.
|
|
369
378
|
* @param {boolean} options.disableUpdateUnderpostConfig - Whether to disable Underpost config updates.
|
|
@@ -391,6 +400,7 @@ spec:
|
|
|
391
400
|
disableUpdateDeployment: false,
|
|
392
401
|
disableUpdateProxy: false,
|
|
393
402
|
disableDeploymentProxy: false,
|
|
403
|
+
disableUpdateVolume: false,
|
|
394
404
|
status: false,
|
|
395
405
|
etcHosts: false,
|
|
396
406
|
disableUpdateUnderpostConfig: false,
|
|
@@ -520,6 +530,26 @@ EOF`);
|
|
|
520
530
|
}
|
|
521
531
|
|
|
522
532
|
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
533
|
+
const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
|
|
534
|
+
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
|
|
535
|
+
: [];
|
|
536
|
+
|
|
537
|
+
if (!options.disableUpdateVolume) {
|
|
538
|
+
for (const volume of confVolume) {
|
|
539
|
+
if (options.remove) {
|
|
540
|
+
shellExec(`kubectl delete pvc ${volume.claimName}`);
|
|
541
|
+
shellExec(`kubectl delete pv ${volume.claimName.replace('pvc-', 'pv-')}`);
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
shellExec(`kubectl apply -f - <<EOF
|
|
545
|
+
${UnderpostDeploy.API.persistentVolumeFactory({
|
|
546
|
+
hostPath: volume.volumeMountPath,
|
|
547
|
+
pvcId: volume.claimName,
|
|
548
|
+
})}
|
|
549
|
+
EOF
|
|
550
|
+
`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
523
553
|
|
|
524
554
|
for (const host of Object.keys(confServer)) {
|
|
525
555
|
if (!options.disableUpdateProxy) {
|
|
@@ -702,6 +732,78 @@ EOF`);
|
|
|
702
732
|
);
|
|
703
733
|
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
704
734
|
},
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Creates volume mounts and volumes for a deployment.
|
|
738
|
+
* @param {Array<volume>} volumes - List of volume configurations.
|
|
739
|
+
* @param {string} volume.volumeName - Name of the volume.
|
|
740
|
+
* @param {string} volume.volumeMountPath - Mount path of the volume in the container.
|
|
741
|
+
* @param {string} volume.volumeHostPath - Host path of the volume.
|
|
742
|
+
* @param {string} volume.volumeType - Type of the volume (e.g. 'Directory').
|
|
743
|
+
* @param {string|null} volume.claimName - Name of the persistent volume claim (if applicable).
|
|
744
|
+
* @param {string|null} volume.configMap - Name of the config map (if applicable).
|
|
745
|
+
* @returns {object} - Object containing the rendered volume mounts and volumes.
|
|
746
|
+
* @memberof UnderpostDeploy
|
|
747
|
+
*/
|
|
748
|
+
volumeFactory(
|
|
749
|
+
volumes = [
|
|
750
|
+
{
|
|
751
|
+
volumeName: 'volume-name',
|
|
752
|
+
volumeMountPath: '/path/in/container',
|
|
753
|
+
volumeHostPath: '/path/on/host',
|
|
754
|
+
volumeType: 'Directory',
|
|
755
|
+
claimName: null,
|
|
756
|
+
configMap: null,
|
|
757
|
+
},
|
|
758
|
+
],
|
|
759
|
+
) {
|
|
760
|
+
let _volumeMounts = `
|
|
761
|
+
volumeMounts:`;
|
|
762
|
+
let _volumes = `
|
|
763
|
+
volumes:`;
|
|
764
|
+
volumes.map((volumeData) => {
|
|
765
|
+
const { volumeName, volumeMountPath, volumeHostPath, volumeType, claimName, configMap } = volumeData;
|
|
766
|
+
_volumeMounts += `
|
|
767
|
+
- name: ${volumeName}
|
|
768
|
+
mountPath: ${volumeMountPath}
|
|
769
|
+
`;
|
|
770
|
+
|
|
771
|
+
_volumes += `
|
|
772
|
+
- name: ${volumeName}
|
|
773
|
+
${
|
|
774
|
+
configMap
|
|
775
|
+
? ` configMap:
|
|
776
|
+
name: ${configMap}`
|
|
777
|
+
: claimName
|
|
778
|
+
? ` persistentVolumeClaim:
|
|
779
|
+
claimName: ${claimName}`
|
|
780
|
+
: ` hostPath:
|
|
781
|
+
path: ${volumeHostPath}
|
|
782
|
+
type: ${volumeType}
|
|
783
|
+
`
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
`;
|
|
787
|
+
});
|
|
788
|
+
return { render: _volumeMounts + _volumes };
|
|
789
|
+
},
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Creates a persistent volume and persistent volume claim for a deployment.
|
|
793
|
+
* @param {object} options - Options for the persistent volume and claim creation.
|
|
794
|
+
* @param {string} options.hostPath - Host path for the persistent volume.
|
|
795
|
+
* @param {string} options.pvcId - Persistent volume claim ID.
|
|
796
|
+
* @returns {string} - YAML configuration for the persistent volume and claim.
|
|
797
|
+
* @memberof UnderpostDeploy
|
|
798
|
+
*/
|
|
799
|
+
persistentVolumeFactory({ hostPath, pvcId }) {
|
|
800
|
+
return fs
|
|
801
|
+
.readFileSync(`./manifests/pv-pvc-dd.yaml`, 'utf8')
|
|
802
|
+
.replace('/home/dd', hostPath)
|
|
803
|
+
.replace('pv-dd', pvcId.replace('pvc-', 'pv-'))
|
|
804
|
+
.replace('pvc-dd', pvcId);
|
|
805
|
+
},
|
|
806
|
+
|
|
705
807
|
/**
|
|
706
808
|
* Creates a hosts file for a deployment.
|
|
707
809
|
* @param {Array<string>} hosts - List of hosts to be added to the hosts file.
|
package/src/cli/index.js
CHANGED
|
@@ -78,6 +78,8 @@ program
|
|
|
78
78
|
.option('--msg <msg>', 'Sets a custom commit message.')
|
|
79
79
|
.option('--deploy-id <deploy-id>', 'Sets the deployment configuration ID for the commit context.')
|
|
80
80
|
.option('--cached', 'Commit staged changes only or context.')
|
|
81
|
+
.option('--hashes <hashes>', 'Comma-separated list of specific file hashes of commits.')
|
|
82
|
+
.option('--extension <extension>', 'specific file extensions of commits.')
|
|
81
83
|
.description('Manages commits to a GitHub repository, supporting various commit types and options.')
|
|
82
84
|
.action(Underpost.repo.commit);
|
|
83
85
|
|
|
@@ -163,6 +165,7 @@ program
|
|
|
163
165
|
.option('--chown', 'Sets the appropriate ownership for Kubernetes kubeconfig files.')
|
|
164
166
|
.option('--k3s', 'Initializes the cluster using K3s (Lightweight Kubernetes).')
|
|
165
167
|
.option('--hosts <hosts>', 'A comma-separated list of cluster hostnames or IP addresses.')
|
|
168
|
+
.option('--remove-volume-host-paths', 'Removes specified volume host paths after execution.')
|
|
166
169
|
.action(Underpost.cluster.init)
|
|
167
170
|
.description('Manages Kubernetes clusters, defaulting to Kind cluster initialization.');
|
|
168
171
|
|
|
@@ -193,6 +196,7 @@ program
|
|
|
193
196
|
.option('--disable-update-deployment', 'Disables updates to deployments.')
|
|
194
197
|
.option('--disable-update-proxy', 'Disables updates to proxies.')
|
|
195
198
|
.option('--disable-deployment-proxy', 'Disables proxies of deployments.')
|
|
199
|
+
.option('--disable-update-volume', 'Disables updates to volume mounts during deployment.')
|
|
196
200
|
.option(
|
|
197
201
|
'--status',
|
|
198
202
|
'Retrieves current network traffic data from resource deployments and the host machine network configuration.',
|
|
@@ -392,6 +396,14 @@ program
|
|
|
392
396
|
.option('--image-name <image-name>', 'Optional: Specifies the image name for test execution.')
|
|
393
397
|
.option('--container-name <container-name>', 'Optional: Specifies the container name for test execution.')
|
|
394
398
|
.option('--namespace <namespace>', 'Optional: Specifies the namespace for test execution.')
|
|
399
|
+
.option('--tty', 'Enables TTY for the container in deploy-job.')
|
|
400
|
+
.option('--stdin', 'Keeps STDIN open for the container in deploy-job.')
|
|
401
|
+
.option('--restart-policy <policy>', 'Sets the restart policy for the job in deploy-job.')
|
|
402
|
+
.option('--runtime-class-name <name>', 'Sets the runtime class name for the job in deploy-job.')
|
|
403
|
+
.option('--image-pull-policy <policy>', 'Sets the image pull policy for the job in deploy-job.')
|
|
404
|
+
.option('--api-version <version>', 'Sets the API version for the job manifest in deploy-job.')
|
|
405
|
+
.option('--claim-name <name>', 'Optional: Specifies the claim name for volume mounting in deploy-job.')
|
|
406
|
+
.option('--kind <kind-type>', 'Specifies the kind of Kubernetes resource (e.g., Job, Deployment) for deploy-job.')
|
|
395
407
|
.option('--kubeadm', 'Flag to indicate Kubeadm cluster type context')
|
|
396
408
|
.option('--k3s', 'Flag to indicate K3s cluster type context')
|
|
397
409
|
.option('--force', 'Forces operation, overriding any warnings or conflicts.')
|
|
@@ -400,6 +412,7 @@ program
|
|
|
400
412
|
.option('--terminal', 'Enables terminal mode for interactive script execution.')
|
|
401
413
|
.option('--dev-proxy-port-offset <port-offset>', 'Sets a custom port offset for development proxy.')
|
|
402
414
|
.option('--conf-server-path <conf-server-path>', 'Sets a custom configuration server path.')
|
|
415
|
+
.option('--underpost-root <underpost-root>', 'Sets a custom Underpost root path.')
|
|
403
416
|
.description('Runs a script from the specified path.')
|
|
404
417
|
.action(UnderpostRun.API.callback);
|
|
405
418
|
|
package/src/cli/repository.js
CHANGED
|
@@ -89,6 +89,8 @@ class UnderpostRepository {
|
|
|
89
89
|
* @param {boolean} [options.lastMsg=0] - If greater than 0, copies or show the last last single n commit message to clipboard.
|
|
90
90
|
* @param {string} [options.msg=''] - If provided, outputs this message instead of committing.
|
|
91
91
|
* @param {string} [options.deployId=''] - An optional deploy ID to include in the commit message.
|
|
92
|
+
* @param {string} [options.hashes=''] - If provided with diff option, shows the diff between two hashes.
|
|
93
|
+
* @param {string} [options.extension=''] - If provided with diff option, filters the diff by this file extension.
|
|
92
94
|
* @memberof UnderpostRepository
|
|
93
95
|
*/
|
|
94
96
|
commit(
|
|
@@ -107,9 +109,19 @@ class UnderpostRepository {
|
|
|
107
109
|
log: 0,
|
|
108
110
|
msg: '',
|
|
109
111
|
deployId: '',
|
|
112
|
+
hashes: '',
|
|
113
|
+
extension: '',
|
|
110
114
|
},
|
|
111
115
|
) {
|
|
112
116
|
if (!repoPath) repoPath = '.';
|
|
117
|
+
if (options.diff && options.hashes) {
|
|
118
|
+
const hashes = options.hashes.split(',');
|
|
119
|
+
const cmd = `git --no-pager diff ${hashes[0]} ${hashes[1] ? hashes[1] : 'HEAD'}${options.extension ? ` -- '*.${options.extension}'` : ''}`;
|
|
120
|
+
if (options.copy) {
|
|
121
|
+
pbcopy(cmd);
|
|
122
|
+
} else console.log(cmd);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
113
125
|
if (options.msg) {
|
|
114
126
|
options.msg = options.msg.replaceAll('"', '').replaceAll(`'`, '').replaceAll('`', '');
|
|
115
127
|
let key = Object.keys(commitData).find((k) => k && options.msg.toLocaleLowerCase().slice(0, 16).match(k));
|
package/src/cli/run.js
CHANGED
|
@@ -60,9 +60,15 @@ class UnderpostRun {
|
|
|
60
60
|
* @property {string} tty - The TTY option for the container.
|
|
61
61
|
* @property {string} stdin - The stdin option for the container.
|
|
62
62
|
* @property {string} restartPolicy - The restart policy for the container.
|
|
63
|
+
* @property {string} runtimeClassName - The runtime class name for the container.
|
|
64
|
+
* @property {string} imagePullPolicy - The image pull policy for the container.
|
|
65
|
+
* @property {string} apiVersion - The API version for the container.
|
|
66
|
+
* @property {string} claimName - The claim name for the volume.
|
|
67
|
+
* @property {string} kind - The kind of resource to create.
|
|
63
68
|
* @property {boolean} terminal - Whether to open a terminal.
|
|
64
69
|
* @property {number} devProxyPortOffset - The port offset for the development proxy.
|
|
65
70
|
* @property {string} confServerPath - The configuration server path.
|
|
71
|
+
* @property {string} underpostRoot - The root path of the Underpost installation.
|
|
66
72
|
* @memberof UnderpostRun
|
|
67
73
|
*/
|
|
68
74
|
static DEFAULT_OPTION = {
|
|
@@ -85,9 +91,15 @@ class UnderpostRun {
|
|
|
85
91
|
tty: '',
|
|
86
92
|
stdin: '',
|
|
87
93
|
restartPolicy: '',
|
|
94
|
+
runtimeClassName: '',
|
|
95
|
+
imagePullPolicy: '',
|
|
96
|
+
apiVersion: '',
|
|
97
|
+
claimName: '',
|
|
98
|
+
kind: '',
|
|
88
99
|
terminal: false,
|
|
89
100
|
devProxyPortOffset: 0,
|
|
90
101
|
confServerPath: '',
|
|
102
|
+
underpostRoot: '',
|
|
91
103
|
};
|
|
92
104
|
/**
|
|
93
105
|
* @static
|
|
@@ -578,39 +590,51 @@ class UnderpostRun {
|
|
|
578
590
|
},
|
|
579
591
|
|
|
580
592
|
/**
|
|
581
|
-
* @method
|
|
582
|
-
* @description
|
|
583
|
-
* @param {string} path - The input value, identifier, or path for the operation (used as
|
|
593
|
+
* @method dd-container
|
|
594
|
+
* @description Deploys a development or debug container tasks jobs, setting up necessary volumes and images, and running specified commands within the container.
|
|
595
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the command to run inside the container).
|
|
584
596
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
585
597
|
* @memberof UnderpostRun
|
|
586
598
|
*/
|
|
587
|
-
'
|
|
588
|
-
options.dev = true;
|
|
599
|
+
'dd-container': async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
589
600
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
590
601
|
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
591
|
-
const currentImage = UnderpostDeploy.API.getCurrentLoadedImages(
|
|
592
|
-
|
|
593
|
-
|
|
602
|
+
const currentImage = UnderpostDeploy.API.getCurrentLoadedImages(
|
|
603
|
+
options.nodeName ? options.nodeName : 'kind-worker',
|
|
604
|
+
false,
|
|
605
|
+
).find((o) => o.IMAGE.match('underpost'));
|
|
594
606
|
const podName = `underpost-dev-container`;
|
|
595
|
-
if (!
|
|
607
|
+
if (!options.nodeName) {
|
|
608
|
+
shellExec(`docker exec -i kind-worker bash -c "rm -rf /home/dd"`);
|
|
596
609
|
shellExec(`docker exec -i kind-worker bash -c "mkdir -p /home/dd"`);
|
|
597
610
|
shellExec(`docker cp /home/dd/engine kind-worker:/home/dd/engine`);
|
|
598
611
|
shellExec(`docker exec -i kind-worker bash -c "chown -R 1000:1000 /home/dd || true; chmod -R 755 /home/dd"`);
|
|
612
|
+
} else {
|
|
613
|
+
shellExec(`kubectl apply -f ${options.underpostRoot}/manifests/pv-pvc-dd.yaml`);
|
|
599
614
|
}
|
|
600
|
-
if (!currentImage)
|
|
615
|
+
if (!currentImage)
|
|
616
|
+
shellExec(
|
|
617
|
+
`${baseCommand} dockerfile-pull-base-images${baseClusterCommand} ${options.dev ? '--kind-load' : '--kubeadm-load'}`,
|
|
618
|
+
);
|
|
601
619
|
// shellExec(`kubectl delete pod ${podName} --ignore-not-found`);
|
|
602
620
|
await UnderpostRun.RUNNERS['deploy-job']('', {
|
|
603
|
-
dev:
|
|
621
|
+
dev: options.dev,
|
|
604
622
|
podName,
|
|
605
|
-
imageName: currentImage
|
|
606
|
-
|
|
623
|
+
imageName: currentImage
|
|
624
|
+
? currentImage.image
|
|
625
|
+
? currentImage.image
|
|
626
|
+
: currentImage.IMAGE
|
|
627
|
+
? `${currentImage.IMAGE}:${currentImage.TAG}`
|
|
628
|
+
: `localhost/rockylinux9-underpost:${Underpost.version}`
|
|
629
|
+
: `localhost/rockylinux9-underpost:${Underpost.version}`,
|
|
607
630
|
volumeMountPath: '/home/dd',
|
|
631
|
+
...(options.dev ? { volumeHostPath: '/home/dd' } : { claimName: 'pvc-dd' }),
|
|
608
632
|
on: {
|
|
609
633
|
init: async () => {
|
|
610
634
|
// openTerminal(`kubectl logs -f ${podName}`);
|
|
611
635
|
},
|
|
612
636
|
},
|
|
613
|
-
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm run test`)],
|
|
637
|
+
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm install && npm run test`)],
|
|
614
638
|
});
|
|
615
639
|
},
|
|
616
640
|
|
|
@@ -1153,28 +1177,34 @@ class UnderpostRun {
|
|
|
1153
1177
|
'deploy-job': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
1154
1178
|
const podName = options.podName || 'deploy-job';
|
|
1155
1179
|
const volumeName = `${podName}-volume`;
|
|
1156
|
-
|
|
1180
|
+
if (typeof options.args === 'string') options.args = options.args.split(',');
|
|
1181
|
+
const args = (options.args ? options.args : path ? [path] : [`python ${path}`]).filter((c) => c.trim());
|
|
1157
1182
|
const imageName = options.imageName || 'nvcr.io/nvidia/tensorflow:24.04-tf2-py3';
|
|
1158
1183
|
const containerName = options.containerName || `${podName}-container`;
|
|
1159
1184
|
const gpuEnable = imageName.match('nvidia');
|
|
1160
|
-
const runtimeClassName = gpuEnable ? 'nvidia' : '';
|
|
1185
|
+
const runtimeClassName = options.runtimeClassName ? options.runtimeClassName : gpuEnable ? 'nvidia' : '';
|
|
1161
1186
|
const namespace = options.namespace || 'default';
|
|
1162
1187
|
const volumeMountPath = options.volumeMountPath || path;
|
|
1163
1188
|
const volumeHostPath = options.volumeHostPath || path;
|
|
1164
|
-
const
|
|
1189
|
+
const claimName = options.claimName || '';
|
|
1190
|
+
const enableVolumeMount = volumeMountPath && (volumeHostPath || claimName);
|
|
1165
1191
|
const tty = options.tty ? 'true' : 'false';
|
|
1166
1192
|
const stdin = options.stdin ? 'true' : 'false';
|
|
1167
1193
|
const restartPolicy = options.restartPolicy || 'Never';
|
|
1168
|
-
|
|
1194
|
+
const kind = options.kind || 'Pod';
|
|
1195
|
+
const imagePullPolicy = options.imagePullPolicy || 'IfNotPresent';
|
|
1196
|
+
const apiVersion = options.apiVersion || 'v1';
|
|
1169
1197
|
if (options.volumeType === 'dev') options.volumeType = 'FileOrCreate';
|
|
1170
1198
|
const volumeType =
|
|
1171
|
-
options.volumeType || (enableVolumeMount && fs.statSync(volumeHostPath).isDirectory())
|
|
1199
|
+
options.volumeType || (enableVolumeMount && volumeHostPath && fs.statSync(volumeHostPath).isDirectory())
|
|
1200
|
+
? 'Directory'
|
|
1201
|
+
: 'File';
|
|
1172
1202
|
|
|
1173
1203
|
const envs = UnderpostRootEnv.API.list();
|
|
1174
1204
|
|
|
1175
1205
|
const cmd = `kubectl apply -f - <<EOF
|
|
1176
|
-
apiVersion:
|
|
1177
|
-
kind:
|
|
1206
|
+
apiVersion: ${apiVersion}
|
|
1207
|
+
kind: ${kind}
|
|
1178
1208
|
metadata:
|
|
1179
1209
|
name: ${podName}
|
|
1180
1210
|
namespace: ${namespace}
|
|
@@ -1186,7 +1216,7 @@ ${runtimeClassName ? ` runtimeClassName: ${runtimeClassName}` : ''}
|
|
|
1186
1216
|
containers:
|
|
1187
1217
|
- name: ${containerName}
|
|
1188
1218
|
image: ${imageName}
|
|
1189
|
-
imagePullPolicy:
|
|
1219
|
+
imagePullPolicy: ${imagePullPolicy}
|
|
1190
1220
|
tty: ${tty}
|
|
1191
1221
|
stdin: ${stdin}
|
|
1192
1222
|
command: ${JSON.stringify(options.command ? options.command : ['/bin/bash', '-c'])}
|
|
@@ -1212,15 +1242,7 @@ ${Object.keys(envs)
|
|
|
1212
1242
|
.join('\n')}`}
|
|
1213
1243
|
${
|
|
1214
1244
|
enableVolumeMount
|
|
1215
|
-
?
|
|
1216
|
-
volumeMounts:
|
|
1217
|
-
- name: ${volumeName}
|
|
1218
|
-
mountPath: ${volumeMountPath}
|
|
1219
|
-
volumes:
|
|
1220
|
-
- name: ${volumeName}
|
|
1221
|
-
hostPath:
|
|
1222
|
-
path: ${volumeHostPath}
|
|
1223
|
-
type: ${volumeType}`
|
|
1245
|
+
? UnderpostDeploy.API.volumeFactory([{ volumeMountPath, volumeName, volumeHostPath, volumeType, claimName }]).render
|
|
1224
1246
|
: ''
|
|
1225
1247
|
}
|
|
1226
1248
|
EOF`;
|
|
@@ -1251,7 +1273,7 @@ EOF`;
|
|
|
1251
1273
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
1252
1274
|
if (options.command) options.command = options.command.split(',');
|
|
1253
1275
|
if (options.args) options.args = options.args.split(',');
|
|
1254
|
-
options.underpostRoot = underpostRoot;
|
|
1276
|
+
if (!options.underpostRoot) options.underpostRoot = underpostRoot;
|
|
1255
1277
|
options.npmRoot = npmRoot;
|
|
1256
1278
|
logger.info('callback', { path, options });
|
|
1257
1279
|
if (!(runner in UnderpostRun.RUNNERS)) throw new Error(`Runner not found: ${runner}`);
|
|
@@ -940,12 +940,13 @@ const ObjectLayerEngineModal = {
|
|
|
940
940
|
const queryParams = getQueryParams();
|
|
941
941
|
queryParams.page = 1;
|
|
942
942
|
setQueryParams(queryParams);
|
|
943
|
-
const
|
|
943
|
+
const modalId = 'modal-object-layer-engine-management';
|
|
944
|
+
const managerComponent = DefaultManagement.Tokens[modalId];
|
|
944
945
|
if (managerComponent) {
|
|
945
946
|
managerComponent.page = 1;
|
|
946
947
|
if (!managerComponent.readyRowDataEvent) managerComponent.readyRowDataEvent = {};
|
|
947
948
|
let readyLoad = false;
|
|
948
|
-
const gridId =
|
|
949
|
+
const gridId = `object-layer-engine-management-grid-${modalId}`;
|
|
949
950
|
managerComponent.readyRowDataEvent['object-layer-engine-management'] = async () => {
|
|
950
951
|
if (readyLoad) {
|
|
951
952
|
AgGrid.grids[gridId].setGridOption('getRowClass', null);
|
|
@@ -961,7 +962,7 @@ const ObjectLayerEngineModal = {
|
|
|
961
962
|
};
|
|
962
963
|
}
|
|
963
964
|
|
|
964
|
-
const _s = s(`.management-table-btn-reload
|
|
965
|
+
const _s = s(`.management-table-btn-reload-${modalId}`);
|
|
965
966
|
if (_s) _s.click();
|
|
966
967
|
|
|
967
968
|
s(`.main-btn-object-layer-engine-management`).click();
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { loggerFactory } from './Logger.js';
|
|
2
|
-
import { getProxyPath, listenQueryPathInstance } from './Router.js';
|
|
2
|
+
import { getProxyPath, listenQueryPathInstance, setPath, setQueryParams } from './Router.js';
|
|
3
3
|
import { ObjectLayerService } from '../../services/object-layer/object-layer.service.js';
|
|
4
4
|
import { NotificationManager } from './NotificationManager.js';
|
|
5
5
|
import { htmls, s } from './VanillaJs.js';
|
|
6
6
|
import { BtnIcon } from './BtnIcon.js';
|
|
7
7
|
import { darkTheme, ThemeEvents } from './Css.js';
|
|
8
|
-
import {
|
|
8
|
+
import { ObjectLayerManagement } from '../../services/object-layer/object-layer.management.js';
|
|
9
|
+
import { ObjectLayerEngineModal } from './ObjectLayerEngineModal.js';
|
|
9
10
|
|
|
10
11
|
const logger = loggerFactory(import.meta);
|
|
11
12
|
|
|
@@ -66,7 +67,7 @@ const ObjectLayerEngineViewer = {
|
|
|
66
67
|
if (cid) {
|
|
67
68
|
await this.loadObjectLayer(cid);
|
|
68
69
|
} else {
|
|
69
|
-
this.renderEmpty();
|
|
70
|
+
this.renderEmpty({ Elements });
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
73
|
},
|
|
@@ -103,9 +104,15 @@ const ObjectLayerEngineViewer = {
|
|
|
103
104
|
`;
|
|
104
105
|
},
|
|
105
106
|
|
|
106
|
-
renderEmpty: async function () {
|
|
107
|
+
renderEmpty: async function ({ Elements }) {
|
|
107
108
|
const id = 'object-layer-engine-viewer';
|
|
108
|
-
htmls(
|
|
109
|
+
htmls(
|
|
110
|
+
`#${id}`,
|
|
111
|
+
await ObjectLayerManagement.RenderTable({
|
|
112
|
+
Elements,
|
|
113
|
+
idModal: 'modal-object-layer-engine-viewer',
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
109
116
|
},
|
|
110
117
|
|
|
111
118
|
loadObjectLayer: async function (objectLayerId) {
|
|
@@ -398,6 +405,14 @@ const ObjectLayerEngineViewer = {
|
|
|
398
405
|
transform: none;
|
|
399
406
|
}
|
|
400
407
|
|
|
408
|
+
.edit-btn {
|
|
409
|
+
background: ${darkTheme ? '#4a9eff' : '#2196F3'};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.edit-btn:hover {
|
|
413
|
+
background: ${darkTheme ? '#3a8eff' : '#1186f2'};
|
|
414
|
+
}
|
|
415
|
+
|
|
401
416
|
@media (max-width: 768px) {
|
|
402
417
|
.gif-display-area {
|
|
403
418
|
max-height: 500px;
|
|
@@ -440,7 +455,8 @@ const ObjectLayerEngineViewer = {
|
|
|
440
455
|
.item-data-value-label {
|
|
441
456
|
font-size: 20px;
|
|
442
457
|
font-weight: 700;
|
|
443
|
-
color: ${darkTheme ? '#
|
|
458
|
+
color: ${darkTheme ? '#aaa' : '#666'};
|
|
459
|
+
text-align: center;
|
|
444
460
|
}
|
|
445
461
|
.item-stat-entry {
|
|
446
462
|
display: flex;
|
|
@@ -493,6 +509,32 @@ const ObjectLayerEngineViewer = {
|
|
|
493
509
|
</div>
|
|
494
510
|
</div>
|
|
495
511
|
|
|
512
|
+
<!-- Stats Data Section -->
|
|
513
|
+
<div class="control-group" style="margin-bottom: 20px;">
|
|
514
|
+
<h4><i class="fa-solid fa-chart-bar"></i> Stats Data</h4>
|
|
515
|
+
<div
|
|
516
|
+
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; padding: 10px 0;"
|
|
517
|
+
>
|
|
518
|
+
${Object.keys(stats).length > 0
|
|
519
|
+
? Object.entries(stats)
|
|
520
|
+
.map(([statKey, statValue]) => {
|
|
521
|
+
const statInfo = ObjectLayerEngineModal.statDescriptions[statKey];
|
|
522
|
+
if (!statInfo) return '';
|
|
523
|
+
return html`
|
|
524
|
+
<div class="item-stat-entry">
|
|
525
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
526
|
+
<i class="${statInfo.icon}" id="stat-icon-${statKey}-${id}"></i>
|
|
527
|
+
<span class="item-data-key-label">${statInfo.title}</span>
|
|
528
|
+
</div>
|
|
529
|
+
<span class="item-data-value-label">${statValue}</span>
|
|
530
|
+
</div>
|
|
531
|
+
`;
|
|
532
|
+
})
|
|
533
|
+
.join('')
|
|
534
|
+
: html`<div class="no-data-container">No stats data available</div>`}
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
496
538
|
<div class="gif-display-area">
|
|
497
539
|
<div class="gif-canvas-container" id="gif-canvas-container">
|
|
498
540
|
<div style="text-align: center; color: ${darkTheme ? '#aaa' : '#666'};">
|
|
@@ -587,30 +629,17 @@ const ObjectLayerEngineViewer = {
|
|
|
587
629
|
</div>
|
|
588
630
|
</div>
|
|
589
631
|
</div>
|
|
590
|
-
|
|
591
|
-
<div
|
|
592
|
-
<
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
>
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
<div class="item-stat-entry">
|
|
601
|
-
<span class="item-data-key-label"> ${statKey} </span>
|
|
602
|
-
<span style="item-data-value-label"> ${statValue} </span>
|
|
603
|
-
</div>
|
|
604
|
-
`,
|
|
605
|
-
)
|
|
606
|
-
.join('')
|
|
607
|
-
: html`<div class="no-data-container">No stats data available</div>`}
|
|
608
|
-
</div>
|
|
632
|
+
|
|
633
|
+
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
|
634
|
+
<button class="download-btn" id="download-gif-btn" style="width: 100%;">
|
|
635
|
+
<i class="fa-solid fa-download"></i>
|
|
636
|
+
<span>Download GIF</span>
|
|
637
|
+
</button>
|
|
638
|
+
<button class="download-btn edit-btn" id="edit-object-layer-btn" style="width: 100%;">
|
|
639
|
+
<i class="fa-solid fa-edit"></i>
|
|
640
|
+
<span>Edit</span>
|
|
641
|
+
</button>
|
|
609
642
|
</div>
|
|
610
|
-
<button class="download-btn" id="download-gif-btn">
|
|
611
|
-
<i class="fa-solid fa-download"></i>
|
|
612
|
-
<span>Download GIF</span>
|
|
613
|
-
</button>
|
|
614
643
|
</div>
|
|
615
644
|
`,
|
|
616
645
|
);
|
|
@@ -658,6 +687,13 @@ const ObjectLayerEngineViewer = {
|
|
|
658
687
|
});
|
|
659
688
|
}
|
|
660
689
|
|
|
690
|
+
const editBtn = s('#edit-object-layer-btn');
|
|
691
|
+
if (editBtn) {
|
|
692
|
+
editBtn.addEventListener('click', () => {
|
|
693
|
+
this.toEngine();
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
|
|
661
697
|
// Back button
|
|
662
698
|
setTimeout(() => {
|
|
663
699
|
const backBtn = s('[data-id="btn-back"]');
|
|
@@ -1046,14 +1082,30 @@ const ObjectLayerEngineViewer = {
|
|
|
1046
1082
|
});
|
|
1047
1083
|
},
|
|
1048
1084
|
|
|
1049
|
-
|
|
1085
|
+
toEngine: function () {
|
|
1086
|
+
const { objectLayer } = this.Data;
|
|
1087
|
+
if (!objectLayer || !objectLayer._id) return;
|
|
1088
|
+
|
|
1089
|
+
// Navigate to editor route first
|
|
1090
|
+
setPath(`${getProxyPath()}object-layer-engine`);
|
|
1091
|
+
// Then add query param without replacing history
|
|
1092
|
+
setQueryParams({ cid: objectLayer._id }, { replace: true });
|
|
1093
|
+
|
|
1094
|
+
if (s(`.modal-object-layer-engine`)) {
|
|
1095
|
+
ObjectLayerEngineModal.Reload();
|
|
1096
|
+
} else {
|
|
1097
|
+
s(`.main-btn-object-layer-engine`)?.click();
|
|
1098
|
+
}
|
|
1099
|
+
},
|
|
1100
|
+
|
|
1101
|
+
Reload: async function ({ Elements }) {
|
|
1050
1102
|
const queryParams = new URLSearchParams(window.location.search);
|
|
1051
1103
|
const cid = queryParams.get('cid');
|
|
1052
1104
|
|
|
1053
1105
|
if (cid) {
|
|
1054
1106
|
await this.loadObjectLayer(cid);
|
|
1055
1107
|
} else {
|
|
1056
|
-
this.renderEmpty();
|
|
1108
|
+
this.renderEmpty({ Elements });
|
|
1057
1109
|
}
|
|
1058
1110
|
},
|
|
1059
1111
|
};
|
package/src/index.js
CHANGED
package/src/server/start.js
CHANGED
|
@@ -132,7 +132,8 @@ class UnderpostStartUp {
|
|
|
132
132
|
const buildBasePath = `/home/dd`;
|
|
133
133
|
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
134
134
|
shellExec(`cd ${buildBasePath} && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}`);
|
|
135
|
-
shellExec(`cd ${buildBasePath} && sudo
|
|
135
|
+
shellExec(`cd ${buildBasePath} && sudo cp -a ./${repoName}/* ./engine`);
|
|
136
|
+
shellExec(`cd ${buildBasePath} && sudo rm -rf ./${repoName}`);
|
|
136
137
|
shellExec(`cd ${buildBasePath}/engine && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}-private`);
|
|
137
138
|
shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
|
|
138
139
|
shellCd(`${buildBasePath}/engine`);
|