From 8e85beee866dae87c2f29187ec90cab2763d812b Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Thu, 19 Aug 2021 16:00:34 +0300 Subject: [PATCH] Saving kubeconfig file refactoring Signed-off-by: Alex Andreev --- package.json | 1 + .../delete-cluster-dialog/save-config.ts | 38 +++++++++++++++++++ src/renderer/initializers/catalog.tsx | 23 +++++++++++ types/json-to-pretty-yaml.d.ts | 25 ++++++++++++ yarn.lock | 18 +++++++++ 5 files changed, 105 insertions(+) create mode 100644 src/renderer/components/delete-cluster-dialog/save-config.ts create mode 100644 types/json-to-pretty-yaml.d.ts diff --git a/package.json b/package.json index 1b5aeebdc9..22c6d83bda 100644 --- a/package.json +++ b/package.json @@ -348,6 +348,7 @@ "jest-canvas-mock": "^2.3.1", "jest-fetch-mock": "^3.0.3", "jest-mock-extended": "^1.0.16", + "json-to-pretty-yaml": "^1.2.2", "make-plural": "^6.2.2", "mini-css-extract-plugin": "^1.6.0", "node-loader": "^1.0.3", diff --git a/src/renderer/components/delete-cluster-dialog/save-config.ts b/src/renderer/components/delete-cluster-dialog/save-config.ts new file mode 100644 index 0000000000..32b5306b59 --- /dev/null +++ b/src/renderer/components/delete-cluster-dialog/save-config.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import type { KubeConfig } from "@kubernetes/client-node"; +import fs from "fs"; +import tempy from "tempy"; +import * as lockFile from "proper-lockfile"; +import YAML from "json-to-pretty-yaml"; + +export async function saveKubeconfig(config: KubeConfig, path: string) { + lockFile.lock(path).then(async () => { + const tmpFilePath = tempy.file(); + const contents = YAML.stringify(JSON.parse(config.exportConfig())); + + await fs.promises.writeFile(tmpFilePath, contents); + await fs.promises.rename(tmpFilePath, path); + }).catch((e) => { + throw new Error(`Failed to aquire lock file.\n${e}`); + }); +} diff --git a/src/renderer/initializers/catalog.tsx b/src/renderer/initializers/catalog.tsx index fd6656d28c..41d4db639d 100644 --- a/src/renderer/initializers/catalog.tsx +++ b/src/renderer/initializers/catalog.tsx @@ -39,6 +39,7 @@ import { HotbarStore } from "../../common/hotbar-store"; import type { ClusterId } from "../../common/cluster-types"; import type { Cluster } from "../../main/cluster"; import { deleteClusterConfirmDialog } from "../components/dialog/delete-cluster-dialog"; +import { DeleteClusterDialog } from "../components/delete-cluster-dialog"; function initWebLinks() { WebLinkCategory.onAdd = () => CommandOverlay.open(); @@ -57,9 +58,31 @@ function initKubernetesClusters() { message: `Delete the "${entity.metadata.name}" context from "${entity.spec.kubeconfigPath}"?` } }); + context.menuItems.push({ + title: "Remove", + icon: "delete", + onClick: () => onClusterDelete(entity.metadata.uid) + }); }); } +async function onClusterDelete(clusterId: string) { + appEventBus.emit({ name: "cluster", action: "remove" }); + const cluster = ClusterStore.getInstance().getById(clusterId); + + if (!cluster) { + return console.warn("[KUBERNETES-CLUSTER]: cannot delete cluster, does not exist in store", { clusterId }); + } + + const { config, error } = loadConfigFromString(await fs.promises.readFile(cluster.kubeConfigPath, "utf-8")); + + if (error) { + throw error; + } + + DeleteClusterDialog.open({ cluster, config }); +} + export function initCatalog() { initWebLinks(); initKubernetesClusters(); diff --git a/types/json-to-pretty-yaml.d.ts b/types/json-to-pretty-yaml.d.ts new file mode 100644 index 0000000000..3d38a42ace --- /dev/null +++ b/types/json-to-pretty-yaml.d.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +export = YAML; + +declare namespace YAML { + function stringify(source: string): string; +} diff --git a/yarn.lock b/yarn.lock index 3c9a6b7ccb..9c68e2070c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8667,6 +8667,14 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json-to-pretty-yaml@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz#f4cd0bd0a5e8fe1df25aaf5ba118b099fd992d5b" + integrity sha1-9M0L0KXo/h3yWq9boRiwmf2ZLVs= + dependencies: + remedial "^1.0.7" + remove-trailing-spaces "^1.0.6" + json3@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" @@ -12243,11 +12251,21 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= +remedial@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/remedial/-/remedial-1.0.8.tgz#a5e4fd52a0e4956adbaf62da63a5a46a78c578a0" + integrity sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg== + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= +remove-trailing-spaces@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz#4354d22f3236374702f58ee373168f6d6887ada7" + integrity sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA== + renderkid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.3.tgz#380179c2ff5ae1365c522bf2fcfcff01c5b74149"