From 7c8ca4085a6fff76aa9a91f5047cd0d2dc5a74cc Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Fri, 15 Jan 2021 11:31:09 +0200 Subject: [PATCH] Add unit tests for validateKubeConfig Signed-off-by: Lauri Nevala --- src/common/__tests__/kube-helpers.test.ts | 120 ++++++++++++++++++++++ src/common/kube-helpers.ts | 22 ++-- 2 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 src/common/__tests__/kube-helpers.test.ts diff --git a/src/common/__tests__/kube-helpers.test.ts b/src/common/__tests__/kube-helpers.test.ts new file mode 100644 index 0000000000..b4e6f8dedd --- /dev/null +++ b/src/common/__tests__/kube-helpers.test.ts @@ -0,0 +1,120 @@ +import { KubeConfig } from "@kubernetes/client-node"; +import { validateKubeConfig } from "../kube-helpers"; + +const validKubeconfig = ` +apiVersion: v1 +clusters: +- cluster: + server: https://localhost + name: test +contexts: +- context: + cluster: test + user: test + name: valid +- context: + cluster: test2 + user: test + name: invalidCluster +- context: + cluster: test + user: test2 + name: invalidUser +- context: + cluster: test + user: invalidExec + name: invalidExec +current-context: test +kind: Config +preferences: {} +users: +- name: test + user: + exec: + command: echo +- name: invalidExec + user: + exec: + command: foo +`; + +describe("validateKubeconfig", () => { + describe("with default validation options", () => { + describe("with valid kubeconfig", () => { + it("does not raise exceptions", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "valid");}).not.toThrow(); + }); + }); + describe("with invalid context object", () => { + it("it raises exception", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalid");}).toThrow("No valid context object provided in kubeconfig for context 'invalid'"); + }); + }); + + describe("with invalid cluster object", () => { + it("it raises exception", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalidCluster");}).toThrow("No valid cluster object provided in kubeconfig for context 'invalidCluster'"); + }); + }); + + describe("with invalid user object", () => { + it("it raises exception", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalidUser");}).toThrow("No valid user object provided in kubeconfig for context 'invalidUser'"); + }); + }); + + describe("with invalid exec command", () => { + it("it raises exception", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalidExec");}).toThrow("User Exec command \"foo\" not found on host. Please ensure binary is found in PATH or use absolute path to binary in Kubeconfig"); + }); + }); + }); + + describe("with validateCluster as false", () => { + describe("with invalid cluster object", () => { + it("does not raise exception", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalidCluster", { validateCluster: false });}).not.toThrow(); + }); + }); + }); + + describe("with validateUser as false", () => { + describe("with invalid user object", () => { + it("does not raise excpetions", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalidUser", { validateUser: false });}).not.toThrow(); + }); + }); + }); + + describe("with validateExec as false", () => { + describe("with invalid exec object", () => { + it("does not raise excpetions", () => { + const kc = new KubeConfig(); + + kc.loadFromString(validKubeconfig); + expect(() => { validateKubeConfig(kc, "invalidExec", { validateExec: false });}).not.toThrow(); + }); + }); + }); +}); \ No newline at end of file diff --git a/src/common/kube-helpers.ts b/src/common/kube-helpers.ts index eb0cd4ec8a..9442ef8891 100644 --- a/src/common/kube-helpers.ts +++ b/src/common/kube-helpers.ts @@ -151,20 +151,14 @@ export function getNodeWarningConditions(node: V1Node) { } /** - * Validates kubeconfig supplied in the add clusters screen. Additionally this will just validate - * the User struct, specifically the command passed to the exec substructure. + * Validates Context, User and Cluster sructs in given kubeconfig. Additionally this will validate + * the command passed to the exec substructure. */ export function validateKubeConfig (config: KubeConfig, contextName: string, validationOpts?: { validateCluster?: boolean, validateUser?: boolean, validateExec?: boolean}) { // we only receive a single context, cluster & user object here so lets validate them as this // will be called when we add a new cluster to Lens - logger.debug(`validateKubeConfig: validating kubeconfig - ${JSON.stringify(config)}`); - const defaultOpts = { - validateContext: true, - validateUser: true, - validateCluster: true, - validateExec: true - }; - const opts = {...defaultOpts, ...validationOpts }; + const opts = validationOpts || {}; + const { validateUser = true, validateCluster = true, validateExec = true } = opts; const contextObject = config.getContextObject(contextName); @@ -174,26 +168,24 @@ export function validateKubeConfig (config: KubeConfig, contextName: string, val } // Validate the Cluster Object - if (opts.validateCluster && !config.getCluster(contextObject.cluster)) { + if (validateCluster && !config.getCluster(contextObject.cluster)) { throw new Error(`No valid cluster object provided in kubeconfig for context '${contextName}'`); } const user = config.getUser(contextObject.user); // Validate the User Object - if (opts.validateUser && !user) { + if (validateUser && !user) { throw new Error(`No valid user object provided in kubeconfig for context '${contextName}'`); } // Validate exec command if present - if (opts.validateExec && user.exec) { + if (validateExec && user?.exec) { const execCommand = user.exec["command"]; // check if the command is absolute or not const isAbsolute = path.isAbsolute(execCommand); // validate the exec struct in the user object, start with the command field - logger.debug(`validateKubeConfig: validating user exec command - ${JSON.stringify(execCommand)}`); - if (!commandExists.sync(execCommand)) { logger.debug(`validateKubeConfig: exec command ${String(execCommand)} in kubeconfig ${contextName} not found`); throw new ExecValidationNotFoundError(execCommand, isAbsolute);