diff --git a/package.json b/package.json index 9da0f23cac..141ec3a5a0 100644 --- a/package.json +++ b/package.json @@ -185,7 +185,6 @@ "@kubernetes/client-node": "^0.15.1", "@sentry/electron": "^2.5.0", "@sentry/integrations": "^6.10.0", - "@types/which": "^2.0.1", "abort-controller": "^3.0.0", "array-move": "^3.0.1", "auto-bind": "^4.0.0", @@ -194,6 +193,7 @@ "byline": "^5.0.0", "chalk": "^4.1.0", "chokidar": "^3.4.3", + "command-exists": "1.2.9", "conf": "^7.0.1", "crypto-js": "^4.1.1", "electron-devtools-installer": "^3.2.0", @@ -246,7 +246,6 @@ "tempy": "^0.5.0", "url-parse": "^1.5.1", "uuid": "^8.3.2", - "which": "^2.0.2", "win-ca": "^3.2.0", "winston": "^3.3.3", "winston-console-format": "^1.0.8", diff --git a/src/common/custom-errors.ts b/src/common/custom-errors.ts index 0016af87ca..2cbc75ccf0 100644 --- a/src/common/custom-errors.ts +++ b/src/common/custom-errors.ts @@ -19,18 +19,15 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import path from "path"; - export class ExecValidationNotFoundError extends Error { - constructor(execPath: string) { + constructor(execPath: string, isAbsolute: boolean) { + super(`User Exec command "${execPath}" not found on host.`); let message = `User Exec command "${execPath}" not found on host.`; - if (!path.isAbsolute(execPath)) { + if (!isAbsolute) { message += ` Please ensure binary is found in PATH or use absolute path to binary in Kubeconfig`; } - - super(message); - + this.message = message; this.name = this.constructor.name; Error.captureStackTrace(this, this.constructor); } diff --git a/src/common/kube-helpers.ts b/src/common/kube-helpers.ts index 4bd420e7b2..aff05e68c6 100644 --- a/src/common/kube-helpers.ts +++ b/src/common/kube-helpers.ts @@ -25,11 +25,11 @@ import path from "path"; import os from "os"; import yaml from "js-yaml"; import logger from "../main/logger"; +import commandExists from "command-exists"; import { ExecValidationNotFoundError } from "./custom-errors"; import { Cluster, Context, newClusters, newContexts, newUsers, User } from "@kubernetes/client-node/dist/config_types"; import { resolvePath } from "./utils"; import Joi from "joi"; -import which from "which"; export type KubeConfigValidationOpts = { validateCluster?: boolean; @@ -295,17 +295,13 @@ export function validateKubeConfig(config: KubeConfig, contextName: string, vali // Validate exec command if present if (validateExec && user?.exec) { - try { - which.sync(user.exec.command); + const execCommand = user.exec["command"]; + // check if the command is absolute or not + const isAbsolute = path.isAbsolute(execCommand); - // If this doesn't throw an error it also means that it has found the executable. - } catch (error) { - switch (error?.code) { - case "ENOENT": - return new ExecValidationNotFoundError(user.exec.command); - default: - return error; - } + // validate the exec struct in the user object, start with the command field + if (!commandExists.sync(execCommand)) { + return new ExecValidationNotFoundError(execCommand, isAbsolute); } } diff --git a/src/renderer/components/+add-cluster/add-cluster.scss b/src/renderer/components/+add-cluster/add-cluster.scss index 8abb38e9d0..faac757c40 100644 --- a/src/renderer/components/+add-cluster/add-cluster.scss +++ b/src/renderer/components/+add-cluster/add-cluster.scss @@ -50,11 +50,4 @@ display: block; padding-top: 6px; } - - .actions-panel { - .Spinner { - vertical-align: middle; - margin-left: $spacing; - } - } } diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 16a6dec19e..e987c1d4bb 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -24,7 +24,7 @@ import "./add-cluster.scss"; import type { KubeConfig } from "@kubernetes/client-node"; import fse from "fs-extra"; import { debounce } from "lodash"; -import { action, computed, observable, makeObservable, runInAction } from "mobx"; +import { action, computed, observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import path from "path"; import React from "react"; @@ -41,7 +41,6 @@ import { SettingLayout } from "../layout/setting-layout"; import MonacoEditor from "react-monaco-editor"; import { ThemeStore } from "../../theme.store"; import { UserStore } from "../../../common/user-store"; -import { Spinner } from "../spinner"; interface Option { config: KubeConfig; @@ -63,7 +62,6 @@ export class AddCluster extends React.Component { @observable kubeContexts = observable.map(); @observable customConfig = ""; @observable isWaiting = false; - @observable isCheckingInput = false; @observable errorText: string; constructor(props: {}) { @@ -82,35 +80,14 @@ export class AddCluster extends React.Component { ].filter(Boolean); } - _refreshContexts = debounce(() => { - runInAction(() => { - try { - const text = this.customConfig.trim(); + @action + refreshContexts = debounce(() => { + const { config, error } = loadConfigFromString(this.customConfig.trim() || "{}"); - if (!text) { - return this.kubeContexts.clear(); - } - - const { config, error } = loadConfigFromString(text); - - this.kubeContexts.replace(getContexts(config)); - this.errorText = error?.toString(); - } catch (error) { - this.kubeContexts.clear(); - this.errorText = error?.toString() || "An error occured"; - } finally { - this.isCheckingInput = false; - } - }); + this.kubeContexts.replace(getContexts(config)); + this.errorText = error?.toString(); }, 500); - refreshContexts = () => { - // Clear the kubeContexts immediately - this.isCheckingInput = true; - this.kubeContexts.clear(); - this._refreshContexts(); - }; - @action addClusters = async () => { this.isWaiting = true; @@ -168,7 +145,6 @@ export class AddCluster extends React.Component { tooltip={this.kubeContexts.size === 0 || "Paste in at least one cluster to add."} tooltipOverrideDisabled /> - {this.isCheckingInput && } ); diff --git a/yarn.lock b/yarn.lock index ce76e9ac72..87a86e853b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2184,11 +2184,6 @@ anymatch "^3.0.0" source-map "^0.6.0" -"@types/which@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/which/-/which-2.0.1.tgz#27ecd67f915b7c3d6ba552135bb1eecd66e63501" - integrity sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ== - "@types/ws@^6.0.1": version "6.0.4" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.4.tgz#7797707c8acce8f76d8c34b370d4645b70421ff1" @@ -4115,6 +4110,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +command-exists@1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + commander@2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"