underpost 2.89.35 → 2.89.44
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/README.md +4 -2
- package/bin/deploy.js +22 -15
- package/cli.md +23 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +10 -6
- package/manifests/deployment/dd-test-development/proxy.yaml +2 -0
- package/manifests/deployment/kafka/deployment.yaml +0 -2
- package/manifests/deployment/spark/spark-pi-py.yaml +0 -1
- package/manifests/deployment/tensorflow/tf-gpu-test.yaml +0 -2
- package/manifests/envoy-service-nodeport.yaml +0 -1
- package/manifests/kubeadm-calico-config.yaml +10 -115
- package/manifests/letsencrypt-prod.yaml +0 -1
- package/manifests/mariadb/statefulset.yaml +1 -1
- package/manifests/mongodb/statefulset.yaml +11 -11
- package/manifests/mongodb-4.4/service-deployment.yaml +1 -3
- package/manifests/mysql/pv-pvc.yaml +1 -1
- package/manifests/mysql/statefulset.yaml +1 -1
- package/manifests/valkey/service.yaml +0 -1
- package/manifests/valkey/statefulset.yaml +2 -3
- package/package.json +1 -1
- package/scripts/device-scan.sh +43 -21
- package/scripts/rpmfusion-ffmpeg-setup.sh +1 -0
- package/src/api/user/user.model.js +10 -1
- package/src/cli/cluster.js +51 -26
- package/src/cli/deploy.js +73 -39
- package/src/cli/index.js +22 -1
- package/src/cli/monitor.js +9 -5
- package/src/cli/repository.js +1 -1
- package/src/cli/run.js +38 -21
- package/src/client/components/core/Logger.js +1 -1
- package/src/client/components/core/Modal.js +5 -0
- package/src/client/components/core/ObjectLayerEngineModal.js +334 -71
- package/src/client/components/core/ObjectLayerEngineViewer.js +170 -403
- package/src/client/components/core/Router.js +10 -1
- package/src/client/services/default/default.management.js +25 -5
- package/src/index.js +1 -1
- package/src/server/client-build.js +5 -4
- package/src/server/conf.js +1 -1
- package/src/server/start.js +1 -1
- package/manifests/kubelet-config.yaml +0 -65
- package/manifests/mongodb/backup-access.yaml +0 -16
- package/manifests/mongodb/backup-cronjob.yaml +0 -42
- package/manifests/mongodb/backup-pv-pvc.yaml +0 -22
- package/manifests/mongodb/configmap.yaml +0 -26
package/scripts/device-scan.sh
CHANGED
|
@@ -1,26 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
set -u -o pipefail
|
|
2
3
|
|
|
3
4
|
for iface_path in /sys/class/net/*; do
|
|
5
|
+
[ -e "$iface_path" ] || continue
|
|
4
6
|
name=$(basename "$iface_path")
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
|
|
8
|
+
# MAC address
|
|
9
|
+
if [ -r "$iface_path/address" ]; then
|
|
10
|
+
mac=$(< "$iface_path/address")
|
|
11
|
+
else
|
|
12
|
+
mac="—"
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
# IPv4: collect all IPv4 CIDRs, strip masks, join with commas (or show —)
|
|
16
|
+
ip_info=$(ip -4 -o addr show dev "$name" 2>/dev/null | awk '{print $4}')
|
|
17
|
+
if [ -n "$ip_info" ]; then
|
|
18
|
+
# Use word-splitting intentionally to iterate lines from ip_info
|
|
19
|
+
ip=$(printf "%s\n" $ip_info | awk -F/ '{print $1}' | paste -sd, -)
|
|
20
|
+
else
|
|
21
|
+
ip="—"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# operstate and mtu
|
|
25
|
+
operstate=$(< "$iface_path/operstate" 2>/dev/null || echo "—")
|
|
26
|
+
mtu=$(< "$iface_path/mtu" 2>/dev/null || echo "—")
|
|
27
|
+
|
|
28
|
+
# Driver (if available)
|
|
29
|
+
if [ -e "$iface_path/device/driver" ]; then
|
|
13
30
|
driver=$(basename "$(readlink -f "$iface_path/device/driver")")
|
|
14
31
|
else
|
|
15
32
|
driver="—"
|
|
16
33
|
fi
|
|
17
34
|
|
|
18
|
-
#
|
|
35
|
+
# PCI vendor:device (if available)
|
|
19
36
|
pci_dev="$iface_path/device"
|
|
20
|
-
if [ -
|
|
37
|
+
if [ -r "$pci_dev/vendor" ] && [ -r "$pci_dev/device" ]; then
|
|
21
38
|
vendor_id=$(< "$pci_dev/vendor")
|
|
22
39
|
device_id=$(< "$pci_dev/device")
|
|
23
|
-
# parse 0x8086 to 8086, etc.
|
|
24
40
|
vendor_id=${vendor_id#0x}
|
|
25
41
|
device_id=${device_id#0x}
|
|
26
42
|
pci="${vendor_id}:${device_id}"
|
|
@@ -28,16 +44,22 @@ for iface_path in /sys/class/net/*; do
|
|
|
28
44
|
pci="—"
|
|
29
45
|
fi
|
|
30
46
|
|
|
31
|
-
# Link
|
|
47
|
+
# Link speed: only append unit if numeric
|
|
32
48
|
speed=$(cat "$iface_path/speed" 2>/dev/null || echo "—")
|
|
49
|
+
if [[ "$speed" =~ ^[0-9]+$ ]]; then
|
|
50
|
+
speed_label="${speed} Mb/s"
|
|
51
|
+
else
|
|
52
|
+
speed_label="$speed"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Print formatted output
|
|
56
|
+
printf 'Interface: %s\n' "$name"
|
|
57
|
+
printf ' MAC: %s\n' "$mac"
|
|
58
|
+
printf ' IPv4: %s\n' "$ip"
|
|
59
|
+
printf ' State: %s\n' "$operstate"
|
|
60
|
+
printf ' MTU: %s\n' "$mtu"
|
|
61
|
+
printf ' Driver: %s\n' "$driver"
|
|
62
|
+
printf ' PCI Vendor:Device: %s\n' "$pci"
|
|
63
|
+
printf ' Link Speed: %s\n\n' "$speed_label"
|
|
33
64
|
|
|
34
|
-
echo "Interface: $name"
|
|
35
|
-
echo " MAC: $mac"
|
|
36
|
-
echo " IPv4: $ip"
|
|
37
|
-
echo " State: $operstate"
|
|
38
|
-
echo " MTU: $mtu"
|
|
39
|
-
echo " Driver: $driver"
|
|
40
|
-
echo " PCI Vendor:Device ID: $pci"
|
|
41
|
-
echo " Link Speed: ${speed}Mb/s"
|
|
42
|
-
echo
|
|
43
65
|
done
|
|
@@ -32,6 +32,7 @@ echo "6) Try to install audio helper packages that sometimes block ffmpeg (ladsp
|
|
|
32
32
|
# These may be provided by CRB/EPEL or other compatible repos
|
|
33
33
|
dnf -y install ladspa || echo "ladspa not available from enabled repos (will try later)"
|
|
34
34
|
dnf -y install rubberband || echo "rubberband not available from enabled repos (will try later)"
|
|
35
|
+
dnf -y install libwebp-tools || echo "libwebp-tools not available from enabled repos (will try later)"
|
|
35
36
|
|
|
36
37
|
echo "7) Try installing ffmpeg (several fallbacks tried)"
|
|
37
38
|
if dnf -y install ffmpeg ffmpeg-devel --allowerasing; then
|
|
@@ -73,7 +73,16 @@ const ProviderSchema = UserSchema;
|
|
|
73
73
|
const UserDto = {
|
|
74
74
|
select: {
|
|
75
75
|
get: () => {
|
|
76
|
-
return {
|
|
76
|
+
return {
|
|
77
|
+
_id: 1,
|
|
78
|
+
username: 1,
|
|
79
|
+
email: 1,
|
|
80
|
+
role: 1,
|
|
81
|
+
emailConfirmed: 1,
|
|
82
|
+
profileImageId: 1,
|
|
83
|
+
createdAt: 1,
|
|
84
|
+
updatedAt: 1,
|
|
85
|
+
};
|
|
77
86
|
},
|
|
78
87
|
getAll: () => {
|
|
79
88
|
return { _id: 1 };
|
package/src/cli/cluster.js
CHANGED
|
@@ -44,7 +44,8 @@ class UnderpostCluster {
|
|
|
44
44
|
* @param {boolean} [options.listPods=false] - List Kubernetes pods.
|
|
45
45
|
* @param {boolean} [options.reset=false] - Perform a comprehensive reset of Kubernetes and container environments.
|
|
46
46
|
* @param {boolean} [options.dev=false] - Run in development mode (adjusts paths).
|
|
47
|
-
* @param {string} [options.nsUse=''] - Set the current kubectl namespace.
|
|
47
|
+
* @param {string} [options.nsUse=''] - Set the current kubectl namespace (creates namespace if it doesn't exist).
|
|
48
|
+
* @param {string} [options.namespace='default'] - Kubernetes namespace for cluster operations.
|
|
48
49
|
* @param {boolean} [options.infoCapacity=false] - Display resource capacity information for the cluster.
|
|
49
50
|
* @param {boolean} [options.infoCapacityPod=false] - Display resource capacity information for pods.
|
|
50
51
|
* @param {boolean} [options.pullImage=false] - Pull necessary Docker images before deployment.
|
|
@@ -79,6 +80,7 @@ class UnderpostCluster {
|
|
|
79
80
|
reset: false,
|
|
80
81
|
dev: false,
|
|
81
82
|
nsUse: '',
|
|
83
|
+
namespace: 'default',
|
|
82
84
|
infoCapacity: false,
|
|
83
85
|
infoCapacityPod: false,
|
|
84
86
|
pullImage: false,
|
|
@@ -116,8 +118,26 @@ class UnderpostCluster {
|
|
|
116
118
|
if (options.infoCapacity === true)
|
|
117
119
|
return logger.info('', UnderpostCluster.API.getResourcesCapacity(options.kubeadm || options.k3s)); // Adjust for k3s
|
|
118
120
|
if (options.listPods === true) return console.table(UnderpostDeploy.API.get(podName ?? undefined));
|
|
121
|
+
// Set default namespace if not specified
|
|
122
|
+
if (!options.namespace) options.namespace = 'default';
|
|
123
|
+
|
|
119
124
|
if (options.nsUse && typeof options.nsUse === 'string') {
|
|
125
|
+
// Verify if namespace exists, create if not
|
|
126
|
+
const namespaceExists = shellExec(`kubectl get namespace ${options.nsUse} --ignore-not-found -o name`, {
|
|
127
|
+
stdout: true,
|
|
128
|
+
silent: true,
|
|
129
|
+
}).trim();
|
|
130
|
+
|
|
131
|
+
if (!namespaceExists) {
|
|
132
|
+
logger.info(`Namespace '${options.nsUse}' does not exist. Creating it...`);
|
|
133
|
+
shellExec(`kubectl create namespace ${options.nsUse}`);
|
|
134
|
+
logger.info(`Namespace '${options.nsUse}' created successfully.`);
|
|
135
|
+
} else {
|
|
136
|
+
logger.info(`Namespace '${options.nsUse}' already exists.`);
|
|
137
|
+
}
|
|
138
|
+
|
|
120
139
|
shellExec(`kubectl config set-context --current --namespace=${options.nsUse}`);
|
|
140
|
+
logger.info(`Context switched to namespace: ${options.nsUse}`);
|
|
121
141
|
return;
|
|
122
142
|
}
|
|
123
143
|
if (options.info === true) {
|
|
@@ -242,14 +262,17 @@ class UnderpostCluster {
|
|
|
242
262
|
shellExec(
|
|
243
263
|
`sudo kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.3/manifests/tigera-operator.yaml`,
|
|
244
264
|
);
|
|
245
|
-
shellExec(
|
|
265
|
+
shellExec(
|
|
266
|
+
`sudo kubectl apply -f ${underpostRoot}/manifests/kubeadm-calico-config.yaml -n ${options.namespace}`,
|
|
267
|
+
);
|
|
268
|
+
|
|
246
269
|
// Untaint control plane node to allow scheduling pods
|
|
247
270
|
const nodeName = os.hostname();
|
|
248
271
|
shellExec(`kubectl taint nodes ${nodeName} node-role.kubernetes.io/control-plane:NoSchedule-`);
|
|
249
272
|
// Install local-path-provisioner for dynamic PVCs (optional but recommended)
|
|
250
273
|
logger.info('Installing local-path-provisioner...');
|
|
251
274
|
shellExec(
|
|
252
|
-
`kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml`,
|
|
275
|
+
`kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml -n ${options.namespace}`,
|
|
253
276
|
);
|
|
254
277
|
} else {
|
|
255
278
|
// Kind cluster initialization (if not using kubeadm or k3s)
|
|
@@ -286,13 +309,13 @@ class UnderpostCluster {
|
|
|
286
309
|
}
|
|
287
310
|
|
|
288
311
|
if (options.grafana === true) {
|
|
289
|
-
shellExec(`kubectl delete deployment grafana --ignore-not-found`);
|
|
290
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/grafana`);
|
|
312
|
+
shellExec(`kubectl delete deployment grafana -n ${options.namespace} --ignore-not-found`);
|
|
313
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/grafana -n ${options.namespace}`);
|
|
291
314
|
const yaml = `${fs
|
|
292
315
|
.readFileSync(`${underpostRoot}/manifests/grafana/deployment.yaml`, 'utf8')
|
|
293
316
|
.replace('{{GF_SERVER_ROOT_URL}}', options.hosts.split(',')[0])}`;
|
|
294
317
|
console.log(yaml);
|
|
295
|
-
shellExec(`kubectl apply -f - <<EOF
|
|
318
|
+
shellExec(`kubectl apply -f - -n ${options.namespace} <<EOF
|
|
296
319
|
${yaml}
|
|
297
320
|
EOF
|
|
298
321
|
`);
|
|
@@ -311,7 +334,7 @@ EOF
|
|
|
311
334
|
.join(',')}]`,
|
|
312
335
|
)}`;
|
|
313
336
|
console.log(yaml);
|
|
314
|
-
shellExec(`kubectl apply -f - <<EOF
|
|
337
|
+
shellExec(`kubectl apply -f - -n ${options.namespace} <<EOF
|
|
315
338
|
${yaml}
|
|
316
339
|
EOF
|
|
317
340
|
`);
|
|
@@ -340,15 +363,15 @@ EOF
|
|
|
340
363
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
341
364
|
shellExec(`sudo crictl pull valkey/valkey:latest`);
|
|
342
365
|
}
|
|
343
|
-
shellExec(`kubectl delete statefulset valkey-service --ignore-not-found`);
|
|
344
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/valkey`);
|
|
366
|
+
shellExec(`kubectl delete statefulset valkey-service -n ${options.namespace} --ignore-not-found`);
|
|
367
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/valkey -n ${options.namespace}`);
|
|
345
368
|
await UnderpostTest.API.statusMonitor('valkey-service', 'Running', 'pods', 1000, 60);
|
|
346
369
|
}
|
|
347
370
|
if (options.full === true || options.mariadb === true) {
|
|
348
371
|
shellExec(
|
|
349
|
-
`sudo kubectl create secret generic mariadb-secret --from-file=username=/home/dd/engine/engine-private/mariadb-username --from-file=password=/home/dd/engine/engine-private/mariadb-password --dry-run=client -o yaml | kubectl apply -f
|
|
372
|
+
`sudo kubectl create secret generic mariadb-secret --from-file=username=/home/dd/engine/engine-private/mariadb-username --from-file=password=/home/dd/engine/engine-private/mariadb-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
350
373
|
);
|
|
351
|
-
shellExec(`kubectl delete statefulset mariadb-statefulset --ignore-not-found`);
|
|
374
|
+
shellExec(`kubectl delete statefulset mariadb-statefulset -n ${options.namespace} --ignore-not-found`);
|
|
352
375
|
|
|
353
376
|
if (options.pullImage === true) {
|
|
354
377
|
// shellExec(`sudo podman pull mariadb:latest`);
|
|
@@ -360,17 +383,17 @@ EOF
|
|
|
360
383
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
361
384
|
shellExec(`sudo crictl pull mariadb:latest`);
|
|
362
385
|
}
|
|
363
|
-
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml`);
|
|
364
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb`);
|
|
386
|
+
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml -n ${options.namespace}`);
|
|
387
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb -n ${options.namespace}`);
|
|
365
388
|
}
|
|
366
389
|
if (options.full === true || options.mysql === true) {
|
|
367
390
|
shellExec(
|
|
368
|
-
`sudo kubectl create secret generic mysql-secret --from-file=username=/home/dd/engine/engine-private/mysql-username --from-file=password=/home/dd/engine/engine-private/mysql-password --dry-run=client -o yaml | kubectl apply -f
|
|
391
|
+
`sudo kubectl create secret generic mysql-secret --from-file=username=/home/dd/engine/engine-private/mysql-username --from-file=password=/home/dd/engine/engine-private/mysql-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
369
392
|
);
|
|
370
393
|
shellExec(`sudo mkdir -p /mnt/data`);
|
|
371
394
|
shellExec(`sudo chmod 777 /mnt/data`);
|
|
372
395
|
shellExec(`sudo chown -R root:root /mnt/data`);
|
|
373
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mysql`);
|
|
396
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mysql -n ${options.namespace}`);
|
|
374
397
|
}
|
|
375
398
|
if (options.full === true || options.postgresql === true) {
|
|
376
399
|
if (options.pullImage === true) {
|
|
@@ -383,9 +406,9 @@ EOF
|
|
|
383
406
|
shellExec(`sudo crictl pull postgres:latest`);
|
|
384
407
|
}
|
|
385
408
|
shellExec(
|
|
386
|
-
`sudo kubectl create secret generic postgres-secret --from-file=password=/home/dd/engine/engine-private/postgresql-password --dry-run=client -o yaml | kubectl apply -f
|
|
409
|
+
`sudo kubectl create secret generic postgres-secret --from-file=password=/home/dd/engine/engine-private/postgresql-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
387
410
|
);
|
|
388
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/postgresql`);
|
|
411
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/postgresql -n ${options.namespace}`);
|
|
389
412
|
}
|
|
390
413
|
if (options.mongodb4 === true) {
|
|
391
414
|
if (options.pullImage === true) {
|
|
@@ -397,7 +420,7 @@ EOF
|
|
|
397
420
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
398
421
|
shellExec(`sudo crictl pull mongo:4.4`);
|
|
399
422
|
}
|
|
400
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb-4.4`);
|
|
423
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb-4.4 -n ${options.namespace}`);
|
|
401
424
|
|
|
402
425
|
const deploymentName = 'mongodb-deployment';
|
|
403
426
|
|
|
@@ -428,14 +451,14 @@ EOF
|
|
|
428
451
|
shellExec(`sudo crictl pull mongo:latest`);
|
|
429
452
|
}
|
|
430
453
|
shellExec(
|
|
431
|
-
`sudo kubectl create secret generic mongodb-keyfile --from-file=/home/dd/engine/engine-private/mongodb-keyfile --dry-run=client -o yaml | kubectl apply -f
|
|
454
|
+
`sudo kubectl create secret generic mongodb-keyfile --from-file=/home/dd/engine/engine-private/mongodb-keyfile --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
432
455
|
);
|
|
433
456
|
shellExec(
|
|
434
|
-
`sudo kubectl create secret generic mongodb-secret --from-file=username=/home/dd/engine/engine-private/mongodb-username --from-file=password=/home/dd/engine/engine-private/mongodb-password --dry-run=client -o yaml | kubectl apply -f
|
|
457
|
+
`sudo kubectl create secret generic mongodb-secret --from-file=username=/home/dd/engine/engine-private/mongodb-username --from-file=password=/home/dd/engine/engine-private/mongodb-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
435
458
|
);
|
|
436
|
-
shellExec(`kubectl delete statefulset mongodb --ignore-not-found`);
|
|
437
|
-
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml`);
|
|
438
|
-
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb`);
|
|
459
|
+
shellExec(`kubectl delete statefulset mongodb -n ${options.namespace} --ignore-not-found`);
|
|
460
|
+
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml -n ${options.namespace}`);
|
|
461
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb -n ${options.namespace}`);
|
|
439
462
|
|
|
440
463
|
const successInstance = await UnderpostTest.API.statusMonitor('mongodb-0', 'Running', 'pods', 1000, 60 * 10);
|
|
441
464
|
|
|
@@ -456,10 +479,12 @@ EOF
|
|
|
456
479
|
}
|
|
457
480
|
|
|
458
481
|
if (options.full === true || options.contour === true) {
|
|
459
|
-
shellExec(`kubectl apply -f https://projectcontour.io/quickstart/contour.yaml`);
|
|
482
|
+
shellExec(`kubectl apply -f https://projectcontour.io/quickstart/contour.yaml -n ${options.namespace}`);
|
|
460
483
|
if (options.kubeadm === true) {
|
|
461
484
|
// Envoy service might need NodePort for kubeadm
|
|
462
|
-
shellExec(
|
|
485
|
+
shellExec(
|
|
486
|
+
`sudo kubectl apply -f ${underpostRoot}/manifests/envoy-service-nodeport.yaml -n ${options.namespace}`,
|
|
487
|
+
);
|
|
463
488
|
}
|
|
464
489
|
// K3s has a built-in LoadBalancer (Klipper-lb) that can expose services,
|
|
465
490
|
// so a specific NodePort service might not be needed or can be configured differently.
|
|
@@ -479,7 +504,7 @@ EOF
|
|
|
479
504
|
|
|
480
505
|
const letsEncName = 'letsencrypt-prod';
|
|
481
506
|
shellExec(`sudo kubectl delete ClusterIssuer ${letsEncName} --ignore-not-found`);
|
|
482
|
-
shellExec(`sudo kubectl apply -f ${underpostRoot}/manifests/${letsEncName}.yaml`);
|
|
507
|
+
shellExec(`sudo kubectl apply -f ${underpostRoot}/manifests/${letsEncName}.yaml -n ${options.namespace}`);
|
|
483
508
|
}
|
|
484
509
|
},
|
|
485
510
|
|
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:
|
|
@@ -179,7 +181,7 @@ spec:
|
|
|
179
181
|
npm install -g underpost &&
|
|
180
182
|
underpost secret underpost --create-from-file /etc/config/.env.${env} &&
|
|
181
183
|
underpost start --build --run ${deployId} ${env}
|
|
182
|
-
${UnderpostDeploy.API.volumeFactory(volumes)
|
|
184
|
+
${UnderpostDeploy.API.volumeFactory(volumes.map((v) => ((v.version = `${deployId}-${env}-${suffix}`), v)))
|
|
183
185
|
.render.split(`\n`)
|
|
184
186
|
.map((l) => ' ' + l)
|
|
185
187
|
.join(`\n`)}
|
|
@@ -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,6 +414,7 @@ spec:
|
|
|
404
414
|
status: false,
|
|
405
415
|
etcHosts: false,
|
|
406
416
|
disableUpdateUnderpostConfig: false,
|
|
417
|
+
namespace: '',
|
|
407
418
|
},
|
|
408
419
|
) {
|
|
409
420
|
if (options.infoUtil === true)
|
|
@@ -437,15 +448,16 @@ kubectl wait --for=jsonpath='{.status.phase}'=Running pod/busybox1
|
|
|
437
448
|
kubectl wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' pod/busybox1
|
|
438
449
|
kubectl wait --for=delete pod/busybox1 --timeout=60s
|
|
439
450
|
|
|
440
|
-
fqdn: <service>.<namespace>.<kind(svc/pod)>.<cluster-domain(cluster.local)>
|
|
441
451
|
node bin run cluster-build
|
|
442
452
|
node bin run template-deploy
|
|
443
453
|
node bin run ssh-deploy (sync-)engine-core
|
|
444
454
|
node bin run cluster --dev 'express,dd-test+dd-core'
|
|
445
455
|
node bin run dd-container --dev
|
|
456
|
+
node bin run promote dd-default production
|
|
446
457
|
node bin dockerfile-pull-base-images --dev --path 'image-path' --kind-load
|
|
447
458
|
node bin/deploy update-default-conf <deploy-id>
|
|
448
459
|
|
|
460
|
+
fqdn: <service>.<namespace>.<kind(svc/pod)>.<cluster-domain(cluster.local)>
|
|
449
461
|
kubectl run --rm -it test-dns --image=busybox:latest --restart=Never -- /bin/sh -c "
|
|
450
462
|
nslookup kubernetes.default.svc.cluster.local;
|
|
451
463
|
nslookup mongodb-service.default.svc.cluster.local;
|
|
@@ -467,10 +479,11 @@ docker login nvcr.io
|
|
|
467
479
|
Username: $oauthtoken
|
|
468
480
|
Password: <Your Key>
|
|
469
481
|
`);
|
|
482
|
+
const namespace = options.namespace ? options.namespace : 'default';
|
|
470
483
|
if (!deployList && options.certHosts) {
|
|
471
484
|
for (const host of options.certHosts.split(',')) {
|
|
472
|
-
shellExec(`sudo kubectl apply -f - <<EOF
|
|
473
|
-
${UnderpostDeploy.API.buildCertManagerCertificate({ host })}
|
|
485
|
+
shellExec(`sudo kubectl apply -f - -n ${namespace} <<EOF
|
|
486
|
+
${UnderpostDeploy.API.buildCertManagerCertificate({ host, namespace })}
|
|
474
487
|
EOF`);
|
|
475
488
|
}
|
|
476
489
|
return;
|
|
@@ -532,36 +545,44 @@ EOF`);
|
|
|
532
545
|
continue;
|
|
533
546
|
}
|
|
534
547
|
|
|
535
|
-
if (!options.disableUpdateDeployment)
|
|
536
|
-
for (const version of options.versions.split(',')) {
|
|
537
|
-
shellExec(`sudo kubectl delete svc ${deployId}-${env}-${version}-service`);
|
|
538
|
-
shellExec(`sudo kubectl delete deployment ${deployId}-${env}-${version}`);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
548
|
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
542
549
|
const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
|
|
543
550
|
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
|
|
544
551
|
: [];
|
|
545
552
|
|
|
546
|
-
if (!options.
|
|
547
|
-
for (const
|
|
548
|
-
shellExec(
|
|
549
|
-
|
|
550
|
-
|
|
553
|
+
if (!options.disableUpdateDeployment)
|
|
554
|
+
for (const version of options.versions.split(',')) {
|
|
555
|
+
shellExec(
|
|
556
|
+
`sudo kubectl delete svc ${deployId}-${env}-${version}-service -n ${namespace} --ignore-not-found`,
|
|
557
|
+
);
|
|
558
|
+
shellExec(
|
|
559
|
+
`sudo kubectl delete deployment ${deployId}-${env}-${version} -n ${namespace} --ignore-not-found`,
|
|
560
|
+
);
|
|
561
|
+
if (!options.disableUpdateVolume) {
|
|
562
|
+
for (const volume of confVolume) {
|
|
563
|
+
const pvcId = `${volume.claimName}-${deployId}-${env}-${version}`;
|
|
564
|
+
const pvId = `${volume.claimName.replace('pvc-', 'pv-')}-${deployId}-${env}-${version}`;
|
|
565
|
+
const rootVolumeHostPath = `/home/dd/engine/volume/${pvId}`;
|
|
566
|
+
if (!fs.existsSync(rootVolumeHostPath)) fs.mkdirSync(rootVolumeHostPath, { recursive: true });
|
|
567
|
+
fs.copySync(volume.volumeMountPath, rootVolumeHostPath);
|
|
568
|
+
shellExec(`kubectl delete pvc ${pvcId} -n ${namespace} --ignore-not-found`);
|
|
569
|
+
shellExec(`kubectl delete pv ${pvId} --ignore-not-found`);
|
|
570
|
+
shellExec(`kubectl apply -f - -n ${namespace} <<EOF
|
|
551
571
|
${UnderpostDeploy.API.persistentVolumeFactory({
|
|
552
|
-
hostPath:
|
|
553
|
-
pvcId
|
|
572
|
+
hostPath: rootVolumeHostPath,
|
|
573
|
+
pvcId,
|
|
554
574
|
})}
|
|
555
575
|
EOF
|
|
556
576
|
`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
557
579
|
}
|
|
558
|
-
}
|
|
559
580
|
|
|
560
581
|
for (const host of Object.keys(confServer)) {
|
|
561
582
|
if (!options.disableUpdateProxy) {
|
|
562
|
-
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
583
|
+
shellExec(`sudo kubectl delete HTTPProxy ${host} -n ${namespace} --ignore-not-found`);
|
|
563
584
|
if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
|
|
564
|
-
shellExec(`sudo kubectl delete Certificate ${host}`);
|
|
585
|
+
shellExec(`sudo kubectl delete Certificate ${host} -n ${namespace} --ignore-not-found`);
|
|
565
586
|
}
|
|
566
587
|
if (!options.remove) etcHosts.push(host);
|
|
567
588
|
}
|
|
@@ -572,11 +593,13 @@ EOF
|
|
|
572
593
|
: `manifests/deployment/${deployId}-${env}`;
|
|
573
594
|
|
|
574
595
|
if (!options.remove) {
|
|
575
|
-
if (!options.disableUpdateDeployment)
|
|
576
|
-
|
|
596
|
+
if (!options.disableUpdateDeployment)
|
|
597
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml -n ${namespace}`);
|
|
598
|
+
if (!options.disableUpdateProxy)
|
|
599
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml -n ${namespace}`);
|
|
577
600
|
|
|
578
601
|
if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
|
|
579
|
-
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
602
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml -n ${namespace}`);
|
|
580
603
|
}
|
|
581
604
|
}
|
|
582
605
|
if (options.etcHosts === true) {
|
|
@@ -593,15 +616,19 @@ EOF
|
|
|
593
616
|
* Retrieves information about a deployment.
|
|
594
617
|
* @param {string} deployId - Deployment ID for which information is being retrieved.
|
|
595
618
|
* @param {string} kindType - Type of Kubernetes resource to retrieve information for (e.g. 'pods').
|
|
619
|
+
* @param {string} namespace - Kubernetes namespace to retrieve information from.
|
|
596
620
|
* @returns {Array<object>} - Array of objects containing information about the deployment.
|
|
597
621
|
* @memberof UnderpostDeploy
|
|
598
622
|
*/
|
|
599
|
-
get(deployId, kindType = 'pods') {
|
|
600
|
-
const raw = shellExec(
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
623
|
+
get(deployId, kindType = 'pods', namespace = '') {
|
|
624
|
+
const raw = shellExec(
|
|
625
|
+
`sudo kubectl get ${kindType}${namespace ? ` -n ${namespace}` : ` --all-namespaces`} -o wide`,
|
|
626
|
+
{
|
|
627
|
+
stdout: true,
|
|
628
|
+
disableLog: true,
|
|
629
|
+
silent: true,
|
|
630
|
+
},
|
|
631
|
+
);
|
|
605
632
|
|
|
606
633
|
const heads = raw
|
|
607
634
|
.split(`\n`)[0]
|
|
@@ -715,12 +742,13 @@ EOF
|
|
|
715
742
|
/**
|
|
716
743
|
* Creates a configmap for a deployment.
|
|
717
744
|
* @param {string} env - Environment for which the configmap is being created.
|
|
745
|
+
* @param {string} [namespace='default'] - Kubernetes namespace for the configmap.
|
|
718
746
|
* @memberof UnderpostDeploy
|
|
719
747
|
*/
|
|
720
|
-
configMap(env) {
|
|
721
|
-
shellExec(`kubectl delete configmap underpost-config`);
|
|
748
|
+
configMap(env, namespace = 'default') {
|
|
749
|
+
shellExec(`kubectl delete configmap underpost-config -n ${namespace} --ignore-not-found`);
|
|
722
750
|
shellExec(
|
|
723
|
-
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
751
|
+
`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}`,
|
|
724
752
|
);
|
|
725
753
|
},
|
|
726
754
|
/**
|
|
@@ -729,14 +757,15 @@ EOF
|
|
|
729
757
|
* @param {string} env - Environment for which the traffic is being switched.
|
|
730
758
|
* @param {string} targetTraffic - Target traffic status for the deployment.
|
|
731
759
|
* @param {number} replicas - Number of replicas for the deployment.
|
|
760
|
+
* @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
|
|
732
761
|
* @memberof UnderpostDeploy
|
|
733
762
|
*/
|
|
734
|
-
switchTraffic(deployId, env, targetTraffic, replicas = 1) {
|
|
763
|
+
switchTraffic(deployId, env, targetTraffic, replicas = 1, namespace = 'default') {
|
|
735
764
|
UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
|
|
736
765
|
shellExec(
|
|
737
|
-
`node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} ${deployId} ${env}`,
|
|
766
|
+
`node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} --namespace ${namespace} ${deployId} ${env}`,
|
|
738
767
|
);
|
|
739
|
-
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
768
|
+
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml -n ${namespace}`);
|
|
740
769
|
},
|
|
741
770
|
|
|
742
771
|
/**
|
|
@@ -760,6 +789,7 @@ EOF
|
|
|
760
789
|
volumeType: 'Directory',
|
|
761
790
|
claimName: null,
|
|
762
791
|
configMap: null,
|
|
792
|
+
version: null,
|
|
763
793
|
},
|
|
764
794
|
],
|
|
765
795
|
) {
|
|
@@ -768,7 +798,11 @@ EOF
|
|
|
768
798
|
let _volumes = `
|
|
769
799
|
volumes:`;
|
|
770
800
|
volumes.map((volumeData) => {
|
|
771
|
-
|
|
801
|
+
let { volumeName, volumeMountPath, volumeHostPath, volumeType, claimName, configMap, version } = volumeData;
|
|
802
|
+
if (version) {
|
|
803
|
+
volumeName = `${volumeName}-${version}`;
|
|
804
|
+
claimName = claimName ? `${claimName}-${version}` : null;
|
|
805
|
+
}
|
|
772
806
|
_volumeMounts += `
|
|
773
807
|
- name: ${volumeName}
|
|
774
808
|
mountPath: ${volumeMountPath}
|
|
@@ -899,7 +933,7 @@ ${renderHosts}`,
|
|
|
899
933
|
getCurrentLoadedImages(node = 'kind-worker', specContainers = false) {
|
|
900
934
|
if (specContainers) {
|
|
901
935
|
const raw = shellExec(
|
|
902
|
-
`kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
|
|
936
|
+
`kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.namespace}{"/"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
|
|
903
937
|
{
|
|
904
938
|
stdout: true,
|
|
905
939
|
silent: true,
|