From 5eb1b8553d3988ccd963616a904b0a1fc1e0b8ed Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 8 Nov 2021 20:11:40 -0500 Subject: [PATCH] Support window nodes for node-shells (#3624) * Support window nodes for node-shells Signed-off-by: Sebastian Malton * Also check beta.kubernetes/os label Signed-off-by: Sebastian Malton * Add comment about linux fallback Signed-off-by: Sebastian Malton --- src/common/k8s-api/endpoints/nodes.api.ts | 11 ++++----- src/common/k8s-api/kube-api.ts | 5 +--- src/common/k8s-api/kube-json-api.ts | 18 ++++++++++++++- src/main/cluster-manager.ts | 13 +++-------- src/main/shell-session/node-shell-session.ts | 24 ++++++++++++++++++-- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/common/k8s-api/endpoints/nodes.api.ts b/src/common/k8s-api/endpoints/nodes.api.ts index 3f4e0fb412..f46eaa8811 100644 --- a/src/common/k8s-api/endpoints/nodes.api.ts +++ b/src/common/k8s-api/endpoints/nodes.api.ts @@ -236,13 +236,10 @@ export class Node extends KubeObject { } getOperatingSystem(): string { - const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")); - - if (label) { - return label.split("=", 2)[1]; - } - - return "linux"; + return this.metadata?.labels?.["kubernetes.io/os"] + || this.metadata?.labels?.["beta.kubernetes.io/os"] + || this.status?.nodeInfo?.operatingSystem + || "linux"; } isUnschedulable() { diff --git a/src/common/k8s-api/kube-api.ts b/src/common/k8s-api/kube-api.ts index 850d5dcb05..79c432c6f9 100644 --- a/src/common/k8s-api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -224,10 +224,7 @@ export class KubeApi { isNamespaced = options.objectConstructor?.namespaced, } = options || {}; - if (!options.apiBase) { - options.apiBase = objectConstructor.apiBase; - } - const { apiBase, apiPrefix, apiGroup, apiVersion, resource } = parseKubeApi(options.apiBase); + const { apiBase, apiPrefix, apiGroup, apiVersion, resource } = parseKubeApi(options.apiBase || objectConstructor.apiBase); this.kind = kind; this.isNamespaced = isNamespaced; diff --git a/src/common/k8s-api/kube-json-api.ts b/src/common/k8s-api/kube-json-api.ts index 2e6e892b21..3776634a47 100644 --- a/src/common/k8s-api/kube-json-api.ts +++ b/src/common/k8s-api/kube-json-api.ts @@ -21,6 +21,9 @@ import { JsonApi, JsonApiData, JsonApiError } from "./json-api"; import type { Response } from "node-fetch"; +import type { Cluster } from "../../main/cluster"; +import { LensProxy } from "../../main/lens-proxy"; +import { apiKubePrefix, isDebugging } from "../vars"; export interface KubeJsonApiListMetadata { resourceVersion: string; @@ -70,6 +73,20 @@ export interface KubeJsonApiError extends JsonApiError { } export class KubeJsonApi extends JsonApi { + static forCluster(cluster: Cluster): KubeJsonApi { + const port = LensProxy.getInstance().port; + + return new this({ + serverAddress: `http://127.0.0.1:${port}`, + apiBase: apiKubePrefix, + debug: isDebugging, + }, { + headers: { + "Host": `${cluster.id}.localhost:${port}`, + }, + }); + } + protected parseError(error: KubeJsonApiError | any, res: Response): string[] { const { status, reason, message } = error; @@ -80,4 +97,3 @@ export class KubeJsonApi extends JsonApi { return super.parseError(error, res); } } - diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 53c79fda7c..b72084751d 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -240,27 +240,20 @@ export class ClusterManager extends Singleton { } getClusterForRequest(req: http.IncomingMessage): Cluster { - let cluster: Cluster = null; - // lens-server is connecting to 127.0.0.1:/ if (req.headers.host.startsWith("127.0.0.1")) { const clusterId = req.url.split("/")[1]; - - cluster = this.store.getById(clusterId); + const cluster = this.store.getById(clusterId); if (cluster) { // we need to swap path prefix so that request is proxied to kube api req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); } - } else if (req.headers["x-cluster-id"]) { - cluster = this.store.getById(req.headers["x-cluster-id"].toString()); - } else { - const clusterId = getClusterIdFromHost(req.headers.host); - cluster = this.store.getById(clusterId); + return cluster; } - return cluster; + return this.store.getById(getClusterIdFromHost(req.headers.host)); } } diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index db0bb89bd3..f13ae9fdb6 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -26,6 +26,9 @@ import type { KubeConfig } from "@kubernetes/client-node"; import type { Cluster } from "../cluster"; import { ShellOpenError, ShellSession } from "./shell-session"; import { get } from "lodash"; +import { Node, NodesApi } from "../../common/k8s-api/endpoints"; +import { KubeJsonApi } from "../../common/k8s-api/kube-json-api"; +import logger from "../logger"; export class NodeShellSession extends ShellSession { ShellType = "node-shell"; @@ -55,10 +58,27 @@ export class NodeShellSession extends ShellSession { throw new ShellOpenError("failed to create node pod", error); } - const args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; const env = await this.getCachedShellEnv(); + const args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--"]; + const nodeApi = new NodesApi({ + objectConstructor: Node, + request: KubeJsonApi.forCluster(this.cluster), + }); + const node = await nodeApi.get({ name: this.nodeName }); + const nodeOs = node.getOperatingSystem(); - await super.open(shell, args, env); + switch (nodeOs) { + default: + logger.warn(`[NODE-SHELL-SESSION]: could not determine node OS, falling back with assumption of linux`); + case "linux": + args.push("sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"); + break; + case "windows": + args.push("powershell"); + break; + } + + return super.open(shell, args, env); } protected createNodeShellPod() {