mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Pre-Validate kubeconfig before making available in Lens (#1078)
This commit is contained in:
1 parent
23c9255b9a
commit
e560baa2d0
5 files changed
+244
-52
No files matched your search
@@ -3,6 +3,9 @@ import mockFs from "mock-fs";
|
||||
import yaml from "js-yaml";
|
||||
import { Cluster } from "../../main/cluster";
|
||||
import { ClusterStore, getClusterIdFromHost } from "../cluster-store";
|
||||
import { Console } from "console";
|
||||
|
||||
console = new Console(process.stdout, process.stderr); // fix mockFS
|
||||
|
||||
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png");
|
||||
const kubeconfig = `
|
||||
@@ -292,6 +295,13 @@ users:
|
||||
});
|
||||
});
|
||||
|
||||
const minimalValidKubeConfig = JSON.stringify({
|
||||
apiVersion: "v1",
|
||||
clusters: [],
|
||||
users: [],
|
||||
contexts: [],
|
||||
});
|
||||
|
||||
describe("pre 2.0 config with an existing cluster", () => {
|
||||
beforeEach(() => {
|
||||
ClusterStore.resetInstance();
|
||||
@@ -303,7 +313,7 @@ describe("pre 2.0 config with an existing cluster", () => {
|
||||
version: "1.0.0"
|
||||
}
|
||||
},
|
||||
cluster1: "kubeconfig content"
|
||||
cluster1: minimalValidKubeConfig,
|
||||
})
|
||||
}
|
||||
};
|
||||
@@ -321,7 +331,7 @@ describe("pre 2.0 config with an existing cluster", () => {
|
||||
it("migrates to modern format with kubeconfig in a file", async () => {
|
||||
const config = clusterStore.clustersList[0].kubeConfigPath;
|
||||
|
||||
expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content");
|
||||
expect(fs.readFileSync(config, "utf8")).toContain(`"contexts":[]`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -375,7 +385,7 @@ describe("pre 2.6.0 config with a cluster icon", () => {
|
||||
}
|
||||
},
|
||||
cluster1: {
|
||||
kubeConfig: "foo",
|
||||
kubeConfig: minimalValidKubeConfig,
|
||||
icon: "icon_path",
|
||||
preferences: {
|
||||
terminalCWD: "/tmp"
|
||||
@@ -417,7 +427,7 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => {
|
||||
}
|
||||
},
|
||||
cluster1: {
|
||||
kubeConfig: "foo",
|
||||
kubeConfig: minimalValidKubeConfig,
|
||||
preferences: {
|
||||
terminalCWD: "/tmp"
|
||||
}
|
||||
@@ -451,7 +461,7 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
|
||||
clusters: [
|
||||
{
|
||||
id: "cluster1",
|
||||
kubeConfig: "kubeconfig content",
|
||||
kubeConfig: minimalValidKubeConfig,
|
||||
contextName: "cluster",
|
||||
preferences: {
|
||||
icon: "store://icon_path",
|
||||
@@ -476,7 +486,7 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
|
||||
it("migrates to modern format with kubeconfig in a file", async () => {
|
||||
const config = clusterStore.clustersList[0].kubeConfigPath;
|
||||
|
||||
expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content");
|
||||
expect(fs.readFileSync(config, "utf8")).toBe(minimalValidKubeConfig);
|
||||
});
|
||||
|
||||
it("migrates to modern format with icon not in file", async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { KubeConfig } from "@kubernetes/client-node";
|
||||
import { validateKubeConfig } from "../kube-helpers";
|
||||
import { validateKubeConfig, loadConfig } from "../kube-helpers";
|
||||
|
||||
const kubeconfig = `
|
||||
apiVersion: v1
|
||||
@@ -40,61 +40,214 @@ users:
|
||||
|
||||
const kc = new KubeConfig();
|
||||
|
||||
describe("validateKubeconfig", () => {
|
||||
beforeAll(() => {
|
||||
kc.loadFromString(kubeconfig);
|
||||
});
|
||||
describe("with default validation options", () => {
|
||||
describe("with valid kubeconfig", () => {
|
||||
it("does not raise exceptions", () => {
|
||||
expect(() => { validateKubeConfig(kc, "valid");}).not.toThrow();
|
||||
});
|
||||
interface kubeconfig {
|
||||
apiVersion: string,
|
||||
clusters: [{
|
||||
name: string,
|
||||
cluster: {
|
||||
server: string
|
||||
}
|
||||
}],
|
||||
contexts: [{
|
||||
context: {
|
||||
cluster: string,
|
||||
user: string,
|
||||
},
|
||||
name: string
|
||||
}],
|
||||
users: [{
|
||||
name: string
|
||||
}],
|
||||
kind: string,
|
||||
"current-context": string,
|
||||
preferences: {}
|
||||
}
|
||||
|
||||
let mockKubeConfig: kubeconfig;
|
||||
|
||||
describe("kube helpers", () => {
|
||||
describe("validateKubeconfig", () => {
|
||||
beforeAll(() => {
|
||||
kc.loadFromString(kubeconfig);
|
||||
});
|
||||
describe("with invalid context object", () => {
|
||||
it("it raises exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalid");}).toThrow("No valid context object provided in kubeconfig for context 'invalid'");
|
||||
describe("with default validation options", () => {
|
||||
describe("with valid kubeconfig", () => {
|
||||
it("does not raise exceptions", () => {
|
||||
expect(() => { validateKubeConfig(kc, "valid");}).not.toThrow();
|
||||
});
|
||||
});
|
||||
describe("with invalid context object", () => {
|
||||
it("it raises exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalid");}).toThrow("No valid context object provided in kubeconfig for context 'invalid'");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with invalid cluster object", () => {
|
||||
it("it raises exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidCluster");}).toThrow("No valid cluster object provided in kubeconfig for context 'invalidCluster'");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with invalid user object", () => {
|
||||
it("it raises exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidUser");}).toThrow("No valid user object provided in kubeconfig for context 'invalidUser'");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with invalid exec command", () => {
|
||||
it("it raises exception", () => {
|
||||
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 invalid cluster object", () => {
|
||||
it("it raises exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidCluster");}).toThrow("No valid cluster object provided in kubeconfig for context 'invalidCluster'");
|
||||
describe("with validateCluster as false", () => {
|
||||
describe("with invalid cluster object", () => {
|
||||
it("does not raise exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidCluster", { validateCluster: false });}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with invalid user object", () => {
|
||||
it("it raises exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidUser");}).toThrow("No valid user object provided in kubeconfig for context 'invalidUser'");
|
||||
describe("with validateUser as false", () => {
|
||||
describe("with invalid user object", () => {
|
||||
it("does not raise exceptions", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidUser", { validateUser: false });}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with invalid exec command", () => {
|
||||
it("it raises exception", () => {
|
||||
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 validateExec as false", () => {
|
||||
describe("with invalid exec object", () => {
|
||||
it("does not raise exceptions", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidExec", { validateExec: false });}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with validateCluster as false", () => {
|
||||
describe("with invalid cluster object", () => {
|
||||
it("does not raise exception", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidCluster", { validateCluster: false });}).not.toThrow();
|
||||
describe("pre-validate context object in kubeconfig tests", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("Check logger.error() output", () => {
|
||||
it("invalid yaml string", () => {
|
||||
const invalidYAMLString = "fancy foo config";
|
||||
|
||||
expect(() => loadConfig(invalidYAMLString)).toThrowError("must be an object");
|
||||
});
|
||||
it("empty contexts", () => {
|
||||
const emptyContexts = `apiVersion: v1\ncontexts:`;
|
||||
|
||||
expect(() => loadConfig(emptyContexts)).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with validateUser as false", () => {
|
||||
describe("with invalid user object", () => {
|
||||
it("does not raise excpetions", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidUser", { validateUser: false });}).not.toThrow();
|
||||
describe("Check valid kubeconfigs", () => {
|
||||
beforeEach(() => {
|
||||
mockKubeConfig = {
|
||||
apiVersion: "v1",
|
||||
clusters: [{
|
||||
name: "minikube",
|
||||
cluster: {
|
||||
server: "https://192.168.64.3:8443",
|
||||
},
|
||||
}],
|
||||
contexts: [{
|
||||
context: {
|
||||
cluster: "minikube",
|
||||
user: "minikube",
|
||||
},
|
||||
name: "minikube",
|
||||
}],
|
||||
users: [{
|
||||
name: "minikube",
|
||||
}],
|
||||
kind: "Config",
|
||||
"current-context": "minikube",
|
||||
preferences: {},
|
||||
};
|
||||
});
|
||||
|
||||
it("single context is ok", async () => {
|
||||
const kc:KubeConfig = loadConfig(JSON.stringify(mockKubeConfig));
|
||||
|
||||
expect(kc.getCurrentContext()).toBe("minikube");
|
||||
});
|
||||
|
||||
it("multiple context is ok", async () => {
|
||||
mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: "cluster-2"}, name: "cluster-2"});
|
||||
const kc:KubeConfig = loadConfig(JSON.stringify(mockKubeConfig));
|
||||
|
||||
expect(kc.getCurrentContext()).toBe("minikube");
|
||||
expect(kc.contexts.length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with validateExec as false", () => {
|
||||
describe("with invalid exec object", () => {
|
||||
it("does not raise excpetions", () => {
|
||||
expect(() => { validateKubeConfig(kc, "invalidExec", { validateExec: false });}).not.toThrow();
|
||||
describe("Check invalid kubeconfigs", () => {
|
||||
beforeEach(() => {
|
||||
mockKubeConfig = {
|
||||
apiVersion: "v1",
|
||||
clusters: [{
|
||||
name: "minikube",
|
||||
cluster: {
|
||||
server: "https://192.168.64.3:8443",
|
||||
},
|
||||
}],
|
||||
contexts: [{
|
||||
context: {
|
||||
cluster: "minikube",
|
||||
user: "minikube",
|
||||
},
|
||||
name: "minikube",
|
||||
}],
|
||||
users: [{
|
||||
name: "minikube",
|
||||
}],
|
||||
kind: "Config",
|
||||
"current-context": "minikube",
|
||||
preferences: {},
|
||||
};
|
||||
});
|
||||
|
||||
it("empty name in context causes it to be removed", async () => {
|
||||
mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: "cluster-2"}, name: ""});
|
||||
expect(mockKubeConfig.contexts.length).toBe(2);
|
||||
const kc:KubeConfig = loadConfig(JSON.stringify(mockKubeConfig));
|
||||
|
||||
expect(kc.getCurrentContext()).toBe("minikube");
|
||||
expect(kc.contexts.length).toBe(1);
|
||||
});
|
||||
|
||||
it("empty cluster in context causes it to be removed", async () => {
|
||||
mockKubeConfig.contexts.push({context: {cluster: "", user: "cluster-2"}, name: "cluster-2"});
|
||||
expect(mockKubeConfig.contexts.length).toBe(2);
|
||||
const kc:KubeConfig = loadConfig(JSON.stringify(mockKubeConfig));
|
||||
|
||||
expect(kc.getCurrentContext()).toBe("minikube");
|
||||
expect(kc.contexts.length).toBe(1);
|
||||
});
|
||||
|
||||
it("empty user in context causes it to be removed", async () => {
|
||||
mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: ""}, name: "cluster-2"});
|
||||
expect(mockKubeConfig.contexts.length).toBe(2);
|
||||
const kc:KubeConfig = loadConfig(JSON.stringify(mockKubeConfig));
|
||||
|
||||
expect(kc.getCurrentContext()).toBe("minikube");
|
||||
expect(kc.contexts.length).toBe(1);
|
||||
});
|
||||
|
||||
it("invalid context in between valid contexts is removed", async () => {
|
||||
mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: ""}, name: "cluster-2"});
|
||||
mockKubeConfig.contexts.push({context: {cluster: "cluster-3", user: "cluster-3"}, name: "cluster-3"});
|
||||
expect(mockKubeConfig.contexts.length).toBe(3);
|
||||
const kc:KubeConfig = loadConfig(JSON.stringify(mockKubeConfig));
|
||||
|
||||
expect(kc.getCurrentContext()).toBe("minikube");
|
||||
expect(kc.contexts.length).toBe(2);
|
||||
expect(kc.contexts[0].name).toBe("minikube");
|
||||
expect(kc.contexts[1].name).toBe("cluster-3");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user