Skip to content

Commit

Permalink
Merge pull request #2288 from headlamp-k8s/kubeconfig-multicluster
Browse files Browse the repository at this point in the history
Add check for multiple clusters with the same context name
  • Loading branch information
joaquimrocha authored Sep 2, 2024
2 parents be6775f + c291058 commit a80242e
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 10 deletions.
2 changes: 2 additions & 0 deletions backend/cmd/headlamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,8 @@ func (c *HeadlampConfig) renameCluster(w http.ResponseWriter, r *http.Request) {
if reqBody.Stateless {
// For stateless clusters we just need to remove cluster from cache
c.handleStatelessClusterRename(w, r, clusterName)

return
}

// Get path of kubeconfig from source
Expand Down
32 changes: 30 additions & 2 deletions frontend/src/components/cluster/KubeConfigLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useDropzone } from 'react-dropzone';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useClustersConf } from '../../lib/k8s';
import { setCluster } from '../../lib/k8s/apiProxy';
import { setStatelessConfig } from '../../redux/configSlice';
import { DialogTitle } from '../common/Dialog';
Expand Down Expand Up @@ -105,6 +106,7 @@ const WideButton = styled(Button)({
const enum Step {
LoadKubeConfig,
SelectClusters,
ValidateKubeConfig,
ConfigureClusters,
Success,
}
Expand All @@ -120,6 +122,7 @@ function KubeConfigLoader() {
currentContext: '',
});
const [selectedClusters, setSelectedClusters] = useState<string[]>([]);
const configuredClusters = useClustersConf(); // Get already configured clusters

useEffect(() => {
if (fileContent.contexts.length > 0) {
Expand All @@ -130,9 +133,27 @@ function KubeConfigLoader() {
}, [fileContent]);

useEffect(() => {
if (state === Step.ValidateKubeConfig) {
const alreadyConfiguredClusters = selectedClusters.filter(
clusterName => configuredClusters && configuredClusters[clusterName]
);

if (alreadyConfiguredClusters.length > 0) {
setError(
t(
'translation|Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.',
{
clusterNames: alreadyConfiguredClusters.join(', '),
}
)
);
setState(Step.SelectClusters);
} else {
setState(Step.ConfigureClusters);
}
}
if (state === Step.ConfigureClusters) {
function loadClusters() {
//@todo: We need to check if the cluster is already configured.
const selectedClusterConfig = configWithSelectedClusters(fileContent, selectedClusters);
setCluster({ kubeconfig: btoa(yaml.dump(selectedClusterConfig)) })
.then(res => {
Expand Down Expand Up @@ -295,7 +316,7 @@ function KubeConfigLoader() {
variant="contained"
color="primary"
onClick={() => {
setState(Step.ConfigureClusters);
setState(Step.ValidateKubeConfig);
}}
disabled={selectedClusters.length === 0}
>
Expand All @@ -318,6 +339,13 @@ function KubeConfigLoader() {
) : null}
</Box>
);
case Step.ValidateKubeConfig:
return (
<Box style={{ textAlign: 'center' }}>
<Typography>{t('translation|Validating selected clusters')}</Typography>
<Loader title={t('translation|Validating selected clusters')} />
</Box>
);
case Step.ConfigureClusters:
return (
<Box style={{ textAlign: 'center' }}>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/i18n/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"Current//context:cluster": "Aktuell",
"Choose cluster": "Cluster auswählen",
"Add Cluster": "Cluster hinzufügen",
"Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.": "",
"Error setting up clusters, please load a valid kubeconfig file": "Fehler beim Einrichten der Cluster. Bitte laden Sie eine korrekte kubeconfig-Datei",
"Couldn't read kubeconfig file": "Konnte die kubeconfig-Datei nicht lesen",
"No clusters found!": "",
Expand All @@ -119,6 +120,7 @@
"Choose file": "Datei auswählen",
"Select clusters": "Cluster auswählen",
"Next": "Weiter",
"Validating selected clusters": "",
"Setting up clusters": "Einrichten der Cluster",
"Clusters successfully set up!": "Cluster erfolgreich eingerichtet!",
"Finish": "Beenden",
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"Current//context:cluster": "Current",
"Choose cluster": "Choose cluster",
"Add Cluster": "Add Cluster",
"Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.": "Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.",
"Error setting up clusters, please load a valid kubeconfig file": "Error setting up clusters, please load a valid kubeconfig file",
"Couldn't read kubeconfig file": "Couldn't read kubeconfig file",
"No clusters found!": "No clusters found!",
Expand All @@ -119,6 +120,7 @@
"Choose file": "Choose file",
"Select clusters": "Select clusters",
"Next": "Next",
"Validating selected clusters": "Validating selected clusters",
"Setting up clusters": "Setting up clusters",
"Clusters successfully set up!": "Clusters successfully set up!",
"Finish": "Finish",
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/i18n/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"Current//context:cluster": "Actuales",
"Choose cluster": "Elegir cluster",
"Add Cluster": "Añadir cluster",
"Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.": "",
"Error setting up clusters, please load a valid kubeconfig file": "Error al configurar los clusters, por favor cargue un archivo kubeconfig válido",
"Couldn't read kubeconfig file": "No se pudo leer el archivo kubeconfig",
"No clusters found!": "",
Expand All @@ -119,6 +120,7 @@
"Choose file": "Elija el archivo",
"Select clusters": "Seleccione los clusters",
"Next": "Siguiente",
"Validating selected clusters": "",
"Setting up clusters": "Configurando los clusters",
"Clusters successfully set up!": "¡Clusters configurados con éxito!",
"Finish": "Finalizar",
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/i18n/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"Current//context:cluster": "Actuel",
"Choose cluster": "Choisir un cluster",
"Add Cluster": "Ajouter un cluster",
"Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.": "",
"Error setting up clusters, please load a valid kubeconfig file": "Erreur lors de la configuration des clusters, veuillez charger un fichier kubeconfig valide",
"Couldn't read kubeconfig file": "Impossible de lire le fichier kubeconfig",
"No clusters found!": "",
Expand All @@ -119,6 +120,7 @@
"Choose file": "Choisir un fichier",
"Select clusters": "Sélectionner des clusters",
"Next": "Suivant",
"Validating selected clusters": "",
"Setting up clusters": "Configuration des clusters",
"Clusters successfully set up!": "Clusters configurés avec succès !",
"Finish": "Terminer",
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/i18n/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"Current//context:cluster": "Actual",
"Choose cluster": "Escolha o cluster",
"Add Cluster": "Adicionar Cluster",
"Duplicate cluster: {{ clusterNames }} in the list. Please edit the context name.": "",
"Error setting up clusters, please load a valid kubeconfig file": "Erro ao configurar clusters, por favor carregue um ficheiro kubeconfig válido",
"Couldn't read kubeconfig file": "Não foi possível ler o ficheiro kubeconfig",
"No clusters found!": "",
Expand All @@ -119,6 +120,7 @@
"Choose file": "Escolha o ficheiro",
"Select clusters": "Selecione os clusters",
"Next": "Seguinte",
"Validating selected clusters": "",
"Setting up clusters": "A configurar clusters",
"Clusters successfully set up!": "Clusters configurados com sucesso!",
"Finish": "Terminar",
Expand Down
18 changes: 10 additions & 8 deletions frontend/src/stateless/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ export function findKubeconfigByClusterName(clusterName: string): Promise<string
?.extension.customName === clusterName
);

const matchingKubeconfig = parsedKubeconfig.clusters.find(
cluster => cluster.name === clusterName
const matchingKubeconfig = parsedKubeconfig.contexts.find(
context => context.name === clusterName
);

if (matchingKubeconfig || matchingContext) {
Expand Down Expand Up @@ -437,9 +437,12 @@ export async function deleteClusterKubeconfig(clusterName: string): Promise<stri
const kubeconfig = kubeconfigObject.kubeconfig;

const parsedKubeconfig = jsyaml.load(atob(kubeconfig)) as KubeconfigObject;

const matchingKubeconfig = parsedKubeconfig.clusters.find(
cluster => cluster.name === clusterName
// Find the context with the matching cluster name or custom name in headlamp_info
const matchingKubeconfig = parsedKubeconfig.contexts.find(
context =>
context.name === clusterName ||
context.context.extensions?.find(extension => extension.name === 'headlamp_info')
?.extension.customName === clusterName
);

if (matchingKubeconfig) {
Expand Down Expand Up @@ -489,11 +492,10 @@ export function updateStatelessClusterKubeconfig(
const request = indexedDB.open('kubeconfigs', 1) as any;
// Parse the kubeconfig from base64
const parsedKubeconfig = jsyaml.load(atob(kubeconfig)) as KubeconfigObject;

// Find the context with the matching cluster name or custom name in headlamp_info
const matchingContext = parsedKubeconfig.contexts.find(
context =>
context.context.cluster === clusterName ||
context.name === clusterName ||
context.context.extensions?.find(extension => extension.name === 'headlamp_info')
?.extension.customName === clusterName
);
Expand All @@ -502,7 +504,7 @@ export function updateStatelessClusterKubeconfig(
const extensions = matchingContext.context.extensions || [];
const headlampExtension = extensions.find(extension => extension.name === 'headlamp_info');

if (matchingContext.context.cluster === clusterName) {
if (matchingContext.name === clusterName) {
// Push the new extension if the cluster name matches
extensions.push({
extension: {
Expand Down

0 comments on commit a80242e

Please sign in to comment.