mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce method to make store migrations injectable
- Use it for ClusterStore Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
3dce6f916e
commit
ad814ebdf6
@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
import type { BaseStoreDependencies } from "../base-store";
|
import type { BaseStoreDependencies } from "../base-store/base-store";
|
||||||
import { BaseStore } from "../base-store";
|
import { BaseStore } from "../base-store/base-store";
|
||||||
import { action, comparer, makeObservable, observable, toJS } from "mobx";
|
import { action, comparer, makeObservable, observable, toJS } from "mobx";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
|
|||||||
@ -5,19 +5,19 @@
|
|||||||
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import type Config from "conf";
|
import type Config from "conf";
|
||||||
import type { Options as ConfOptions } from "conf/dist/source/types";
|
import type { Migrations, Options as ConfOptions } from "conf/dist/source/types";
|
||||||
import { ipcMain, ipcRenderer } from "electron";
|
import { ipcMain, ipcRenderer } from "electron";
|
||||||
import type { IEqualsComparer } from "mobx";
|
import type { IEqualsComparer } from "mobx";
|
||||||
import { makeObservable, reaction, runInAction } from "mobx";
|
import { makeObservable, reaction, runInAction } from "mobx";
|
||||||
import type { Disposer } from "./utils";
|
import type { Disposer } from "../utils";
|
||||||
import { isPromiseLike, toJS } from "./utils";
|
import { isPromiseLike, toJS } from "../utils";
|
||||||
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc";
|
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "../ipc";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
import { kebabCase } from "lodash";
|
import { kebabCase } from "lodash";
|
||||||
import type { GetConfigurationFileModel } from "./get-configuration-file-model/get-configuration-file-model.injectable";
|
import type { GetConfigurationFileModel } from "../get-configuration-file-model/get-configuration-file-model.injectable";
|
||||||
import type { Logger } from "./logger";
|
import type { Logger } from "../logger";
|
||||||
|
|
||||||
export interface BaseStoreParams<T> extends ConfOptions<T> {
|
export interface BaseStoreParams<T> extends Omit<ConfOptions<T>, "migrations"> {
|
||||||
syncOptions?: {
|
syncOptions?: {
|
||||||
fireImmediately?: boolean;
|
fireImmediately?: boolean;
|
||||||
equals?: IEqualsComparer<T>;
|
equals?: IEqualsComparer<T>;
|
||||||
@ -29,6 +29,7 @@ export interface BaseStoreDependencies {
|
|||||||
readonly logger: Logger;
|
readonly logger: Logger;
|
||||||
readonly storeMigrationVersion: string;
|
readonly storeMigrationVersion: string;
|
||||||
readonly directoryForUserData: string;
|
readonly directoryForUserData: string;
|
||||||
|
readonly migrations: Migrations<Record<string, unknown>>;
|
||||||
getConfigurationFileModel: GetConfigurationFileModel;
|
getConfigurationFileModel: GetConfigurationFileModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ export abstract class BaseStore<T extends object> {
|
|||||||
protected storeConfig?: Config<T>;
|
protected storeConfig?: Config<T>;
|
||||||
protected syncDisposers: Disposer[] = [];
|
protected syncDisposers: Disposer[] = [];
|
||||||
|
|
||||||
readonly displayName: string;
|
readonly displayName = this.params.configName;
|
||||||
|
|
||||||
protected constructor(
|
protected constructor(
|
||||||
protected readonly dependencies: BaseStoreDependencies,
|
protected readonly dependencies: BaseStoreDependencies,
|
||||||
@ -48,10 +49,6 @@ export abstract class BaseStore<T extends object> {
|
|||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
|
|
||||||
this.displayName = this.params.configName;
|
this.displayName = this.params.configName;
|
||||||
|
|
||||||
if (ipcRenderer) {
|
|
||||||
this.params.migrations = undefined; // don't run migrations on renderer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,6 +61,7 @@ export abstract class BaseStore<T extends object> {
|
|||||||
projectVersion: this.dependencies.storeMigrationVersion,
|
projectVersion: this.dependencies.storeMigrationVersion,
|
||||||
cwd: this.cwd(),
|
cwd: this.cwd(),
|
||||||
...this.params,
|
...this.params,
|
||||||
|
migrations: this.dependencies.migrations as Migrations<T>,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = this.fromStore(this.storeConfig.store);
|
const res = this.fromStore(this.storeConfig.store);
|
||||||
46
src/common/base-store/migrations.injectable.ts
Normal file
46
src/common/base-store/migrations.injectable.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { InjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import { lifecycleEnum, getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type Conf from "conf/dist/source";
|
||||||
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
|
import loggerInjectable from "../logger.injectable";
|
||||||
|
import { getOrInsert, iter } from "../utils";
|
||||||
|
|
||||||
|
export interface MigrationDeclaration {
|
||||||
|
version: string;
|
||||||
|
run(store: Conf<Partial<Record<string, unknown>>>): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeMigrationsInjectable = getInjectable({
|
||||||
|
id: "store-migrations",
|
||||||
|
instantiate: (di, token): Migrations<Record<string, unknown>> => {
|
||||||
|
const logger = di.inject(loggerInjectable);
|
||||||
|
const declarations = di.injectMany(token);
|
||||||
|
const migrations = new Map<string, MigrationDeclaration["run"][]>();
|
||||||
|
|
||||||
|
for (const decl of declarations) {
|
||||||
|
getOrInsert(migrations, decl.version, []).push(decl.run);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.fromEntries(
|
||||||
|
iter.map(
|
||||||
|
migrations,
|
||||||
|
([v, fns]) => [v, (store) => {
|
||||||
|
logger.info(`Running ${v} migration for ${store.path}`);
|
||||||
|
|
||||||
|
for (const fn of fns) {
|
||||||
|
fn(store);
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
lifecycle: lifecycleEnum.keyedSingleton({
|
||||||
|
getInstanceKey: (di, token: InjectionToken<MigrationDeclaration, void>) => token.id,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default storeMigrationsInjectable;
|
||||||
@ -11,6 +11,8 @@ import directoryForUserDataInjectable from "../app-paths/directory-for-user-data
|
|||||||
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
|
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
|
||||||
import loggerInjectable from "../logger.injectable";
|
import loggerInjectable from "../logger.injectable";
|
||||||
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
||||||
|
import storeMigrationsInjectable from "../base-store/migrations.injectable";
|
||||||
|
import { clusterStoreMigrationInjectionToken } from "./migration-token";
|
||||||
|
|
||||||
const clusterStoreInjectable = getInjectable({
|
const clusterStoreInjectable = getInjectable({
|
||||||
id: "cluster-store",
|
id: "cluster-store",
|
||||||
@ -23,6 +25,7 @@ const clusterStoreInjectable = getInjectable({
|
|||||||
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
|
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
|
migrations: di.inject(storeMigrationsInjectable, clusterStoreMigrationInjectionToken),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -6,10 +6,9 @@
|
|||||||
|
|
||||||
import { ipcMain, ipcRenderer, webFrame } from "electron";
|
import { ipcMain, ipcRenderer, webFrame } from "electron";
|
||||||
import { action, comparer, computed, makeObservable, observable, reaction } from "mobx";
|
import { action, comparer, computed, makeObservable, observable, reaction } from "mobx";
|
||||||
import type { BaseStoreDependencies } from "../base-store";
|
import type { BaseStoreDependencies } from "../base-store/base-store";
|
||||||
import { BaseStore } from "../base-store";
|
import { BaseStore } from "../base-store/base-store";
|
||||||
import { Cluster } from "../cluster/cluster";
|
import { Cluster } from "../cluster/cluster";
|
||||||
import migrations from "../../migrations/cluster-store";
|
|
||||||
import { disposer, toJS } from "../utils";
|
import { disposer, toJS } from "../utils";
|
||||||
import type { ClusterModel, ClusterId, ClusterState } from "../cluster-types";
|
import type { ClusterModel, ClusterId, ClusterState } from "../cluster-types";
|
||||||
import { requestInitialClusterStates } from "../../renderer/ipc";
|
import { requestInitialClusterStates } from "../../renderer/ipc";
|
||||||
@ -31,7 +30,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
readonly displayName = "ClusterStore";
|
readonly displayName = "ClusterStore";
|
||||||
readonly clusters = observable.map<ClusterId, Cluster>();
|
readonly clusters = observable.map<ClusterId, Cluster>();
|
||||||
|
|
||||||
protected disposer = disposer();
|
protected readonly disposer = disposer();
|
||||||
|
|
||||||
constructor(protected readonly dependencies: Dependencies) {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
super(dependencies, {
|
super(dependencies, {
|
||||||
@ -40,7 +39,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
syncOptions: {
|
syncOptions: {
|
||||||
equals: comparer.structural,
|
equals: comparer.structural,
|
||||||
},
|
},
|
||||||
migrations,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
|
|||||||
11
src/common/cluster-store/migration-token.ts
Normal file
11
src/common/cluster-store/migration-token.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import type { MigrationDeclaration } from "../../migrations/helpers";
|
||||||
|
|
||||||
|
export const clusterStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||||
|
id: "cluster-store-migration",
|
||||||
|
});
|
||||||
19
src/common/fs/read-file-buffer-sync.injectable.ts
Normal file
19
src/common/fs/read-file-buffer-sync.injectable.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import fsInjectable from "./fs.injectable";
|
||||||
|
|
||||||
|
export type ReadFileBufferSync = (filePath: string) => Buffer;
|
||||||
|
|
||||||
|
const readFileBufferSyncInjectable = getInjectable({
|
||||||
|
id: "read-file-buffer-sync",
|
||||||
|
instantiate: (di): ReadFileBufferSync => {
|
||||||
|
const { readFileSync } = di.inject(fsInjectable);
|
||||||
|
|
||||||
|
return (filePath) => readFileSync(filePath);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default readFileBufferSyncInjectable;
|
||||||
13
src/common/fs/read-json-sync.injectable.ts
Normal file
13
src/common/fs/read-json-sync.injectable.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import fsInjectable from "./fs.injectable";
|
||||||
|
|
||||||
|
const readJsonSyncInjectable = getInjectable({
|
||||||
|
id: "read-json-sync",
|
||||||
|
instantiate: (di) => di.inject(fsInjectable).readJsonSync,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default readJsonSyncInjectable;
|
||||||
@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, comparer, observable, makeObservable, computed } from "mobx";
|
import { action, comparer, observable, makeObservable, computed } from "mobx";
|
||||||
import type { BaseStoreDependencies } from "../base-store";
|
import type { BaseStoreDependencies } from "../base-store/base-store";
|
||||||
import { BaseStore } from "../base-store";
|
import { BaseStore } from "../base-store/base-store";
|
||||||
import migrations from "../../migrations/hotbar-store";
|
import migrations from "../../migrations/hotbar-store";
|
||||||
import { toJS } from "../utils";
|
import { toJS } from "../utils";
|
||||||
import type { CatalogEntity } from "../catalog";
|
import type { CatalogEntity } from "../catalog";
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import { action, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx";
|
import { action, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx";
|
||||||
import type { BaseStoreDependencies } from "../base-store";
|
import type { BaseStoreDependencies } from "../base-store/base-store";
|
||||||
import { BaseStore } from "../base-store";
|
import { BaseStore } from "../base-store/base-store";
|
||||||
import migrations from "../../migrations/user-store";
|
import migrations from "../../migrations/user-store";
|
||||||
import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils";
|
import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils";
|
||||||
import { DESCRIPTORS } from "./preferences-helpers";
|
import { DESCRIPTORS } from "./preferences-helpers";
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, comparer, observable, makeObservable } from "mobx";
|
import { action, comparer, observable, makeObservable } from "mobx";
|
||||||
import type { BaseStoreDependencies } from "./base-store";
|
import type { BaseStoreDependencies } from "./base-store/base-store";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store/base-store";
|
||||||
import migrations from "../migrations/weblinks-store";
|
import migrations from "../migrations/weblinks-store";
|
||||||
import * as uuid from "uuid";
|
import * as uuid from "uuid";
|
||||||
import { toJS } from "./utils";
|
import { toJS } from "./utils";
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
import { SHA256 } from "crypto-js";
|
import { SHA256 } from "crypto-js";
|
||||||
import { action, makeObservable, observable } from "mobx";
|
import { action, makeObservable, observable } from "mobx";
|
||||||
import type { BaseStoreDependencies } from "../../../common/base-store";
|
import type { BaseStoreDependencies } from "../../../common/base-store/base-store";
|
||||||
import { BaseStore } from "../../../common/base-store";
|
import { BaseStore } from "../../../common/base-store/base-store";
|
||||||
import type { LensExtensionId } from "../../lens-extension";
|
import type { LensExtensionId } from "../../lens-extension";
|
||||||
import { getOrInsertWithAsync, toJS } from "../../../common/utils";
|
import { getOrInsertWithAsync, toJS } from "../../../common/utils";
|
||||||
import type { EnsureDirectory } from "../../../common/fs/ensure-dir.injectable";
|
import type { EnsureDirectory } from "../../../common/fs/ensure-dir.injectable";
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { BaseStoreParams } from "../common/base-store";
|
import type { BaseStoreParams } from "../common/base-store/base-store";
|
||||||
import { BaseStore } from "../common/base-store";
|
import { BaseStore } from "../common/base-store/base-store";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import type { LensExtension } from "./lens-extension";
|
import type { LensExtension } from "./lens-extension";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
@ -15,6 +15,11 @@ import directoryForUserDataInjectable from "../common/app-paths/directory-for-us
|
|||||||
import getConfigurationFileModelInjectable from "../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
import getConfigurationFileModelInjectable from "../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
||||||
import loggerInjectable from "../common/logger.injectable";
|
import loggerInjectable from "../common/logger.injectable";
|
||||||
import storeMigrationVersionInjectable from "../common/vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../common/vars/store-migration-version.injectable";
|
||||||
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
|
|
||||||
|
export interface ExtensionStoreParams<T extends object> extends BaseStoreParams<T> {
|
||||||
|
migrations?: Migrations<T>;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class ExtensionStore<T extends object> extends BaseStore<T> {
|
export abstract class ExtensionStore<T extends object> extends BaseStore<T> {
|
||||||
private static readonly instances = new WeakMap<object, ExtensionStore<object>>();
|
private static readonly instances = new WeakMap<object, ExtensionStore<object>>();
|
||||||
@ -39,7 +44,7 @@ export abstract class ExtensionStore<T extends object> extends BaseStore<T> {
|
|||||||
return ExtensionStore.instances.get(this) as (T | undefined);
|
return ExtensionStore.instances.get(this) as (T | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(params: BaseStoreParams<T>) {
|
constructor({ migrations, ...params }: ExtensionStoreParams<T>) {
|
||||||
const di = getLegacyGlobalDiForExtensionApi();
|
const di = getLegacyGlobalDiForExtensionApi();
|
||||||
|
|
||||||
super({
|
super({
|
||||||
@ -47,6 +52,7 @@ export abstract class ExtensionStore<T extends object> extends BaseStore<T> {
|
|||||||
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
|
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
|
migrations: migrations as Migrations<Record<string, unknown>>,
|
||||||
}, params);
|
}, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
import type { LensExtensionId } from "../lens-extension";
|
import type { LensExtensionId } from "../lens-extension";
|
||||||
import { action, computed, makeObservable, observable } from "mobx";
|
import { action, computed, makeObservable, observable } from "mobx";
|
||||||
import { toJS } from "../../common/utils";
|
import { toJS } from "../../common/utils";
|
||||||
import type { BaseStoreDependencies } from "../../common/base-store";
|
import type { BaseStoreDependencies } from "../../common/base-store/base-store";
|
||||||
import { BaseStore } from "../../common/base-store";
|
import { BaseStore } from "../../common/base-store/base-store";
|
||||||
|
|
||||||
export interface LensExtensionsStoreModel {
|
export interface LensExtensionsStoreModel {
|
||||||
extensions: Record<LensExtensionId, LensExtensionState>;
|
extensions: Record<LensExtensionId, LensExtensionState>;
|
||||||
|
|||||||
103
src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts
Normal file
103
src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Move embedded kubeconfig into separate file and add reference to it to cluster settings
|
||||||
|
// convert file path cluster icons to their base64 encoded versions
|
||||||
|
|
||||||
|
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||||
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
|
import getCustomKubeConfigDirectoryInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||||
|
import type { ClusterModel } from "../../../common/cluster-types";
|
||||||
|
import readFileSyncInjectable from "../../../common/fs/read-file-sync.injectable";
|
||||||
|
import { loadConfigFromString } from "../../../common/kube-helpers";
|
||||||
|
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||||
|
import { migrationLog } from "../../../migrations/helpers";
|
||||||
|
|
||||||
|
interface Pre360ClusterModel extends ClusterModel {
|
||||||
|
kubeConfig?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
|
||||||
|
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||||
|
import readFileBufferSyncInjectable from "../../../common/fs/read-file-buffer-sync.injectable";
|
||||||
|
|
||||||
|
const v360Beta1ClusterStoreMigrationInjectable = getInjectable({
|
||||||
|
id: "v3.6.0-beta.1-cluster-store-migration",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||||
|
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
|
||||||
|
const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigDirectoryInjectable);
|
||||||
|
const readFileSync = di.inject(readFileSyncInjectable);
|
||||||
|
const readFileBufferSync = di.inject(readFileBufferSyncInjectable);
|
||||||
|
const joinPaths = di.inject(joinPathsInjectable);
|
||||||
|
const {
|
||||||
|
ensureDirSync,
|
||||||
|
writeFileSync,
|
||||||
|
} = di.inject(fsInjectable);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: "3.6.0-beta.1",
|
||||||
|
run: (store) => {
|
||||||
|
const storedClusters = (store.get("clusters") ?? []) as Pre360ClusterModel[];
|
||||||
|
const migratedClusters: ClusterModel[] = [];
|
||||||
|
|
||||||
|
ensureDirSync(kubeConfigsPath);
|
||||||
|
|
||||||
|
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
||||||
|
|
||||||
|
for (const clusterModel of storedClusters) {
|
||||||
|
/**
|
||||||
|
* migrate kubeconfig
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
const absPath = getCustomKubeConfigDirectory(clusterModel.id);
|
||||||
|
|
||||||
|
if (!clusterModel.kubeConfig) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take the embedded kubeconfig and dump it into a file
|
||||||
|
writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 });
|
||||||
|
|
||||||
|
clusterModel.kubeConfigPath = absPath;
|
||||||
|
clusterModel.contextName = loadConfigFromString(readFileSync(absPath)).config.getCurrentContext();
|
||||||
|
delete clusterModel.kubeConfig;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
migrationLog(`Failed to migrate Kubeconfig for cluster "${clusterModel.id}", removing clusterModel...`, error);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* migrate cluster icon
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
if (clusterModel.preferences?.icon) {
|
||||||
|
migrationLog(`migrating ${clusterModel.preferences.icon} for ${clusterModel.preferences.clusterName}`);
|
||||||
|
const iconPath = clusterModel.preferences.icon.replace("store://", "");
|
||||||
|
const fileData = readFileBufferSync(joinPaths(userDataPath, iconPath));
|
||||||
|
|
||||||
|
clusterModel.preferences.icon = `data:;base64,${fileData.toString("base64")}`;
|
||||||
|
} else {
|
||||||
|
delete clusterModel.preferences?.icon;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
migrationLog(`Failed to migrate cluster icon for cluster "${clusterModel.id}"`, error);
|
||||||
|
delete clusterModel.preferences?.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
migratedClusters.push(clusterModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set("clusters", migratedClusters);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: clusterStoreMigrationInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default v360Beta1ClusterStoreMigrationInjectable;
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
|
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
|
||||||
|
import type { ClusterModel } from "../../../common/cluster-types";
|
||||||
|
import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable";
|
||||||
|
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||||
|
import { isErrnoException } from "../../../common/utils";
|
||||||
|
|
||||||
|
interface Pre500WorkspaceStoreModel {
|
||||||
|
workspaces: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const v500Beta10ClusterStoreMigrationInjectable = getInjectable({
|
||||||
|
id: "v5.0.0-beta.10-cluster-store-migration",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||||
|
const joinPaths = di.inject(joinPathsInjectable);
|
||||||
|
const readJsonSync = di.inject(readJsonSyncInjectable);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: "5.0.0-beta.10",
|
||||||
|
run(store) {
|
||||||
|
try {
|
||||||
|
const workspaceData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json"));
|
||||||
|
const workspaces = new Map<string, string>(); // mapping from WorkspaceId to name
|
||||||
|
|
||||||
|
for (const { id, name } of workspaceData.workspaces) {
|
||||||
|
workspaces.set(id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clusters = (store.get("clusters") ?? []) as ClusterModel[];
|
||||||
|
|
||||||
|
for (const cluster of clusters) {
|
||||||
|
if (cluster.workspace) {
|
||||||
|
const workspace = workspaces.get(cluster.workspace);
|
||||||
|
|
||||||
|
if (workspace) {
|
||||||
|
(cluster.labels ??= {}).workspace = workspace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set("clusters", clusters);
|
||||||
|
} catch (error) {
|
||||||
|
if (isErrnoException(error) && !(error.code === "ENOENT" && error.path?.endsWith("lens-workspace-store.json"))) {
|
||||||
|
// ignore lens-workspace-store.json being missing
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: clusterStoreMigrationInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default v500Beta10ClusterStoreMigrationInjectable;
|
||||||
@ -3,15 +3,12 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../common/cluster-types";
|
import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../../common/cluster-types";
|
||||||
import type { MigrationDeclaration } from "../helpers";
|
|
||||||
import { migrationLog } from "../helpers";
|
|
||||||
import { generateNewIdFor } from "../utils";
|
|
||||||
import { moveSync, removeSync } from "fs-extra";
|
import { moveSync, removeSync } from "fs-extra";
|
||||||
import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
import { isDefined } from "../../../common/utils";
|
||||||
import { isDefined } from "../../common/utils";
|
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
import { generateNewIdFor } from "../../../migrations/utils";
|
||||||
|
|
||||||
function mergePrometheusPreferences(left: ClusterPrometheusPreferences, right: ClusterPrometheusPreferences): ClusterPrometheusPreferences {
|
function mergePrometheusPreferences(left: ClusterPrometheusPreferences, right: ClusterPrometheusPreferences): ClusterPrometheusPreferences {
|
||||||
if (left.prometheus && left.prometheusProvider) {
|
if (left.prometheus && left.prometheusProvider) {
|
||||||
@ -78,13 +75,16 @@ function mergeClusterModel(prev: ClusterModel, right: Omit<ClusterModel, "id">):
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
version: "5.0.0-beta.13",
|
import loggerInjectable from "../../../common/logger.injectable";
|
||||||
run(store) {
|
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
|
||||||
const di = getLegacyGlobalDiForExtensionApi();
|
|
||||||
|
|
||||||
|
const v500Beta13ClusterStoreMigrationInjectable = getInjectable({
|
||||||
|
id: "v5.0.0-beta.13-cluster-store-migration",
|
||||||
|
instantiate: (di) => {
|
||||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||||
const joinPaths = di.inject(joinPathsInjectable);
|
const joinPaths = di.inject(joinPathsInjectable);
|
||||||
|
const logger = di.inject(loggerInjectable);
|
||||||
|
|
||||||
const moveStorageFolder = ({ folder, newId, oldId }: { folder: string; newId: string; oldId: string }): void => {
|
const moveStorageFolder = ({ folder, newId, oldId }: { folder: string; newId: string; oldId: string }): void => {
|
||||||
const oldPath = joinPaths(folder, `${oldId}.json`);
|
const oldPath = joinPaths(folder, `${oldId}.json`);
|
||||||
@ -94,14 +94,17 @@ export default {
|
|||||||
moveSync(oldPath, newPath);
|
moveSync(oldPath, newPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (String(error).includes("dest already exists")) {
|
if (String(error).includes("dest already exists")) {
|
||||||
migrationLog(`Multiple old lens-local-storage files for newId=${newId}. Removing ${oldId}.json`);
|
logger.info(`Multiple old lens-local-storage files for newId=${newId}. Removing ${oldId}.json`);
|
||||||
removeSync(oldPath);
|
removeSync(oldPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: "5.0.0-beta.13",
|
||||||
|
run(store) {
|
||||||
const folder = joinPaths(userDataPath, "lens-local-storage");
|
const folder = joinPaths(userDataPath, "lens-local-storage");
|
||||||
const oldClusters: ClusterModel[] = store.get("clusters") ?? [];
|
const oldClusters = (store.get("clusters") ?? []) as ClusterModel[];
|
||||||
const clusters = new Map<string, ClusterModel>();
|
const clusters = new Map<string, ClusterModel>();
|
||||||
|
|
||||||
for (const { id: oldId, ...cluster } of oldClusters) {
|
for (const { id: oldId, ...cluster } of oldClusters) {
|
||||||
@ -109,10 +112,10 @@ export default {
|
|||||||
const newCluster = clusters.get(newId);
|
const newCluster = clusters.get(newId);
|
||||||
|
|
||||||
if (newCluster) {
|
if (newCluster) {
|
||||||
migrationLog(`Duplicate entries for ${newId}`, { oldId });
|
logger.info(`Duplicate entries for ${newId}`, { oldId });
|
||||||
clusters.set(newId, mergeClusterModel(newCluster, cluster));
|
clusters.set(newId, mergeClusterModel(newCluster, cluster));
|
||||||
} else {
|
} else {
|
||||||
migrationLog(`First entry for ${newId}`, { oldId });
|
logger.info(`First entry for ${newId}`, { oldId });
|
||||||
clusters.set(newId, {
|
clusters.set(newId, {
|
||||||
...cluster,
|
...cluster,
|
||||||
id: newId,
|
id: newId,
|
||||||
@ -124,4 +127,9 @@ export default {
|
|||||||
|
|
||||||
store.set("clusters", [...clusters.values()]);
|
store.set("clusters", [...clusters.values()]);
|
||||||
},
|
},
|
||||||
} as MigrationDeclaration;
|
};
|
||||||
|
},
|
||||||
|
injectionToken: clusterStoreMigrationInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default v500Beta13ClusterStoreMigrationInjectable;
|
||||||
60
src/main/cluster/store-migrations/snap.injectable.ts
Normal file
60
src/main/cluster/store-migrations/snap.injectable.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fix embedded kubeconfig paths under snap config
|
||||||
|
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import applicationInformationInjectable from "../../../common/vars/application-information.injectable";
|
||||||
|
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
|
||||||
|
import loggerInjectable from "../../../common/logger.injectable";
|
||||||
|
import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable";
|
||||||
|
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||||
|
import type { ClusterModel } from "../../../common/cluster-types";
|
||||||
|
|
||||||
|
const clusterStoreSnapMigrationInjectable = getInjectable({
|
||||||
|
id: "cluster-store-snap-migration",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const { version } = di.inject(applicationInformationInjectable);
|
||||||
|
const logger = di.inject(loggerInjectable);
|
||||||
|
const isSnapPackage = di.inject(isSnapPackageInjectable);
|
||||||
|
const { existsSync } = di.inject(fsInjectable);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version, // Run always after upgrade
|
||||||
|
run(store) {
|
||||||
|
if (!isSnapPackage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Migrating embedded kubeconfig paths");
|
||||||
|
const storedClusters = (store.get("clusters") || []) as ClusterModel[];
|
||||||
|
|
||||||
|
if (!storedClusters.length) return;
|
||||||
|
|
||||||
|
logger.info("Number of clusters to migrate: ", storedClusters.length);
|
||||||
|
const migratedClusters = storedClusters
|
||||||
|
.map(cluster => {
|
||||||
|
/**
|
||||||
|
* replace snap version with 'current' in kubeconfig path
|
||||||
|
*/
|
||||||
|
if (!existsSync(cluster.kubeConfigPath)) {
|
||||||
|
const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/");
|
||||||
|
|
||||||
|
cluster.kubeConfigPath = kubeconfigPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cluster;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
store.set("clusters", migratedClusters);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: clusterStoreMigrationInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default clusterStoreSnapMigrationInjectable;
|
||||||
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Move embedded kubeconfig into separate file and add reference to it to cluster settings
|
|
||||||
// convert file path cluster icons to their base64 encoded versions
|
|
||||||
|
|
||||||
import fse from "fs-extra";
|
|
||||||
import { loadConfigFromString } from "../../common/kube-helpers";
|
|
||||||
import type { MigrationDeclaration } from "../helpers";
|
|
||||||
import { migrationLog } from "../helpers";
|
|
||||||
import type { ClusterModel } from "../../common/cluster-types";
|
|
||||||
import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
|
||||||
import directoryForUserDataInjectable
|
|
||||||
from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
|
||||||
import directoryForKubeConfigsInjectable
|
|
||||||
from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
|
||||||
import getCustomKubeConfigDirectoryInjectable
|
|
||||||
from "../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
|
||||||
import readFileSyncInjectable from "../../common/fs/read-file-sync.injectable";
|
|
||||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
|
||||||
|
|
||||||
interface Pre360ClusterModel extends ClusterModel {
|
|
||||||
kubeConfig?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
version: "3.6.0-beta.1",
|
|
||||||
run(store) {
|
|
||||||
const di = getLegacyGlobalDiForExtensionApi();
|
|
||||||
|
|
||||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
|
||||||
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
|
|
||||||
const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigDirectoryInjectable);
|
|
||||||
const readFileSync = di.inject(readFileSyncInjectable);
|
|
||||||
const joinPaths = di.inject(joinPathsInjectable);
|
|
||||||
|
|
||||||
const storedClusters: Pre360ClusterModel[] = store.get("clusters") ?? [];
|
|
||||||
const migratedClusters: ClusterModel[] = [];
|
|
||||||
|
|
||||||
fse.ensureDirSync(kubeConfigsPath);
|
|
||||||
|
|
||||||
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
|
||||||
|
|
||||||
for (const clusterModel of storedClusters) {
|
|
||||||
/**
|
|
||||||
* migrate kubeconfig
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
const absPath = getCustomKubeConfigDirectory(clusterModel.id);
|
|
||||||
|
|
||||||
if (!clusterModel.kubeConfig) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// take the embedded kubeconfig and dump it into a file
|
|
||||||
fse.writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 });
|
|
||||||
|
|
||||||
clusterModel.kubeConfigPath = absPath;
|
|
||||||
clusterModel.contextName = loadConfigFromString(readFileSync(absPath)).config.getCurrentContext();
|
|
||||||
delete clusterModel.kubeConfig;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
migrationLog(`Failed to migrate Kubeconfig for cluster "${clusterModel.id}", removing clusterModel...`, error);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* migrate cluster icon
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
if (clusterModel.preferences?.icon) {
|
|
||||||
migrationLog(`migrating ${clusterModel.preferences.icon} for ${clusterModel.preferences.clusterName}`);
|
|
||||||
const iconPath = clusterModel.preferences.icon.replace("store://", "");
|
|
||||||
const fileData = fse.readFileSync(joinPaths(userDataPath, iconPath));
|
|
||||||
|
|
||||||
clusterModel.preferences.icon = `data:;base64,${fileData.toString("base64")}`;
|
|
||||||
} else {
|
|
||||||
delete clusterModel.preferences?.icon;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
migrationLog(`Failed to migrate cluster icon for cluster "${clusterModel.id}"`, error);
|
|
||||||
delete clusterModel.preferences?.icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
migratedClusters.push(clusterModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
store.set("clusters", migratedClusters);
|
|
||||||
},
|
|
||||||
} as MigrationDeclaration;
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import fse from "fs-extra";
|
|
||||||
import type { ClusterModel } from "../../common/cluster-types";
|
|
||||||
import type { MigrationDeclaration } from "../helpers";
|
|
||||||
import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
|
||||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
|
||||||
import { isErrnoException } from "../../common/utils";
|
|
||||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
|
||||||
|
|
||||||
interface Pre500WorkspaceStoreModel {
|
|
||||||
workspaces: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
version: "5.0.0-beta.10",
|
|
||||||
run(store) {
|
|
||||||
const di = getLegacyGlobalDiForExtensionApi();
|
|
||||||
|
|
||||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
|
||||||
const joinPaths = di.inject(joinPathsInjectable);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const workspaceData: Pre500WorkspaceStoreModel = fse.readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json"));
|
|
||||||
const workspaces = new Map<string, string>(); // mapping from WorkspaceId to name
|
|
||||||
|
|
||||||
for (const { id, name } of workspaceData.workspaces) {
|
|
||||||
workspaces.set(id, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const clusters: ClusterModel[] = store.get("clusters") ?? [];
|
|
||||||
|
|
||||||
for (const cluster of clusters) {
|
|
||||||
if (cluster.workspace) {
|
|
||||||
const workspace = workspaces.get(cluster.workspace);
|
|
||||||
|
|
||||||
if (workspace) {
|
|
||||||
(cluster.labels ??= {}).workspace = workspace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
store.set("clusters", clusters);
|
|
||||||
} catch (error) {
|
|
||||||
if (isErrnoException(error) && !(error.code === "ENOENT" && error.path?.endsWith("lens-workspace-store.json"))) {
|
|
||||||
// ignore lens-workspace-store.json being missing
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
} as MigrationDeclaration;
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Cluster store migrations
|
|
||||||
|
|
||||||
import { joinMigrations } from "../helpers";
|
|
||||||
|
|
||||||
import version360Beta1 from "./3.6.0-beta.1";
|
|
||||||
import version500Beta10 from "./5.0.0-beta.10";
|
|
||||||
import version500Beta13 from "./5.0.0-beta.13";
|
|
||||||
import snap from "./snap";
|
|
||||||
|
|
||||||
export default joinMigrations(
|
|
||||||
version360Beta1,
|
|
||||||
version500Beta10,
|
|
||||||
version500Beta13,
|
|
||||||
snap,
|
|
||||||
);
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Fix embedded kubeconfig paths under snap config
|
|
||||||
|
|
||||||
import type { ClusterModel } from "../../common/cluster-types";
|
|
||||||
import fs from "fs";
|
|
||||||
import type { MigrationDeclaration } from "../helpers";
|
|
||||||
import { migrationLog } from "../helpers";
|
|
||||||
import packageJson from "../../../package.json";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
// TODO: replace with injection once migrations are made as injectables
|
|
||||||
version: packageJson.version, // Run always after upgrade
|
|
||||||
run(store) {
|
|
||||||
if (!process.env["SNAP"]) return;
|
|
||||||
|
|
||||||
migrationLog("Migrating embedded kubeconfig paths");
|
|
||||||
const storedClusters: ClusterModel[] = store.get("clusters") || [];
|
|
||||||
|
|
||||||
if (!storedClusters.length) return;
|
|
||||||
|
|
||||||
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
|
||||||
const migratedClusters = storedClusters
|
|
||||||
.map(cluster => {
|
|
||||||
/**
|
|
||||||
* replace snap version with 'current' in kubeconfig path
|
|
||||||
*/
|
|
||||||
if (!fs.existsSync(cluster.kubeConfigPath)) {
|
|
||||||
const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/");
|
|
||||||
|
|
||||||
cluster.kubeConfigPath = kubeconfigPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cluster;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
store.set("clusters", migratedClusters);
|
|
||||||
},
|
|
||||||
} as MigrationDeclaration;
|
|
||||||
@ -16,7 +16,7 @@ export function migrationLog(...args: any[]) {
|
|||||||
|
|
||||||
export interface MigrationDeclaration {
|
export interface MigrationDeclaration {
|
||||||
version: string;
|
version: string;
|
||||||
run(store: Conf<any>): void;
|
run(store: Conf<Partial<Record<string, unknown>>>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function joinMigrations(...declarations: MigrationDeclaration[]): Migrations<any> {
|
export function joinMigrations(...declarations: MigrationDeclaration[]): Migrations<any> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user