/**
* PodsPage — lists all pods requesting Intel GPU resources.
*
* Shows GPU resource requests/limits per container and pod-level status.
*/
import {
Loader,
NameValueTable,
SectionBox,
SectionHeader,
SimpleTable,
StatusLabel,
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
import React from 'react';
import { useIntelGpuContext } from '../api/IntelGpuDataContext';
import {
formatAge,
formatGpuResourceName,
getPodGpuRequests,
getPodRestarts,
INTEL_GPU_RESOURCE_PREFIX,
IntelGpuPod,
} from '../api/k8s';
// ---------------------------------------------------------------------------
// Phase → status mapping
// ---------------------------------------------------------------------------
function phaseToStatus(phase: string | undefined): 'success' | 'warning' | 'error' {
switch (phase) {
case 'Running':
return 'success';
case 'Succeeded':
return 'success';
case 'Pending':
return 'warning';
case 'Failed':
return 'error';
default:
return 'warning';
}
}
// ---------------------------------------------------------------------------
// GPU container list for a pod
// ---------------------------------------------------------------------------
function GpuContainerList({ pod }: { pod: IntelGpuPod }) {
const containers = pod.spec?.containers ?? [];
const gpuContainers = containers.filter(c => {
const resources = { ...c.resources?.requests, ...c.resources?.limits };
return Object.keys(resources).some(k => k.startsWith(INTEL_GPU_RESOURCE_PREFIX));
});
if (gpuContainers.length === 0) return —;
return (
<>
{gpuContainers.map(c => {
const requests = c.resources?.requests ?? {};
const limits = c.resources?.limits ?? {};
const gpuKeys = new Set([
...Object.keys(requests).filter(k => k.startsWith(INTEL_GPU_RESOURCE_PREFIX)),
...Object.keys(limits).filter(k => k.startsWith(INTEL_GPU_RESOURCE_PREFIX)),
]);
const parts: string[] = [];
for (const key of gpuKeys) {
const shortKey = formatGpuResourceName(key);
const req = requests[key];
const lim = limits[key];
if (req && lim && req === lim) {
parts.push(`${shortKey}: ${req}`);
} else if (req || lim) {
parts.push(`${shortKey}: req=${req ?? '—'} lim=${lim ?? '—'}`);
}
}
return (
{c.name}: {parts.join(', ')}
);
})}
>
);
}
// ---------------------------------------------------------------------------
// Main component
// ---------------------------------------------------------------------------
export default function PodsPage() {
const { gpuPods, loading, error, refresh } = useIntelGpuContext();
if (loading) {
return ;
}
// Group by phase
const running = gpuPods.filter(p => p.status?.phase === 'Running');
const pending = gpuPods.filter(p => p.status?.phase === 'Pending');
const failed = gpuPods.filter(p => p.status?.phase === 'Failed');
return (
<>
{error && (
{error} }]}
/>
)}
{gpuPods.length === 0 && (
No pods requesting Intel GPU resources were found
),
},
{
name: 'Note',
value:
'Pods appear here when they request resources like gpu.intel.com/i915 or gpu.intel.com/xe.',
},
]}
/>
)}
{/* Summary */}
{gpuPods.length > 0 && (
0
? [
{
name: 'Running',
value: {running.length},
},
]
: []),
...(pending.length > 0
? [
{
name: 'Pending',
value: {pending.length},
},
]
: []),
...(failed.length > 0
? [
{
name: 'Failed',
value: {failed.length},
},
]
: []),
]}
/>
)}
{/* All pods table */}
{gpuPods.length > 0 && (
p.metadata.name },
{ label: 'Namespace', getter: p => p.metadata.namespace ?? '—' },
{ label: 'Node', getter: p => p.spec?.nodeName ?? '—' },
{
label: 'Phase',
getter: p => (
{p.status?.phase ?? 'Unknown'}
),
},
{
label: 'GPU Resources',
getter: p => ,
},
{
label: 'Restarts',
getter: p => {
const restarts = getPodRestarts(p);
return restarts > 0 ? (
{restarts}
) : (
String(restarts)
);
},
},
{ label: 'Age', getter: p => formatAge(p.metadata.creationTimestamp) },
]}
data={gpuPods}
/>
)}
{/* Pending pods attention box */}
{pending.length > 0 && (
p.metadata.name },
{ label: 'Namespace', getter: p => p.metadata.namespace ?? '—' },
{
label: 'GPU Resources',
getter: p => {
const reqs = getPodGpuRequests(p);
return (
Object.entries(reqs)
.map(([k, v]) => `${formatGpuResourceName(k)}: ${v}`)
.join(', ') || '—'
);
},
},
{
label: 'Waiting Reason',
getter: p => {
const reason = p.status?.containerStatuses?.[0]?.state?.waiting?.reason;
return reason ?? '—';
},
},
{ label: 'Age', getter: p => formatAge(p.metadata.creationTimestamp) },
]}
data={pending}
/>
)}
>
);
}