From ee89dd69cf287056b0af08696c57b935fadeaac0 Mon Sep 17 00:00:00 2001 From: Anmol Date: Fri, 8 Nov 2024 15:31:49 +0530 Subject: [PATCH] feature: add `waitForPodsTerminating` on stop command, update related cli and test (#586) * add waitForPodsTerminating on stop command, update related cli and test * run lint fixes --- clients/js/packages/cli/src/index.ts | 5 +- clients/js/packages/cli/src/utils.ts | 3 +- .../__snapshots__/client.config.test.ts.snap | 9 +- .../__snapshots__/client.ports.test.ts.snap | 9 +- .../__snapshots__/client.test.ts.snap | 9 +- clients/js/packages/client/src/client.ts | 92 ++++++++++++++----- 6 files changed, 94 insertions(+), 33 deletions(-) diff --git a/clients/js/packages/cli/src/index.ts b/clients/js/packages/cli/src/index.ts index 0253a25ab..642b0b507 100755 --- a/clients/js/packages/cli/src/index.ts +++ b/clients/js/packages/cli/src/index.ts @@ -104,7 +104,10 @@ async function main() { client.stopPortForward(); break; case 'stop': - client.stop(); + client.stop().catch((err: any) => { + console.error('An error occurred during stop:', err); + process.exit(1); + }); break; case 'undeploy': client.deleteHelm(); diff --git a/clients/js/packages/cli/src/utils.ts b/clients/js/packages/cli/src/utils.ts index 5d543bc24..c65128f8c 100644 --- a/clients/js/packages/cli/src/utils.ts +++ b/clients/js/packages/cli/src/utils.ts @@ -43,7 +43,6 @@ export const params: string[] = [ ]; export const loadConfig = (argv: any): Config => { - console.log('argv: ', argv); const context: StarshipContext = { ...defaultStarshipContext } as StarshipContext; @@ -52,7 +51,7 @@ export const loadConfig = (argv: any): Config => { // Override context with command-line arguments dynamically based on StarshipContext keys params.forEach((key) => { if (argv[key] !== undefined) { - console.log('key: ', key, ' argv[key]: ', argv[key]); + console.log('argv:', key, ':', argv[key]); // @ts-expect-error - dynamic assignment context[key] = argv[key]; } diff --git a/clients/js/packages/client/__tests__/__snapshots__/client.config.test.ts.snap b/clients/js/packages/client/__tests__/__snapshots__/client.config.test.ts.snap index 5c8d17f99..0a3255e30 100644 --- a/clients/js/packages/client/__tests__/__snapshots__/client.config.test.ts.snap +++ b/clients/js/packages/client/__tests__/__snapshots__/client.config.test.ts.snap @@ -39,7 +39,10 @@ Call: stop() Log: Trying to stop all port-forward, if any.... ps -ef | grep -i 'kubectl port-forward' | grep -v 'grep' | awk '{print $2}' sleep 2 -helm delete osmojs" +kubectl get pods --no-headers -o custom-columns=:metadata.name +helm delete osmojs +kubectl get pods --no-headers -o custom-columns=:metadata.name +Log: All pods have been sucessfully terminated!" `; exports[`StarshipClient setup 2`] = ` @@ -59,5 +62,7 @@ kubectl port-forward service/registry 8081:8080 > /dev/null 2>&1 & kubectl port-forward service/registry 9091:9090 > /dev/null 2>&1 & ps -ef | grep -i 'kubectl port-forward' | grep -v 'grep' | awk '{print $2}' sleep 2 -helm delete osmojs" +kubectl get pods --no-headers -o custom-columns=:metadata.name +helm delete osmojs +kubectl get pods --no-headers -o custom-columns=:metadata.name" `; diff --git a/clients/js/packages/client/__tests__/__snapshots__/client.ports.test.ts.snap b/clients/js/packages/client/__tests__/__snapshots__/client.ports.test.ts.snap index fe3ed3207..888308a16 100644 --- a/clients/js/packages/client/__tests__/__snapshots__/client.ports.test.ts.snap +++ b/clients/js/packages/client/__tests__/__snapshots__/client.ports.test.ts.snap @@ -37,7 +37,10 @@ Call: stop() Log: Trying to stop all port-forward, if any.... ps -ef | grep -i 'kubectl port-forward' | grep -v 'grep' | awk '{print $2}' sleep 2 -helm delete osmojs" +kubectl get pods --no-headers -o custom-columns=:metadata.name +helm delete osmojs +kubectl get pods --no-headers -o custom-columns=:metadata.name +Log: All pods have been sucessfully terminated!" `; exports[`StarshipClient setup 2`] = ` @@ -56,5 +59,7 @@ kubectl port-forward service/registry 8081:8080 > /dev/null 2>&1 & kubectl port-forward service/registry 9091:9090 > /dev/null 2>&1 & ps -ef | grep -i 'kubectl port-forward' | grep -v 'grep' | awk '{print $2}' sleep 2 -helm delete osmojs" +kubectl get pods --no-headers -o custom-columns=:metadata.name +helm delete osmojs +kubectl get pods --no-headers -o custom-columns=:metadata.name" `; diff --git a/clients/js/packages/client/__tests__/__snapshots__/client.test.ts.snap b/clients/js/packages/client/__tests__/__snapshots__/client.test.ts.snap index 05e282839..c5ee0b792 100644 --- a/clients/js/packages/client/__tests__/__snapshots__/client.test.ts.snap +++ b/clients/js/packages/client/__tests__/__snapshots__/client.test.ts.snap @@ -37,7 +37,10 @@ Call: stop() Log: Trying to stop all port-forward, if any.... ps -ef | grep -i 'kubectl port-forward' | grep -v 'grep' | awk '{print $2}' sleep 2 -helm delete osmojs" +kubectl get pods --no-headers -o custom-columns=:metadata.name +helm delete osmojs +kubectl get pods --no-headers -o custom-columns=:metadata.name +Log: All pods have been sucessfully terminated!" `; exports[`StarshipClient setup 2`] = ` @@ -57,5 +60,7 @@ kubectl port-forward service/registry 8081:8080 > /dev/null 2>&1 & kubectl port-forward service/registry 9091:9090 > /dev/null 2>&1 & ps -ef | grep -i 'kubectl port-forward' | grep -v 'grep' | awk '{print $2}' sleep 2 -helm delete osmojs" +kubectl get pods --no-headers -o custom-columns=:metadata.name +helm delete osmojs +kubectl get pods --no-headers -o custom-columns=:metadata.name" `; diff --git a/clients/js/packages/client/src/client.ts b/clients/js/packages/client/src/client.ts index 60e9e44f0..1a9a89b21 100644 --- a/clients/js/packages/client/src/client.ts +++ b/clients/js/packages/client/src/client.ts @@ -343,9 +343,11 @@ export class StarshipClient implements StarshipClientI { ]); } - public stop(): void { + public async stop(): Promise { this.stopPortForward(); + this.setPodStatues(); // set pod statues before deleting the helm this.deleteHelm(); + await this.waitForPodsTermination(); } public async start(): Promise { @@ -495,7 +497,7 @@ export class StarshipClient implements StarshipClientI { return allRunning; } - private checkPodStatus(podName: string): void { + private checkPodStatus(podName: string, exitEarly: boolean = true): void { const result = this.exec( [ 'kubectl', @@ -537,7 +539,7 @@ export class StarshipClient implements StarshipClientI { .reduce((acc, count) => acc + parseInt(count, 10), 0); // check for repeated image pull errors - this.checkImagePullFailures(podName); + this.checkImagePullFailures(podName, exitEarly); this.podStatuses.set(podName, { phase, @@ -550,10 +552,18 @@ export class StarshipClient implements StarshipClientI { this.log( `${chalk.red('Error:')} Pod ${podName} has restarted more than ${this.ctx.restartThreshold} times.` ); - this.exit(1); + if (exitEarly) this.exit(1); } } + private setPodStatues(): void { + const podNames = this.getPodNames(); + + podNames.forEach((podName) => { + this.checkPodStatus(podName, false); // set exitEarly to false, only set the this.PodStatuses + }); + } + public async waitForPods(): Promise { const podNames = this.getPodNames(); @@ -581,6 +591,34 @@ export class StarshipClient implements StarshipClientI { } } + public async waitForPodsTermination(): Promise { + const podNames = this.getPodNames(); + + // Remove pods that are no longer active from the podStatuses map + this.podStatuses.forEach((_value, podName) => { + if (!podNames.includes(podName)) { + this.podStatuses.delete(podName); + } + }); + + if (this.podStatuses.size === 0) { + this.log(chalk.green('All pods have been sucessfully terminated!')); + // once the pods are in done state, wait for 1 more seconds + await new Promise((resolve) => setTimeout(resolve, 1000)); + return; + } + + // Check the status of each pod to terminating + podNames.forEach((podName) => { + const podStatus = this.podStatuses.get(podName); + podStatus.phase = 'Terminating'; + }); + this.displayPodStatuses(); + + await new Promise((resolve) => setTimeout(resolve, 2500)); + await this.waitForPodsTermination(); // Recursive call + } + private displayPodStatuses(): void { console.clear(); this.podStatuses.forEach((status, podName) => { @@ -590,7 +628,7 @@ export class StarshipClient implements StarshipClientI { } else if (status.phase === 'Running' && !status.ready) { statusColor = chalk.yellow('RunningButNotReady'); } else if (status.phase === 'Terminating') { - statusColor = chalk.gray(status.phase); + statusColor = chalk.red(status.phase); } else { statusColor = chalk.red(status.phase); } @@ -601,7 +639,10 @@ export class StarshipClient implements StarshipClientI { }); } - public checkImagePullFailures(podName: string): void { + public checkImagePullFailures( + podName: string, + exitEarly: boolean = true + ): void { // Fetch events from kubectl describe for the given pod const eventLines = this.getPodEventsFromDescribe(podName); const errorPattern = /Failed to pull image/; @@ -631,7 +672,7 @@ export class StarshipClient implements StarshipClientI { ` )}` ); - this.exit(1); + if (exitEarly) this.exit(1); } }); } @@ -840,21 +881,24 @@ export class StarshipClient implements StarshipClientI { } private getForwardPids(): string[] { - const result = this.exec([ - 'ps', - '-ef', - '|', - 'grep', - '-i', - "'kubectl port-forward'", - '|', - 'grep', - '-v', - "'grep'", - '|', - 'awk', - "'{print $2}'" - ]); + const result = this.exec( + [ + 'ps', + '-ef', + '|', + 'grep', + '-i', + "'kubectl port-forward'", + '|', + 'grep', + '-v', + "'grep'", + '|', + 'awk', + "'{print $2}'" + ], + { log: false, silent: true } + ); const pids = (result || '') .split('\n') .map((pid) => pid.trim()) @@ -866,9 +910,9 @@ export class StarshipClient implements StarshipClientI { this.log(chalk.green('Trying to stop all port-forward, if any....')); const pids = this.getForwardPids(); pids.forEach((pid) => { - this.exec(['kill', '-15', pid]); + this.exec(['kill', '-15', pid], { log: false, silent: true }); }); - this.exec(['sleep', '2']); + this.exec(['sleep', '2'], { log: false, silent: true }); } public printForwardPids(): void {