freenas-proxmox/.claude/cos/plans/plan-001-revive-project.md

172 lines
8.4 KiB
Markdown

# Plan 001: Project Revival — Overall Roadmap
**Date**: 2026-05-15
**Status**: Approved — ready for implementation
**Owner**: Kevin Adams
## Decisions Made
| Topic | Decision |
|-------|----------|
| Build pipeline | Consolidate into this repo; eliminate packer repo dispatch |
| Install-time deps | No git, diff, or patch at install time — embed all files in .deb |
| apt hosting | Transition to GitHub Pages (parallel with Cloudsmith, then cut over) |
| UI strategy | Full `PVE::Storage::Custom::TrueNASPlugin` + standalone JS file |
| JS patching | Single minimal patch to `index.html.tpl` to load `truenas-plugin.js` |
| Auth | Bearer Token as primary; basic auth as fallback for compat |
| Cleanup on failure | Rollback dangling TrueNAS resources on any step failure (ADR-004) |
| Code hardening | All findings in plan-002-code-review.md to be addressed |
---
## Architecture After v3.x
### What Gets Installed
```
/usr/share/perl5/PVE/Storage/Custom/TrueNASPlugin.pm ← new custom storage plugin
/usr/share/perl5/PVE/Storage/LunCmd/TrueNAS.pm ← API client (renamed + hardened)
/usr/share/pve-manager/js/truenas-plugin.js ← standalone UI JS (NO pvemanagerlib patch)
```
### What Gets Patched (minimal, stable)
```
/usr/share/pve-manager/index.html.tpl ← ONE LINE: add <script> for truenas-plugin.js
```
That's it. No `ZFSPlugin.pm` patch. No `pvemanagerlib.js` patch. No `apidoc.js` patch. The `index.html.tpl` is orders of magnitude more stable than the JS bundle.
### How `truenas-plugin.js` Works
Ships a proper `Ext.define('PVE.storage.TrueNASInputPanel', {...})` that registers as the configuration panel for `type = 'truenas'` storage. The panel handles:
- API host field
- Toggle: Bearer Token vs Username/Password
- Conditional field visibility (hide username when token auth is selected)
- Secret/token field with confirm
- SSL checkbox
- Pool field
When PVE renders the storage configuration dialog and sees `type = 'truenas'`, it picks up our registered panel class.
### `postinst` — What It Does
```bash
1. cp /usr/share/truenas-proxmox/TrueNASPlugin.pm /usr/share/perl5/PVE/Storage/Custom/
2. cp /usr/share/truenas-proxmox/TrueNAS.pm /usr/share/perl5/PVE/Storage/LunCmd/
3. cp /usr/share/truenas-proxmox/truenas-plugin.js /usr/share/pve-manager/js/
4. patch /usr/share/pve-manager/index.html.tpl (one <script> line, idempotent check first)
5. pvedaemon restart && pveproxy restart && pvestatd restart
```
No git. No curl. No version-matrix. No patch selection logic.
---
## Implementation Phases
### Phase 0 — Lab Environment Setup
**Owner**: Kevin
**What**: Build a PVE 8.x node in the lab for testing
**Needed before**: Phase 2
### Phase 1 — Build Pipeline (no source changes)
**Goal**: CI/CD lives entirely in this repo; .deb builds and deploys from here
Tasks:
- [ ] Create `packaging/DEBIAN/` directory with `control`, `postinst`, `postrm`, `triggers`
- [ ] Port existing packaging from packer repo (keeping the v2.x approach for now)
- [ ] Rewrite `postinst` to not git-clone at install (embed files at build time)
- [ ] Create `.github/workflows/build.yml` replacing `action.yml`
- Branch → version + component mapping (feature_ → alpha, master → beta, 2.0 → stable)
- `dpkg-deb` build step
- Cloudsmith push (existing key)
- GitHub Release asset upload
- [ ] Set up GitHub Pages apt repo structure in `docs/` branch or `gh-pages` branch
- `apt-ftparchive` to generate Packages/Release files
- GPG signing step (new key, stored as GH secret)
- [ ] Archive packer repo (do NOT delete — it has release history)
**Result**: Same v2.x packages but built entirely from this repo with no git at install.
### Phase 2 — Code Hardening (FreeNAS.pm / current approach)
**Goal**: Fix all critical and high issues in the existing `LunCmd/FreeNAS.pm` BEFORE porting to new architecture
Tasks (from plan-002-code-review.md):
- [ ] Fix #4: Regex bug in method validation (`$method !~ /^(?:GET|DELETE|POST)$/`)
- [ ] Fix #1: Rollback on failure in `run_create_lu` and `run_modify_lu` (ADR-004)
- [ ] Fix #3: `$runawayprevent` scope; fix `$freenas_rest_connection->{$apihost}` check
- [ ] Fix #11: Store `$product_name` per-host in `$freenas_server_list`
- [ ] Fix #2: Replace `eval $value` with explicit substitution map
- [ ] Fix #6: Per-request LUN list cache
- [ ] Fix #5: Log warning when SSL verification disabled
- [ ] Fix #8: Consistent taint validation on API response data
- [ ] Improve logging (remove "FreeNAS::" naming in syslog messages, add context)
- [ ] Remove debug `console.warn()` from pvemanagerlib patches
- [ ] Fix `postinst` `&> /dev/null` → redirect to log file
### Phase 3 — Custom Storage Plugin (`TrueNASPlugin.pm`)
**Goal**: New `PVE::Storage::Custom::TrueNASPlugin` with full plugin interface
Starting from `perl5/PVE/Storage/Custom/FreeNAS.pm` (existing unfinished file):
- [ ] Remove duplicate `properties()` and `options()` subs (#9)
- [ ] Implement `type()``'truenas'`
- [ ] Implement `properties()` with all TrueNAS-specific fields (see ADR-005)
- [ ] Implement `options()` including new truenas fields as optional
- [ ] Implement `status()` — pool stats via TrueNAS API v2.0 (`GET /api/v2.0/pool/dataset`)
- [ ] Implement `list_images()` — zvol listing via TrueNAS API
- [ ] Implement `alloc_image()` — create zvol + iSCSI extent + targetextent (with rollback)
- [ ] Implement `free_image()` — delete extent (force=true) + zvol (with logging)
- [ ] Implement `activate_volume()``iscsiadm` login
- [ ] Implement `deactivate_volume()``iscsiadm` logout
- [ ] Implement `path()` — find device from NAA/wwid after iSCSI login
- [ ] Implement `volume_resize()` — resize zvol via TrueNAS API + re-present LUN
- [ ] Port hardened API client from Phase 2 into TrueNASPlugin.pm (or keep as shared module)
- [ ] Integrate Bearer Token as default auth (ADR-005)
### Phase 4 — Standalone UI (`truenas-plugin.js`)
**Goal**: Full Ext.js panel for the 'truenas' storage type; loaded via one-line template patch
- [ ] Research: confirm `index.html.tpl` is the right injection point in PVE 8.x
- [ ] Write `pve-manager/js/truenas-plugin.js`:
- `Ext.define('PVE.storage.TrueNASInputPanel', {...})`
- Fields: API host, Bearer Token toggle, secret/confirm, username (conditional), SSL, pool, portal, target
- Controller logic for field visibility (show/hide username based on token toggle)
- Form submit/load value mapping (compat: `freenas_password``truenas_secret`)
- [ ] Write `index.html.tpl` patch (minimal: one `<script>` tag line)
- [ ] Test on lab PVE 8.x node
### Phase 5 — New Package (`v3.x`) + Migration
- [ ] Update `packaging/DEBIAN/control` (no `git` or `librest-client-perl` dependency)
- [ ] Update `packaging/DEBIAN/postinst` (Phase 0 design above — no patches, just cp)
- [ ] `packaging/DEBIAN/postrm` — remove Custom/*.pm, LunCmd/TrueNAS.pm, truenas-plugin.js, reverse index.html.tpl patch
- [ ] Migration guide in README: how to move from v2.x (ZFS-over-iSCSI + freenas provider) to v3.x (`truenas` storage type)
- [ ] Update Cloudsmith + GitHub Pages with v3.x packages
- [ ] Update README to point at GitHub Pages repo as primary
### Phase 6 — SSH Elimination (stretch goal)
**Goal**: Remove the SSH key requirement for ZFS pool listing
Currently, ZFS pool listing uses SSH (via `ZFSPoolPlugin.pm` upstream, not our code). The TrueNAS v2.0 API can return pool stats and dataset listings, so our custom plugin can return pool `status()` without SSH. The only remaining SSH need is in Proxmox's own ZFSPoolPlugin which we don't control.
If our plugin handles the pool listing entirely internally (using the API), we may be able to advise users to NOT configure SSH at all — needs investigation against the actual Proxmox boot and storage scan flow.
---
## Open Questions Before Implementation Starts
1. Does `index.html.tpl` exist at a known stable path in PVE 8.x? (need lab access)
2. Does PVE auto-pick up `Custom::*` plugins without any additional registration in pvemanagerlib.js?
3. Does `Ext.define('PVE.storage.TrueNASInputPanel')` get auto-wired to `type='truenas'` storage, or does pvemanagerlib.js need a registration entry?
4. Are there TrueNAS API v2.0 endpoints for creating/deleting zvols (not just iSCSI)? (needed for Phase 3)
Items 1-3 can be answered once the lab PVE 8.x node is up.
Item 4: checking TrueNAS API docs — `POST /api/v2.0/pool/dataset` with `type=VOLUME` and `volsize` should work.