06d18a3eb3
- Replace .eslintrc.json with .eslintrc.js (standard @headlamp-k8s/eslint-config)
- Create .prettierrc.js (standard Headlamp prettier config)
- Add .headlamp-plugin/, .env, .env.local, .eslintcache to .gitignore
- Remove .claude/settings.json and .claude/settings.local.json from .gitignore
- Create .claude/settings.local.json with enabled MCP servers
- Remove "Subagent guidance" section and hardcoded test count from CLAUDE.md
- Fix 8 component test files: replace require('./__mocks__/commonComponents.ts')
with await import('./__mocks__/commonComponents') in vi.mock factories —
require() cannot process TypeScript in hoisted mock context
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
88 lines
3.0 KiB
Markdown
88 lines
3.0 KiB
Markdown
# headlamp-tns-csi-plugin
|
|
|
|
Headlamp plugin for tns-csi CSI driver visibility and kbench benchmarking.
|
|
|
|
## Project
|
|
|
|
- **Plugin name**: `headlamp-tns-csi-plugin`
|
|
- **Provisioner**: `tns.csi.io`
|
|
- **Upstream driver**: https://github.com/fenio/tns-csi
|
|
- **Benchmark tool**: https://github.com/longhorn/kbench
|
|
- **Reference plugin**: `../headlamp-polaris-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 (provisioner: tns.csi.io)
|
|
│ ├── metrics.ts # Prometheus text format parser
|
|
│ ├── kbench.ts # kbench Job/PVC lifecycle + FIO log parser
|
|
│ └── TnsCsiDataContext.tsx # Shared React context provider
|
|
└── components/
|
|
├── OverviewPage.tsx
|
|
├── StorageClassesPage.tsx
|
|
├── VolumesPage.tsx
|
|
├── SnapshotsPage.tsx
|
|
├── MetricsPage.tsx
|
|
├── BenchmarkPage.tsx # ONLY write operation in the plugin
|
|
├── DriverStatusCard.tsx
|
|
└── PVCDetailSection.tsx # Injected into Headlamp PVC detail view
|
|
```
|
|
|
|
## Key constants
|
|
|
|
- Provisioner: `tns.csi.io`
|
|
- Controller pod selector: `app.kubernetes.io/name=tns-csi-driver,app.kubernetes.io/component=controller`
|
|
- Node pod selector: `app.kubernetes.io/name=tns-csi-driver,app.kubernetes.io/component=node`
|
|
- Driver namespace: `kube-system`
|
|
- Metrics port: `8080`
|
|
- kbench image: `yasker/kbench:latest`
|
|
- kbench managed-by label: `app.kubernetes.io/managed-by=headlamp-tns-csi-plugin`
|
|
|
|
## 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
|
|
- Slide-in detail panels follow the polaris plugin pattern: URL hash state, Escape to close, backdrop overlay
|
|
- Context provider (`TnsCsiDataProvider`) 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
|
|
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]) },
|
|
},
|
|
},
|
|
}));
|
|
```
|