mirror of
https://github.com/podman-desktop/podman-desktop
synced 2026-05-24 10:18:53 +00:00
feat: Reload kubernetes context if it is changed over time (#813)
Before it was read only at startup. Also, move the watcher in the core part and expose it with API Change-Id: I574d9dbfcacdfcdcaea8e89230fe24cb01920fb0 Signed-off-by: Florent Benoit <fbenoit@redhat.com> Signed-off-by: Florent Benoit <fbenoit@redhat.com>
This commit is contained in:
parent
fa540d320e
commit
df9172a921
5 changed files with 78 additions and 60 deletions
|
|
@ -25,9 +25,7 @@ interface KubeContext {
|
|||
}
|
||||
|
||||
const menuItemsRegistered: extensionApi.Disposable[] = [];
|
||||
|
||||
let kubeConfigWatcher: extensionApi.FileSystemWatcher;
|
||||
let kubeconfigFile: string;
|
||||
let kubeconfigFile: string | undefined;
|
||||
|
||||
async function deleteContext(): Promise<void> {
|
||||
// remove the context from the list
|
||||
|
|
@ -78,30 +76,7 @@ async function updateContext(extensionContext: extensionApi.ExtensionContext, ku
|
|||
extensionContext.subscriptions.push(subscription);
|
||||
}
|
||||
|
||||
function setupWatcher(
|
||||
extensionContext: extensionApi.ExtensionContext,
|
||||
kubeconfigFile: string,
|
||||
): extensionApi.FileSystemWatcher {
|
||||
// monitor the kube config file for changes
|
||||
const kubeConfigWatcher = extensionApi.fs.createFileSystemWatcher(kubeconfigFile);
|
||||
|
||||
// update the tray everytime .kube/config file is updated
|
||||
kubeConfigWatcher.onDidChange(() => {
|
||||
updateContext(extensionContext, kubeconfigFile);
|
||||
});
|
||||
|
||||
kubeConfigWatcher.onDidCreate(() => {
|
||||
updateContext(extensionContext, kubeconfigFile);
|
||||
});
|
||||
|
||||
kubeConfigWatcher.onDidDelete(() => {
|
||||
deleteContext();
|
||||
});
|
||||
|
||||
return kubeConfigWatcher;
|
||||
}
|
||||
|
||||
function getKubeconfig(): string {
|
||||
function getKubeconfig(): string | undefined {
|
||||
return kubeconfigFile;
|
||||
}
|
||||
|
||||
|
|
@ -110,21 +85,24 @@ export async function activate(extensionContext: extensionApi.ExtensionContext):
|
|||
|
||||
// grab current file
|
||||
const kubeconfigUri = await extensionApi.kubernetes.getKubeconfig();
|
||||
|
||||
kubeconfigFile = kubeconfigUri.fsPath;
|
||||
|
||||
// setup watcher
|
||||
kubeConfigWatcher = setupWatcher(extensionContext, kubeconfigFile);
|
||||
extensionContext.subscriptions.push(kubeConfigWatcher);
|
||||
// if path exists, update context
|
||||
if (fs.existsSync(kubeconfigFile)) {
|
||||
updateContext(extensionContext, kubeconfigFile);
|
||||
}
|
||||
|
||||
extensionApi.kubernetes.onDidChangeKubeconfig((event: extensionApi.KubeConfigChangeEvent) => {
|
||||
kubeconfigFile = event.newLocation.fsPath;
|
||||
|
||||
// dispose the old watcher
|
||||
kubeConfigWatcher.dispose();
|
||||
|
||||
// setup new watcher
|
||||
kubeConfigWatcher = setupWatcher(extensionContext, kubeconfigFile);
|
||||
extensionContext.subscriptions.push(kubeConfigWatcher);
|
||||
// update context menu on change
|
||||
extensionApi.kubernetes.onDidUpdateKubeconfig((event: extensionApi.KubeconfigUpdateEvent) => {
|
||||
// update the tray everytime .kube/config file is updated
|
||||
if (event.type === 'UPDATE' || event.type === 'CREATE') {
|
||||
kubeconfigFile = event.location.fsPath;
|
||||
updateContext(extensionContext, kubeconfigFile);
|
||||
} else if (event.type === 'DELETE') {
|
||||
deleteContext();
|
||||
kubeconfigFile = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const command = extensionApi.commands.registerCommand('kubecontext.switch', async (newContext: string) => {
|
||||
|
|
|
|||
10
packages/extension-api/src/extension-api.d.ts
vendored
10
packages/extension-api/src/extension-api.d.ts
vendored
|
|
@ -653,14 +653,14 @@ declare module '@tmpwip/extension-api' {
|
|||
export namespace kubernetes {
|
||||
// Path to the configuration file
|
||||
export function getKubeconfig(): Uri;
|
||||
export const onDidChangeKubeconfig: Event<KubeConfigChangeEvent>;
|
||||
export const onDidUpdateKubeconfig: Event<KubeconfigUpdateEvent>;
|
||||
export function setKubeconfig(kubeconfig: Uri): Promise<void>;
|
||||
}
|
||||
/**
|
||||
* An event describing the change in kubeconfig location
|
||||
* An event describing the update in kubeconfig location
|
||||
*/
|
||||
export interface KubeConfigChangeEvent {
|
||||
readonly oldLocation: Uri;
|
||||
readonly newLocation: Uri;
|
||||
export interface KubeconfigUpdateEvent {
|
||||
readonly type: 'CREATE' | 'UPDATE' | 'DELETE';
|
||||
readonly location: Uri;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import type { NotificationImpl } from './notification-impl';
|
|||
import { StatusBarItemImpl } from './statusbar/statusbar-item';
|
||||
import type { StatusBarRegistry } from './statusbar/statusbar-registry';
|
||||
import { StatusBarAlignLeft, StatusBarAlignRight, StatusBarItemDefaultPriority } from './statusbar/statusbar-item';
|
||||
import { FilesystemMonitoring } from './filesystem-monitoring';
|
||||
import type { FilesystemMonitoring } from './filesystem-monitoring';
|
||||
import { Uri } from './types/uri';
|
||||
import type { KubernetesClient } from './kubernetes-client';
|
||||
|
||||
|
|
@ -67,7 +67,6 @@ export class ExtensionLoader {
|
|||
private activatedExtensions = new Map<string, ActivatedExtension>();
|
||||
private analyzedExtensions = new Map<string, AnalyzedExtension>();
|
||||
private extensionsStoragePath = '';
|
||||
private fileSystemMonitoring: FilesystemMonitoring;
|
||||
|
||||
constructor(
|
||||
private commandRegistry: CommandRegistry,
|
||||
|
|
@ -82,9 +81,8 @@ export class ExtensionLoader {
|
|||
private notifications: NotificationImpl,
|
||||
private statusBarRegistry: StatusBarRegistry,
|
||||
private kubernetesClient: KubernetesClient,
|
||||
) {
|
||||
this.fileSystemMonitoring = new FilesystemMonitoring();
|
||||
}
|
||||
private fileSystemMonitoring: FilesystemMonitoring,
|
||||
) {}
|
||||
|
||||
async listExtensions(): Promise<ExtensionInfo[]> {
|
||||
return Array.from(this.analyzedExtensions.values()).map(extension => ({
|
||||
|
|
@ -393,8 +391,8 @@ export class ExtensionLoader {
|
|||
async setKubeconfig(kubeconfig: containerDesktopAPI.Uri): Promise<void> {
|
||||
return kubernetesClient.setKubeconfig(kubeconfig);
|
||||
},
|
||||
onDidChangeKubeconfig: (listener, thisArg, disposables) => {
|
||||
return kubernetesClient.onDidChangeKubeconfig(listener, thisArg, disposables);
|
||||
onDidUpdateKubeconfig: (listener, thisArg, disposables) => {
|
||||
return kubernetesClient.onDidUpdateKubeconfig(listener, thisArg, disposables);
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ import { KubernetesClient } from './kubernetes-client';
|
|||
import type { V1Pod, V1ConfigMap, V1NamespaceList, V1PodList, V1Service } from '@kubernetes/client-node';
|
||||
import type { V1Route } from './api/openshift-types';
|
||||
import type { NetworkInspectInfo } from './api/network-info';
|
||||
import { FilesystemMonitoring } from './filesystem-monitoring';
|
||||
|
||||
type LogType = 'log' | 'warn' | 'trace' | 'debug' | 'error';
|
||||
export class PluginSystem {
|
||||
|
|
@ -208,7 +209,9 @@ export class PluginSystem {
|
|||
const providerRegistry = new ProviderRegistry(apiSender, containerProviderRegistry, telemetry);
|
||||
const trayMenuRegistry = new TrayMenuRegistry(this.trayMenu, commandRegistry, providerRegistry, telemetry);
|
||||
const statusBarRegistry = new StatusBarRegistry(apiSender);
|
||||
const kubernetesClient = new KubernetesClient(configurationRegistry);
|
||||
const fileSystemMonitoring = new FilesystemMonitoring();
|
||||
|
||||
const kubernetesClient = new KubernetesClient(configurationRegistry, fileSystemMonitoring);
|
||||
await kubernetesClient.init();
|
||||
const closeBehaviorConfiguration = new CloseBehavior(configurationRegistry, providerRegistry);
|
||||
await closeBehaviorConfiguration.init();
|
||||
|
|
@ -242,6 +245,7 @@ export class PluginSystem {
|
|||
new NotificationImpl(),
|
||||
statusBarRegistry,
|
||||
kubernetesClient,
|
||||
fileSystemMonitoring,
|
||||
);
|
||||
|
||||
const contributionManager = new ContributionManager(apiSender);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { homedir } from 'node:os';
|
|||
import { resolve } from 'node:path';
|
||||
import { existsSync } from 'node:fs';
|
||||
import type { ConfigurationRegistry, IConfigurationNode } from './configuration-registry';
|
||||
import type { FilesystemMonitoring } from './filesystem-monitoring';
|
||||
|
||||
/**
|
||||
* Handle calls to kubernetes API
|
||||
|
|
@ -41,11 +42,17 @@ export class KubernetesClient {
|
|||
|
||||
private currrentNamespace: string | undefined;
|
||||
private currentContextName: string | undefined;
|
||||
private readonly _onDidChangeKubeconfig = new Emitter<containerDesktopAPI.KubeConfigChangeEvent>();
|
||||
readonly onDidChangeKubeconfig: containerDesktopAPI.Event<containerDesktopAPI.KubeConfigChangeEvent> =
|
||||
this._onDidChangeKubeconfig.event;
|
||||
|
||||
constructor(private configurationRegistry: ConfigurationRegistry) {
|
||||
private kubeConfigWatcher: containerDesktopAPI.FileSystemWatcher | undefined;
|
||||
|
||||
private readonly _onDidUpdateKubeconfig = new Emitter<containerDesktopAPI.KubeconfigUpdateEvent>();
|
||||
readonly onDidUpdateKubeconfig: containerDesktopAPI.Event<containerDesktopAPI.KubeconfigUpdateEvent> =
|
||||
this._onDidUpdateKubeconfig.event;
|
||||
|
||||
constructor(
|
||||
private configurationRegistry: ConfigurationRegistry,
|
||||
private fileSystemMonitoring: FilesystemMonitoring,
|
||||
) {
|
||||
this.kubeConfig = new KubeConfig();
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +81,7 @@ export class KubernetesClient {
|
|||
const kubernetesConfiguration = this.configurationRegistry.getConfiguration('kubernetes');
|
||||
const userKubeconfigPath = kubernetesConfiguration.get<string>('Kubeconfig');
|
||||
if (userKubeconfigPath) {
|
||||
this.setupWatcher(userKubeconfigPath);
|
||||
// check if path exists
|
||||
if (existsSync(userKubeconfigPath)) {
|
||||
this.kubeconfigPath = userKubeconfigPath;
|
||||
|
|
@ -87,11 +95,38 @@ export class KubernetesClient {
|
|||
this.configurationRegistry.onDidChangeConfiguration(e => {
|
||||
if (e.key === 'kubernetes.Kubeconfig') {
|
||||
const val = e.value as string;
|
||||
this.setupWatcher(val);
|
||||
this.setKubeconfig(Uri.file(val));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setupWatcher(kubeconfigFile: string): void {
|
||||
// cancel the previous one (if any)
|
||||
this.kubeConfigWatcher?.dispose();
|
||||
|
||||
// monitor the kube config file for changes
|
||||
this.kubeConfigWatcher = this.fileSystemMonitoring.createFileSystemWatcher(kubeconfigFile);
|
||||
|
||||
const location = Uri.file(kubeconfigFile);
|
||||
|
||||
// needs to refresh
|
||||
this.kubeConfigWatcher.onDidChange(() => {
|
||||
this._onDidUpdateKubeconfig.fire({ type: 'UPDATE', location });
|
||||
this.refresh();
|
||||
});
|
||||
|
||||
this.kubeConfigWatcher.onDidCreate(() => {
|
||||
this._onDidUpdateKubeconfig.fire({ type: 'CREATE', location });
|
||||
this.refresh();
|
||||
});
|
||||
|
||||
this.kubeConfigWatcher.onDidDelete(() => {
|
||||
this._onDidUpdateKubeconfig.fire({ type: 'DELETE', location });
|
||||
this.kubeConfig = new KubeConfig();
|
||||
});
|
||||
}
|
||||
|
||||
getContexts(): Context[] {
|
||||
return this.kubeConfig.contexts;
|
||||
}
|
||||
|
|
@ -242,11 +277,14 @@ export class KubernetesClient {
|
|||
return Uri.file(this.kubeconfigPath);
|
||||
}
|
||||
|
||||
async setKubeconfig(newLocation: containerDesktopAPI.Uri): Promise<void> {
|
||||
const oldLocation = Uri.file(this.kubeconfigPath);
|
||||
this.kubeconfigPath = newLocation.fsPath;
|
||||
async setKubeconfig(location: containerDesktopAPI.Uri): Promise<void> {
|
||||
this.kubeconfigPath = location.fsPath;
|
||||
this.refresh();
|
||||
// notify change
|
||||
this._onDidChangeKubeconfig.fire({ oldLocation, newLocation });
|
||||
this._onDidUpdateKubeconfig.fire({ type: 'UPDATE', location });
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
this.kubeConfigWatcher?.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue