/** * 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} /> )} ); }