Files
headlamp-rook-plugin/src/components/CephPodDetailSection.tsx
T
DevContainer User 62c24e3857 fix: register AppBarClusterBadge, fix CSI label mismatch, improve accessibility and theme support
- Register AppBarClusterBadge via registerAppBarAction (was dead code)
- Add Rook 1.12+ CSI pod labels to CephPodDetailSection alongside legacy labels
- Add sidebar entries for Storage Classes and Volumes pages
- Add role="dialog", aria-modal, aria-labelledby, and Escape key to all detail drawers
- Replace hardcoded hex colors with CSS custom properties for dark/light theme compat
- Remove duplicate parseStorageToBytes from OverviewPage (import from k8s.ts)
- Add endpoints field to CephObjectStoreStatus interface (remove unsafe cast)
- Use ROOK_CEPH_API_GROUP/VERSION constants in API URL construction
- Hoist extractJsonData to module level
- Remove dead extractPoolFromVolumeHandle function
- Fix redundant storageClasses.length guard in OverviewPage
- Fix lint indent warnings
- Update CLAUDE.md and CHANGELOG.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:55:37 +00:00

132 lines
3.9 KiB
TypeScript

/**
* CephPodDetailSection — injected into Headlamp's Pod detail view.
*
* Shown only for Rook-Ceph daemon pods (operator, mon, osd, mgr, csi).
* Guards on rook-ceph label presence.
*/
import {
NameValueTable,
SectionBox,
StatusLabel,
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
import React from 'react';
import { formatAge } from '../api/k8s';
interface CephPodDetailSectionProps {
resource: {
metadata?: {
name?: string;
namespace?: string;
labels?: Record<string, string>;
creationTimestamp?: string;
};
spec?: { nodeName?: string; containers?: Array<{ name: string; image?: string }> };
status?: {
phase?: string;
conditions?: Array<{ type: string; status: string }>;
containerStatuses?: Array<{
name: string;
ready: boolean;
restartCount: number;
state?: {
running?: { startedAt?: string };
waiting?: { reason?: string };
terminated?: { reason?: string; exitCode?: number };
};
}>;
};
jsonData?: unknown;
};
}
const ROOK_APP_LABELS = new Set([
'rook-ceph-operator',
'rook-ceph-mon',
'rook-ceph-osd',
'rook-ceph-mgr',
'rook-ceph-mds',
'rook-ceph-rgw',
// Legacy CSI labels (pre-Rook 1.12)
'csi-rbdplugin-provisioner',
'csi-cephfsplugin-provisioner',
'csi-rbdplugin',
'csi-cephfsplugin',
// New CSI labels (Rook 1.12+)
'rook-ceph.rbd.csi.ceph.com-ctrlplugin',
'rook-ceph.cephfs.csi.ceph.com-ctrlplugin',
]);
const ROLE_LABELS: Record<string, string> = {
'rook-ceph-operator': 'Operator',
'rook-ceph-mon': 'Monitor (MON)',
'rook-ceph-osd': 'OSD',
'rook-ceph-mgr': 'Manager (MGR)',
'rook-ceph-mds': 'MDS (CephFS)',
'rook-ceph-rgw': 'RGW (Object Gateway)',
'csi-rbdplugin-provisioner': 'CSI RBD Provisioner',
'csi-cephfsplugin-provisioner': 'CSI CephFS Provisioner',
'csi-rbdplugin': 'CSI RBD Node Plugin',
'csi-cephfsplugin': 'CSI CephFS Node Plugin',
'rook-ceph.rbd.csi.ceph.com-ctrlplugin': 'CSI RBD Provisioner',
'rook-ceph.cephfs.csi.ceph.com-ctrlplugin': 'CSI CephFS Provisioner',
};
export default function CephPodDetailSection({ resource }: CephPodDetailSectionProps) {
const raw =
resource.jsonData && typeof resource.jsonData === 'object'
? (resource.jsonData as typeof resource)
: resource;
const labels = raw.metadata?.labels ?? {};
const appLabel = labels['app'] ?? '';
if (!ROOK_APP_LABELS.has(appLabel)) return null;
const role = ROLE_LABELS[appLabel] ?? appLabel;
const phase = raw.status?.phase ?? 'Unknown';
const isReady =
raw.status?.conditions?.some(c => c.type === 'Ready' && c.status === 'True') ?? false;
const restarts = raw.status?.containerStatuses?.reduce((s, c) => s + c.restartCount, 0) ?? 0;
const containerRows = (raw.status?.containerStatuses ?? []).map(cs => {
let stateStr = 'Unknown';
if (cs.state?.running) stateStr = 'Running';
else if (cs.state?.waiting) stateStr = `Waiting: ${cs.state.waiting.reason ?? ''}`;
else if (cs.state?.terminated)
stateStr = `Terminated: ${cs.state.terminated.reason ?? ''} (exit ${
cs.state.terminated.exitCode ?? ''
})`;
return {
name: cs.name,
value: (
<StatusLabel status={cs.ready ? 'success' : 'warning'}>
{stateStr} | Restarts: {cs.restartCount}
</StatusLabel>
),
};
});
return (
<SectionBox title="Rook-Ceph Daemon Info">
<NameValueTable
rows={[
{
name: 'Role',
value: <StatusLabel status="success">{role}</StatusLabel>,
},
{
name: 'Phase',
value: <StatusLabel status={isReady ? 'success' : 'error'}>{phase}</StatusLabel>,
},
{ name: 'Node', value: raw.spec?.nodeName ?? '—' },
{ name: 'Restarts', value: String(restarts) },
{ name: 'Age', value: formatAge(raw.metadata?.creationTimestamp) },
...containerRows,
]}
/>
</SectionBox>
);
}