Add pre-deployment node/namespace/resource diagnostics and wrap kubectl apply in explicit error handling with cluster state dump on failure. This gives us actionable output in the GitHub Actions logs when the Deploy E2E step fails, instead of a silent exit code. PRI-956 Co-Authored-By: Paperclip <noreply@paperclip.ing>
Headlamp Rook Plugin
A Headlamp plugin that surfaces Rook-Ceph cluster health, storage resources, and CSI driver status directly in the Headlamp UI.
Installation | Features | Security | Development
What It Does
Adds a Rook-Ceph top-level sidebar section to Headlamp with full cluster observability:
Main Views
- Overview Dashboard — CephCluster health (HEALTH_OK/WARN/ERR), cluster capacity bar, storage resource counts (block pools, filesystems, object stores, PVs), daemon pod health summary, non-Bound PVC alerts
- Block Pools — table of CephBlockPool resources with phase, replication factor, failure domain, and mirroring status; click a row for a slide-in detail panel
- Pods — all Rook-Ceph daemon pods grouped by role (Operator, MON, MGR, OSD, CSI RBD, CSI CephFS) with ready/total counts and restart counts
Integrated Features (Native Headlamp Views)
- StorageClass columns — adds Rook Type (Block/Filesystem), Pool, and Cluster ID columns to the native
/storage-classestable for Rook-Ceph StorageClasses;—for non-Rook rows - PV columns — adds Rook Type and Pool columns to the native
/persistent-volumestable - PVC Detail Injection — Rook-Ceph section automatically injected into Headlamp's PVC detail view (driver, type, pool, volume handle, PV name)
- PV Detail Injection — Rook-Ceph section injected into PV detail view with full CSI volume attributes
- Pod Detail Injection — Ceph daemon role badge (Operator, MON, OSD, MGR, etc.) injected into matching Pod detail pages
- App Bar Badge — cluster health badge (
rook-ceph: HEALTH_OK) in top nav bar, color-coded; hidden when no CephCluster is present
Data Sources
- CephCluster, CephBlockPool, CephFilesystem, CephObjectStore CRDs fetched via
ApiProxy.requestfromceph.rook.io/v1 - StorageClasses, PVs, PVCs fetched via Headlamp's
K8s.ResourceClasseshooks (live watch) - Daemon pods (operator, mon, osd, mgr, csi-rbdplugin-provisioner, csi-cephfsplugin-provisioner) fetched via label selector
The plugin is read-only — no write operations.
Prerequisites
| Requirement | Minimum version |
|---|---|
| Headlamp | v0.20+ |
| Rook | v1.12+ |
| Ceph | v17 (Quincy)+ |
| Kubernetes | v1.24+ |
Rook-Ceph must be deployed in the rook-ceph namespace with standard labels. The CephCluster, CephBlockPool, CephFilesystem, and CephObjectStore CRDs (ceph.rook.io/v1) must be installed.
Installing
Browse the Headlamp Plugin Manager (Settings → Plugins → Catalog) and install headlamp-rook-plugin directly.
RBAC & Security Setup
The plugin reads Rook-Ceph CRDs and Kubernetes resources. Your Headlamp service account needs:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: headlamp-rook-ceph-reader
rules:
# Rook-Ceph CRDs
- apiGroups: ["ceph.rook.io"]
resources:
- cephclusters
- cephblockpools
- cephfilesystems
- cephobjectstores
verbs: ["get", "list", "watch"]
# Native K8s resources
- apiGroups: [""]
resources:
- pods
- persistentvolumes
- persistentvolumeclaims
verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: headlamp-rook-ceph-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: headlamp-rook-ceph-reader
subjects:
- kind: ServiceAccount
name: headlamp
namespace: headlamp
Troubleshooting
| Symptom | Likely Cause | Quick Fix |
|---|---|---|
| Plugin not in sidebar | Plugin not installed or needs browser refresh | Hard refresh (Cmd+Shift+R / Ctrl+Shift+F5) |
| No CephCluster data | CRDs not installed or RBAC insufficient | Verify kubectl get cephclusters -n rook-ceph works |
| Block Pools empty | No CephBlockPool resources | Check kubectl get cephblockpools -n rook-ceph |
| App bar badge missing | No CephCluster present | Verify rook-ceph is deployed with a CephCluster resource |
| StorageClass columns not showing | Rook provisioner not matching | Verify SC provisioner ends in .rbd.csi.ceph.com or .cephfs.csi.ceph.com |
Development
Prerequisites
- Node.js 20+
- npm
Setup
git clone https://github.com/privilegedescalation/headlamp-rook-plugin.git
cd headlamp-rook-plugin
npm install
Commands
npm start # dev server with hot reload
npm run build # production build
npm run package # package for headlamp
npm run tsc # TypeScript type check (no emit)
npm run lint # ESLint
npm test # vitest run
npm run test:watch # vitest watch mode
Architecture
src/
├── index.tsx # Plugin entry: registerRoute, registerSidebarEntry, etc.
├── api/
│ ├── k8s.ts # Types + filtering helpers (ceph.rook.io/v1)
│ └── RookCephDataContext.tsx # Shared React context provider
└── components/
├── OverviewPage.tsx # Dashboard: health, capacity, resource counts
├── BlockPoolsPage.tsx # CephBlockPool table + detail panel
├── StorageClassesPage.tsx # Rook-Ceph StorageClass table
├── VolumesPage.tsx # Rook-Ceph PV table + detail panel
├── PodsPage.tsx # Daemon pods grouped by role
├── ClusterStatusCard.tsx # Reusable cluster health + capacity card
├── AppBarClusterBadge.tsx # App bar health badge
├── PVCDetailSection.tsx # Injected into Headlamp PVC detail view
├── PVDetailSection.tsx # Injected into Headlamp PV detail view
├── CephPodDetailSection.tsx # Injected into Headlamp Pod detail view
└── integrations/
└── StorageClassColumns.tsx # Column processors for SC + PV tables
Testing
npm test # runs all unit tests
npm run tsc # must exit 0
Mock pattern for headlamp APIs:
vi.mock('@kinvolk/headlamp-plugin/lib', () => ({
ApiProxy: { request: vi.fn().mockResolvedValue({ items: [] }) },
K8s: {
ResourceClasses: {
StorageClass: { useList: vi.fn(() => [[], null]) },
PersistentVolume: { useList: vi.fn(() => [[], null]) },
PersistentVolumeClaim: { useList: vi.fn(() => [[], null]) },
},
},
}));
License
Apache-2.0 — see LICENSE for details.