cyberia 2.89.2 → 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.
- package/.env.development +2 -0
- package/.env.production +2 -0
- package/.env.test +2 -0
- package/.github/workflows/engine-cyberia.cd.yml +4 -0
- package/.github/workflows/release.cd.yml +2 -0
- package/bin/cyberia.js +10 -7
- package/bin/deploy.js +22 -15
- package/bin/index.js +10 -7
- package/cli.md +105 -54
- package/deployment.yaml +34 -6
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +18 -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/pv-pvc-dd.yaml +34 -0
- package/manifests/valkey/service.yaml +0 -1
- package/manifests/valkey/statefulset.yaml +2 -3
- package/package.json +1 -1
- package/proxy.yaml +6 -0
- package/scripts/device-scan.sh +43 -21
- package/scripts/gen-fqdns.sh +14 -0
- package/scripts/ip-info.sh +118 -0
- package/scripts/rpmfusion-ffmpeg-setup.sh +1 -0
- package/src/api/object-layer/object-layer.controller.js +19 -0
- package/src/api/object-layer/object-layer.router.js +4 -0
- package/src/api/object-layer/object-layer.service.js +111 -0
- package/src/api/user/user.model.js +10 -1
- package/src/cli/cluster.js +88 -75
- package/src/cli/deploy.js +165 -85
- package/src/cli/index.js +44 -3
- package/src/cli/monitor.js +12 -6
- package/src/cli/repository.js +13 -1
- package/src/cli/run.js +127 -60
- 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 +336 -72
- package/src/client/components/core/ObjectLayerEngineViewer.js +239 -420
- package/src/client/components/core/Router.js +10 -1
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/ObjectLayerCyberiaPortal.js +44 -4
- package/src/client/services/default/default.management.js +25 -5
- package/src/client/services/object-layer/object-layer.management.js +8 -8
- package/src/client/services/object-layer/object-layer.service.js +34 -0
- 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 +3 -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/src/cli/deploy.js
CHANGED
|
@@ -129,15 +129,28 @@ 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'));
|
|
138
|
+
let volumes = [
|
|
139
|
+
{
|
|
140
|
+
volumeMountPath: '/etc/config',
|
|
141
|
+
volumeName: 'config-volume',
|
|
142
|
+
configMap: 'underpost-config',
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
|
|
146
|
+
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
|
|
147
|
+
: [];
|
|
148
|
+
volumes = volumes.concat(confVolume);
|
|
137
149
|
return `apiVersion: apps/v1
|
|
138
150
|
kind: Deployment
|
|
139
151
|
metadata:
|
|
140
152
|
name: ${deployId}-${env}-${suffix}
|
|
153
|
+
namespace: ${namespace ? namespace : 'default'}
|
|
141
154
|
labels:
|
|
142
155
|
app: ${deployId}-${env}-${suffix}
|
|
143
156
|
spec:
|
|
@@ -168,18 +181,16 @@ spec:
|
|
|
168
181
|
npm install -g underpost &&
|
|
169
182
|
underpost secret underpost --create-from-file /etc/config/.env.${env} &&
|
|
170
183
|
underpost start --build --run ${deployId} ${env}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- name: config-volume
|
|
176
|
-
configMap:
|
|
177
|
-
name: underpost-config
|
|
184
|
+
${UnderpostDeploy.API.volumeFactory(volumes.map((v) => ((v.version = `${deployId}-${env}-${suffix}`), v)))
|
|
185
|
+
.render.split(`\n`)
|
|
186
|
+
.map((l) => ' ' + l)
|
|
187
|
+
.join(`\n`)}
|
|
178
188
|
---
|
|
179
189
|
apiVersion: v1
|
|
180
190
|
kind: Service
|
|
181
191
|
metadata:
|
|
182
192
|
name: ${deployId}-${env}-${suffix}-service
|
|
193
|
+
namespace: ${namespace}
|
|
183
194
|
spec:
|
|
184
195
|
selector:
|
|
185
196
|
app: ${deployId}-${env}-${suffix}
|
|
@@ -193,6 +204,7 @@ spec:
|
|
|
193
204
|
* @param {object} options - Options for the manifest build process.
|
|
194
205
|
* @param {string} options.replicas - Number of replicas for each deployment.
|
|
195
206
|
* @param {string} options.image - Docker image for the deployment.
|
|
207
|
+
* @param {string} options.namespace - Kubernetes namespace for the deployment.
|
|
196
208
|
* @returns {Promise<void>} - Promise that resolves when the manifest is built.
|
|
197
209
|
* @memberof UnderpostDeploy
|
|
198
210
|
*/
|
|
@@ -200,6 +212,7 @@ spec:
|
|
|
200
212
|
const resources = UnderpostDeploy.API.resourcesFactory();
|
|
201
213
|
const replicas = options.replicas;
|
|
202
214
|
const image = options.image;
|
|
215
|
+
if (!options.namespace) options.namespace = 'default';
|
|
203
216
|
|
|
204
217
|
for (const _deployId of deployList.split(',')) {
|
|
205
218
|
const deployId = _deployId.trim();
|
|
@@ -227,6 +240,7 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
|
|
|
227
240
|
resources,
|
|
228
241
|
replicas,
|
|
229
242
|
image,
|
|
243
|
+
namespace: options.namespace,
|
|
230
244
|
}).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
|
|
231
245
|
`;
|
|
232
246
|
}
|
|
@@ -249,6 +263,7 @@ apiVersion: projectcontour.io/v1
|
|
|
249
263
|
kind: HTTPProxy
|
|
250
264
|
metadata:
|
|
251
265
|
name: ${host}
|
|
266
|
+
namespace: ${options.namespace}
|
|
252
267
|
spec:
|
|
253
268
|
virtualhost:
|
|
254
269
|
fqdn: ${host}${
|
|
@@ -308,16 +323,18 @@ spec:
|
|
|
308
323
|
/**
|
|
309
324
|
* Builds a Certificate resource for a host using cert-manager.
|
|
310
325
|
* @param {string} host - Hostname for which the certificate is being built.
|
|
326
|
+
* @param {string} namespace - Kubernetes namespace for the certificate.
|
|
311
327
|
* @returns {string} - Certificate resource YAML for the specified host.
|
|
312
328
|
* @memberof UnderpostDeploy
|
|
313
329
|
*/
|
|
314
|
-
buildCertManagerCertificate({ host }) {
|
|
330
|
+
buildCertManagerCertificate({ host, namespace }) {
|
|
315
331
|
return `
|
|
316
332
|
---
|
|
317
333
|
apiVersion: cert-manager.io/v1
|
|
318
334
|
kind: Certificate
|
|
319
335
|
metadata:
|
|
320
336
|
name: ${host}
|
|
337
|
+
namespace: ${namespace}
|
|
321
338
|
spec:
|
|
322
339
|
commonName: ${host}
|
|
323
340
|
dnsNames:
|
|
@@ -364,9 +381,11 @@ spec:
|
|
|
364
381
|
* @param {boolean} options.disableUpdateDeployment - Whether to disable deployment updates.
|
|
365
382
|
* @param {boolean} options.disableUpdateProxy - Whether to disable proxy updates.
|
|
366
383
|
* @param {boolean} options.disableDeploymentProxy - Whether to disable deployment proxy.
|
|
384
|
+
* @param {boolean} options.disableUpdateVolume - Whether to disable volume updates.
|
|
367
385
|
* @param {boolean} options.status - Whether to display deployment status.
|
|
368
386
|
* @param {boolean} options.etcHosts - Whether to display the /etc/hosts file.
|
|
369
387
|
* @param {boolean} options.disableUpdateUnderpostConfig - Whether to disable Underpost config updates.
|
|
388
|
+
* @param {string} [options.namespace] - Kubernetes namespace for the deployment.
|
|
370
389
|
* @returns {Promise<void>} - Promise that resolves when the deployment process is complete.
|
|
371
390
|
* @memberof UnderpostDeploy
|
|
372
391
|
*/
|
|
@@ -391,67 +410,18 @@ spec:
|
|
|
391
410
|
disableUpdateDeployment: false,
|
|
392
411
|
disableUpdateProxy: false,
|
|
393
412
|
disableDeploymentProxy: false,
|
|
413
|
+
disableUpdateVolume: false,
|
|
394
414
|
status: false,
|
|
395
415
|
etcHosts: false,
|
|
396
416
|
disableUpdateUnderpostConfig: false,
|
|
417
|
+
namespace: '',
|
|
397
418
|
},
|
|
398
419
|
) {
|
|
399
|
-
|
|
400
|
-
return logger.info(`
|
|
401
|
-
kubectl rollout restart deployment/deployment-name
|
|
402
|
-
kubectl rollout undo deployment/deployment-name
|
|
403
|
-
kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
404
|
-
kubectl get pods -w
|
|
405
|
-
kubectl patch statefulset valkey-service --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"valkey/valkey:latest"}]'
|
|
406
|
-
kubectl patch statefulset valkey-service -p '{"spec":{"template":{"spec":{"containers":[{"name":"valkey-service","imagePullPolicy":"Never"}]}}}}'
|
|
407
|
-
kubectl logs -f <pod-name>
|
|
408
|
-
kubectl describe pod <pod-name>
|
|
409
|
-
kubectl exec -it <pod-name> -- bash
|
|
410
|
-
kubectl exec -it <pod-name> -- sh
|
|
411
|
-
docker exec -it kind-control-plane bash
|
|
412
|
-
curl -4 -v google.com
|
|
413
|
-
kubectl taint nodes <node-name> node-role.kubernetes.io/control-plane:NoSchedule-
|
|
414
|
-
kubectl run test-pod --image=busybox:latest --restart=Never -- /bin/sh -c "while true; do sleep 30; done;"
|
|
415
|
-
kubectl run test-pod --image=alpine/curl:latest --restart=Never -- sh -c "sleep infinity"
|
|
416
|
-
kubectl get ippools -o yaml
|
|
417
|
-
kubectl get node <node-name> -o jsonpath='{.spec.podCIDR}'
|
|
418
|
-
kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "10.244.0.0/16"}]'
|
|
419
|
-
kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "192.168.0.0/24"}]'
|
|
420
|
-
sudo podman run --rm localhost/<image-name>:<image-version> <command>
|
|
421
|
-
kubectl get configmap kubelet-config -n kube-system -o yaml > kubelet-config.yaml
|
|
422
|
-
kubectl -n kube-system rollout restart daemonset kube-proxy
|
|
423
|
-
kubectl get EndpointSlice -o wide --all-namespaces -w
|
|
424
|
-
kubectl apply -k manifests/deployment/adminer/.
|
|
425
|
-
kubectl wait --for=condition=Ready pod/busybox1
|
|
426
|
-
kubectl wait --for=jsonpath='{.status.phase}'=Running pod/busybox1
|
|
427
|
-
kubectl wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' pod/busybox1
|
|
428
|
-
kubectl wait --for=delete pod/busybox1 --timeout=60s
|
|
429
|
-
|
|
430
|
-
kubectl run --rm -it test-dns --image=busybox:latest --restart=Never -- /bin/sh -c "
|
|
431
|
-
nslookup kubernetes.default.svc.cluster.local;
|
|
432
|
-
nslookup mongodb-service.default.svc.cluster.local;
|
|
433
|
-
nslookup valkey-service.default.svc.cluster.local;
|
|
434
|
-
nc -vz mongodb-service 27017;
|
|
435
|
-
nc -vz valkey-service 6379;
|
|
436
|
-
echo exit code: \\\$?
|
|
437
|
-
"
|
|
438
|
-
|
|
439
|
-
kubectl apply -f - <<EOF
|
|
440
|
-
apiVersion: apps/v1
|
|
441
|
-
kind: StatefulSet
|
|
442
|
-
metadata:
|
|
443
|
-
name: ...
|
|
444
|
-
EOF
|
|
445
|
-
|
|
446
|
-
https://org.ngc.nvidia.com/setup/api-keys
|
|
447
|
-
docker login nvcr.io
|
|
448
|
-
Username: $oauthtoken
|
|
449
|
-
Password: <Your Key>
|
|
450
|
-
`);
|
|
420
|
+
const namespace = options.namespace ? options.namespace : 'default';
|
|
451
421
|
if (!deployList && options.certHosts) {
|
|
452
422
|
for (const host of options.certHosts.split(',')) {
|
|
453
|
-
shellExec(`sudo kubectl apply -f - <<EOF
|
|
454
|
-
${UnderpostDeploy.API.buildCertManagerCertificate({ host })}
|
|
423
|
+
shellExec(`sudo kubectl apply -f - -n ${namespace} <<EOF
|
|
424
|
+
${UnderpostDeploy.API.buildCertManagerCertificate({ host, namespace })}
|
|
455
425
|
EOF`);
|
|
456
426
|
}
|
|
457
427
|
return;
|
|
@@ -513,19 +483,44 @@ EOF`);
|
|
|
513
483
|
continue;
|
|
514
484
|
}
|
|
515
485
|
|
|
486
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
487
|
+
const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
|
|
488
|
+
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
|
|
489
|
+
: [];
|
|
490
|
+
|
|
516
491
|
if (!options.disableUpdateDeployment)
|
|
517
492
|
for (const version of options.versions.split(',')) {
|
|
518
|
-
shellExec(
|
|
519
|
-
|
|
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
|
+
);
|
|
499
|
+
if (!options.disableUpdateVolume) {
|
|
500
|
+
for (const volume of confVolume) {
|
|
501
|
+
const pvcId = `${volume.claimName}-${deployId}-${env}-${version}`;
|
|
502
|
+
const pvId = `${volume.claimName.replace('pvc-', 'pv-')}-${deployId}-${env}-${version}`;
|
|
503
|
+
const rootVolumeHostPath = `/home/dd/engine/volume/${pvId}`;
|
|
504
|
+
if (!fs.existsSync(rootVolumeHostPath)) fs.mkdirSync(rootVolumeHostPath, { recursive: true });
|
|
505
|
+
fs.copySync(volume.volumeMountPath, rootVolumeHostPath);
|
|
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
|
|
509
|
+
${UnderpostDeploy.API.persistentVolumeFactory({
|
|
510
|
+
hostPath: rootVolumeHostPath,
|
|
511
|
+
pvcId,
|
|
512
|
+
})}
|
|
513
|
+
EOF
|
|
514
|
+
`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
520
517
|
}
|
|
521
518
|
|
|
522
|
-
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
523
|
-
|
|
524
519
|
for (const host of Object.keys(confServer)) {
|
|
525
520
|
if (!options.disableUpdateProxy) {
|
|
526
|
-
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
521
|
+
shellExec(`sudo kubectl delete HTTPProxy ${host} -n ${namespace} --ignore-not-found`);
|
|
527
522
|
if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
|
|
528
|
-
shellExec(`sudo kubectl delete Certificate ${host}`);
|
|
523
|
+
shellExec(`sudo kubectl delete Certificate ${host} -n ${namespace} --ignore-not-found`);
|
|
529
524
|
}
|
|
530
525
|
if (!options.remove) etcHosts.push(host);
|
|
531
526
|
}
|
|
@@ -536,11 +531,13 @@ EOF`);
|
|
|
536
531
|
: `manifests/deployment/${deployId}-${env}`;
|
|
537
532
|
|
|
538
533
|
if (!options.remove) {
|
|
539
|
-
if (!options.disableUpdateDeployment)
|
|
540
|
-
|
|
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}`);
|
|
541
538
|
|
|
542
539
|
if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
|
|
543
|
-
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
540
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml -n ${namespace}`);
|
|
544
541
|
}
|
|
545
542
|
}
|
|
546
543
|
if (options.etcHosts === true) {
|
|
@@ -557,15 +554,19 @@ EOF`);
|
|
|
557
554
|
* Retrieves information about a deployment.
|
|
558
555
|
* @param {string} deployId - Deployment ID for which information is being retrieved.
|
|
559
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.
|
|
560
558
|
* @returns {Array<object>} - Array of objects containing information about the deployment.
|
|
561
559
|
* @memberof UnderpostDeploy
|
|
562
560
|
*/
|
|
563
|
-
get(deployId, kindType = 'pods') {
|
|
564
|
-
const raw = shellExec(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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
|
+
);
|
|
569
570
|
|
|
570
571
|
const heads = raw
|
|
571
572
|
.split(`\n`)[0]
|
|
@@ -679,12 +680,13 @@ EOF`);
|
|
|
679
680
|
/**
|
|
680
681
|
* Creates a configmap for a deployment.
|
|
681
682
|
* @param {string} env - Environment for which the configmap is being created.
|
|
683
|
+
* @param {string} [namespace='default'] - Kubernetes namespace for the configmap.
|
|
682
684
|
* @memberof UnderpostDeploy
|
|
683
685
|
*/
|
|
684
|
-
configMap(env) {
|
|
685
|
-
shellExec(`kubectl delete configmap underpost-config`);
|
|
686
|
+
configMap(env, namespace = 'default') {
|
|
687
|
+
shellExec(`kubectl delete configmap underpost-config -n ${namespace} --ignore-not-found`);
|
|
686
688
|
shellExec(
|
|
687
|
-
`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}`,
|
|
688
690
|
);
|
|
689
691
|
},
|
|
690
692
|
/**
|
|
@@ -693,15 +695,93 @@ EOF`);
|
|
|
693
695
|
* @param {string} env - Environment for which the traffic is being switched.
|
|
694
696
|
* @param {string} targetTraffic - Target traffic status for the deployment.
|
|
695
697
|
* @param {number} replicas - Number of replicas for the deployment.
|
|
698
|
+
* @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
|
|
696
699
|
* @memberof UnderpostDeploy
|
|
697
700
|
*/
|
|
698
|
-
switchTraffic(deployId, env, targetTraffic, replicas = 1) {
|
|
701
|
+
switchTraffic(deployId, env, targetTraffic, replicas = 1, namespace = 'default') {
|
|
699
702
|
UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
|
|
700
703
|
shellExec(
|
|
701
|
-
`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}`,
|
|
702
705
|
);
|
|
703
|
-
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}`);
|
|
704
707
|
},
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Creates volume mounts and volumes for a deployment.
|
|
711
|
+
* @param {Array<volume>} volumes - List of volume configurations.
|
|
712
|
+
* @param {string} volume.volumeName - Name of the volume.
|
|
713
|
+
* @param {string} volume.volumeMountPath - Mount path of the volume in the container.
|
|
714
|
+
* @param {string} volume.volumeHostPath - Host path of the volume.
|
|
715
|
+
* @param {string} volume.volumeType - Type of the volume (e.g. 'Directory').
|
|
716
|
+
* @param {string|null} volume.claimName - Name of the persistent volume claim (if applicable).
|
|
717
|
+
* @param {string|null} volume.configMap - Name of the config map (if applicable).
|
|
718
|
+
* @returns {object} - Object containing the rendered volume mounts and volumes.
|
|
719
|
+
* @memberof UnderpostDeploy
|
|
720
|
+
*/
|
|
721
|
+
volumeFactory(
|
|
722
|
+
volumes = [
|
|
723
|
+
{
|
|
724
|
+
volumeName: 'volume-name',
|
|
725
|
+
volumeMountPath: '/path/in/container',
|
|
726
|
+
volumeHostPath: '/path/on/host',
|
|
727
|
+
volumeType: 'Directory',
|
|
728
|
+
claimName: null,
|
|
729
|
+
configMap: null,
|
|
730
|
+
version: null,
|
|
731
|
+
},
|
|
732
|
+
],
|
|
733
|
+
) {
|
|
734
|
+
let _volumeMounts = `
|
|
735
|
+
volumeMounts:`;
|
|
736
|
+
let _volumes = `
|
|
737
|
+
volumes:`;
|
|
738
|
+
volumes.map((volumeData) => {
|
|
739
|
+
let { volumeName, volumeMountPath, volumeHostPath, volumeType, claimName, configMap, version } = volumeData;
|
|
740
|
+
if (version) {
|
|
741
|
+
volumeName = `${volumeName}-${version}`;
|
|
742
|
+
claimName = claimName ? `${claimName}-${version}` : null;
|
|
743
|
+
}
|
|
744
|
+
_volumeMounts += `
|
|
745
|
+
- name: ${volumeName}
|
|
746
|
+
mountPath: ${volumeMountPath}
|
|
747
|
+
`;
|
|
748
|
+
|
|
749
|
+
_volumes += `
|
|
750
|
+
- name: ${volumeName}
|
|
751
|
+
${
|
|
752
|
+
configMap
|
|
753
|
+
? ` configMap:
|
|
754
|
+
name: ${configMap}`
|
|
755
|
+
: claimName
|
|
756
|
+
? ` persistentVolumeClaim:
|
|
757
|
+
claimName: ${claimName}`
|
|
758
|
+
: ` hostPath:
|
|
759
|
+
path: ${volumeHostPath}
|
|
760
|
+
type: ${volumeType}
|
|
761
|
+
`
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
`;
|
|
765
|
+
});
|
|
766
|
+
return { render: _volumeMounts + _volumes };
|
|
767
|
+
},
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Creates a persistent volume and persistent volume claim for a deployment.
|
|
771
|
+
* @param {object} options - Options for the persistent volume and claim creation.
|
|
772
|
+
* @param {string} options.hostPath - Host path for the persistent volume.
|
|
773
|
+
* @param {string} options.pvcId - Persistent volume claim ID.
|
|
774
|
+
* @returns {string} - YAML configuration for the persistent volume and claim.
|
|
775
|
+
* @memberof UnderpostDeploy
|
|
776
|
+
*/
|
|
777
|
+
persistentVolumeFactory({ hostPath, pvcId }) {
|
|
778
|
+
return fs
|
|
779
|
+
.readFileSync(`./manifests/pv-pvc-dd.yaml`, 'utf8')
|
|
780
|
+
.replace('/home/dd', hostPath)
|
|
781
|
+
.replace('pv-dd', pvcId.replace('pvc-', 'pv-'))
|
|
782
|
+
.replace('pvc-dd', pvcId);
|
|
783
|
+
},
|
|
784
|
+
|
|
705
785
|
/**
|
|
706
786
|
* Creates a hosts file for a deployment.
|
|
707
787
|
* @param {Array<string>} hosts - List of hosts to be added to the hosts file.
|
|
@@ -791,7 +871,7 @@ ${renderHosts}`,
|
|
|
791
871
|
getCurrentLoadedImages(node = 'kind-worker', specContainers = false) {
|
|
792
872
|
if (specContainers) {
|
|
793
873
|
const raw = shellExec(
|
|
794
|
-
`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}'`,
|
|
795
875
|
{
|
|
796
876
|
stdout: true,
|
|
797
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();
|
|
@@ -78,6 +80,8 @@ program
|
|
|
78
80
|
.option('--msg <msg>', 'Sets a custom commit message.')
|
|
79
81
|
.option('--deploy-id <deploy-id>', 'Sets the deployment configuration ID for the commit context.')
|
|
80
82
|
.option('--cached', 'Commit staged changes only or context.')
|
|
83
|
+
.option('--hashes <hashes>', 'Comma-separated list of specific file hashes of commits.')
|
|
84
|
+
.option('--extension <extension>', 'specific file extensions of commits.')
|
|
81
85
|
.description('Manages commits to a GitHub repository, supporting various commit types and options.')
|
|
82
86
|
.action(Underpost.repo.commit);
|
|
83
87
|
|
|
@@ -127,6 +131,16 @@ program
|
|
|
127
131
|
.description('Displays the root path of the npm installation.')
|
|
128
132
|
.action(() => console.log(getNpmRootPath()));
|
|
129
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
|
+
|
|
130
144
|
// 'cluster' command: Manage Kubernetes clusters
|
|
131
145
|
program
|
|
132
146
|
.command('cluster')
|
|
@@ -142,10 +156,20 @@ program
|
|
|
142
156
|
.option('--contour', 'Initializes the cluster with Project Contour base HTTPProxy and Envoy.')
|
|
143
157
|
.option('--cert-manager', "Initializes the cluster with a Let's Encrypt production ClusterIssuer.")
|
|
144
158
|
.option('--dedicated-gpu', 'Initializes the cluster with dedicated GPU base resources and environment settings.')
|
|
145
|
-
.option('--info', 'Retrieves information about all deployed Kubernetes objects.')
|
|
146
159
|
.option('--full', 'Initializes the cluster with all available statefulsets and services.')
|
|
147
|
-
.option(
|
|
160
|
+
.option(
|
|
161
|
+
'--ns-use <ns-name>',
|
|
162
|
+
"Switches the current Kubernetes context to the specified namespace (creates if it doesn't exist).",
|
|
163
|
+
)
|
|
148
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
|
+
)
|
|
149
173
|
.option('--grafana', 'Initializes the cluster with a Grafana deployment.')
|
|
150
174
|
.option(
|
|
151
175
|
'--prom [hosts]',
|
|
@@ -163,6 +187,8 @@ program
|
|
|
163
187
|
.option('--chown', 'Sets the appropriate ownership for Kubernetes kubeconfig files.')
|
|
164
188
|
.option('--k3s', 'Initializes the cluster using K3s (Lightweight Kubernetes).')
|
|
165
189
|
.option('--hosts <hosts>', 'A comma-separated list of cluster hostnames or IP addresses.')
|
|
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").')
|
|
166
192
|
.action(Underpost.cluster.init)
|
|
167
193
|
.description('Manages Kubernetes clusters, defaulting to Kind cluster initialization.');
|
|
168
194
|
|
|
@@ -178,7 +204,6 @@ program
|
|
|
178
204
|
.option('--sync', 'Synchronizes deployment environment variables, ports, and replica counts.')
|
|
179
205
|
.option('--info-router', 'Displays the current router structure and configuration.')
|
|
180
206
|
.option('--expose', 'Exposes services matching the provided deployment ID list.')
|
|
181
|
-
.option('--info-util', 'Displays useful `kubectl` utility management commands.')
|
|
182
207
|
.option('--cert', 'Resets TLS/SSL certificate secrets for deployments.')
|
|
183
208
|
.option('--cert-hosts <hosts>', 'Resets TLS/SSL certificate secrets for specified hosts.')
|
|
184
209
|
.option('--node <node>', 'Sets optional node for deployment operations.')
|
|
@@ -193,6 +218,7 @@ program
|
|
|
193
218
|
.option('--disable-update-deployment', 'Disables updates to deployments.')
|
|
194
219
|
.option('--disable-update-proxy', 'Disables updates to proxies.')
|
|
195
220
|
.option('--disable-deployment-proxy', 'Disables proxies of deployments.')
|
|
221
|
+
.option('--disable-update-volume', 'Disables updates to volume mounts during deployment.')
|
|
196
222
|
.option(
|
|
197
223
|
'--status',
|
|
198
224
|
'Retrieves current network traffic data from resource deployments and the host machine network configuration.',
|
|
@@ -201,6 +227,7 @@ program
|
|
|
201
227
|
.option('--etc-hosts', 'Enables the etc-hosts context for deployment operations.')
|
|
202
228
|
.option('--restore-hosts', 'Restores default `/etc/hosts` entries.')
|
|
203
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").')
|
|
204
231
|
.description('Manages application deployments, defaulting to deploying development pods.')
|
|
205
232
|
.action(Underpost.deploy.callback);
|
|
206
233
|
|
|
@@ -392,6 +419,18 @@ program
|
|
|
392
419
|
.option('--image-name <image-name>', 'Optional: Specifies the image name for test execution.')
|
|
393
420
|
.option('--container-name <container-name>', 'Optional: Specifies the container name for test execution.')
|
|
394
421
|
.option('--namespace <namespace>', 'Optional: Specifies the namespace for test execution.')
|
|
422
|
+
.option('--tty', 'Enables TTY for the container in deploy-job.')
|
|
423
|
+
.option('--stdin', 'Keeps STDIN open for the container in deploy-job.')
|
|
424
|
+
.option('--restart-policy <policy>', 'Sets the restart policy for the job in deploy-job.')
|
|
425
|
+
.option('--runtime-class-name <name>', 'Sets the runtime class name for the job in deploy-job.')
|
|
426
|
+
.option('--image-pull-policy <policy>', 'Sets the image pull policy for the job in deploy-job.')
|
|
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
|
+
)
|
|
432
|
+
.option('--claim-name <name>', 'Optional: Specifies the claim name for volume mounting in deploy-job.')
|
|
433
|
+
.option('--kind <kind-type>', 'Specifies the kind of Kubernetes resource (e.g., Job, Deployment) for deploy-job.')
|
|
395
434
|
.option('--kubeadm', 'Flag to indicate Kubeadm cluster type context')
|
|
396
435
|
.option('--k3s', 'Flag to indicate K3s cluster type context')
|
|
397
436
|
.option('--force', 'Forces operation, overriding any warnings or conflicts.')
|
|
@@ -399,7 +438,9 @@ program
|
|
|
399
438
|
.option('--reset', 'Resets the runner state before execution.')
|
|
400
439
|
.option('--terminal', 'Enables terminal mode for interactive script execution.')
|
|
401
440
|
.option('--dev-proxy-port-offset <port-offset>', 'Sets a custom port offset for development proxy.')
|
|
441
|
+
.option('--host-network', 'Enables host network mode for the runner execution.')
|
|
402
442
|
.option('--conf-server-path <conf-server-path>', 'Sets a custom configuration server path.')
|
|
443
|
+
.option('--underpost-root <underpost-root>', 'Sets a custom Underpost root path.')
|
|
403
444
|
.description('Runs a script from the specified path.')
|
|
404
445
|
.action(UnderpostRun.API.callback);
|
|
405
446
|
|
package/src/cli/monitor.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
164
|
+
shellExec(
|
|
165
|
+
`sudo kubectl rollout restart deployment/${deployId}-${env}-${traffic} -n ${namespace}`,
|
|
166
|
+
);
|
|
161
167
|
|
|
162
168
|
switchTraffic();
|
|
163
169
|
}
|
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));
|
|
@@ -167,7 +179,7 @@ class UnderpostRepository {
|
|
|
167
179
|
return;
|
|
168
180
|
}
|
|
169
181
|
if (options.info) return logger.info('', commitData);
|
|
170
|
-
const _message = `${commitType}${subModule ? `(${subModule})` : ''}
|
|
182
|
+
const _message = `${commitType}${subModule ? `(${subModule})` : ''}: ${
|
|
171
183
|
commitData[commitType].emoji
|
|
172
184
|
} ${message ? message : commitData[commitType].description}`;
|
|
173
185
|
if (options.copy) return pbcopy(_message);
|