diff --git a/src/common/k8s-api/__tests__/nodes.test.ts b/src/common/k8s-api/__tests__/nodes.test.ts new file mode 100644 index 0000000000..4b109a8f96 --- /dev/null +++ b/src/common/k8s-api/__tests__/nodes.test.ts @@ -0,0 +1,131 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { Node } from "../endpoints"; + +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +describe("Nodes tests", () => { + describe("getRoleLabels()", () => { + it("should return empty string if labels is not present", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + }, + }); + + expect(node.getRoleLabels()).toBe(""); + }); + + it("should return empty string if labels is empty object", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + labels: {}, + }, + }); + + expect(node.getRoleLabels()).toBe(""); + }); + + it("should return rest of keys with substring node-role.kubernetes.io/", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + labels: { + "node-role.kubernetes.io/foobar": "bat", + "hellonode-role.kubernetes.io/foobar1": "bat", + }, + }, + }); + + expect(node.getRoleLabels()).toBe("foobar, foobar1"); + }); + + it("should return rest of keys with substring node-role.kubernetes.io/ after last /", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + labels: { + "node-role.kubernetes.io/foobar": "bat", + "hellonode-role.kubernetes.io//////foobar1": "bat", + }, + }, + }); + + expect(node.getRoleLabels()).toBe("foobar, foobar1"); + }); + + it("should return value of label kubernetes.io/role if present", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + labels: { + "kubernetes.io/role": "master", + }, + }, + }); + + expect(node.getRoleLabels()).toBe("master"); + }); + + it("should return value of label node.kubernetes.io/role if present", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + labels: { + "node.kubernetes.io/role": "master", + }, + }, + }); + + expect(node.getRoleLabels()).toBe("master"); + }); + + it("all sources should be joined together", () => { + const node = new Node({ + apiVersion: "foo", + kind: "Node", + metadata: { + name: "bar", + resourceVersion: "1", + uid: "bat", + labels: { + "aksjhdkjahsdnode-role.kubernetes.io/foobar": "bat", + "kubernetes.io/role": "master", + "node.kubernetes.io/role": "master-v2-max", + }, + }, + }); + + expect(node.getRoleLabels()).toBe("foobar, master, master-v2-max"); + }); + }); +}); diff --git a/src/common/k8s-api/endpoints/nodes.api.ts b/src/common/k8s-api/endpoints/nodes.api.ts index 34e1dd0863..afe379f3b1 100644 --- a/src/common/k8s-api/endpoints/nodes.api.ts +++ b/src/common/k8s-api/endpoints/nodes.api.ts @@ -140,6 +140,12 @@ function* getTrueConditionTypes(conditions: IterableIterator | It } } +/** + * This regex is used in the `getRoleLabels()` method bellow, but placed here + * as factoring out regexes is best practice. + */ +const nodeRoleLabelKeyMatcher = /^.*node-role.kubernetes.io\/+(?.+)$/; + export class Node extends KubeObject { static kind = "Node"; static namespaced = false; @@ -165,17 +171,29 @@ export class Node extends KubeObject { return this.spec.taints || []; } - getRoleLabels() { - if (!this.metadata?.labels || typeof this.metadata.labels !== "object") { + getRoleLabels(): string { + const { labels } = this.metadata; + + if (!labels || typeof labels !== "object") { return ""; } - const roleLabels = Object.keys(this.metadata.labels) - .filter(key => key.includes("node-role.kubernetes.io")) - .map(key => key.match(/([^/]+$)/)[0]); // all after last slash + const roleLabels: string[] = []; - if (this.metadata.labels["kubernetes.io/role"] != undefined) { - roleLabels.push(this.metadata.labels["kubernetes.io/role"]); + for (const labelKey of Object.keys(labels)) { + const match = nodeRoleLabelKeyMatcher.exec(labelKey); + + if (match) { + roleLabels.push(match.groups.role); + } + } + + if (typeof labels["kubernetes.io/role"] === "string") { + roleLabels.push(labels["kubernetes.io/role"]); + } + + if (typeof labels["node.kubernetes.io/role"] === "string") { + roleLabels.push(labels["node.kubernetes.io/role"]); } return roleLabels.join(", ");