2023-08-17 22:00:25 +12:00
|
|
|
import { Server } from 'lucide-react';
|
|
|
|
import { useCurrentStateAndParams } from '@uirouter/react';
|
|
|
|
import { useMemo } from 'react';
|
2025-07-21 15:05:08 +12:00
|
|
|
import { Pod } from 'kubernetes-types/core/v1';
|
2023-08-17 22:00:25 +12:00
|
|
|
|
|
|
|
import { IndexOptional } from '@/react/kubernetes/configs/types';
|
|
|
|
import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store';
|
2024-02-16 14:02:05 +13:00
|
|
|
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
2023-08-17 22:00:25 +12:00
|
|
|
import { useEnvironment } from '@/react/portainer/environments/queries';
|
|
|
|
|
2025-07-21 15:05:08 +12:00
|
|
|
import {
|
|
|
|
Datatable,
|
|
|
|
TableSettingsMenu,
|
|
|
|
TableSettingsMenuAutoRefresh,
|
|
|
|
} from '@@/datatables';
|
2023-08-17 22:00:25 +12:00
|
|
|
import { useTableState } from '@@/datatables/useTableState';
|
|
|
|
|
2024-10-25 12:28:05 +13:00
|
|
|
import { useApplication } from '../../queries/useApplication';
|
|
|
|
import { useApplicationPods } from '../../queries/useApplicationPods';
|
2023-08-17 22:00:25 +12:00
|
|
|
|
|
|
|
import { ContainerRowData } from './types';
|
|
|
|
import { getColumns } from './columns';
|
2025-07-21 15:05:08 +12:00
|
|
|
import { computeContainerStatus } from './computeContainerStatus';
|
2023-08-17 22:00:25 +12:00
|
|
|
|
|
|
|
const storageKey = 'k8sContainersDatatable';
|
|
|
|
const settingsStore = createStore(storageKey);
|
|
|
|
|
|
|
|
export function ApplicationContainersDatatable() {
|
2024-02-16 14:02:05 +13:00
|
|
|
const environmentId = useEnvironmentId();
|
|
|
|
const useServerMetricsQuery = useEnvironment(
|
|
|
|
environmentId,
|
|
|
|
(env) => !!env?.Kubernetes?.Configuration.UseServerMetrics
|
|
|
|
);
|
2023-08-17 22:00:25 +12:00
|
|
|
const tableState = useTableState(settingsStore, storageKey);
|
|
|
|
const {
|
2024-02-16 14:02:05 +13:00
|
|
|
params: { name, namespace, 'resource-type': resourceType },
|
2023-08-17 22:00:25 +12:00
|
|
|
} = useCurrentStateAndParams();
|
|
|
|
|
|
|
|
// get the containers from the aapplication pods
|
2024-02-16 14:02:05 +13:00
|
|
|
const applicationQuery = useApplication(
|
2023-08-17 22:00:25 +12:00
|
|
|
environmentId,
|
|
|
|
namespace,
|
|
|
|
name,
|
2025-07-21 15:05:08 +12:00
|
|
|
resourceType,
|
|
|
|
{
|
|
|
|
autoRefreshRate: tableState.autoRefreshRate * 1000,
|
|
|
|
}
|
2023-08-17 22:00:25 +12:00
|
|
|
);
|
2024-02-16 14:02:05 +13:00
|
|
|
const podsQuery = useApplicationPods(
|
2023-08-17 22:00:25 +12:00
|
|
|
environmentId,
|
|
|
|
namespace,
|
|
|
|
name,
|
2025-07-21 15:05:08 +12:00
|
|
|
applicationQuery.data,
|
|
|
|
{
|
|
|
|
autoRefreshRate: tableState.autoRefreshRate * 1000,
|
|
|
|
}
|
2023-08-17 22:00:25 +12:00
|
|
|
);
|
2024-02-16 14:02:05 +13:00
|
|
|
const appContainers = useContainersRowData(podsQuery.data);
|
2023-08-17 22:00:25 +12:00
|
|
|
|
|
|
|
return (
|
|
|
|
<Datatable<IndexOptional<ContainerRowData>>
|
|
|
|
dataset={appContainers}
|
2024-02-16 14:02:05 +13:00
|
|
|
columns={getColumns(!!useServerMetricsQuery.data)}
|
2023-08-17 22:00:25 +12:00
|
|
|
settingsManager={tableState}
|
2024-02-16 14:02:05 +13:00
|
|
|
isLoading={
|
|
|
|
applicationQuery.isLoading ||
|
|
|
|
podsQuery.isLoading ||
|
|
|
|
useServerMetricsQuery.isLoading
|
|
|
|
}
|
2023-08-17 22:00:25 +12:00
|
|
|
title="Application containers"
|
|
|
|
titleIcon={Server}
|
2023-08-27 23:01:35 +02:00
|
|
|
getRowId={(row) => row.podName} // use pod name because it's unique (name is not unique)
|
2023-08-17 22:00:25 +12:00
|
|
|
disableSelect
|
2024-04-11 12:11:38 +12:00
|
|
|
data-cy="k8s-application-containers-datatable"
|
2025-07-21 15:05:08 +12:00
|
|
|
renderTableSettings={() => (
|
|
|
|
<TableSettingsMenu>
|
|
|
|
<TableSettingsMenuAutoRefresh
|
|
|
|
value={tableState.autoRefreshRate}
|
|
|
|
onChange={(value) => tableState.setAutoRefreshRate(value)}
|
|
|
|
/>
|
|
|
|
</TableSettingsMenu>
|
|
|
|
)}
|
2023-08-17 22:00:25 +12:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// useContainersRowData row data gets the pod.spec?.containers and pod.spec?.initContainers from an array of pods
|
|
|
|
// it then appends the podName, nodeName, podId, creationDate, and status to each container
|
|
|
|
function useContainersRowData(pods?: Pod[]): ContainerRowData[] {
|
|
|
|
return (
|
|
|
|
useMemo(
|
|
|
|
() =>
|
|
|
|
pods?.flatMap((pod) => {
|
|
|
|
const containers = [
|
2025-07-21 15:05:08 +12:00
|
|
|
...(pod.spec?.containers?.map((c) => ({ ...c, isInit: false })) ||
|
|
|
|
[]),
|
|
|
|
...(pod.spec?.initContainers?.map((c) => ({
|
|
|
|
...c,
|
|
|
|
isInit: true,
|
|
|
|
// https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/#sidecar-containers-and-pod-lifecycle
|
|
|
|
isSidecar: c.restartPolicy === 'Always',
|
|
|
|
})) || []),
|
2023-08-17 22:00:25 +12:00
|
|
|
];
|
|
|
|
return containers.map((container) => ({
|
|
|
|
...container,
|
|
|
|
podName: pod.metadata?.name ?? '',
|
|
|
|
nodeName: pod.spec?.nodeName ?? '',
|
|
|
|
podIp: pod.status?.podIP ?? '',
|
|
|
|
creationDate: pod.status?.startTime ?? '',
|
|
|
|
status: computeContainerStatus(
|
|
|
|
container.name,
|
2025-07-21 15:05:08 +12:00
|
|
|
pod.status?.containerStatuses,
|
|
|
|
pod.status?.initContainerStatuses
|
2023-08-17 22:00:25 +12:00
|
|
|
),
|
|
|
|
}));
|
|
|
|
}) || [],
|
|
|
|
[pods]
|
|
|
|
) || []
|
|
|
|
);
|
|
|
|
}
|