mirror of
https://github.com/portainer/portainer.git
synced 2025-07-22 23:09:41 +02:00
fix(kubeapi): fix ts api error handling [EE-5558] (#10488)
* fix(kubeapi): fix ts api error handling [EE-5558] * use portainer errors for mapped functions * don't parse long patch responses * allow nested kube error that's thrown to bubble up --------- Co-authored-by: testa113 <testa113>
This commit is contained in:
parent
6c55cac52a
commit
96ead31a8d
17 changed files with 210 additions and 234 deletions
|
@ -13,6 +13,8 @@ import axios, { parseAxiosError } from '@/portainer/services/axios';
|
|||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { isFulfilled } from '@/portainer/helpers/promise-utils';
|
||||
|
||||
import { parseKubernetesAxiosError } from '../axiosError';
|
||||
|
||||
import { getPod, getNamespacePods, patchPod } from './pod.service';
|
||||
import { filterRevisionsByOwnerUid, getNakedPods } from './utils';
|
||||
import {
|
||||
|
@ -29,22 +31,15 @@ export async function getApplicationsForCluster(
|
|||
environmentId: EnvironmentId,
|
||||
namespaceNames?: string[]
|
||||
) {
|
||||
try {
|
||||
if (!namespaceNames) {
|
||||
return [];
|
||||
}
|
||||
const applications = await Promise.all(
|
||||
namespaceNames.map((namespace) =>
|
||||
getApplicationsForNamespace(environmentId, namespace)
|
||||
)
|
||||
);
|
||||
return applications.flat();
|
||||
} catch (e) {
|
||||
throw parseAxiosError(
|
||||
e as Error,
|
||||
'Unable to retrieve applications for cluster'
|
||||
);
|
||||
if (!namespaceNames) {
|
||||
return [];
|
||||
}
|
||||
const applications = await Promise.all(
|
||||
namespaceNames.map((namespace) =>
|
||||
getApplicationsForNamespace(environmentId, namespace)
|
||||
)
|
||||
);
|
||||
return applications.flat();
|
||||
}
|
||||
|
||||
// get a list of all Deployments, DaemonSets, StatefulSets and naked pods (https://portainer.atlassian.net/browse/CE-2) in one namespace
|
||||
|
@ -52,34 +47,23 @@ async function getApplicationsForNamespace(
|
|||
environmentId: EnvironmentId,
|
||||
namespace: string
|
||||
) {
|
||||
try {
|
||||
const [deployments, daemonSets, statefulSets, pods] = await Promise.all([
|
||||
getApplicationsByKind<DeploymentList>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'Deployment'
|
||||
),
|
||||
getApplicationsByKind<DaemonSetList>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'DaemonSet'
|
||||
),
|
||||
getApplicationsByKind<StatefulSetList>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'StatefulSet'
|
||||
),
|
||||
getNamespacePods(environmentId, namespace),
|
||||
]);
|
||||
// find all pods which are 'naked' (not owned by a deployment, daemonset or statefulset)
|
||||
const nakedPods = getNakedPods(pods, deployments, daemonSets, statefulSets);
|
||||
return [...deployments, ...daemonSets, ...statefulSets, ...nakedPods];
|
||||
} catch (e) {
|
||||
throw parseAxiosError(
|
||||
e as Error,
|
||||
`Unable to retrieve applications in namespace '${namespace}'`
|
||||
);
|
||||
}
|
||||
const [deployments, daemonSets, statefulSets, pods] = await Promise.all([
|
||||
getApplicationsByKind<DeploymentList>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'Deployment'
|
||||
),
|
||||
getApplicationsByKind<DaemonSetList>(environmentId, namespace, 'DaemonSet'),
|
||||
getApplicationsByKind<StatefulSetList>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'StatefulSet'
|
||||
),
|
||||
getNamespacePods(environmentId, namespace),
|
||||
]);
|
||||
// find all pods which are 'naked' (not owned by a deployment, daemonset or statefulset)
|
||||
const nakedPods = getNakedPods(pods, deployments, daemonSets, statefulSets);
|
||||
return [...deployments, ...daemonSets, ...statefulSets, ...nakedPods];
|
||||
}
|
||||
|
||||
// if not known, get the type of an application (Deployment, DaemonSet, StatefulSet or naked pod) by name
|
||||
|
@ -92,72 +76,65 @@ export async function getApplication<
|
|||
appKind?: AppKind,
|
||||
yaml?: boolean
|
||||
) {
|
||||
try {
|
||||
// if resourceType is known, get the application by type and name
|
||||
if (appKind) {
|
||||
switch (appKind) {
|
||||
case 'Deployment':
|
||||
case 'DaemonSet':
|
||||
case 'StatefulSet':
|
||||
return await getApplicationByKind<T>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
yaml
|
||||
);
|
||||
case 'Pod':
|
||||
return await getPod(environmentId, namespace, name, yaml);
|
||||
default:
|
||||
throw new Error('Unknown resource type');
|
||||
}
|
||||
// if resourceType is known, get the application by type and name
|
||||
if (appKind) {
|
||||
switch (appKind) {
|
||||
case 'Deployment':
|
||||
case 'DaemonSet':
|
||||
case 'StatefulSet':
|
||||
return getApplicationByKind<T>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
yaml
|
||||
);
|
||||
case 'Pod':
|
||||
return getPod(environmentId, namespace, name, yaml);
|
||||
default:
|
||||
throw new Error('Unknown resource type');
|
||||
}
|
||||
|
||||
// if resourceType is not known, get the application by name and return the first one that is fulfilled
|
||||
const [deployment, daemonSet, statefulSet, pod] = await Promise.allSettled([
|
||||
getApplicationByKind<Deployment>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'Deployment',
|
||||
name,
|
||||
yaml
|
||||
),
|
||||
getApplicationByKind<DaemonSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'DaemonSet',
|
||||
name,
|
||||
yaml
|
||||
),
|
||||
getApplicationByKind<StatefulSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'StatefulSet',
|
||||
name,
|
||||
yaml
|
||||
),
|
||||
getPod(environmentId, namespace, name, yaml),
|
||||
]);
|
||||
|
||||
if (isFulfilled(deployment)) {
|
||||
return deployment.value;
|
||||
}
|
||||
if (isFulfilled(daemonSet)) {
|
||||
return daemonSet.value;
|
||||
}
|
||||
if (isFulfilled(statefulSet)) {
|
||||
return statefulSet.value;
|
||||
}
|
||||
if (isFulfilled(pod)) {
|
||||
return pod.value;
|
||||
}
|
||||
throw new Error('Unable to retrieve application');
|
||||
} catch (e) {
|
||||
throw parseAxiosError(
|
||||
e as Error,
|
||||
`Unable to retrieve application ${name} in namespace '${namespace}'`
|
||||
);
|
||||
}
|
||||
|
||||
// if resourceType is not known, get the application by name and return the first one that is fulfilled
|
||||
const [deployment, daemonSet, statefulSet, pod] = await Promise.allSettled([
|
||||
getApplicationByKind<Deployment>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'Deployment',
|
||||
name,
|
||||
yaml
|
||||
),
|
||||
getApplicationByKind<DaemonSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'DaemonSet',
|
||||
name,
|
||||
yaml
|
||||
),
|
||||
getApplicationByKind<StatefulSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
'StatefulSet',
|
||||
name,
|
||||
yaml
|
||||
),
|
||||
getPod(environmentId, namespace, name, yaml),
|
||||
]);
|
||||
|
||||
if (isFulfilled(deployment)) {
|
||||
return deployment.value;
|
||||
}
|
||||
if (isFulfilled(daemonSet)) {
|
||||
return daemonSet.value;
|
||||
}
|
||||
if (isFulfilled(statefulSet)) {
|
||||
return statefulSet.value;
|
||||
}
|
||||
if (isFulfilled(pod)) {
|
||||
return pod.value;
|
||||
}
|
||||
throw new Error('Unable to retrieve application');
|
||||
}
|
||||
|
||||
export async function patchApplication(
|
||||
|
@ -167,44 +144,37 @@ export async function patchApplication(
|
|||
name: string,
|
||||
patch: ApplicationPatch
|
||||
) {
|
||||
try {
|
||||
switch (appKind) {
|
||||
case 'Deployment':
|
||||
return await patchApplicationByKind<Deployment>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
patch
|
||||
);
|
||||
case 'DaemonSet':
|
||||
return await patchApplicationByKind<DaemonSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
patch,
|
||||
'application/strategic-merge-patch+json'
|
||||
);
|
||||
case 'StatefulSet':
|
||||
return await patchApplicationByKind<StatefulSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
patch,
|
||||
'application/strategic-merge-patch+json'
|
||||
);
|
||||
case 'Pod':
|
||||
return await patchPod(environmentId, namespace, name, patch);
|
||||
default:
|
||||
throw new Error(`Unknown application kind ${appKind}`);
|
||||
}
|
||||
} catch (e) {
|
||||
throw parseAxiosError(
|
||||
e as Error,
|
||||
`Unable to patch application ${name} in namespace '${namespace}'`
|
||||
);
|
||||
switch (appKind) {
|
||||
case 'Deployment':
|
||||
return patchApplicationByKind<Deployment>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
patch
|
||||
);
|
||||
case 'DaemonSet':
|
||||
return patchApplicationByKind<DaemonSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
patch,
|
||||
'application/strategic-merge-patch+json'
|
||||
);
|
||||
case 'StatefulSet':
|
||||
return patchApplicationByKind<StatefulSet>(
|
||||
environmentId,
|
||||
namespace,
|
||||
appKind,
|
||||
name,
|
||||
patch,
|
||||
'application/strategic-merge-patch+json'
|
||||
);
|
||||
case 'Pod':
|
||||
return patchPod(environmentId, namespace, name, patch);
|
||||
default:
|
||||
throw new Error(`Unknown application kind ${appKind}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,7 +188,7 @@ async function patchApplicationByKind<T extends Application>(
|
|||
) {
|
||||
try {
|
||||
const res = await axios.patch<T>(
|
||||
buildUrl(environmentId, namespace, `${appKind}s`, name),
|
||||
buildUrl(environmentId, namespace, `${appKind}s`, `${name}sd`),
|
||||
patch,
|
||||
{
|
||||
headers: {
|
||||
|
@ -228,7 +198,7 @@ async function patchApplicationByKind<T extends Application>(
|
|||
);
|
||||
return res;
|
||||
} catch (e) {
|
||||
throw parseAxiosError(e as Error, 'Unable to patch application');
|
||||
throw parseKubernetesAxiosError(e, 'Unable to patch application');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,7 +220,7 @@ async function getApplicationByKind<
|
|||
);
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw parseAxiosError(e as Error, 'Unable to retrieve application');
|
||||
throw parseKubernetesAxiosError(e, 'Unable to retrieve application');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +235,10 @@ async function getApplicationsByKind<T extends ApplicationList>(
|
|||
);
|
||||
return data.items as T['items'];
|
||||
} catch (e) {
|
||||
throw parseAxiosError(e as Error, `Unable to retrieve ${appKind}s`);
|
||||
throw parseKubernetesAxiosError(
|
||||
e,
|
||||
`Unable to retrieve ${appKind}s in namespace '${namespace}'`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,7 +323,7 @@ export async function getReplicaSetList(
|
|||
);
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw parseAxiosError(e as Error, 'Unable to retrieve ReplicaSets');
|
||||
throw parseKubernetesAxiosError(e, 'Unable to retrieve ReplicaSets');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,7 +343,10 @@ export async function getControllerRevisionList(
|
|||
);
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw parseAxiosError(e as Error, 'Unable to retrieve ControllerRevisions');
|
||||
throw parseKubernetesAxiosError(
|
||||
e,
|
||||
'Unable to retrieve ControllerRevisions'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue