underpost 2.89.45 → 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.
@@ -431,21 +432,39 @@ EOF`);
431
432
  if (options.status === true) {
432
433
  for (const _deployId of deployList.split(',')) {
433
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
+ }
434
452
  logger.info('', {
435
453
  deployId,
436
454
  env,
437
- traffic: UnderpostDeploy.API.getCurrentTraffic(deployId),
455
+ traffic: UnderpostDeploy.API.getCurrentTraffic(deployId, { namespace }),
438
456
  router: await UnderpostDeploy.API.routerFactory(deployId, env),
439
457
  pods: await UnderpostDeploy.API.get(deployId),
458
+ instances,
440
459
  });
441
460
  }
442
461
  const interfaceName = Dns.getDefaultNetworkInterface();
443
462
  logger.info('Machine', {
444
- node: os.hostname(),
463
+ hostname: os.hostname(),
445
464
  arch: UnderpostBaremetal.API.getHostArch(),
446
465
  ipv4Public: await Dns.getPublicIp(),
447
466
  ipv4Local: getLocalIPv4Address(),
448
- resources: UnderpostCluster.API.getResourcesCapacity(),
467
+ resources: UnderpostCluster.API.getResourcesCapacity(options.node),
449
468
  defaultInterfaceName: interfaceName,
450
469
  defaultInterfaceInfo: os.networkInterfaces()[interfaceName],
451
470
  });
@@ -453,7 +472,10 @@ EOF`);
453
472
  }
454
473
  if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
455
474
  if (!options.replicas) options.replicas = 1;
456
- if (options.sync) UnderpostDeploy.API.sync(deployList, options);
475
+ if (options.sync)
476
+ getDataDeploy({
477
+ buildSingleReplica: true,
478
+ });
457
479
  if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
458
480
  if (options.infoRouter === true || options.buildManifest === true) {
459
481
  logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
@@ -496,24 +518,15 @@ EOF`);
496
518
  shellExec(
497
519
  `sudo kubectl delete deployment ${deployId}-${env}-${version} -n ${namespace} --ignore-not-found`,
498
520
  );
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
- }
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
+ });
517
530
  }
518
531
 
519
532
  for (const host of Object.keys(confServer)) {
@@ -592,24 +605,7 @@ EOF
592
605
 
593
606
  return result;
594
607
  },
595
- /**
596
- * Retrieves the resources factory for a deployment.
597
- * @returns {object} - Object containing the resources factory for the deployment.
598
- * @memberof UnderpostDeploy
599
- */
600
- resourcesFactory() {
601
- return {
602
- requests: {
603
- memory: UnderpostRootEnv.API.get('resources.requests.memory'),
604
- cpu: UnderpostRootEnv.API.get('resources.requests.cpu'),
605
- },
606
- limits: {
607
- memory: UnderpostRootEnv.API.get('resources.limits.memory'),
608
- cpu: UnderpostRootEnv.API.get('resources.limits.cpu'),
609
- },
610
- totalPods: UnderpostRootEnv.API.get('total-pods'),
611
- };
612
- },
608
+
613
609
  /**
614
610
  * Checks if a container file exists in a pod.
615
611
  * @param {object} options - Options for the check.
@@ -706,6 +702,60 @@ EOF
706
702
  shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml -n ${namespace}`);
707
703
  },
708
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
+
709
759
  /**
710
760
  * Creates volume mounts and volumes for a deployment.
711
761
  * @param {Array<volume>} volumes - List of volume configurations.
@@ -838,19 +888,32 @@ ${renderHosts}`,
838
888
  * @param {string} env - Environment for which the ready status is being monitored.
839
889
  * @param {string} targetTraffic - Target traffic status for the deployment.
840
890
  * @param {Array<string>} ignorePods - List of pod names to ignore.
891
+ * @returns {object} - Object containing the ready status of the deployment.
841
892
  * @memberof UnderpostDeploy
842
893
  */
843
894
  async monitorReadyRunner(deployId, env, targetTraffic, ignorePods = []) {
844
895
  let checkStatusIteration = 0;
845
896
  const checkStatusIterationMsDelay = 1000;
897
+ const maxIterations = 500;
846
898
  const iteratorTag = `[${deployId}-${env}-${targetTraffic}]`;
847
899
  logger.info('Deployment init', { deployId, env, targetTraffic, checkStatusIterationMsDelay });
848
900
  const minReadyOk = 3;
849
901
  let readyOk = 0;
902
+ let result = {
903
+ ready: false,
904
+ notReadyPods: [],
905
+ readyPods: [],
906
+ };
850
907
 
851
908
  while (readyOk < minReadyOk) {
852
- const ready = UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready;
853
- 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) {
854
917
  readyOk++;
855
918
  logger.info(`${iteratorTag} | Deployment ready. Verification number: ${readyOk}`);
856
919
  }
@@ -861,6 +924,7 @@ ${renderHosts}`,
861
924
  );
862
925
  }
863
926
  logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
927
+ return result;
864
928
  },
865
929
 
866
930
  /**
@@ -915,6 +979,106 @@ ${renderHosts}`,
915
979
  }
916
980
  return result;
917
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
+ },
918
1082
  };
919
1083
  }
920
1084
 
package/src/cli/index.js CHANGED
@@ -177,8 +177,6 @@ program
177
177
  )
178
178
  .option('--dev', 'Initializes a development-specific cluster configuration.')
179
179
  .option('--list-pods', 'Displays detailed information about all pods.')
180
- .option('--info-capacity', 'Displays the current total machine capacity information.')
181
- .option('--info-capacity-pod', 'Displays the current machine capacity information per pod.')
182
180
  .option('--pull-image', 'Sets an optional associated image to pull during initialization.')
183
181
  .option('--init-host', 'Installs necessary Kubernetes node CLI tools (e.g., kind, kubeadm, docker, podman, helm).')
184
182
  .option('--uninstall-host', 'Uninstalls all host components installed by init-host.')
@@ -439,6 +437,16 @@ program
439
437
  .option('--terminal', 'Enables terminal mode for interactive script execution.')
440
438
  .option('--dev-proxy-port-offset <port-offset>', 'Sets a custom port offset for development proxy.')
441
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.')
442
450
  .option('--conf-server-path <conf-server-path>', 'Sets a custom configuration server path.')
443
451
  .option('--underpost-root <underpost-root>', 'Sets a custom Underpost root path.')
444
452
  .description('Runs a script from the specified path.')
@@ -75,7 +75,7 @@ class UnderpostMonitor {
75
75
 
76
76
  let errorPayloads = [];
77
77
  if (options.sync === true) {
78
- const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
78
+ const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId, { namespace: options.namespace });
79
79
  if (currentTraffic) UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, currentTraffic);
80
80
  }
81
81
  let traffic = UnderpostRootEnv.API.get(`${deployId}-${env}-traffic`) ?? 'blue';