diff --git a/backend/cmd/headlamp.go b/backend/cmd/headlamp.go
index 268f908e6e..e13f3af882 100644
--- a/backend/cmd/headlamp.go
+++ b/backend/cmd/headlamp.go
@@ -234,6 +234,17 @@ func serveWithNoCacheHeader(fs http.Handler) http.HandlerFunc {
}
}
+// defaultKubeConfigFile returns the default path to the kubeconfig file.
+func defaultKubeConfigFile() (string, error) {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return "", fmt.Errorf("failed to get user home directory: %v", err)
+ }
+
+ kubeConfigFile := filepath.Join(homeDir, ".kube", "config")
+ return kubeConfigFile, nil
+}
+
// defaultKubeConfigPersistenceDir returns the default directory to store kubeconfig
// files of clusters that are loaded in Headlamp.
func defaultKubeConfigPersistenceDir() (string, error) {
@@ -1384,6 +1395,26 @@ func (c *HeadlampConfig) deleteCluster(w http.ResponseWriter, r *http.Request) {
return
}
+ removeKubeConfig := r.URL.Query().Get("removeKubeConfig") == "true"
+
+ if removeKubeConfig {
+ // delete context from actual deafult kubecofig file
+ kubeConfigFile, err := defaultKubeConfigFile()
+ if err != nil {
+ logger.Log(logger.LevelError, map[string]string{"cluster": name}, err, "failed to get default kubeconfig file path")
+ http.Error(w, "failed to get default kubeconfig file path", http.StatusInternalServerError)
+ return
+ }
+
+ // Use kubeConfigFile to remove the context from the default kubeconfig file
+ err = kubeconfig.RemoveContextFromFile(name, kubeConfigFile)
+ if err != nil {
+ logger.Log(logger.LevelError, map[string]string{"cluster": name}, err, "removing context from default kubeconfig file")
+ http.Error(w, "removing context from default kubeconfig file", http.StatusInternalServerError)
+ return
+ }
+ }
+
kubeConfigPersistenceFile, err := defaultKubeConfigPersistenceFile()
if err != nil {
logger.Log(logger.LevelError, map[string]string{"cluster": name},
@@ -1396,8 +1427,7 @@ func (c *HeadlampConfig) deleteCluster(w http.ResponseWriter, r *http.Request) {
logger.Log(logger.LevelInfo, map[string]string{
"cluster": name,
"kubeConfigPersistenceFile": kubeConfigPersistenceFile,
- },
- nil, "Removing cluster from kubeconfig")
+ }, nil, "Removing cluster from kubeconfig")
err = kubeconfig.RemoveContextFromFile(name, kubeConfigPersistenceFile)
if err != nil {
diff --git a/frontend/src/components/App/Home/index.tsx b/frontend/src/components/App/Home/index.tsx
index 94c5e95159..776496b4c9 100644
--- a/frontend/src/components/App/Home/index.tsx
+++ b/frontend/src/components/App/Home/index.tsx
@@ -25,6 +25,24 @@ import { ConfirmDialog } from '../../common';
import ResourceTable from '../../common/Resource/ResourceTable';
import RecentClusters from './RecentClusters';
+/**
+ * Gets the origin of a cluster.
+ *
+ * @param cluster
+ * @returns A description of where the cluster is picked up from: dynamic, in-cluster, or from a kubeconfig file.
+ */
+function getOrigin(cluster: Cluster): string {
+ if (cluster.meta_data?.source === 'kubeconfig') {
+ const kubeconfigPath = process.env.KUBECONFIG ?? '~/.kube/config';
+ return `Kubeconfig: ${kubeconfigPath}`;
+ } else if (cluster.meta_data?.source === 'dynamic_cluster') {
+ return t('translation|Plugin');
+ } else if (cluster.meta_data?.source === 'in_cluster') {
+ return t('translation|In-cluster');
+ }
+ return 'Unknown';
+}
+
function ContextMenu({ cluster }: { cluster: Cluster }) {
const { t } = useTranslation(['translation']);
const history = useHistory();
@@ -33,8 +51,8 @@ function ContextMenu({ cluster }: { cluster: Cluster }) {
const menuId = useId('context-menu');
const [openConfirmDialog, setOpenConfirmDialog] = React.useState(false);
- function removeCluster(cluster: Cluster) {
- deleteCluster(cluster.name || '')
+ function removeCluster(cluster: Cluster, removeKubeconfig?: boolean) {
+ deleteCluster(cluster.name || '', removeKubeconfig)
.then(config => {
dispatch(setConfig(config));
})
@@ -92,7 +110,8 @@ function ContextMenu({ cluster }: { cluster: Cluster }) {
>
{t('translation|Settings')}
- {helpers.isElectron() && cluster.meta_data?.source === 'dynamic_cluster' && (
+
+ {helpers.isElectron() && (