UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

125 lines (124 loc) 6.81 kB
/* * Copyright 2025 The Kubernetes Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as jsyaml from 'js-yaml'; import { findMatchingContexts, handleDataBaseError, handleDatabaseUpgrade, } from '.'; /** * deleteClusterKubeconfig deletes the kubeconfig for a stateless cluster from indexedDB * @param clusterName - The name of the cluster * @param clusterID The ID for a cluster, composed of the kubeconfig path and cluster name * @returns A promise that resolves with the kubeconfig, or null if not found. */ export async function deleteClusterKubeconfig(clusterName, clusterID) { return new Promise(async (resolve, reject) => { try { const request = indexedDB.open('kubeconfigs', 1); // The onupgradeneeded event is fired when the database is created for the first time. request.onupgradeneeded = handleDatabaseUpgrade; // The onsuccess event is fired when the database is opened. // This event is where you specify the actions to take when the database is opened. request.onsuccess = function handleDatabaseSuccess(event) { const db = event.target.result; const transaction = db.transaction(['kubeconfigStore'], 'readwrite'); const store = transaction.objectStore('kubeconfigStore'); // The onsuccess event is fired when the request has succeeded. // This is where you handle the results of the request. // The result is the cursor. It is used to iterate through the object store. // The cursor is null when there are no more objects to iterate through. // The cursor is used to find the kubeconfig by cluster name. store.openCursor().onsuccess = function storeSuccess(event) { // delete the kubeconfig by cluster name const successEvent = event; const cursor = successEvent.target.result; // when we do not find a cursor, we resolve with null if (!cursor) { resolve(null); return; } const row = cursor.value; const kubeconfig64 = row.kubeconfig; const parsed = jsyaml.load(atob(kubeconfig64)); const { matchingKubeconfig, matchingContext } = findMatchingContexts(clusterName, parsed, clusterID); // if neither a matching kubeconfig nor a matching context is found, continue to the next cursor if (!matchingKubeconfig && !matchingContext) { cursor.continue(); return; } // for matches found we compute the names we will delete const contextName = matchingContext?.name ?? matchingKubeconfig?.name ?? undefined; // remove only the matched context from the kubeconfig store parsed.contexts = (parsed.contexts || []).filter(context => context.name !== contextName); // if the context was the 'current-context' we just removed then we need to reset it if (parsed['current-context'] === contextName) { const nextContext = parsed.contexts && parsed.contexts[0]?.name; if (nextContext) { parsed['current-context'] = nextContext; } else { delete parsed['current-context']; } } // determine what clusters/users are still referenced by remaining contexts const remainingRefs = new Set((parsed.contexts || []).flatMap(c => { const arr = []; if (c.context.cluster) arr.push(c.context.cluster); if (c.context.user) arr.push(c.context.user); return arr; })); // clean up unreferenced clusters/users if (parsed.clusters) { parsed.clusters = parsed.clusters.filter(c => remainingRefs.has(c.name)); } if (parsed.users) { parsed.users = parsed.users.filter(u => remainingRefs.has(u.name)); } // if no contexts remain, delete the whole indexDB row if (!parsed.contexts || parsed.contexts.length === 0) { const deleteRequest = store.delete(cursor.key); deleteRequest.onsuccess = () => { console.debug('Kubeconfig deleted from IndexedDB'); resolve(kubeconfig64); }; deleteRequest.onerror = () => { console.error('Error deleting kubeconfig from IndexedDB'); reject('Error deleting kubeconfig from IndexedDB'); }; return; } // save the updated kubeconfig back to indexedDB const updatedKubeconfig64 = btoa(jsyaml.dump(parsed)); const updatedRow = { ...row, kubeconfig: updatedKubeconfig64 }; const putRequest = store.put(updatedRow); putRequest.onsuccess = () => { console.debug('Kubeconfig updated in IndexedDB'); resolve(kubeconfig64); }; putRequest.onerror = () => { console.error('Error updating kubeconfig in IndexedDB'); reject('Error updating kubeconfig in IndexedDB'); }; }; }; // The onerror event is fired when the database is opened. // This is where you handle errors. request.onerror = handleDataBaseError; } catch (error) { reject(error); } }); }