underpost 2.89.37 → 2.89.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +3 -2
  2. package/bin/deploy.js +22 -15
  3. package/cli.md +89 -61
  4. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  5. package/manifests/deployment/dd-test-development/deployment.yaml +6 -2
  6. package/manifests/deployment/dd-test-development/proxy.yaml +2 -0
  7. package/manifests/deployment/kafka/deployment.yaml +0 -2
  8. package/manifests/deployment/spark/spark-pi-py.yaml +0 -1
  9. package/manifests/deployment/tensorflow/tf-gpu-test.yaml +0 -2
  10. package/manifests/envoy-service-nodeport.yaml +0 -1
  11. package/manifests/kubeadm-calico-config.yaml +10 -115
  12. package/manifests/letsencrypt-prod.yaml +0 -1
  13. package/manifests/mariadb/statefulset.yaml +1 -1
  14. package/manifests/mongodb/statefulset.yaml +11 -11
  15. package/manifests/mongodb-4.4/service-deployment.yaml +1 -3
  16. package/manifests/mysql/pv-pvc.yaml +1 -1
  17. package/manifests/mysql/statefulset.yaml +1 -1
  18. package/manifests/valkey/service.yaml +0 -1
  19. package/manifests/valkey/statefulset.yaml +2 -3
  20. package/package.json +1 -1
  21. package/scripts/device-scan.sh +43 -21
  22. package/scripts/rpmfusion-ffmpeg-setup.sh +1 -0
  23. package/src/cli/cluster.js +58 -57
  24. package/src/cli/deploy.js +51 -89
  25. package/src/cli/index.js +30 -3
  26. package/src/cli/monitor.js +12 -6
  27. package/src/cli/repository.js +1 -1
  28. package/src/cli/run.js +32 -19
  29. package/src/client/components/core/Logger.js +1 -1
  30. package/src/client/components/core/Modal.js +5 -0
  31. package/src/client/components/core/ObjectLayerEngineModal.js +334 -71
  32. package/src/client/components/core/ObjectLayerEngineViewer.js +170 -403
  33. package/src/client/components/core/Router.js +10 -1
  34. package/src/client/services/default/default.management.js +25 -5
  35. package/src/index.js +1 -1
  36. package/src/server/client-build.js +5 -4
  37. package/src/server/conf.js +1 -1
  38. package/manifests/kubelet-config.yaml +0 -65
  39. package/manifests/mongodb/backup-access.yaml +0 -16
  40. package/manifests/mongodb/backup-cronjob.yaml +0 -42
  41. package/manifests/mongodb/backup-pv-pvc.yaml +0 -22
  42. package/manifests/mongodb/configmap.yaml +0 -26
package/src/cli/deploy.js CHANGED
@@ -129,10 +129,11 @@ class UnderpostDeploy {
129
129
  * @param {object} resources - Resource configuration for the deployment.
130
130
  * @param {number} replicas - Number of replicas for the deployment.
131
131
  * @param {string} image - Docker image for the deployment.
132
+ * @param {string} namespace - Kubernetes namespace for the deployment.
132
133
  * @returns {string} - YAML deployment configuration for the specified deployment.
133
134
  * @memberof UnderpostDeploy
134
135
  */
135
- deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image }) {
136
+ deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image, namespace }) {
136
137
  const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
137
138
  let volumes = [
138
139
  {
@@ -149,6 +150,7 @@ class UnderpostDeploy {
149
150
  kind: Deployment
150
151
  metadata:
151
152
  name: ${deployId}-${env}-${suffix}
153
+ namespace: ${namespace ? namespace : 'default'}
152
154
  labels:
153
155
  app: ${deployId}-${env}-${suffix}
154
156
  spec:
@@ -188,6 +190,7 @@ apiVersion: v1
188
190
  kind: Service
189
191
  metadata:
190
192
  name: ${deployId}-${env}-${suffix}-service
193
+ namespace: ${namespace}
191
194
  spec:
192
195
  selector:
193
196
  app: ${deployId}-${env}-${suffix}
@@ -201,6 +204,7 @@ spec:
201
204
  * @param {object} options - Options for the manifest build process.
202
205
  * @param {string} options.replicas - Number of replicas for each deployment.
203
206
  * @param {string} options.image - Docker image for the deployment.
207
+ * @param {string} options.namespace - Kubernetes namespace for the deployment.
204
208
  * @returns {Promise<void>} - Promise that resolves when the manifest is built.
205
209
  * @memberof UnderpostDeploy
206
210
  */
@@ -208,6 +212,7 @@ spec:
208
212
  const resources = UnderpostDeploy.API.resourcesFactory();
209
213
  const replicas = options.replicas;
210
214
  const image = options.image;
215
+ if (!options.namespace) options.namespace = 'default';
211
216
 
212
217
  for (const _deployId of deployList.split(',')) {
213
218
  const deployId = _deployId.trim();
@@ -235,6 +240,7 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
235
240
  resources,
236
241
  replicas,
237
242
  image,
243
+ namespace: options.namespace,
238
244
  }).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
239
245
  `;
240
246
  }
@@ -257,6 +263,7 @@ apiVersion: projectcontour.io/v1
257
263
  kind: HTTPProxy
258
264
  metadata:
259
265
  name: ${host}
266
+ namespace: ${options.namespace}
260
267
  spec:
261
268
  virtualhost:
262
269
  fqdn: ${host}${
@@ -316,16 +323,18 @@ spec:
316
323
  /**
317
324
  * Builds a Certificate resource for a host using cert-manager.
318
325
  * @param {string} host - Hostname for which the certificate is being built.
326
+ * @param {string} namespace - Kubernetes namespace for the certificate.
319
327
  * @returns {string} - Certificate resource YAML for the specified host.
320
328
  * @memberof UnderpostDeploy
321
329
  */
322
- buildCertManagerCertificate({ host }) {
330
+ buildCertManagerCertificate({ host, namespace }) {
323
331
  return `
324
332
  ---
325
333
  apiVersion: cert-manager.io/v1
326
334
  kind: Certificate
327
335
  metadata:
328
336
  name: ${host}
337
+ namespace: ${namespace}
329
338
  spec:
330
339
  commonName: ${host}
331
340
  dnsNames:
@@ -376,6 +385,7 @@ spec:
376
385
  * @param {boolean} options.status - Whether to display deployment status.
377
386
  * @param {boolean} options.etcHosts - Whether to display the /etc/hosts file.
378
387
  * @param {boolean} options.disableUpdateUnderpostConfig - Whether to disable Underpost config updates.
388
+ * @param {string} [options.namespace] - Kubernetes namespace for the deployment.
379
389
  * @returns {Promise<void>} - Promise that resolves when the deployment process is complete.
380
390
  * @memberof UnderpostDeploy
381
391
  */
@@ -404,74 +414,14 @@ spec:
404
414
  status: false,
405
415
  etcHosts: false,
406
416
  disableUpdateUnderpostConfig: false,
417
+ namespace: '',
407
418
  },
408
419
  ) {
409
- if (options.infoUtil === true)
410
- return logger.info(`
411
- kubectl rollout restart deployment/deployment-name
412
- kubectl rollout undo deployment/deployment-name
413
- kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
414
- kubectl get pods -w
415
- kubectl patch statefulset valkey-service --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"valkey/valkey:latest"}]'
416
- kubectl patch statefulset valkey-service -p '{"spec":{"template":{"spec":{"containers":[{"name":"valkey-service","imagePullPolicy":"Never"}]}}}}'
417
- kubectl logs -f <pod-name>
418
- kubectl describe pod <pod-name>
419
- kubectl exec -it <pod-name> -- bash
420
- kubectl exec -it <pod-name> -- sh
421
- docker exec -it kind-control-plane bash
422
- curl -4 -v google.com
423
- kubectl taint nodes <node-name> node-role.kubernetes.io/control-plane:NoSchedule-
424
- kubectl run test-pod --image=busybox:latest --restart=Never -- /bin/sh -c "while true; do sleep 30; done;"
425
- kubectl run test-pod --image=alpine/curl:latest --restart=Never -- sh -c "sleep infinity"
426
- kubectl get ippools -o yaml
427
- kubectl get node <node-name> -o jsonpath='{.spec.podCIDR}'
428
- kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "10.244.0.0/16"}]'
429
- kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "192.168.0.0/24"}]'
430
- sudo podman run --rm localhost/<image-name>:<image-version> <command>
431
- kubectl get configmap kubelet-config -n kube-system -o yaml > kubelet-config.yaml
432
- kubectl -n kube-system rollout restart daemonset kube-proxy
433
- kubectl get EndpointSlice -o wide --all-namespaces -w
434
- kubectl apply -k manifests/deployment/adminer/.
435
- kubectl wait --for=condition=Ready pod/busybox1
436
- kubectl wait --for=jsonpath='{.status.phase}'=Running pod/busybox1
437
- kubectl wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' pod/busybox1
438
- kubectl wait --for=delete pod/busybox1 --timeout=60s
439
-
440
- fqdn: <service>.<namespace>.<kind(svc/pod)>.<cluster-domain(cluster.local)>
441
- node bin run cluster-build
442
- node bin run template-deploy
443
- node bin run ssh-deploy (sync-)engine-core
444
- node bin run cluster --dev 'express,dd-test+dd-core'
445
- node bin run dd-container --dev
446
- node bin run promote dd-default production
447
- node bin dockerfile-pull-base-images --dev --path 'image-path' --kind-load
448
- node bin/deploy update-default-conf <deploy-id>
449
-
450
- kubectl run --rm -it test-dns --image=busybox:latest --restart=Never -- /bin/sh -c "
451
- nslookup kubernetes.default.svc.cluster.local;
452
- nslookup mongodb-service.default.svc.cluster.local;
453
- nslookup valkey-service.default.svc.cluster.local;
454
- nc -vz mongodb-service 27017;
455
- nc -vz valkey-service 6379;
456
- echo exit code: \\\$?
457
- "
458
-
459
- kubectl apply -f - <<EOF
460
- apiVersion: apps/v1
461
- kind: StatefulSet
462
- metadata:
463
- name: ...
464
- EOF
465
-
466
- https://org.ngc.nvidia.com/setup/api-keys
467
- docker login nvcr.io
468
- Username: $oauthtoken
469
- Password: <Your Key>
470
- `);
420
+ const namespace = options.namespace ? options.namespace : 'default';
471
421
  if (!deployList && options.certHosts) {
472
422
  for (const host of options.certHosts.split(',')) {
473
- shellExec(`sudo kubectl apply -f - <<EOF
474
- ${UnderpostDeploy.API.buildCertManagerCertificate({ host })}
423
+ shellExec(`sudo kubectl apply -f - -n ${namespace} <<EOF
424
+ ${UnderpostDeploy.API.buildCertManagerCertificate({ host, namespace })}
475
425
  EOF`);
476
426
  }
477
427
  return;
@@ -540,8 +490,12 @@ EOF`);
540
490
 
541
491
  if (!options.disableUpdateDeployment)
542
492
  for (const version of options.versions.split(',')) {
543
- shellExec(`sudo kubectl delete svc ${deployId}-${env}-${version}-service`);
544
- shellExec(`sudo kubectl delete deployment ${deployId}-${env}-${version}`);
493
+ shellExec(
494
+ `sudo kubectl delete svc ${deployId}-${env}-${version}-service -n ${namespace} --ignore-not-found`,
495
+ );
496
+ shellExec(
497
+ `sudo kubectl delete deployment ${deployId}-${env}-${version} -n ${namespace} --ignore-not-found`,
498
+ );
545
499
  if (!options.disableUpdateVolume) {
546
500
  for (const volume of confVolume) {
547
501
  const pvcId = `${volume.claimName}-${deployId}-${env}-${version}`;
@@ -549,9 +503,9 @@ EOF`);
549
503
  const rootVolumeHostPath = `/home/dd/engine/volume/${pvId}`;
550
504
  if (!fs.existsSync(rootVolumeHostPath)) fs.mkdirSync(rootVolumeHostPath, { recursive: true });
551
505
  fs.copySync(volume.volumeMountPath, rootVolumeHostPath);
552
- shellExec(`kubectl delete pvc ${pvcId}`);
553
- shellExec(`kubectl delete pv ${pvId}`);
554
- shellExec(`kubectl apply -f - <<EOF
506
+ shellExec(`kubectl delete pvc ${pvcId} -n ${namespace} --ignore-not-found`);
507
+ shellExec(`kubectl delete pv ${pvId} --ignore-not-found`);
508
+ shellExec(`kubectl apply -f - -n ${namespace} <<EOF
555
509
  ${UnderpostDeploy.API.persistentVolumeFactory({
556
510
  hostPath: rootVolumeHostPath,
557
511
  pvcId,
@@ -564,9 +518,9 @@ EOF
564
518
 
565
519
  for (const host of Object.keys(confServer)) {
566
520
  if (!options.disableUpdateProxy) {
567
- shellExec(`sudo kubectl delete HTTPProxy ${host}`);
521
+ shellExec(`sudo kubectl delete HTTPProxy ${host} -n ${namespace} --ignore-not-found`);
568
522
  if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
569
- shellExec(`sudo kubectl delete Certificate ${host}`);
523
+ shellExec(`sudo kubectl delete Certificate ${host} -n ${namespace} --ignore-not-found`);
570
524
  }
571
525
  if (!options.remove) etcHosts.push(host);
572
526
  }
@@ -577,11 +531,13 @@ EOF
577
531
  : `manifests/deployment/${deployId}-${env}`;
578
532
 
579
533
  if (!options.remove) {
580
- if (!options.disableUpdateDeployment) shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
581
- if (!options.disableUpdateProxy) shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
534
+ if (!options.disableUpdateDeployment)
535
+ shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml -n ${namespace}`);
536
+ if (!options.disableUpdateProxy)
537
+ shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml -n ${namespace}`);
582
538
 
583
539
  if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
584
- shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
540
+ shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml -n ${namespace}`);
585
541
  }
586
542
  }
587
543
  if (options.etcHosts === true) {
@@ -598,15 +554,19 @@ EOF
598
554
  * Retrieves information about a deployment.
599
555
  * @param {string} deployId - Deployment ID for which information is being retrieved.
600
556
  * @param {string} kindType - Type of Kubernetes resource to retrieve information for (e.g. 'pods').
557
+ * @param {string} namespace - Kubernetes namespace to retrieve information from.
601
558
  * @returns {Array<object>} - Array of objects containing information about the deployment.
602
559
  * @memberof UnderpostDeploy
603
560
  */
604
- get(deployId, kindType = 'pods') {
605
- const raw = shellExec(`sudo kubectl get ${kindType} --all-namespaces -o wide`, {
606
- stdout: true,
607
- disableLog: true,
608
- silent: true,
609
- });
561
+ get(deployId, kindType = 'pods', namespace = '') {
562
+ const raw = shellExec(
563
+ `sudo kubectl get ${kindType}${namespace ? ` -n ${namespace}` : ` --all-namespaces`} -o wide`,
564
+ {
565
+ stdout: true,
566
+ disableLog: true,
567
+ silent: true,
568
+ },
569
+ );
610
570
 
611
571
  const heads = raw
612
572
  .split(`\n`)[0]
@@ -720,12 +680,13 @@ EOF
720
680
  /**
721
681
  * Creates a configmap for a deployment.
722
682
  * @param {string} env - Environment for which the configmap is being created.
683
+ * @param {string} [namespace='default'] - Kubernetes namespace for the configmap.
723
684
  * @memberof UnderpostDeploy
724
685
  */
725
- configMap(env) {
726
- shellExec(`kubectl delete configmap underpost-config`);
686
+ configMap(env, namespace = 'default') {
687
+ shellExec(`kubectl delete configmap underpost-config -n ${namespace} --ignore-not-found`);
727
688
  shellExec(
728
- `kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
689
+ `kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env} --dry-run=client -o yaml | kubectl apply -f - -n ${namespace}`,
729
690
  );
730
691
  },
731
692
  /**
@@ -734,14 +695,15 @@ EOF
734
695
  * @param {string} env - Environment for which the traffic is being switched.
735
696
  * @param {string} targetTraffic - Target traffic status for the deployment.
736
697
  * @param {number} replicas - Number of replicas for the deployment.
698
+ * @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
737
699
  * @memberof UnderpostDeploy
738
700
  */
739
- switchTraffic(deployId, env, targetTraffic, replicas = 1) {
701
+ switchTraffic(deployId, env, targetTraffic, replicas = 1, namespace = 'default') {
740
702
  UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
741
703
  shellExec(
742
- `node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} ${deployId} ${env}`,
704
+ `node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} --namespace ${namespace} ${deployId} ${env}`,
743
705
  );
744
- shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
706
+ shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml -n ${namespace}`);
745
707
  },
746
708
 
747
709
  /**
@@ -909,7 +871,7 @@ ${renderHosts}`,
909
871
  getCurrentLoadedImages(node = 'kind-worker', specContainers = false) {
910
872
  if (specContainers) {
911
873
  const raw = shellExec(
912
- `kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
874
+ `kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.namespace}{"/"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
913
875
  {
914
876
  stdout: true,
915
877
  silent: true,
package/src/cli/index.js CHANGED
@@ -7,6 +7,8 @@ import { commitData } from '../client/components/core/CommonJs.js';
7
7
  import UnderpostLxd from './lxd.js';
8
8
  import UnderpostBaremetal from './baremetal.js';
9
9
  import UnderpostRun from './run.js';
10
+ import Dns from '../server/dns.js';
11
+ import { pbcopy } from '../server/process.js';
10
12
 
11
13
  // Load environment variables from .env file
12
14
  const underpostRootPath = getUnderpostRootPath();
@@ -129,6 +131,16 @@ program
129
131
  .description('Displays the root path of the npm installation.')
130
132
  .action(() => console.log(getNpmRootPath()));
131
133
 
134
+ program
135
+ .command('ip')
136
+ .option('--copy', 'Copies the IP addresses to the clipboard.')
137
+ .description('Displays the current public machine IP addresses.')
138
+ .action(async (options) => {
139
+ const ip = await Dns.getPublicIp();
140
+ if (options.copy) return pbcopy(ip);
141
+ return console.log(ip);
142
+ });
143
+
132
144
  // 'cluster' command: Manage Kubernetes clusters
133
145
  program
134
146
  .command('cluster')
@@ -144,10 +156,20 @@ program
144
156
  .option('--contour', 'Initializes the cluster with Project Contour base HTTPProxy and Envoy.')
145
157
  .option('--cert-manager', "Initializes the cluster with a Let's Encrypt production ClusterIssuer.")
146
158
  .option('--dedicated-gpu', 'Initializes the cluster with dedicated GPU base resources and environment settings.')
147
- .option('--info', 'Retrieves information about all deployed Kubernetes objects.')
148
159
  .option('--full', 'Initializes the cluster with all available statefulsets and services.')
149
- .option('--ns-use <ns-name>', 'Switches the current Kubernetes context to the specified namespace.')
160
+ .option(
161
+ '--ns-use <ns-name>',
162
+ "Switches the current Kubernetes context to the specified namespace (creates if it doesn't exist).",
163
+ )
150
164
  .option('--kubeadm', 'Initializes the cluster using kubeadm for control plane management.')
165
+ .option(
166
+ '--pod-network-cidr <cidr>',
167
+ 'Sets custom pod network CIDR for kubeadm cluster initialization (defaults to "192.168.0.0/16").',
168
+ )
169
+ .option(
170
+ '--control-plane-endpoint <endpoint>',
171
+ 'Sets custom control plane endpoint for kubeadm cluster initialization (defaults to "localhost:6443").',
172
+ )
151
173
  .option('--grafana', 'Initializes the cluster with a Grafana deployment.')
152
174
  .option(
153
175
  '--prom [hosts]',
@@ -166,6 +188,7 @@ program
166
188
  .option('--k3s', 'Initializes the cluster using K3s (Lightweight Kubernetes).')
167
189
  .option('--hosts <hosts>', 'A comma-separated list of cluster hostnames or IP addresses.')
168
190
  .option('--remove-volume-host-paths', 'Removes specified volume host paths after execution.')
191
+ .option('--namespace <namespace>', 'Kubernetes namespace for cluster operations (defaults to "default").')
169
192
  .action(Underpost.cluster.init)
170
193
  .description('Manages Kubernetes clusters, defaulting to Kind cluster initialization.');
171
194
 
@@ -181,7 +204,6 @@ program
181
204
  .option('--sync', 'Synchronizes deployment environment variables, ports, and replica counts.')
182
205
  .option('--info-router', 'Displays the current router structure and configuration.')
183
206
  .option('--expose', 'Exposes services matching the provided deployment ID list.')
184
- .option('--info-util', 'Displays useful `kubectl` utility management commands.')
185
207
  .option('--cert', 'Resets TLS/SSL certificate secrets for deployments.')
186
208
  .option('--cert-hosts <hosts>', 'Resets TLS/SSL certificate secrets for specified hosts.')
187
209
  .option('--node <node>', 'Sets optional node for deployment operations.')
@@ -205,6 +227,7 @@ program
205
227
  .option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
206
228
  .option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
207
229
  .option('--disable-update-underpost-config', 'Disables updates to Underpost configuration during deployment.')
230
+ .option('--namespace <namespace>', 'Kubernetes namespace for deployment operations (defaults to "default").')
208
231
  .description('Manages application deployments, defaulting to deploying development pods.')
209
232
  .action(Underpost.deploy.callback);
210
233
 
@@ -402,6 +425,10 @@ program
402
425
  .option('--runtime-class-name <name>', 'Sets the runtime class name for the job in deploy-job.')
403
426
  .option('--image-pull-policy <policy>', 'Sets the image pull policy for the job in deploy-job.')
404
427
  .option('--api-version <version>', 'Sets the API version for the job manifest in deploy-job.')
428
+ .option(
429
+ '--labels <labels>',
430
+ 'Optional: Specifies a comma-separated list of key-value pairs for labels (e.g., "app=my-app,env=prod").',
431
+ )
405
432
  .option('--claim-name <name>', 'Optional: Specifies the claim name for volume mounting in deploy-job.')
406
433
  .option('--kind <kind-type>', 'Specifies the kind of Kubernetes resource (e.g., Job, Deployment) for deploy-job.')
407
434
  .option('--kubeadm', 'Flag to indicate Kubeadm cluster type context')
@@ -39,6 +39,7 @@ class UnderpostMonitor {
39
39
  * @param {string} [options.type=''] - Type of deployment (e.g., 'blue-green', 'remote').
40
40
  * @param {string} [options.replicas=''] - Number of replicas for the deployment.
41
41
  * @param {boolean} [options.sync=false] - Synchronize traffic switching with the deployment.
42
+ * @param {string} [options.namespace=''] - Kubernetes namespace for the deployment.
42
43
  * @param {object} [commanderOptions] - Options passed from the command line interface.
43
44
  * @param {object} [auxRouter] - Optional router configuration for the deployment.
44
45
  * @memberof UnderpostMonitor
@@ -46,10 +47,11 @@ class UnderpostMonitor {
46
47
  async callback(
47
48
  deployId,
48
49
  env = 'development',
49
- options = { now: false, single: false, msInterval: '', type: '', replicas: '', sync: false },
50
+ options = { now: false, single: false, msInterval: '', type: '', replicas: '', sync: false, namespace: '' },
50
51
  commanderOptions,
51
52
  auxRouter,
52
53
  ) {
54
+ if (!options.namespace) options.namespace = 'default';
53
55
  if (deployId === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`)) {
54
56
  for (const _deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(','))
55
57
  UnderpostMonitor.API.callback(
@@ -95,12 +97,13 @@ class UnderpostMonitor {
95
97
  if (traffic === 'blue') traffic = 'green';
96
98
  else traffic = 'blue';
97
99
  UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, traffic);
100
+ const namespace = options.namespace || 'default';
98
101
  shellExec(
99
102
  `node bin deploy --info-router --build-manifest --traffic ${traffic} --replicas ${
100
103
  options.replicas ? options.replicas : 1
101
- } ${deployId} ${env}`,
104
+ } --namespace ${namespace} ${deployId} ${env}`,
102
105
  );
103
- shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
106
+ shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml -n ${namespace}`);
104
107
  };
105
108
 
106
109
  const monitor = async (reject) => {
@@ -152,12 +155,15 @@ class UnderpostMonitor {
152
155
  fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
153
156
  );
154
157
 
155
- UnderpostDeploy.API.configMap(env);
158
+ const namespace = options.namespace || 'default';
159
+ UnderpostDeploy.API.configMap(env, namespace);
156
160
 
157
161
  for (const host of Object.keys(confServer)) {
158
- shellExec(`sudo kubectl delete HTTPProxy ${host}`);
162
+ shellExec(`sudo kubectl delete HTTPProxy ${host} -n ${namespace} --ignore-not-found`);
159
163
  }
160
- shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${traffic}`);
164
+ shellExec(
165
+ `sudo kubectl rollout restart deployment/${deployId}-${env}-${traffic} -n ${namespace}`,
166
+ );
161
167
 
162
168
  switchTraffic();
163
169
  }
@@ -179,7 +179,7 @@ class UnderpostRepository {
179
179
  return;
180
180
  }
181
181
  if (options.info) return logger.info('', commitData);
182
- const _message = `${commitType}${subModule ? `(${subModule})` : ''}${process.argv.includes('!') ? '!' : ''}: ${
182
+ const _message = `${commitType}${subModule ? `(${subModule})` : ''}: ${
183
183
  commitData[commitType].emoji
184
184
  } ${message ? message : commitData[commitType].description}`;
185
185
  if (options.copy) return pbcopy(_message);
package/src/cli/run.js CHANGED
@@ -81,7 +81,7 @@ class UnderpostRun {
81
81
  volumeMountPath: '',
82
82
  imageName: '',
83
83
  containerName: '',
84
- namespace: '',
84
+ namespace: 'default',
85
85
  build: false,
86
86
  replicas: 1,
87
87
  k3s: false,
@@ -209,10 +209,10 @@ class UnderpostRun {
209
209
  * @memberof UnderpostRun
210
210
  */
211
211
  'tf-gpu-test': (path, options = UnderpostRun.DEFAULT_OPTION) => {
212
- const { underpostRoot } = options;
213
- shellExec(`kubectl delete configmap tf-gpu-test-script`);
214
- shellExec(`kubectl delete pod tf-gpu-test-pod`);
215
- shellExec(`kubectl apply -f ${underpostRoot}/manifests/deployment/tensorflow/tf-gpu-test.yaml`);
212
+ const { underpostRoot, namespace } = options;
213
+ shellExec(`kubectl delete configmap tf-gpu-test-script -n ${namespace} --ignore-not-found`);
214
+ shellExec(`kubectl delete pod tf-gpu-test-pod -n ${namespace} --ignore-not-found`);
215
+ shellExec(`kubectl apply -f ${underpostRoot}/manifests/deployment/tensorflow/tf-gpu-test.yaml -n ${namespace}`);
216
216
  },
217
217
  /**
218
218
  * @method dev-cluster
@@ -493,7 +493,7 @@ class UnderpostRun {
493
493
  versions = versions ? versions.replaceAll('+', ',') : defaultPath[2];
494
494
  image = image ? image : defaultPath[3];
495
495
  node = node ? node : defaultPath[4];
496
-
496
+ shellExec(`${baseCommand} cluster --ns-use ${options.namespace}`);
497
497
  if (isDeployRunnerContext(path, options)) {
498
498
  const { validVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
499
499
  if (!validVersion) throw new Error('Version mismatch');
@@ -510,11 +510,13 @@ class UnderpostRun {
510
510
  shellExec(
511
511
  `${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
512
512
  replicas ? replicas : 1
513
- } --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
513
+ } --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''}${options.namespace ? ` --namespace ${options.namespace}` : ''} dd ${env}`,
514
514
  );
515
515
 
516
516
  if (isDeployRunnerContext(path, options)) {
517
- shellExec(`${baseCommand} deploy --kubeadm --disable-update-proxy ${deployId} ${env} --versions ${versions}`);
517
+ shellExec(
518
+ `${baseCommand} deploy --kubeadm --disable-update-proxy ${deployId} ${env} --versions ${versions}${options.namespace ? ` --namespace ${options.namespace}` : ''}`,
519
+ );
518
520
  if (!targetTraffic) targetTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
519
521
  await UnderpostDeploy.API.monitorReadyRunner(deployId, env, targetTraffic);
520
522
  UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
@@ -619,7 +621,7 @@ class UnderpostRun {
619
621
  `docker exec -i kind-worker bash -c "chown -R 1000:1000 ${volumeHostPath} || true; chmod -R 755 ${volumeHostPath}"`,
620
622
  );
621
623
  } else {
622
- shellExec(`kubectl apply -f ${options.underpostRoot}/manifests/pv-pvc-dd.yaml`);
624
+ shellExec(`kubectl apply -f ${options.underpostRoot}/manifests/pv-pvc-dd.yaml -n ${options.namespace}`);
623
625
  }
624
626
 
625
627
  if (!currentImage)
@@ -682,7 +684,7 @@ class UnderpostRun {
682
684
  switch (path) {
683
685
  case 'tf-vae-test':
684
686
  {
685
- const nameSpace = 'default';
687
+ const nameSpace = options.namespace || 'default';
686
688
  const podName = path;
687
689
  const basePath = '/home/dd';
688
690
  const scriptPath = '/site/en/tutorials/generative/cvae.py';
@@ -764,8 +766,8 @@ class UnderpostRun {
764
766
  // For kubeadm/k3s, ensure it's available for containerd
765
767
  shellExec(`sudo crictl pull ${image}`);
766
768
 
767
- shellExec(`kubectl delete deployment adminer`);
768
- shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/.`);
769
+ shellExec(`kubectl delete deployment adminer -n ${options.namespace} --ignore-not-found`);
770
+ shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/. -n ${options.namespace}`);
769
771
  const successInstance = await UnderpostTest.API.statusMonitor('adminer', 'Running', 'pods', 1000, 60 * 10);
770
772
 
771
773
  if (successInstance) {
@@ -922,7 +924,7 @@ class UnderpostRun {
922
924
  const env = 'production';
923
925
  const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
924
926
 
925
- shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
927
+ shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic} -n ${options.namespace}`);
926
928
 
927
929
  await UnderpostDeploy.API.monitorReadyRunner(deployId, env, targetTraffic, ignorePods);
928
930
 
@@ -1043,9 +1045,9 @@ class UnderpostRun {
1043
1045
  );
1044
1046
  switch (serviceId) {
1045
1047
  case 'mongo-express-service': {
1046
- shellExec(`kubectl delete svc mongo-express-service --ignore-not-found`);
1047
- shellExec(`kubectl delete deployment mongo-express --ignore-not-found`);
1048
- shellExec(`kubectl apply -f manifests/deployment/mongo-express/deployment.yaml`);
1048
+ shellExec(`kubectl delete svc mongo-express-service -n ${options.namespace} --ignore-not-found`);
1049
+ shellExec(`kubectl delete deployment mongo-express -n ${options.namespace} --ignore-not-found`);
1050
+ shellExec(`kubectl apply -f manifests/deployment/mongo-express/deployment.yaml -n ${options.namespace}`);
1049
1051
  podToMonitor = 'mongo-express';
1050
1052
  break;
1051
1053
  }
@@ -1225,6 +1227,16 @@ class UnderpostRun {
1225
1227
  const imagePullPolicy = options.imagePullPolicy || 'IfNotPresent';
1226
1228
  const hostNetwork = options.hostNetwork ? options.hostNetwork : '';
1227
1229
  const apiVersion = options.apiVersion || 'v1';
1230
+ const labels = options.labels
1231
+ ? options.labels
1232
+ .split(',')
1233
+ .map((keyValue) => {
1234
+ const [key, value] = keyValue.split('=');
1235
+ return ` ${key}: ${value}
1236
+ `;
1237
+ })
1238
+ .join('')
1239
+ : ` app: ${podName}`;
1228
1240
  if (options.volumeType === 'dev') options.volumeType = 'FileOrCreate';
1229
1241
  const volumeType =
1230
1242
  options.volumeType || (enableVolumeMount && volumeHostPath && fs.statSync(volumeHostPath).isDirectory())
@@ -1240,7 +1252,7 @@ metadata:
1240
1252
  name: ${podName}
1241
1253
  namespace: ${namespace}
1242
1254
  labels:
1243
- app: ${podName}
1255
+ ${labels}
1244
1256
  spec:
1245
1257
  restartPolicy: ${restartPolicy}
1246
1258
  ${runtimeClassName ? ` runtimeClassName: ${runtimeClassName}` : ''}
@@ -1278,13 +1290,13 @@ ${
1278
1290
  : ''
1279
1291
  }
1280
1292
  EOF`;
1281
- shellExec(`kubectl delete pod ${podName} --ignore-not-found`);
1293
+ shellExec(`kubectl delete pod ${podName} -n ${namespace} --ignore-not-found`);
1282
1294
  console.log(cmd);
1283
1295
  shellExec(cmd, { disableLog: true });
1284
1296
  const successInstance = await UnderpostTest.API.statusMonitor(podName);
1285
1297
  if (successInstance) {
1286
1298
  options.on?.init ? await options.on.init() : null;
1287
- shellExec(`kubectl logs -f ${podName}`);
1299
+ shellExec(`kubectl logs -f ${podName} -n ${namespace}`);
1288
1300
  }
1289
1301
  },
1290
1302
  };
@@ -1306,6 +1318,7 @@ EOF`;
1306
1318
  if (options.command) options.command = options.command.split(',');
1307
1319
  if (options.args) options.args = options.args.split(',');
1308
1320
  if (!options.underpostRoot) options.underpostRoot = underpostRoot;
1321
+ if (!options.namespace) options.namespace = 'default';
1309
1322
  options.npmRoot = npmRoot;
1310
1323
  logger.info('callback', { path, options });
1311
1324
  if (!(runner in UnderpostRun.RUNNERS)) throw new Error(`Runner not found: ${runner}`);
@@ -6,7 +6,7 @@ const loggerFactory = (meta, options = { trace: false }) => {
6
6
  const logger = {
7
7
  log: function (type, args) {
8
8
  if (!window.renderPayload.dev) return;
9
- if (options.trace === true) args.push(getCurrentTrace().split('Logger.js:23')[1]);
9
+ if (options.trace === true) args.push(getCurrentTrace().split('Logger.js')[1]);
10
10
  return console[type](`[${meta}] ${new Date().toISOString()} ${type}:`, ...args);
11
11
  },
12
12
  };
@@ -87,6 +87,7 @@ const Modal = {
87
87
  onExpandUiListener: {},
88
88
  onBarUiOpen: {},
89
89
  onBarUiClose: {},
90
+ onReloadModalListener: {},
90
91
  onHome: {},
91
92
  homeModals: options.homeModals ? options.homeModals : [],
92
93
  query: options.query ? `${window.location.search}` : undefined,
@@ -121,6 +122,7 @@ const Modal = {
121
122
  top = `${windowGetH() / 2 - height / 2}px`;
122
123
  left = `${windowGetW() / 2 - width / 2}px`;
123
124
  },
125
+ ...this.Data[idModal],
124
126
  };
125
127
 
126
128
  if (options && 'mode' in options) {
@@ -1387,6 +1389,9 @@ const Modal = {
1387
1389
  if (options.zIndexSync) this.zIndexSync({ idModal });
1388
1390
 
1389
1391
  if (s(`.${idModal}`)) {
1392
+ for (const event of Object.keys(Modal.Data[idModal].onReloadModalListener))
1393
+ await Modal.Data[idModal].onReloadModalListener[event]();
1394
+
1390
1395
  s(`.btn-maximize-${idModal}`).click();
1391
1396
  return;
1392
1397
  }