import { Server } from 'lucide-react'; import { useCurrentStateAndParams } from '@uirouter/react'; import { useMemo } from 'react'; import { Pod } from 'kubernetes-types/core/v1'; import { IndexOptional } from '@/react/kubernetes/configs/types'; import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useEnvironment } from '@/react/portainer/environments/queries'; import { Datatable, TableSettingsMenu, TableSettingsMenuAutoRefresh, } from '@@/datatables'; import { useTableState } from '@@/datatables/useTableState'; import { useApplication } from '../../queries/useApplication'; import { useApplicationPods } from '../../queries/useApplicationPods'; import { ContainerRowData } from './types'; import { getColumns } from './columns'; import { computeContainerStatus } from './computeContainerStatus'; const storageKey = 'k8sContainersDatatable'; const settingsStore = createStore(storageKey); export function ApplicationContainersDatatable() { const environmentId = useEnvironmentId(); const useServerMetricsQuery = useEnvironment( environmentId, (env) => !!env?.Kubernetes?.Configuration.UseServerMetrics ); const tableState = useTableState(settingsStore, storageKey); const { params: { name, namespace, 'resource-type': resourceType }, } = useCurrentStateAndParams(); // get the containers from the aapplication pods const applicationQuery = useApplication( environmentId, namespace, name, resourceType, { autoRefreshRate: tableState.autoRefreshRate * 1000, } ); const podsQuery = useApplicationPods( environmentId, namespace, name, applicationQuery.data, { autoRefreshRate: tableState.autoRefreshRate * 1000, } ); const appContainers = useContainersRowData(podsQuery.data); return ( > dataset={appContainers} columns={getColumns(!!useServerMetricsQuery.data)} settingsManager={tableState} isLoading={ applicationQuery.isLoading || podsQuery.isLoading || useServerMetricsQuery.isLoading } title="Application containers" titleIcon={Server} getRowId={(row) => row.podName} // use pod name because it's unique (name is not unique) disableSelect data-cy="k8s-application-containers-datatable" renderTableSettings={() => ( tableState.setAutoRefreshRate(value)} /> )} /> ); } // 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 = [ ...(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', })) || []), ]; 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, pod.status?.containerStatuses, pod.status?.initContainerStatuses ), })); }) || [], [pods] ) || [] ); }