feat: initial release of headlamp-rook-ceph-plugin v0.1.0
Headlamp plugin for Rook-Ceph cluster visibility. Pages: - Overview dashboard: CephCluster health, capacity bar, resource counts (block pools, filesystems, object stores, PVs, PVCs), daemon pod health summary, non-Bound PVC alerts - Block Pools: CephBlockPool table with replication, failure domain, mirroring; slide-in detail panel - Pods: all Rook-Ceph daemon pods grouped by role with ready/total counts Native Headlamp integrations: - StorageClass table: Rook Type, Pool, Cluster ID columns - PV table: Rook Type, Pool columns - PVC detail injection: driver, type, pool, volume handle - PV detail injection: CSI volume attributes - Pod detail injection: Ceph daemon role badge - App bar badge: cluster health (HEALTH_OK/WARN/ERR), color-coded API / architecture: - src/api/k8s.ts: types + filters for ceph.rook.io/v1 CRDs; handles both default rook-ceph.* and custom-namespace provisioner strings - src/api/RookCephDataContext.tsx: shared context provider; fetches CephCluster, CephBlockPool, CephFilesystem, CephObjectStore CRDs plus daemon pods via label selectors - 37 unit tests (vitest + @testing-library/react) - TypeScript strict mode, zero any types - CI + release GitHub Actions workflows Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# headlamp-rook-ceph-plugin
|
||||
|
||||
Headlamp plugin for Rook-Ceph cluster visibility.
|
||||
|
||||
## Project
|
||||
|
||||
- **Plugin name**: `headlamp-rook-ceph-plugin`
|
||||
- **Rook-Ceph API group**: `ceph.rook.io/v1`
|
||||
- **Default namespace**: `rook-ceph`
|
||||
- **RBD provisioner**: `rook-ceph.rbd.csi.ceph.com`
|
||||
- **CephFS provisioner**: `rook-ceph.cephfs.csi.ceph.com`
|
||||
- **Reference plugin**: `../headlamp-tns-csi-plugin`
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
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)
|
||||
│ └── RookCephDataContext.tsx # Shared React context provider
|
||||
└── components/
|
||||
├── OverviewPage.tsx
|
||||
├── BlockPoolsPage.tsx
|
||||
├── StorageClassesPage.tsx
|
||||
├── VolumesPage.tsx
|
||||
├── PodsPage.tsx
|
||||
├── ClusterStatusCard.tsx
|
||||
├── AppBarClusterBadge.tsx
|
||||
├── 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
|
||||
```
|
||||
|
||||
## Key constants (src/api/k8s.ts)
|
||||
|
||||
- Namespace: `rook-ceph`
|
||||
- API group: `ceph.rook.io/v1`
|
||||
- RBD provisioner: `rook-ceph.rbd.csi.ceph.com`
|
||||
- CephFS provisioner: `rook-ceph.cephfs.csi.ceph.com`
|
||||
- Custom namespace provisioners: any string ending in `.rbd.csi.ceph.com` or `.cephfs.csi.ceph.com`
|
||||
- Pod selectors: `app=rook-ceph-operator`, `app=rook-ceph-mon`, `app=rook-ceph-osd`, `app=rook-ceph-mgr`, `app=csi-rbdplugin-provisioner`, `app=csi-cephfsplugin-provisioner`
|
||||
|
||||
## Code conventions
|
||||
|
||||
- Functional React components only — no class components
|
||||
- All imports from `@kinvolk/headlamp-plugin/lib` and `@kinvolk/headlamp-plugin/lib/CommonComponents`
|
||||
- No additional UI libraries (no MUI direct imports, no Ant Design, etc.)
|
||||
- TypeScript strict mode — no `any`, use `unknown` + type guards at API boundaries
|
||||
- Context provider (`RookCephDataProvider`) wraps each route component in `index.tsx`
|
||||
- Tests: vitest + @testing-library/react, mock with `vi.mock('@kinvolk/headlamp-plugin/lib', ...)`
|
||||
|
||||
## Testing
|
||||
|
||||
All tests must pass before committing:
|
||||
|
||||
```bash
|
||||
npm test # tests across test files
|
||||
npm run tsc # must exit 0
|
||||
```
|
||||
|
||||
Mock pattern for headlamp APIs:
|
||||
```typescript
|
||||
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]) },
|
||||
},
|
||||
},
|
||||
}));
|
||||
```
|
||||
Reference in New Issue
Block a user