mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29: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
|
@ -2,9 +2,11 @@ import { EventList } from 'kubernetes-types/core/v1';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
import axios from '@/portainer/services/axios';
|
||||||
import { withError } from '@/react-tools/react-query';
|
import { withError } from '@/react-tools/react-query';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../../axiosError';
|
||||||
|
|
||||||
async function getNamespaceEvents(
|
async function getNamespaceEvents(
|
||||||
environmentId: EnvironmentId,
|
environmentId: EnvironmentId,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
|
@ -21,7 +23,7 @@ async function getNamespaceEvents(
|
||||||
);
|
);
|
||||||
return data.items;
|
return data.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to retrieve events');
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve events');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import { isFulfilled } from '@/portainer/helpers/promise-utils';
|
import { isFulfilled } from '@/portainer/helpers/promise-utils';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
import { getPod, getNamespacePods, patchPod } from './pod.service';
|
import { getPod, getNamespacePods, patchPod } from './pod.service';
|
||||||
import { filterRevisionsByOwnerUid, getNakedPods } from './utils';
|
import { filterRevisionsByOwnerUid, getNakedPods } from './utils';
|
||||||
import {
|
import {
|
||||||
|
@ -29,22 +31,15 @@ export async function getApplicationsForCluster(
|
||||||
environmentId: EnvironmentId,
|
environmentId: EnvironmentId,
|
||||||
namespaceNames?: string[]
|
namespaceNames?: string[]
|
||||||
) {
|
) {
|
||||||
try {
|
if (!namespaceNames) {
|
||||||
if (!namespaceNames) {
|
return [];
|
||||||
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'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
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
|
// 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,
|
environmentId: EnvironmentId,
|
||||||
namespace: string
|
namespace: string
|
||||||
) {
|
) {
|
||||||
try {
|
const [deployments, daemonSets, statefulSets, pods] = await Promise.all([
|
||||||
const [deployments, daemonSets, statefulSets, pods] = await Promise.all([
|
getApplicationsByKind<DeploymentList>(
|
||||||
getApplicationsByKind<DeploymentList>(
|
environmentId,
|
||||||
environmentId,
|
namespace,
|
||||||
namespace,
|
'Deployment'
|
||||||
'Deployment'
|
),
|
||||||
),
|
getApplicationsByKind<DaemonSetList>(environmentId, namespace, 'DaemonSet'),
|
||||||
getApplicationsByKind<DaemonSetList>(
|
getApplicationsByKind<StatefulSetList>(
|
||||||
environmentId,
|
environmentId,
|
||||||
namespace,
|
namespace,
|
||||||
'DaemonSet'
|
'StatefulSet'
|
||||||
),
|
),
|
||||||
getApplicationsByKind<StatefulSetList>(
|
getNamespacePods(environmentId, namespace),
|
||||||
environmentId,
|
]);
|
||||||
namespace,
|
// find all pods which are 'naked' (not owned by a deployment, daemonset or statefulset)
|
||||||
'StatefulSet'
|
const nakedPods = getNakedPods(pods, deployments, daemonSets, statefulSets);
|
||||||
),
|
return [...deployments, ...daemonSets, ...statefulSets, ...nakedPods];
|
||||||
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}'`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not known, get the type of an application (Deployment, DaemonSet, StatefulSet or naked pod) by name
|
// 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,
|
appKind?: AppKind,
|
||||||
yaml?: boolean
|
yaml?: boolean
|
||||||
) {
|
) {
|
||||||
try {
|
// if resourceType is known, get the application by type and name
|
||||||
// if resourceType is known, get the application by type and name
|
if (appKind) {
|
||||||
if (appKind) {
|
switch (appKind) {
|
||||||
switch (appKind) {
|
case 'Deployment':
|
||||||
case 'Deployment':
|
case 'DaemonSet':
|
||||||
case 'DaemonSet':
|
case 'StatefulSet':
|
||||||
case 'StatefulSet':
|
return getApplicationByKind<T>(
|
||||||
return await getApplicationByKind<T>(
|
environmentId,
|
||||||
environmentId,
|
namespace,
|
||||||
namespace,
|
appKind,
|
||||||
appKind,
|
name,
|
||||||
name,
|
yaml
|
||||||
yaml
|
);
|
||||||
);
|
case 'Pod':
|
||||||
case 'Pod':
|
return getPod(environmentId, namespace, name, yaml);
|
||||||
return await getPod(environmentId, namespace, name, yaml);
|
default:
|
||||||
default:
|
throw new Error('Unknown resource type');
|
||||||
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(
|
export async function patchApplication(
|
||||||
|
@ -167,44 +144,37 @@ export async function patchApplication(
|
||||||
name: string,
|
name: string,
|
||||||
patch: ApplicationPatch
|
patch: ApplicationPatch
|
||||||
) {
|
) {
|
||||||
try {
|
switch (appKind) {
|
||||||
switch (appKind) {
|
case 'Deployment':
|
||||||
case 'Deployment':
|
return patchApplicationByKind<Deployment>(
|
||||||
return await patchApplicationByKind<Deployment>(
|
environmentId,
|
||||||
environmentId,
|
namespace,
|
||||||
namespace,
|
appKind,
|
||||||
appKind,
|
name,
|
||||||
name,
|
patch
|
||||||
patch
|
);
|
||||||
);
|
case 'DaemonSet':
|
||||||
case 'DaemonSet':
|
return patchApplicationByKind<DaemonSet>(
|
||||||
return await patchApplicationByKind<DaemonSet>(
|
environmentId,
|
||||||
environmentId,
|
namespace,
|
||||||
namespace,
|
appKind,
|
||||||
appKind,
|
name,
|
||||||
name,
|
patch,
|
||||||
patch,
|
'application/strategic-merge-patch+json'
|
||||||
'application/strategic-merge-patch+json'
|
);
|
||||||
);
|
case 'StatefulSet':
|
||||||
case 'StatefulSet':
|
return patchApplicationByKind<StatefulSet>(
|
||||||
return await patchApplicationByKind<StatefulSet>(
|
environmentId,
|
||||||
environmentId,
|
namespace,
|
||||||
namespace,
|
appKind,
|
||||||
appKind,
|
name,
|
||||||
name,
|
patch,
|
||||||
patch,
|
'application/strategic-merge-patch+json'
|
||||||
'application/strategic-merge-patch+json'
|
);
|
||||||
);
|
case 'Pod':
|
||||||
case 'Pod':
|
return patchPod(environmentId, namespace, name, patch);
|
||||||
return await patchPod(environmentId, namespace, name, patch);
|
default:
|
||||||
default:
|
throw new Error(`Unknown application kind ${appKind}`);
|
||||||
throw new Error(`Unknown application kind ${appKind}`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw parseAxiosError(
|
|
||||||
e as Error,
|
|
||||||
`Unable to patch application ${name} in namespace '${namespace}'`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +188,7 @@ async function patchApplicationByKind<T extends Application>(
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const res = await axios.patch<T>(
|
const res = await axios.patch<T>(
|
||||||
buildUrl(environmentId, namespace, `${appKind}s`, name),
|
buildUrl(environmentId, namespace, `${appKind}s`, `${name}sd`),
|
||||||
patch,
|
patch,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -228,7 +198,7 @@ async function patchApplicationByKind<T extends Application>(
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
} catch (e) {
|
} 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;
|
return data;
|
||||||
} catch (e) {
|
} 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'];
|
return data.items as T['items'];
|
||||||
} catch (e) {
|
} 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;
|
return data;
|
||||||
} catch (e) {
|
} 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;
|
return data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to retrieve ControllerRevisions');
|
throw parseKubernetesAxiosError(
|
||||||
|
e,
|
||||||
|
'Unable to retrieve ControllerRevisions'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ export async function getNamespaceHorizontalPodAutoscalers(
|
||||||
return autoScalarList.items;
|
return autoScalarList.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw parseKubernetesAxiosError(
|
||||||
e as Error,
|
e,
|
||||||
'Unable to retrieve horizontal pod autoscalers'
|
'Unable to retrieve horizontal pod autoscalers'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ export async function getNamespaceHorizontalPodAutoscaler<
|
||||||
return autoScalar;
|
return autoScalar;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw parseKubernetesAxiosError(
|
||||||
e as Error,
|
e,
|
||||||
'Unable to retrieve horizontal pod autoscaler'
|
'Unable to retrieve horizontal pod autoscaler'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { Pod, PodList } from 'kubernetes-types/core/v1';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
import { ApplicationPatch } from './types';
|
import { ApplicationPatch } from './types';
|
||||||
|
|
||||||
export async function getNamespacePods(
|
export async function getNamespacePods(
|
||||||
|
@ -21,7 +23,10 @@ export async function getNamespacePods(
|
||||||
);
|
);
|
||||||
return data.items;
|
return data.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to retrieve pods');
|
throw parseKubernetesAxiosError(
|
||||||
|
e,
|
||||||
|
`Unable to retrieve pods in namespace '${namespace}'`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +45,7 @@ export async function getPod<T extends Pod | string = Pod>(
|
||||||
);
|
);
|
||||||
return data;
|
return data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to retrieve pod');
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve pod');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +66,7 @@ export async function patchPod(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to update pod');
|
throw parseAxiosError(e, 'Unable to update pod');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +78,7 @@ export async function deletePod(
|
||||||
try {
|
try {
|
||||||
return await axios.delete<Pod>(buildUrl(environmentId, namespace, name));
|
return await axios.delete<Pod>(buildUrl(environmentId, namespace, name));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to delete pod');
|
throw parseKubernetesAxiosError(e as Error, 'Unable to delete pod');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,6 @@ export function kubernetesErrorParser(axiosError: AxiosError) {
|
||||||
* @param msg An optional error message to prepend.
|
* @param msg An optional error message to prepend.
|
||||||
* @returns An error object with an error message and details.
|
* @returns An error object with an error message and details.
|
||||||
*/
|
*/
|
||||||
export function parseKubernetesAxiosError(err: Error, msg = '') {
|
export function parseKubernetesAxiosError(err: unknown, msg = '') {
|
||||||
return parseAxiosError(err, msg, kubernetesErrorParser);
|
return parseAxiosError(err, msg, kubernetesErrorParser);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ import {
|
||||||
UpdateEnvironmentPayload,
|
UpdateEnvironmentPayload,
|
||||||
updateEnvironment,
|
updateEnvironment,
|
||||||
} from '@/react/portainer/environments/queries/useUpdateEnvironmentMutation';
|
} from '@/react/portainer/environments/queries/useUpdateEnvironmentMutation';
|
||||||
import axios from '@/portainer/services/axios';
|
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||||
import { parseKubernetesAxiosError } from '@/react/kubernetes/axiosError';
|
|
||||||
|
|
||||||
import { updateIngressControllerClassMap } from '../../ingressClass/useIngressControllerClassMap';
|
import { updateIngressControllerClassMap } from '../../ingressClass/useIngressControllerClassMap';
|
||||||
import { IngressControllerClassMap } from '../../ingressClass/types';
|
import { IngressControllerClassMap } from '../../ingressClass/types';
|
||||||
|
@ -72,9 +71,6 @@ async function patchStorageClass(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw parseAxiosError(e, `Unable to patch StorageClass ${name}`);
|
||||||
e as Error,
|
|
||||||
`Unable to patch StorageClass ${name}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,10 +65,7 @@ async function getStorageClasses(
|
||||||
);
|
);
|
||||||
return storageClassList.items;
|
return storageClassList.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve Storage Classes');
|
||||||
e as Error,
|
|
||||||
'Unable to retrieve Storage Classes'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import axios from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import { withError } from '@/react-tools/react-query';
|
import { withError } from '@/react-tools/react-query';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../../axiosError';
|
||||||
|
|
||||||
const queryKeys = {
|
const queryKeys = {
|
||||||
node: (environmentId: number, nodeName: string) => [
|
node: (environmentId: number, nodeName: string) => [
|
||||||
'environments',
|
'environments',
|
||||||
|
@ -22,10 +24,14 @@ const queryKeys = {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getNode(environmentId: EnvironmentId, nodeName: string) {
|
async function getNode(environmentId: EnvironmentId, nodeName: string) {
|
||||||
const { data: node } = await axios.get<Node>(
|
try {
|
||||||
`/endpoints/${environmentId}/kubernetes/api/v1/nodes/${nodeName}`
|
const { data: node } = await axios.get<Node>(
|
||||||
);
|
`/endpoints/${environmentId}/kubernetes/api/v1/nodes/${nodeName}`
|
||||||
return node;
|
);
|
||||||
|
return node;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseKubernetesAxiosError(e, 'Unable to get node details');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useNodeQuery(environmentId: EnvironmentId, nodeName: string) {
|
export function useNodeQuery(environmentId: EnvironmentId, nodeName: string) {
|
||||||
|
@ -33,20 +39,21 @@ export function useNodeQuery(environmentId: EnvironmentId, nodeName: string) {
|
||||||
queryKeys.node(environmentId, nodeName),
|
queryKeys.node(environmentId, nodeName),
|
||||||
() => getNode(environmentId, nodeName),
|
() => getNode(environmentId, nodeName),
|
||||||
{
|
{
|
||||||
...withError(
|
...withError('Unable to get node details'),
|
||||||
'Unable to get node details from the Kubernetes api',
|
|
||||||
'Failed to get node details'
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNodes is used to get a list of nodes using the kubernetes API
|
// getNodes is used to get a list of nodes using the kubernetes API
|
||||||
async function getNodes(environmentId: EnvironmentId) {
|
async function getNodes(environmentId: EnvironmentId) {
|
||||||
const { data: nodeList } = await axios.get<NodeList>(
|
try {
|
||||||
`/endpoints/${environmentId}/kubernetes/api/v1/nodes`
|
const { data: nodeList } = await axios.get<NodeList>(
|
||||||
);
|
`/endpoints/${environmentId}/kubernetes/api/v1/nodes`
|
||||||
return nodeList.items;
|
);
|
||||||
|
return nodeList.items;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseKubernetesAxiosError(e, 'Unable to get nodes');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// useNodesQuery is used to get an array of nodes using the kubernetes API
|
// useNodesQuery is used to get an array of nodes using the kubernetes API
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
import PortainerError from '@/portainer/error';
|
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||||
import axios from '@/portainer/services/axios';
|
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import { withError } from '@/react-tools/react-query';
|
import { withError } from '@/react-tools/react-query';
|
||||||
|
|
||||||
|
@ -23,6 +22,6 @@ export async function getIsRBACEnabled(environmentId: EnvironmentId) {
|
||||||
);
|
);
|
||||||
return data;
|
return data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new PortainerError('Unable to check if RBAC is enabled.', e as Error);
|
throw parseAxiosError(e, 'Unable to check if RBAC is enabled.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import { IngressClassList } from 'kubernetes-types/networking/v1';
|
import { IngressClassList } from 'kubernetes-types/networking/v1';
|
||||||
|
|
||||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
import axios from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../../axiosError';
|
||||||
|
|
||||||
export async function getAllIngressClasses(environmentId: EnvironmentId) {
|
export async function getAllIngressClasses(environmentId: EnvironmentId) {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
data: { items },
|
data: { items },
|
||||||
} = await axios.get<IngressClassList>(urlBuilder(environmentId));
|
} = await axios.get<IngressClassList>(urlBuilder(environmentId));
|
||||||
return items;
|
return items;
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
throw parseAxiosError(error as Error);
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve ingress classes');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import PortainerError from '@/portainer/error';
|
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||||
import axios from '@/portainer/services/axios';
|
|
||||||
import { withError } from '@/react-tools/react-query';
|
import { withError } from '@/react-tools/react-query';
|
||||||
|
|
||||||
import { IngressControllerClassMap } from './types';
|
import { IngressControllerClassMap } from './types';
|
||||||
|
@ -61,7 +60,7 @@ export async function getIngressControllerClassMap({
|
||||||
);
|
);
|
||||||
return controllerMaps;
|
return controllerMaps;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new PortainerError('Unable to get ingress controllers.', e as Error);
|
throw parseAxiosError(e, 'Unable to get ingress controllers.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +76,7 @@ export async function updateIngressControllerClassMap(
|
||||||
>(buildUrl(environmentId, namespace), ingressControllerClassMap);
|
>(buildUrl(environmentId, namespace), ingressControllerClassMap);
|
||||||
return controllerMaps;
|
return controllerMaps;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new PortainerError(
|
throw parseAxiosError(e, 'Unable to update ingress controllers.');
|
||||||
'Unable to update ingress controllers.',
|
|
||||||
e as Error
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,17 @@ import axios from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
import { withError } from '@/react-tools/react-query';
|
import { withError } from '@/react-tools/react-query';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
async function getKubernetesEndpoints(environmentId: EnvironmentId) {
|
async function getKubernetesEndpoints(environmentId: EnvironmentId) {
|
||||||
const { data: endpointsList } = await axios.get<EndpointsList>(
|
try {
|
||||||
`/endpoints/${environmentId}/kubernetes/api/v1/endpoints`
|
const { data: endpointsList } = await axios.get<EndpointsList>(
|
||||||
);
|
`/endpoints/${environmentId}/kubernetes/api/v1/endpoints`
|
||||||
return endpointsList.items;
|
);
|
||||||
|
return endpointsList.items;
|
||||||
|
} catch (e) {
|
||||||
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve endpoints');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useKubernetesEndpointsQuery(
|
export function useKubernetesEndpointsQuery(
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from '@/portainer/services/notifications';
|
} from '@/portainer/services/notifications';
|
||||||
import { isFulfilled, isRejected } from '@/portainer/helpers/promise-utils';
|
import { isFulfilled, isRejected } from '@/portainer/helpers/promise-utils';
|
||||||
import { pluralize } from '@/portainer/helpers/strings';
|
import { pluralize } from '@/portainer/helpers/strings';
|
||||||
|
import PortainerError from '@/portainer/error';
|
||||||
|
|
||||||
import { parseKubernetesAxiosError } from '../axiosError';
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
|
@ -127,10 +128,7 @@ async function getConfigMapsForCluster(
|
||||||
);
|
);
|
||||||
return configMaps.flat();
|
return configMaps.flat();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw new PortainerError('Unable to retrieve ConfigMaps', e);
|
||||||
e as Error,
|
|
||||||
'Unable to retrieve ConfigMaps for cluster'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,10 +140,7 @@ async function getConfigMaps(environmentId: EnvironmentId, namespace: string) {
|
||||||
);
|
);
|
||||||
return data.items;
|
return data.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve ConfigMaps');
|
||||||
e as Error,
|
|
||||||
'Unable to retrieve ConfigMaps'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +152,7 @@ async function deleteConfigMap(
|
||||||
try {
|
try {
|
||||||
await axios.delete(buildUrl(environmentId, namespace, name));
|
await axios.delete(buildUrl(environmentId, namespace, name));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(e as Error, 'Unable to remove ConfigMap');
|
throw parseKubernetesAxiosError(e, 'Unable to remove ConfigMap');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from '@/portainer/services/notifications';
|
} from '@/portainer/services/notifications';
|
||||||
import { isFulfilled, isRejected } from '@/portainer/helpers/promise-utils';
|
import { isFulfilled, isRejected } from '@/portainer/helpers/promise-utils';
|
||||||
import { pluralize } from '@/portainer/helpers/strings';
|
import { pluralize } from '@/portainer/helpers/strings';
|
||||||
|
import PortainerError from '@/portainer/error';
|
||||||
|
|
||||||
import { parseKubernetesAxiosError } from '../axiosError';
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
|
@ -123,10 +124,7 @@ async function getSecretsForCluster(
|
||||||
);
|
);
|
||||||
return secrets.flat();
|
return secrets.flat();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(
|
throw new PortainerError('Unable to retrieve secrets for cluster', e);
|
||||||
e as Error,
|
|
||||||
'Unable to retrieve secrets for cluster'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +136,7 @@ async function getSecrets(environmentId: EnvironmentId, namespace: string) {
|
||||||
);
|
);
|
||||||
return data.items;
|
return data.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(e as Error, 'Unable to retrieve secrets');
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve secrets');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +148,7 @@ async function deleteSecret(
|
||||||
try {
|
try {
|
||||||
await axios.delete(buildUrl(environmentId, namespace, name));
|
await axios.delete(buildUrl(environmentId, namespace, name));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(e as Error, 'Unable to remove secret');
|
throw parseKubernetesAxiosError(e, 'Unable to remove secret');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
import axios from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
interface SelfSubjectAccessReviewResponse {
|
interface SelfSubjectAccessReviewResponse {
|
||||||
status: {
|
status: {
|
||||||
allowed: boolean;
|
allowed: boolean;
|
||||||
|
@ -43,8 +45,8 @@ export async function getSelfSubjectAccessReview(
|
||||||
);
|
);
|
||||||
return accessReview;
|
return accessReview;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(
|
throw parseKubernetesAxiosError(
|
||||||
e as Error,
|
e,
|
||||||
'Unable to retrieve self subject access review'
|
'Unable to retrieve self subject access review'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ export async function getServices(
|
||||||
);
|
);
|
||||||
return services;
|
return services;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(e as Error, 'Unable to retrieve services');
|
throw parseAxiosError(e, 'Unable to retrieve services');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ export async function getNamespaceServices(
|
||||||
);
|
);
|
||||||
return services.items;
|
return services.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(e as Error, 'Unable to retrieve services');
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve services');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ async function getService<T extends Service | string = Service>(
|
||||||
);
|
);
|
||||||
return service;
|
return service;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseKubernetesAxiosError(e as Error, 'Unable to retrieve service');
|
throw parseKubernetesAxiosError(e, 'Unable to retrieve service');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
import { PersistentVolumeClaimList } from 'kubernetes-types/core/v1';
|
import { PersistentVolumeClaimList } from 'kubernetes-types/core/v1';
|
||||||
|
|
||||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
import axios from '@/portainer/services/axios';
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
|
|
||||||
|
import { parseKubernetesAxiosError } from '../axiosError';
|
||||||
|
|
||||||
export async function getPVCsForCluster(
|
export async function getPVCsForCluster(
|
||||||
environmentId: EnvironmentId,
|
environmentId: EnvironmentId,
|
||||||
namespaces: string[]
|
namespaces: string[]
|
||||||
) {
|
) {
|
||||||
try {
|
const pvcs = await Promise.all(
|
||||||
const pvcs = await Promise.all(
|
namespaces.map((namespace) => getPVCs(environmentId, namespace))
|
||||||
namespaces.map((namespace) => getPVCs(environmentId, namespace))
|
);
|
||||||
);
|
return pvcs.flat();
|
||||||
return pvcs.flat();
|
|
||||||
} catch (e) {
|
|
||||||
throw parseAxiosError(
|
|
||||||
e as Error,
|
|
||||||
'Unable to retrieve persistent volume claims for cluster'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all persistent volume claims for a namespace
|
// get all persistent volume claims for a namespace
|
||||||
|
@ -28,8 +23,8 @@ export async function getPVCs(environmentId: EnvironmentId, namespace: string) {
|
||||||
);
|
);
|
||||||
return data.items;
|
return data.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw parseAxiosError(
|
throw parseKubernetesAxiosError(
|
||||||
e as Error,
|
e,
|
||||||
'Unable to retrieve persistent volume claims'
|
'Unable to retrieve persistent volume claims'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue