Skip to content

Commit

Permalink
change: [M3-8997] - LKE missing notice/error indicator when downloadi…
Browse files Browse the repository at this point in the history
…ng Kubeconfig fails (#11683)

* Improve error handling for kubeconfig download during cluster provisioning

* Added changeset: Improve error handling for kubeconfig download during cluster provisioning

* Change snackbar variant type to an error

* Handle Kubeconfig decoding erros safely

* Throw errors as APIError format

* Remove comment

* Trigger CI build
  • Loading branch information
bill-akamai authored Feb 27, 2025
1 parent 3a536ea commit b3f863f
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 10 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-11683-changed-1739919225511.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

Improve error handling for kubeconfig download during cluster provisioning ([#11683](https://github.com/linode/manager/pull/11683))
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,36 @@ export const KubeConfigDisplay = (props: Props) => {

const downloadKubeConfig = async () => {
try {
const { data } = await getKubeConfig();
const queryResult = await getKubeConfig();

if (
Array.isArray(queryResult.error) &&
queryResult.error[0]?.reason?.includes(
'kubeconfig is not yet available'
)
) {
enqueueSnackbar(
'Your cluster is still provisioning. Please try again in a few minutes.',
{ variant: 'error' }
);
return;
}

if (data) {
downloadFile(`${clusterLabel}-kubeconfig.yaml`, data);
if (queryResult.isError) {
throw queryResult.error;
}

if (!queryResult.data) {
throw new Error('No kubeconfig data available');
}

downloadFile(`${clusterLabel}-kubeconfig.yaml`, queryResult.data);
} catch (error) {
const errorText = getAPIErrorOrDefault(
error,
'Unable to download your kubeconfig'
)[0].reason;
const errorText =
error instanceof Error
? error.message
: getAPIErrorOrDefault(error, 'Unable to download your kubeconfig')[0]
.reason;

enqueueSnackbar(errorText, { variant: 'error' });
}
Expand Down
57 changes: 54 additions & 3 deletions packages/manager/src/queries/kubernetes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,53 @@ export const kubernetesQueries = createQueryKeys('kubernetes', {
},
kubeconfig: {
queryFn: async () => {
const result = await getKubeConfig(id);
return window.atob(result.kubeconfig);
try {
const result = await getKubeConfig(id);
if (!result || !result.kubeconfig) {
throw [{ reason: 'Invalid KubeConfig response' } as APIError];
}

let decodedKubeConfig;
try {
decodedKubeConfig = window.atob(result.kubeconfig);
} catch (decodeError) {
throw [{ reason: 'Failed to decode KubeConfig' } as APIError];
}
return decodedKubeConfig;
} catch (error) {
const err = error as {
response?: { status?: number };
reason?: string;
};
const serviceUnavailableStatus = 503;
if (
err?.response?.status === serviceUnavailableStatus ||
(Array.isArray(err) &&
err[0]?.reason?.includes('kubeconfig is not yet available'))
) {
// Custom error to identify when KubeConfig is still provisioning
const notReadyError = [
{
reason:
'Cluster kubeconfig is not yet available. Please try again later.',
} as APIError & { isKubeConfigNotReady: true },
];

notReadyError[0].isKubeConfigNotReady = true;

throw notReadyError;
}

if (Array.isArray(error)) {
throw error;
}

if (error instanceof Error) {
throw [{ reason: error.message } as APIError];
}

throw [{ reason: 'An unexpected error occurred' } as APIError];
}
},
queryKey: null,
},
Expand Down Expand Up @@ -211,7 +256,13 @@ export const useKubernetesKubeConfigQuery = (
useQuery<string, APIError[]>({
...kubernetesQueries.cluster(clusterId)._ctx.kubeconfig,
enabled,
retry: 3,
retry: (failureCount, error: any) => {
// Skip retries when cluster is still provisioning
if (Array.isArray(error) && error[0]?.isKubeConfigNotReady) {
return false;
}
return failureCount < 3;
},
retryDelay: 5000,
// Disable stale time to prevent caching of the kubeconfig
// because it can take some time for config to get updated in the API
Expand Down

0 comments on commit b3f863f

Please sign in to comment.