underpost 2.89.44 → 2.90.0

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/src/cli/deploy.js CHANGED
@@ -37,36 +37,6 @@ const logger = loggerFactory(import.meta);
37
37
  class UnderpostDeploy {
38
38
  static NETWORK = {};
39
39
  static API = {
40
- /**
41
- * Synchronizes deployment configurations for a list of deployments.
42
- * @param {string} deployList - List of deployment IDs to synchronize.
43
- * @param {object} options - Options for the synchronization process.
44
- * @param {string} options.versions - Comma-separated list of versions to deploy.
45
- * @param {string} options.replicas - Number of replicas for each deployment.
46
- * @param {string} options.node - Node name for resource allocation.
47
- * @returns {object} - Deployment data for the specified deployments.
48
- * @memberof UnderpostDeploy
49
- */
50
- sync(deployList, { versions, replicas, node }) {
51
- fs.writeFileSync(`./engine-private/deploy/dd.router`, deployList, 'utf8');
52
- const totalPods = deployList.split(',').length * versions.split(',').length * parseInt(replicas);
53
- const limitFactor = 0.8;
54
- const reserveFactor = 0.05;
55
- const resources = UnderpostCluster.API.getResourcesCapacity(node);
56
- const memory = parseInt(resources.memory.value / totalPods);
57
- const cpu = parseInt(resources.cpu.value / totalPods);
58
- UnderpostRootEnv.API.set(
59
- 'resources.requests.memory',
60
- `${parseInt(memory * reserveFactor)}${resources.memory.unit}`,
61
- );
62
- UnderpostRootEnv.API.set('resources.requests.cpu', `${parseInt(cpu * reserveFactor)}${resources.cpu.unit}`);
63
- UnderpostRootEnv.API.set('resources.limits.memory', `${parseInt(memory * limitFactor)}${resources.memory.unit}`);
64
- UnderpostRootEnv.API.set('resources.limits.cpu', `${parseInt(cpu * limitFactor)}${resources.cpu.unit}`);
65
- UnderpostRootEnv.API.set('total-pods', totalPods);
66
- return getDataDeploy({
67
- buildSingleReplica: true,
68
- });
69
- },
70
40
  /**
71
41
  * Creates a router configuration for a list of deployments.
72
42
  * @param {string} deployList - List of deployment IDs to include in the router.
@@ -130,18 +100,28 @@ class UnderpostDeploy {
130
100
  * @param {number} replicas - Number of replicas for the deployment.
131
101
  * @param {string} image - Docker image for the deployment.
132
102
  * @param {string} namespace - Kubernetes namespace for the deployment.
103
+ * @param {Array<object>} volumes - Volume configurations for the deployment.
104
+ * @param {Array<string>} cmd - Command to run in the deployment container.
133
105
  * @returns {string} - YAML deployment configuration for the specified deployment.
134
106
  * @memberof UnderpostDeploy
135
107
  */
136
- deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image, namespace }) {
108
+ deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image, namespace, volumes, cmd }) {
109
+ if (!cmd)
110
+ cmd = [
111
+ `npm install -g npm@11.2.0`,
112
+ `npm install -g underpost`,
113
+ `underpost secret underpost --create-from-file /etc/config/.env.${env}`,
114
+ `underpost start --build --run ${deployId} ${env}`,
115
+ ];
137
116
  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
- ];
117
+ if (!volumes)
118
+ volumes = [
119
+ {
120
+ volumeMountPath: '/etc/config',
121
+ volumeName: 'config-volume',
122
+ configMap: 'underpost-config',
123
+ },
124
+ ];
145
125
  const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
146
126
  ? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
147
127
  : [];
@@ -166,21 +146,23 @@ spec:
166
146
  containers:
167
147
  - name: ${deployId}-${env}-${suffix}
168
148
  image: ${image ?? `localhost/rockylinux9-underpost:v${packageJson.version}`}
169
- # resources:
170
- # requests:
171
- # memory: "${resources.requests.memory}"
172
- # cpu: "${resources.requests.cpu}"
173
- # limits:
174
- # memory: "${resources.limits.memory}"
175
- # cpu: "${resources.limits.cpu}"
149
+ ${
150
+ resources
151
+ ? ` resources:
152
+ requests:
153
+ memory: "${resources.requests.memory}"
154
+ cpu: "${resources.requests.cpu}"
155
+ limits:
156
+ memory: "${resources.limits.memory}"
157
+ cpu: "${resources.limits.cpu}"`
158
+ : ''
159
+ }
176
160
  command:
177
161
  - /bin/sh
178
162
  - -c
179
163
  - >
180
- npm install -g npm@11.2.0 &&
181
- npm install -g underpost &&
182
- underpost secret underpost --create-from-file /etc/config/.env.${env} &&
183
- underpost start --build --run ${deployId} ${env}
164
+ ${cmd.join(` && `)}
165
+
184
166
  ${UnderpostDeploy.API.volumeFactory(volumes.map((v) => ((v.version = `${deployId}-${env}-${suffix}`), v)))
185
167
  .render.split(`\n`)
186
168
  .map((l) => ' ' + l)
@@ -209,7 +191,6 @@ spec:
209
191
  * @memberof UnderpostDeploy
210
192
  */
211
193
  async buildManifest(deployList, env, options) {
212
- const resources = UnderpostDeploy.API.resourcesFactory();
213
194
  const replicas = options.replicas;
214
195
  const image = options.image;
215
196
  if (!options.namespace) options.namespace = 'default';
@@ -237,7 +218,6 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
237
218
  deployId,
238
219
  env,
239
220
  suffix: deploymentVersion,
240
- resources,
241
221
  replicas,
242
222
  image,
243
223
  namespace: options.namespace,
@@ -253,27 +233,12 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
253
233
  : [];
254
234
 
255
235
  for (const host of Object.keys(confServer)) {
256
- if (env === 'production') secretYaml += UnderpostDeploy.API.buildCertManagerCertificate({ host });
236
+ if (env === 'production')
237
+ secretYaml += UnderpostDeploy.API.buildCertManagerCertificate({ host, namespace: options.namespace });
257
238
 
258
239
  const pathPortAssignment = pathPortAssignmentData[host];
259
240
  // logger.info('', { host, pathPortAssignment });
260
- let _proxyYaml = `
261
- ---
262
- apiVersion: projectcontour.io/v1
263
- kind: HTTPProxy
264
- metadata:
265
- name: ${host}
266
- namespace: ${options.namespace}
267
- spec:
268
- virtualhost:
269
- fqdn: ${host}${
270
- env === 'development'
271
- ? ''
272
- : `
273
- tls:
274
- secretName: ${host}`
275
- }
276
- routes:`;
241
+ let _proxyYaml = UnderpostDeploy.API.baseProxyYamlFactory({ host, env, options });
277
242
  const deploymentVersions =
278
243
  options.traffic && typeof options.traffic === 'string' ? options.traffic.split(',') : ['blue'];
279
244
  let proxyRoutes = '';
@@ -347,18 +312,54 @@ spec:
347
312
  /**
348
313
  * Retrieves the current traffic status for a deployment.
349
314
  * @param {string} deployId - Deployment ID for which the traffic status is being retrieved.
315
+ * @param {object} options - Options for the traffic retrieval.
316
+ * @param {string} options.hostTest - Hostname to test for traffic status.
317
+ * @param {string} options.namespace - Kubernetes namespace for the deployment.
350
318
  * @returns {string|null} - Current traffic status ('blue' or 'green') or null if not found.
351
319
  * @memberof UnderpostDeploy
352
320
  */
353
- getCurrentTraffic(deployId) {
321
+ getCurrentTraffic(deployId, options = { hostTest: '', namespace: '' }) {
322
+ if (!options.namespace) options.namespace = 'default';
354
323
  // kubectl get deploy,sts,svc,configmap,secret -n default -o yaml --export > default.yaml
355
- const hostTest = Object.keys(
356
- JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
357
- )[0];
358
- const info = shellExec(`sudo kubectl get HTTPProxy/${hostTest} -o yaml`, { silent: true, stdout: true });
324
+ const hostTest = options?.hostTest
325
+ ? options.hostTest
326
+ : Object.keys(JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')))[0];
327
+ const info = shellExec(`sudo kubectl get HTTPProxy/${hostTest} -n ${options.namespace} -o yaml`, {
328
+ silent: true,
329
+ stdout: true,
330
+ });
359
331
  return info.match('blue') ? 'blue' : info.match('green') ? 'green' : null;
360
332
  },
361
333
 
334
+ /**
335
+ * Creates a base YAML configuration for an HTTPProxy resource.
336
+ * @param {string} host - Hostname for which the HTTPProxy is being created.
337
+ * @param {string} env - Environment for which the HTTPProxy is being created.
338
+ * @param {object} options - Options for the HTTPProxy creation.
339
+ * @param {string} options.namespace - Kubernetes namespace for the HTTPProxy.
340
+ * @returns {string} - Base YAML configuration for the HTTPProxy resource.
341
+ * @memberof UnderpostDeploy
342
+ */
343
+ baseProxyYamlFactory({ host, env, options }) {
344
+ return `
345
+ ---
346
+ apiVersion: projectcontour.io/v1
347
+ kind: HTTPProxy
348
+ metadata:
349
+ name: ${host}
350
+ namespace: ${options.namespace}
351
+ spec:
352
+ virtualhost:
353
+ fqdn: ${host}${
354
+ env === 'development'
355
+ ? ''
356
+ : `
357
+ tls:
358
+ secretName: ${host}`
359
+ }
360
+ routes:`;
361
+ },
362
+
362
363
  /**
363
364
  * Callback function for handling deployment options.
364
365
  * @param {string} deployList - List of deployment IDs to process.
@@ -417,68 +418,6 @@ spec:
417
418
  namespace: '',
418
419
  },
419
420
  ) {
420
- if (options.infoUtil === true)
421
- return logger.info(`
422
- kubectl rollout restart deployment/deployment-name
423
- kubectl rollout undo deployment/deployment-name
424
- kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
425
- kubectl get pods -w
426
- kubectl patch statefulset valkey-service --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"valkey/valkey:latest"}]'
427
- kubectl patch statefulset valkey-service -p '{"spec":{"template":{"spec":{"containers":[{"name":"valkey-service","imagePullPolicy":"Never"}]}}}}'
428
- kubectl logs -f <pod-name>
429
- kubectl describe pod <pod-name>
430
- kubectl exec -it <pod-name> -- bash
431
- kubectl exec -it <pod-name> -- sh
432
- docker exec -it kind-control-plane bash
433
- curl -4 -v google.com
434
- kubectl taint nodes <node-name> node-role.kubernetes.io/control-plane:NoSchedule-
435
- kubectl run test-pod --image=busybox:latest --restart=Never -- /bin/sh -c "while true; do sleep 30; done;"
436
- kubectl run test-pod --image=alpine/curl:latest --restart=Never -- sh -c "sleep infinity"
437
- kubectl get ippools -o yaml
438
- kubectl get node <node-name> -o jsonpath='{.spec.podCIDR}'
439
- kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "10.244.0.0/16"}]'
440
- kubectl patch ippool default-ipv4-ippool --type='json' -p='[{"op": "replace", "path": "/spec/cidr", "value": "192.168.0.0/24"}]'
441
- sudo podman run --rm localhost/<image-name>:<image-version> <command>
442
- kubectl get configmap kubelet-config -n kube-system -o yaml > kubelet-config.yaml
443
- kubectl -n kube-system rollout restart daemonset kube-proxy
444
- kubectl get EndpointSlice -o wide --all-namespaces -w
445
- kubectl apply -k manifests/deployment/adminer/.
446
- kubectl wait --for=condition=Ready pod/busybox1
447
- kubectl wait --for=jsonpath='{.status.phase}'=Running pod/busybox1
448
- kubectl wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' pod/busybox1
449
- kubectl wait --for=delete pod/busybox1 --timeout=60s
450
-
451
- node bin run cluster-build
452
- node bin run template-deploy
453
- node bin run ssh-deploy (sync-)engine-core
454
- node bin run cluster --dev 'express,dd-test+dd-core'
455
- node bin run dd-container --dev
456
- node bin run promote dd-default production
457
- node bin dockerfile-pull-base-images --dev --path 'image-path' --kind-load
458
- node bin/deploy update-default-conf <deploy-id>
459
-
460
- fqdn: <service>.<namespace>.<kind(svc/pod)>.<cluster-domain(cluster.local)>
461
- kubectl run --rm -it test-dns --image=busybox:latest --restart=Never -- /bin/sh -c "
462
- nslookup kubernetes.default.svc.cluster.local;
463
- nslookup mongodb-service.default.svc.cluster.local;
464
- nslookup valkey-service.default.svc.cluster.local;
465
- nc -vz mongodb-service 27017;
466
- nc -vz valkey-service 6379;
467
- echo exit code: \\\$?
468
- "
469
-
470
- kubectl apply -f - <<EOF
471
- apiVersion: apps/v1
472
- kind: StatefulSet
473
- metadata:
474
- name: ...
475
- EOF
476
-
477
- https://org.ngc.nvidia.com/setup/api-keys
478
- docker login nvcr.io
479
- Username: $oauthtoken
480
- Password: <Your Key>
481
- `);
482
421
  const namespace = options.namespace ? options.namespace : 'default';
483
422
  if (!deployList && options.certHosts) {
484
423
  for (const host of options.certHosts.split(',')) {
@@ -493,21 +432,39 @@ EOF`);
493
432
  if (options.status === true) {
494
433
  for (const _deployId of deployList.split(',')) {
495
434
  const deployId = _deployId.trim();
435
+ const instances = [];
436
+ if (fs.existsSync(`./engine-private/conf/${deployId}/conf.instances.json`)) {
437
+ const confInstances = JSON.parse(
438
+ fs.readFileSync(`./engine-private/conf/${deployId}/conf.instances.json`, 'utf8'),
439
+ );
440
+ for (const instance of confInstances) {
441
+ const _deployId = `${deployId}-${instance.id}`;
442
+ instances.push({
443
+ id: instance.id,
444
+ host: instance.host,
445
+ path: instance.path,
446
+ fromPort: instance.fromPort,
447
+ toPort: instance.toPort,
448
+ traffic: UnderpostDeploy.API.getCurrentTraffic(_deployId, { namespace, hostTest: instance.host }),
449
+ });
450
+ }
451
+ }
496
452
  logger.info('', {
497
453
  deployId,
498
454
  env,
499
- traffic: UnderpostDeploy.API.getCurrentTraffic(deployId),
455
+ traffic: UnderpostDeploy.API.getCurrentTraffic(deployId, { namespace }),
500
456
  router: await UnderpostDeploy.API.routerFactory(deployId, env),
501
457
  pods: await UnderpostDeploy.API.get(deployId),
458
+ instances,
502
459
  });
503
460
  }
504
461
  const interfaceName = Dns.getDefaultNetworkInterface();
505
462
  logger.info('Machine', {
506
- node: os.hostname(),
463
+ hostname: os.hostname(),
507
464
  arch: UnderpostBaremetal.API.getHostArch(),
508
465
  ipv4Public: await Dns.getPublicIp(),
509
466
  ipv4Local: getLocalIPv4Address(),
510
- resources: UnderpostCluster.API.getResourcesCapacity(),
467
+ resources: UnderpostCluster.API.getResourcesCapacity(options.node),
511
468
  defaultInterfaceName: interfaceName,
512
469
  defaultInterfaceInfo: os.networkInterfaces()[interfaceName],
513
470
  });
@@ -515,7 +472,10 @@ EOF`);
515
472
  }
516
473
  if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
517
474
  if (!options.replicas) options.replicas = 1;
518
- if (options.sync) UnderpostDeploy.API.sync(deployList, options);
475
+ if (options.sync)
476
+ getDataDeploy({
477
+ buildSingleReplica: true,
478
+ });
519
479
  if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
520
480
  if (options.infoRouter === true || options.buildManifest === true) {
521
481
  logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
@@ -558,24 +518,15 @@ EOF`);
558
518
  shellExec(
559
519
  `sudo kubectl delete deployment ${deployId}-${env}-${version} -n ${namespace} --ignore-not-found`,
560
520
  );
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
571
- ${UnderpostDeploy.API.persistentVolumeFactory({
572
- hostPath: rootVolumeHostPath,
573
- pvcId,
574
- })}
575
- EOF
576
- `);
577
- }
578
- }
521
+ if (!options.disableUpdateVolume)
522
+ for (const volume of confVolume)
523
+ UnderpostDeploy.API.deployVolume(volume, {
524
+ deployId,
525
+ env,
526
+ version,
527
+ namespace,
528
+ nodeName: options.node ? options.node : env === 'development' ? 'kind-worker' : os.hostname(),
529
+ });
579
530
  }
580
531
 
581
532
  for (const host of Object.keys(confServer)) {
@@ -654,24 +605,7 @@ EOF
654
605
 
655
606
  return result;
656
607
  },
657
- /**
658
- * Retrieves the resources factory for a deployment.
659
- * @returns {object} - Object containing the resources factory for the deployment.
660
- * @memberof UnderpostDeploy
661
- */
662
- resourcesFactory() {
663
- return {
664
- requests: {
665
- memory: UnderpostRootEnv.API.get('resources.requests.memory'),
666
- cpu: UnderpostRootEnv.API.get('resources.requests.cpu'),
667
- },
668
- limits: {
669
- memory: UnderpostRootEnv.API.get('resources.limits.memory'),
670
- cpu: UnderpostRootEnv.API.get('resources.limits.cpu'),
671
- },
672
- totalPods: UnderpostRootEnv.API.get('total-pods'),
673
- };
674
- },
608
+
675
609
  /**
676
610
  * Checks if a container file exists in a pod.
677
611
  * @param {object} options - Options for the check.
@@ -768,6 +702,60 @@ EOF
768
702
  shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml -n ${namespace}`);
769
703
  },
770
704
 
705
+ /**
706
+ * Deploys a volume for a deployment.
707
+ * @param {object} volume - Volume configuration.
708
+ * @param {string} volume.claimName - Name of the persistent volume claim.
709
+ * @param {string} volume.volumeMountPath - Mount path of the volume in the container.
710
+ * @param {string} volume.volumeName - Name of the volume.
711
+ * @param {object} options - Options for the volume deployment.
712
+ * @param {string} options.deployId - Deployment ID.
713
+ * @param {string} options.env - Environment for the deployment.
714
+ * @param {string} options.version - Version of the deployment.
715
+ * @param {string} options.namespace - Kubernetes namespace for the deployment.
716
+ * @param {string} options.nodeName - Node name for the deployment.
717
+ * @memberof UnderpostDeploy
718
+ */
719
+ deployVolume(
720
+ volume = { claimName: '', volumeMountPath: '', volumeName: '' },
721
+ options = {
722
+ deployId: '',
723
+ env: '',
724
+ version: '',
725
+ namespace: '',
726
+ nodeName: '',
727
+ },
728
+ ) {
729
+ if (!volume.claimName) {
730
+ logger.warn('Volume claimName is required to deploy volume', volume);
731
+ return;
732
+ }
733
+ const { deployId, env, version, namespace } = options;
734
+ const pvcId = `${volume.claimName}-${deployId}-${env}-${version}`;
735
+ const pvId = `${volume.claimName.replace('pvc-', 'pv-')}-${deployId}-${env}-${version}`;
736
+ const rootVolumeHostPath = `/home/dd/engine/volume/${pvId}`;
737
+ if (options.nodeName) {
738
+ if (!fs.existsSync(rootVolumeHostPath)) fs.mkdirSync(rootVolumeHostPath, { recursive: true });
739
+ fs.copySync(volume.volumeMountPath, rootVolumeHostPath);
740
+ } else {
741
+ shellExec(`docker exec -i kind-worker bash -c "mkdir -p ${rootVolumeHostPath}"`);
742
+ // shellExec(`docker cp ${volume.volumeMountPath} kind-worker:${rootVolumeHostPath}`);
743
+ shellExec(`tar -C ${volume.volumeMountPath} -c . | docker cp - kind-worker:${rootVolumeHostPath}`);
744
+ shellExec(
745
+ `docker exec -i kind-worker bash -c "chown -R 1000:1000 ${rootVolumeHostPath} || true; chmod -R 755 ${rootVolumeHostPath}"`,
746
+ );
747
+ }
748
+ shellExec(`kubectl delete pvc ${pvcId} -n ${namespace} --ignore-not-found`);
749
+ shellExec(`kubectl delete pv ${pvId} --ignore-not-found`);
750
+ shellExec(`kubectl apply -f - -n ${namespace} <<EOF
751
+ ${UnderpostDeploy.API.persistentVolumeFactory({
752
+ hostPath: rootVolumeHostPath,
753
+ pvcId,
754
+ })}
755
+ EOF
756
+ `);
757
+ },
758
+
771
759
  /**
772
760
  * Creates volume mounts and volumes for a deployment.
773
761
  * @param {Array<volume>} volumes - List of volume configurations.
@@ -900,19 +888,32 @@ ${renderHosts}`,
900
888
  * @param {string} env - Environment for which the ready status is being monitored.
901
889
  * @param {string} targetTraffic - Target traffic status for the deployment.
902
890
  * @param {Array<string>} ignorePods - List of pod names to ignore.
891
+ * @returns {object} - Object containing the ready status of the deployment.
903
892
  * @memberof UnderpostDeploy
904
893
  */
905
894
  async monitorReadyRunner(deployId, env, targetTraffic, ignorePods = []) {
906
895
  let checkStatusIteration = 0;
907
896
  const checkStatusIterationMsDelay = 1000;
897
+ const maxIterations = 500;
908
898
  const iteratorTag = `[${deployId}-${env}-${targetTraffic}]`;
909
899
  logger.info('Deployment init', { deployId, env, targetTraffic, checkStatusIterationMsDelay });
910
900
  const minReadyOk = 3;
911
901
  let readyOk = 0;
902
+ let result = {
903
+ ready: false,
904
+ notReadyPods: [],
905
+ readyPods: [],
906
+ };
912
907
 
913
908
  while (readyOk < minReadyOk) {
914
- const ready = UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready;
915
- if (ready === true) {
909
+ if (checkStatusIteration >= maxIterations) {
910
+ logger.error(
911
+ `${iteratorTag} | Deployment check ready status timeout. Max iterations reached: ${maxIterations}`,
912
+ );
913
+ break;
914
+ }
915
+ result = UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods);
916
+ if (result.ready === true) {
916
917
  readyOk++;
917
918
  logger.info(`${iteratorTag} | Deployment ready. Verification number: ${readyOk}`);
918
919
  }
@@ -923,6 +924,7 @@ ${renderHosts}`,
923
924
  );
924
925
  }
925
926
  logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
927
+ return result;
926
928
  },
927
929
 
928
930
  /**
@@ -977,6 +979,106 @@ ${renderHosts}`,
977
979
  }
978
980
  return result;
979
981
  },
982
+
983
+ /**
984
+ * Predefined resource templates for Kubernetes deployments.
985
+ * @memberof UnderpostDeploy
986
+ */
987
+ resourcesTemplate: {
988
+ dev_small: {
989
+ id: 'dev_small',
990
+ useCase: 'microservice_development',
991
+ resources: {
992
+ requests: {
993
+ memory: '128Mi',
994
+ cpu: '250m',
995
+ },
996
+ limits: {
997
+ memory: '512Mi',
998
+ cpu: '1',
999
+ },
1000
+ },
1001
+ },
1002
+ prod_moderate: {
1003
+ id: 'prod_moderate',
1004
+ useCase: 'production_moderate',
1005
+ resources: {
1006
+ requests: {
1007
+ memory: '256Mi',
1008
+ cpu: '500m',
1009
+ },
1010
+ limits: {
1011
+ memory: '512Mi',
1012
+ cpu: '1',
1013
+ },
1014
+ },
1015
+ },
1016
+ memory_heavy: {
1017
+ id: 'memory_heavy',
1018
+ useCase: 'memory_intensive_app',
1019
+ resources: {
1020
+ requests: {
1021
+ memory: '512Mi',
1022
+ cpu: '500m',
1023
+ },
1024
+ limits: {
1025
+ memory: '1Gi',
1026
+ cpu: '1',
1027
+ },
1028
+ },
1029
+ },
1030
+ cpu_bound: {
1031
+ id: 'cpu_bound',
1032
+ useCase: 'cpu_intensive_job',
1033
+ resources: {
1034
+ requests: {
1035
+ memory: '256Mi',
1036
+ cpu: '1000m',
1037
+ },
1038
+ limits: {
1039
+ memory: '512Mi',
1040
+ cpu: '2000m',
1041
+ },
1042
+ },
1043
+ },
1044
+ },
1045
+
1046
+ /**
1047
+ * Creates a resource object for Kubernetes deployments.
1048
+ * @param {object} resources - Resource specifications.
1049
+ * @param {string} resources.requestsMemory - Memory request for the container.
1050
+ * @param {string} resources.requestsCpu - CPU request for the container.
1051
+ * @param {string} resources.limitsMemory - Memory limit for the container.
1052
+ * @param {string} resources.limitsCpu - CPU limit for the container.
1053
+ * @returns {object|undefined} - Resource object for Kubernetes deployments or undefined if any resource is missing.
1054
+ * @memberof UnderpostDeploy
1055
+ */
1056
+ resourcesFactory: (
1057
+ resources = {
1058
+ resourceTemplateId: '',
1059
+ requestsMemory: '',
1060
+ requestsCpu: '',
1061
+ limitsMemory: '',
1062
+ limitsCpu: '',
1063
+ },
1064
+ ) => {
1065
+ if (resources) {
1066
+ if (resources.resourceTemplateId)
1067
+ return UnderpostDeploy.API.resourcesTemplate[resources.resourceTemplateId].resources;
1068
+ if (resources.requestsMemory && resources.requestsCpu && resources.limitsMemory && resources.limitsCpu)
1069
+ return {
1070
+ requests: {
1071
+ memory: resources.requestsMemory,
1072
+ cpu: resources.requestsCpu,
1073
+ },
1074
+ limits: {
1075
+ memory: resources.limitsMemory,
1076
+ cpu: resources.limitsCpu,
1077
+ },
1078
+ };
1079
+ }
1080
+ return undefined;
1081
+ },
980
1082
  };
981
1083
  }
982
1084
 
package/src/cli/index.js CHANGED
@@ -156,13 +156,20 @@ program
156
156
  .option('--contour', 'Initializes the cluster with Project Contour base HTTPProxy and Envoy.')
157
157
  .option('--cert-manager', "Initializes the cluster with a Let's Encrypt production ClusterIssuer.")
158
158
  .option('--dedicated-gpu', 'Initializes the cluster with dedicated GPU base resources and environment settings.')
159
- .option('--info', 'Retrieves information about all deployed Kubernetes objects.')
160
159
  .option('--full', 'Initializes the cluster with all available statefulsets and services.')
161
160
  .option(
162
161
  '--ns-use <ns-name>',
163
162
  "Switches the current Kubernetes context to the specified namespace (creates if it doesn't exist).",
164
163
  )
165
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
+ )
166
173
  .option('--grafana', 'Initializes the cluster with a Grafana deployment.')
167
174
  .option(
168
175
  '--prom [hosts]',
@@ -170,8 +177,6 @@ program
170
177
  )
171
178
  .option('--dev', 'Initializes a development-specific cluster configuration.')
172
179
  .option('--list-pods', 'Displays detailed information about all pods.')
173
- .option('--info-capacity', 'Displays the current total machine capacity information.')
174
- .option('--info-capacity-pod', 'Displays the current machine capacity information per pod.')
175
180
  .option('--pull-image', 'Sets an optional associated image to pull during initialization.')
176
181
  .option('--init-host', 'Installs necessary Kubernetes node CLI tools (e.g., kind, kubeadm, docker, podman, helm).')
177
182
  .option('--uninstall-host', 'Uninstalls all host components installed by init-host.')
@@ -197,7 +202,6 @@ program
197
202
  .option('--sync', 'Synchronizes deployment environment variables, ports, and replica counts.')
198
203
  .option('--info-router', 'Displays the current router structure and configuration.')
199
204
  .option('--expose', 'Exposes services matching the provided deployment ID list.')
200
- .option('--info-util', 'Displays useful `kubectl` utility management commands.')
201
205
  .option('--cert', 'Resets TLS/SSL certificate secrets for deployments.')
202
206
  .option('--cert-hosts <hosts>', 'Resets TLS/SSL certificate secrets for specified hosts.')
203
207
  .option('--node <node>', 'Sets optional node for deployment operations.')
@@ -433,6 +437,16 @@ program
433
437
  .option('--terminal', 'Enables terminal mode for interactive script execution.')
434
438
  .option('--dev-proxy-port-offset <port-offset>', 'Sets a custom port offset for development proxy.')
435
439
  .option('--host-network', 'Enables host network mode for the runner execution.')
440
+ .option('--requests-memory <requests-memory>', 'Requests memory limit for the runner execution.')
441
+ .option('--requests-cpu <requests-cpu>', 'Requests CPU limit for the runner execution.')
442
+ .option('--limits-memory <limits-memory>', 'Sets memory limit for the runner execution.')
443
+ .option('--limits-cpu <limits-cpu>', 'Sets CPU limit for the runner execution.')
444
+ .option(
445
+ '--resource-template-id <resource-template-id >',
446
+ 'Specifies a resource template ID for the runner execution.',
447
+ )
448
+ .option('--etcHosts', 'Enables /etc/hosts management for the runner execution.')
449
+ .option('--expose', 'Enables service exposure for the runner execution.')
436
450
  .option('--conf-server-path <conf-server-path>', 'Sets a custom configuration server path.')
437
451
  .option('--underpost-root <underpost-root>', 'Sets a custom Underpost root path.')
438
452
  .description('Runs a script from the specified path.')