From c4a6abb86159f84279ef9fec2e9ec228640fb94a Mon Sep 17 00:00:00 2001 From: Charlie Drage Date: Wed, 21 Feb 2024 14:41:05 -0500 Subject: [PATCH] nit: improve kubernetes http error reporting (#6086) --- .../main/src/plugin/kubernetes-client.spec.ts | 34 +++++++++++++++++++ packages/main/src/plugin/kubernetes-client.ts | 10 ++++++ 2 files changed, 44 insertions(+) diff --git a/packages/main/src/plugin/kubernetes-client.spec.ts b/packages/main/src/plugin/kubernetes-client.spec.ts index 9daab186a35be..fedd435fbfdcd 100644 --- a/packages/main/src/plugin/kubernetes-client.spec.ts +++ b/packages/main/src/plugin/kubernetes-client.spec.ts @@ -37,6 +37,8 @@ import type { Telemetry } from '/@/plugin/telemetry/telemetry.js'; import * as fs from 'node:fs'; import type { V1Route } from './api/openshift-types.js'; import { KubernetesInformerManager } from './kubernetes-informer-registry.js'; +import { IncomingMessage } from 'node:http'; +import { Socket } from 'node:net'; const configurationRegistry: ConfigurationRegistry = {} as unknown as ConfigurationRegistry; const informerManager: KubernetesInformerManager = new KubernetesInformerManager(); @@ -121,6 +123,13 @@ beforeAll(() => { VersionApi: {}, makeInformer: vi.fn(), KubernetesObjectApi: vi.fn(), + HttpError: class HttpError extends Error { + statusCode: number; + constructor(statusCode: number, message: string) { + super(message); + this.statusCode = statusCode; + } + }, }; }); }); @@ -1257,3 +1266,28 @@ test('Expect apply should patch if object exists', async () => { expect(objects).toHaveLength(1); expect(objects[0]).toEqual(patchedObj); }); + +test('If Kubernetes returns a http error, output the http body message error.', async () => { + const client = createTestClient(); + makeApiClientMock.mockReturnValue({ + read: vi.fn().mockReturnValue({}), + create: vi + .fn() + .mockRejectedValue( + new clientNode.HttpError( + new IncomingMessage(new Socket()), + { body: { message: 'A K8sError within message body' } }, + 500, + ), + ), + }); + try { + await client.createResources('dummy', [{ apiVersion: 'v1' }]); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (err: any) { + console.log(err); + // Check that the error is clientNode.HttpError + expect(err).to.be.a('Error'); + expect(err.message).contain('A K8sError within message body'); + } +}); diff --git a/packages/main/src/plugin/kubernetes-client.ts b/packages/main/src/plugin/kubernetes-client.ts index 149a8481d6ab6..dd29e3133aa4d 100644 --- a/packages/main/src/plugin/kubernetes-client.ts +++ b/packages/main/src/plugin/kubernetes-client.ts @@ -1166,9 +1166,19 @@ export class KubernetesClient { telemetryOptions.error = error; if (error instanceof HttpError) { const httpError = error as HttpError; + + // If there is a "message" in the body of the http error, throw that + // as that's where Kubernetes tends to put the error message + if (httpError.body?.message) { + throw new Error(httpError.body.message); + } + + // Otherwise, throw the "generic" HTTP error message if (httpError.message) { throw new Error(httpError.message); } + + // If all else fails, throw the body of the error throw new Error(httpError.body); } throw error;