From 497e47b277b374e1e8c18131a4d6aea29a530ba5 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 7 Jul 2021 16:29:58 -0400 Subject: [PATCH] Automatically sync all kubeConfigPaths (#3227) --- .../package/package.json | 25 ------- package.json | 2 +- src/common/user-store/index.ts | 2 +- src/common/user-store/user-store.ts | 5 +- src/main/index.ts | 2 +- src/migrations/hotbar-store/5.0.0-beta.10.ts | 4 +- src/migrations/user-store/5.0.3-beta.1.ts | 75 +++++++++++++++++++ src/migrations/user-store/index.ts | 2 + .../+extensions/__tests__/extensions.test.tsx | 12 ++- 9 files changed, 90 insertions(+), 39 deletions(-) delete mode 100644 extensions/kube-object-event-status/package/package.json create mode 100644 src/migrations/user-store/5.0.3-beta.1.ts diff --git a/extensions/kube-object-event-status/package/package.json b/extensions/kube-object-event-status/package/package.json deleted file mode 100644 index e6ab1bb688..0000000000 --- a/extensions/kube-object-event-status/package/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "kube-object-event-status", - "version": "0.1.0", - "description": "Adds kube object status from events", - "renderer": "dist/renderer.js", - "lens": { - "metadata": {}, - "styles": [] - }, - "scripts": { - "build": "webpack && npm pack", - "dev": "webpack --watch", - "test": "echo NO TESTS" - }, - "files": [ - "dist/**/*" - ], - "dependencies": {}, - "devDependencies": { - "@k8slens/extensions": "file:../../src/extensions/npm/extensions", - "ts-loader": "^8.0.4", - "typescript": "^4.0.3", - "webpack": "^4.44.2" - } -} diff --git a/package.json b/package.json index 4844f6f10a..8f7af30980 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.0.2", + "version": "5.0.3-beta.1", "main": "static/build/main.js", "copyright": "© 2021 OpenLens Authors", "license": "MIT", diff --git a/src/common/user-store/index.ts b/src/common/user-store/index.ts index dc00ab6737..a8dc6eb028 100644 --- a/src/common/user-store/index.ts +++ b/src/common/user-store/index.ts @@ -20,4 +20,4 @@ */ export * from "./user-store"; -export type { KubeconfigSyncEntry, KubeconfigSyncValue } from "./preferences-helpers"; +export type { KubeconfigSyncEntry, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 9801405b27..9aa814890f 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -31,6 +31,7 @@ import path from "path"; import { fileNameMigration } from "../../migrations/user-store"; import { ObservableToggleSet, toJS } from "../../renderer/utils"; import { DESCRIPTORS, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; +import logger from "../../main/logger"; export interface UserStoreModel { lastSeenAppVersion: string; @@ -155,8 +156,8 @@ export class UserStore extends BaseStore /* implements UserStore } @action - protected fromStore(data: Partial = {}) { - const { lastSeenAppVersion, preferences } = data; + protected fromStore({ lastSeenAppVersion, preferences }: Partial = {}) { + logger.debug("UserStore.fromStore()", { lastSeenAppVersion, preferences }); if (lastSeenAppVersion) { this.lastSeenAppVersion = lastSeenAppVersion; diff --git a/src/main/index.ts b/src/main/index.ts index 0599f820cb..c94c561daa 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -138,8 +138,8 @@ app.on("ready", async () => { logger.info("💾 Loading stores"); - UserStore.createInstance().startMainReactions(); ClusterStore.createInstance().provideInitialFromMain(); + UserStore.createInstance().startMainReactions(); HotbarStore.createInstance(); ExtensionsStore.createInstance(); FilesystemProvisionerStore.createInstance(); diff --git a/src/migrations/hotbar-store/5.0.0-beta.10.ts b/src/migrations/hotbar-store/5.0.0-beta.10.ts index af6af5370c..f0a8fb4872 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.10.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.10.ts @@ -148,8 +148,8 @@ export default { store.set("hotbars", hotbars); } catch (error) { - if (!(error.code === "ENOENT" && error.path.endsWith("lens-workspace-store.json"))) { - // ignore lens-workspace-store.json being missing + if (error.code !== "ENOENT") { + // ignore files being missing throw error; } } diff --git a/src/migrations/user-store/5.0.3-beta.1.ts b/src/migrations/user-store/5.0.3-beta.1.ts new file mode 100644 index 0000000000..57271e30a4 --- /dev/null +++ b/src/migrations/user-store/5.0.3-beta.1.ts @@ -0,0 +1,75 @@ +/** + * 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 { app } from "electron"; +import { existsSync, readJsonSync } from "fs-extra"; +import path from "path"; +import os from "os"; +import { ClusterStore, ClusterStoreModel } from "../../common/cluster-store"; +import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store"; +import { MigrationDeclaration, migrationLog } from "../helpers"; + +export default { + version: "5.0.3-beta.1", + run(store) { + try { + const { syncKubeconfigEntries = [], ...preferences }: UserPreferencesModel = store.get("preferences") ?? {}; + const { clusters = [] }: ClusterStoreModel = readJsonSync(path.resolve(app.getPath("userData"), "lens-cluster-store.json")) ?? {}; + const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath)); + + syncPaths.add(path.join(os.homedir(), ".kube")); + + for (const cluster of clusters) { + const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath); + + if (dirOfKubeconfig === ClusterStore.storedKubeConfigFolder) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under ClusterStore.storedKubeConfigFolder`); + continue; + } + + if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is already being synced`); + continue; + } + + if (!existsSync(cluster.kubeConfigPath)) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath no longer exists`); + continue; + } + + migrationLog(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`); + syncPaths.add(cluster.kubeConfigPath); + } + + const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath })); + + migrationLog("Final list of synced paths", updatedSyncEntries); + store.set("preferences", { ...preferences, syncKubeconfigEntries: updatedSyncEntries }); + } catch (error) { + console.log(error); + + if (error.code !== "ENOENT") { + // ignore files being missing + throw error; + } + } + }, +} as MigrationDeclaration; diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index c08ef2c5c5..87628daeef 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -25,6 +25,7 @@ import { joinMigrations } from "../helpers"; import version210Beta4 from "./2.1.0-beta.4"; import version500Alpha3 from "./5.0.0-alpha.3"; +import version503Beta1 from "./5.0.3-beta.1"; import { fileNameMigration } from "./file-name-migration"; export { @@ -34,4 +35,5 @@ export { export default joinMigrations( version210Beta4, version500Alpha3, + version503Beta1, ); diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx index 3c2484b92e..f51ba24575 100644 --- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx +++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx @@ -59,14 +59,7 @@ describe("Extensions", () => { }); ExtensionInstallationStateStore.reset(); - UserStore.resetInstance(); - UserStore.createInstance(); - - ExtensionDiscovery.resetInstance(); - ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve()); - - ExtensionLoader.resetInstance(); ExtensionLoader.createInstance().addExtension({ id: "extensionId", manifest: { @@ -79,10 +72,15 @@ describe("Extensions", () => { isEnabled: true, isCompatible: true }); + ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve()); + UserStore.createInstance(); }); afterEach(() => { mockFs.restore(); + UserStore.resetInstance(); + ExtensionDiscovery.resetInstance(); + ExtensionLoader.resetInstance(); }); it("disables uninstall and disable buttons while uninstalling", async () => {