Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/core/src/common/cluster-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export interface ClusterPreferences extends ClusterPrometheusPreferences {
httpsProxy?: string;
hiddenMetrics?: string[];
nodeShellImage?: string;
nodeShellWindowsImage?: string;
imagePullSecret?: string;
defaultNamespace?: string;
}
Expand Down Expand Up @@ -177,7 +178,12 @@ export enum ClusterMetricsResourceType {
/**
* The default node shell image
*/
export const initialNodeShellImage = "docker.io/alpine:3.13";
export const initialNodeShellImage = "docker.io/library/alpine";

/**
* The default node shell image for Windows
*/
export const initialNodeShellWindowsImage = "mcr.microsoft.com/powershell";

/**
* The data representing a cluster's state, for passing between main and renderer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { NodeApi } from "@k8slens/kube-api";
import { TerminalChannels } from "../../../common/terminal/channels";
import type { CreateKubeJsonApiForCluster } from "../../../common/k8s-api/create-kube-json-api-for-cluster.injectable";
import type { CreateKubeApi } from "../../../common/k8s-api/create-kube-api.injectable";
import { initialNodeShellImage } from "../../../common/cluster-types";
import { initialNodeShellImage, initialNodeShellWindowsImage } from "../../../common/cluster-types";
import type { LoadProxyKubeconfig } from "../../cluster/load-proxy-kubeconfig.injectable";
import type { Pod } from "@k8slens/kube-object";

Expand Down Expand Up @@ -71,7 +71,23 @@ export class NodeShellSession extends ShellSession {
}

const env = await this.getCachedShellEnv();
const args = ["exec", "-i", "-t", "-n", "kube-system", this.podName, "--"];
const args = ["attach", "-q", "-i", "-t", "-n", "kube-system", this.podName];

await this.openShellProcess(await this.kubectl.getPath(), args, env);
}

protected async createNodeShellPod(coreApi: CoreV1Api) {
const {
imagePullSecret,
nodeShellImage,
} = this.cluster.preferences;

const imagePullSecrets = imagePullSecret
? [{
name: imagePullSecret,
}]
: undefined;

const nodeApi = this.dependencies.createKubeApi(NodeApi, {
request: this.dependencies.createKubeJsonApiForCluster(this.cluster.id),
});
Expand All @@ -82,34 +98,45 @@ export class NodeShellSession extends ShellSession {
}

const nodeOs = node.getOperatingSystem();
const nodeOsImage = node.getOperatingSystemImage();

let image: string;
let command: string[];
let args: string[];
let securityContext: any;

switch (nodeOs) {
default:
this.dependencies.logger.warn(`[NODE-SHELL-SESSION]: could not determine node OS, falling back with assumption of linux`);
// fallthrough
case "linux":
args.push("sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))");
image = nodeShellImage || initialNodeShellImage;
command = ["nsenter"];

if (nodeOsImage && nodeOsImage.startsWith("Bottlerocket OS")) {
args = ["-t", "1", "-m", "-u", "-i", "-n", "-p", "--", "apiclient", "exec", "admin", "bash", "-l"];
} else {
args = ["-t", "1", "-m", "-u", "-i", "-n", "-p", "--", "bash", "-l"];
}

securityContext = {
privileged: true,
};
break;
case "windows":
args.push("powershell");
image = nodeShellImage || initialNodeShellWindowsImage;
command = ["cmd.exe"];
args = ["/c", "%CONTAINER_SANDBOX_MOUNT_POINT%\\Program Files\\PowerShell\\latest\\pwsh.exe", "-nol", "-wd", "C:\\"];
securityContext = {
privileged: true,
windowsOptions: {
hostProcess: true,
runAsUserName: "NT AUTHORITY\\SYSTEM",
},
};
break;
}

await this.openShellProcess(await this.kubectl.getPath(), args, env);
}

protected createNodeShellPod(coreApi: CoreV1Api) {
const {
imagePullSecret,
nodeShellImage,
} = this.cluster.preferences;

const imagePullSecrets = imagePullSecret
? [{
name: imagePullSecret,
}]
: undefined;

return coreApi
.createNamespacedPod("kube-system", {
metadata: {
Expand All @@ -129,12 +156,13 @@ export class NodeShellSession extends ShellSession {
priorityClassName: "system-node-critical",
containers: [{
name: "shell",
image: nodeShellImage || initialNodeShellImage,
securityContext: {
privileged: true,
},
command: ["nsenter"],
args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"],
image,
securityContext,
command,
args,
stdin: true,
stdinOnce: true,
tty: true,
}],
imagePullSecrets,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React from "react";
import { Input } from "../input/input";
import { observer } from "mobx-react";
import { Icon } from "@k8slens/icon";
import { initialNodeShellImage } from "../../../common/cluster-types";
import { initialNodeShellImage, initialNodeShellWindowsImage } from "../../../common/cluster-types";
import Gutter from "../gutter/gutter";

export interface ClusterNodeShellSettingProps {
Expand All @@ -20,6 +20,7 @@ export interface ClusterNodeShellSettingProps {
@observer
export class ClusterNodeShellSetting extends React.Component<ClusterNodeShellSettingProps> {
@observable nodeShellImage = this.props.cluster.preferences?.nodeShellImage || "";
@observable nodeShellWindowsImage = this.props.cluster.preferences?.nodeShellWindowsImage || "";
@observable imagePullSecret = this.props.cluster.preferences?.imagePullSecret || "";

constructor(props: ClusterNodeShellSettingProps) {
Expand All @@ -30,6 +31,7 @@ export class ClusterNodeShellSetting extends React.Component<ClusterNodeShellSet
componentWillUnmount() {
runInAction(() => {
this.props.cluster.preferences.nodeShellImage = this.nodeShellImage || undefined;
this.props.cluster.preferences.nodeShellWindowsImage = this.nodeShellWindowsImage || undefined;
this.props.cluster.preferences.imagePullSecret = this.imagePullSecret || undefined;
});
}
Expand All @@ -38,7 +40,7 @@ export class ClusterNodeShellSetting extends React.Component<ClusterNodeShellSet
return (
<>
<section>
<SubTitle title="Node shell image" id="node-shell-image"/>
<SubTitle title="Node shell image for Linux" id="node-shell-image"/>
<Input
theme="round-black"
placeholder={`Default image: ${initialNodeShellImage}`}
Expand All @@ -58,7 +60,32 @@ export class ClusterNodeShellSetting extends React.Component<ClusterNodeShellSet
}
/>
<small className="hint">
Node shell image. Used for creating node shell pod.
Node shell image. Used for creating node shell pod on Linux nodes.
</small>
</section>
<Gutter />
<section>
<SubTitle title="Node shell image for Windows" id="node-shell-windows-image"/>
<Input
theme="round-black"
placeholder={`Default image: ${initialNodeShellWindowsImage}`}
value={this.nodeShellWindowsImage}
onChange={value => this.nodeShellWindowsImage = value}
iconRight={
this.nodeShellWindowsImage
? (
<Icon
smallest
material="close"
onClick={() => this.nodeShellWindowsImage = ""}
tooltip="Reset"
/>
)
: undefined
}
/>
<small className="hint">
Node shell image. Used for creating node shell pod on Windows nodes.
</small>
</section>
<Gutter />
Expand Down
4 changes: 4 additions & 0 deletions packages/kube-object/src/specifics/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ export class Node extends KubeObject<ClusterScopedMetadata, NodeStatus, NodeSpec
);
}

getOperatingSystemImage(): string | undefined {
return this.status?.nodeInfo?.osImage;
}

isUnschedulable() {
return this.spec.unschedulable;
}
Expand Down