Consolidating to a single payment path to reduce decision friction.
GitHub Sponsors has no platform fee; PayPal does.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move sponsor ask above the fold with context (4M downloads, ISP/MSP
production use) so it reaches users who never scroll to the bottom.
Expand the Support section with tier descriptions and remove PayPal
in favour of GitHub Sponsors which has no platform fee.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The regex was testing whether the TrueNAS target's short name ends with
the user-supplied value — the opposite of what we want. When truenas_target
holds a full IQN (iqn...ctl:proxmox) the check must test whether that IQN
ends with the short name stored in TrueNAS. Silently fell through to
auto-discovery for every user who supplied a full IQN.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add TPM state disk known limitation to v3.0 Prerequisites with clear
workaround (local-lvm or NFS for tpmstate0, shared storage for live
migration with TPM)
- Expand Upgrading section with v2.x→v3.0 Move Disk migration path,
confirmed tested on PVE 8.4 with CORE 13.0-U6 and SCALE 24.10
- Note in-place rename is not supported; Move Disk is the supported path
Closes#260, #228, #252
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 env var to suppress deprecation
warnings ahead of GitHub's June 2nd forced cutover. Pin actions/checkout
to v4.3.1 (latest v4 patch). Upload/download-artifact left at @v4 pending
a separate audit of the v7/v8 breaking changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Inject pveOnlineHelpInfo entry in truenas-storage.js so PVE wires
the Help button automatically via the StorageBase framework
- Add onlineHelp: 'storage_truenas' to the input panel definition
- Add ui/truenas-storage-help.html — local help page installed to
/usr/share/pve-docs/truenas-storage.html (no internet required)
- Add docs/getting-started.md and docs/architecture.md
- Update postinst/postrm to install and remove the help HTML file
- Update build.yml to include the help HTML in the package staging dir
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove all references to the external packer repo and v2.x patch
approach. Document the self-contained build.yml pipeline, packaging
layout, and current open issues accurately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cobia and Dragonfish remain listed as compatible but are not yet tested
against v3.0 — would require reinstalling those versions in the lab.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a VM has multiple disks on the same per-VM target, migrating one
disk while the VM is running leaves the target in use for the other
disks. TrueNAS refuses to delete an extent associated with an in-use
target even with force=true.
Fix: delete the targetextent (LUN mapping) first, then delete the
extent. Removing the mapping severs this disk's association without
touching the active session or other LUNs on the same target.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed _vm_is_running() check from free_image. When a disk is detached
from a running VM (unused0), QEMU immediately closes its libiscsi
connection — there is no active session to block the delete. The
force=true flag on the TrueNAS extent DELETE is the correct guard for
any residual session. The VM-running check was overly broad and blocked
legitimate deletes of already-detached disks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v3.0 is fully API-driven: no SSH keys, no pre-created iSCSI targets.
v2.x still requires both. Separating them prevents confusion for users
on either version and removes incorrect guidance from the v3.0 path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#257. Many support issues are misrouted because users don't know
which layer generated the error — the plugin (REST API orchestration),
the iSCSI/QEMU data path, or the Proxmox core storage stack. Added a
new section at the top of Troubleshooting that explains all three layers
with example log lines and a quick-triage table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each VM now gets its own TrueNAS iSCSI target (proxmox-vm-<vmid>)
instead of sharing a single storage-wide target. path() returns
iscsi://portal/iqn:proxmox-vm-<vmid>/lun — QEMU connects via libiscsi,
the same pattern ZFSPlugin.pm uses.
When a VM stops, QEMU closes its libiscsi connection. TrueNAS sees
no active session on that VM's target, so extent DELETE with force=true
succeeds without stopping the iSCSI service. Deleting one VM's disk
while other VMs are running on the same storage now works correctly.
Changes:
- Remove all iscsiadm session management (_iscsi_ensure_session,
_iscsi_session_exists, _wait_for_device, _dev_path,
_running_vms_on_storage, _resolve_target)
- Add _resolve_vm_target: find-or-create proxmox-vm-<vmid> target,
inherit portal/initiator groups from existing targets
- Add _maybe_cleanup_vm_target: delete empty VM target after last disk
- Add _vm_is_running: check owning VM before deletion (uses PID file)
- Add _api_global: cached iSCSI global config (basename)
- path(): returns iscsi://portal/per-vm-iqn/lun (target looked up by
target_id from extent, so legacy shared-target disks still work)
- activate_storage: API reachability check only
- activate_volume: verify extent exists, QEMU handles the connection
- deactivate_storage/volume: clear cache, return 1
- free_image: check owning VM stopped, force-DELETE extent, zvol,
cleanup empty target — no service-stop fallback needed
Closes#255
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PVE runs pvedaemon with -T (taint mode). Data read from files is tainted
and cannot be passed to kill() without explicit untainting. Extract PID
via regex capture which Perl treats as safe.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stopping the TrueNAS iSCSI service to clear session state (required on
CORE 13 when force=true is ignored) disrupts all LUNs on the target,
causing io-error on any other running VM using this storage.
Before triggering the service-stop path, scan /etc/pve/qemu-server/*.conf
for running VMs (PID file exists + process alive) that reference this
storage ID. If any are found, fail with a clear message naming the
blocking VMs rather than silently disrupting them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
force=true on extent/targetextent DELETE is unconditionally ignored by
CORE 13.0 — it always checks for active sessions. POST /service/restart
is async and iscsid reconnects in milliseconds, so the restart window
was never clear enough for the DELETE to succeed.
New fallback sequence (only triggered when force=true fails):
1. Set iscsiadm node to manual startup — prevents auto-reconnect
2. iscsiadm --logout — drops initiator session
3. POST /service/stop + poll until service is stopped (up to 15s)
4. DELETE targetextent — succeeds with service fully stopped
5. DELETE extent
6. POST /service/start — restore service
7. Restore automatic startup + discovery + login + rescan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
force=true on extent DELETE is not sufficient when CORE 13 has an active
or recovering session holding the targetextent (422 persists through retries).
Fallback path (triggered only when force fails and a targetextent exists):
1. POST /service/restart — purges all server-side session state
2. DELETE /iscsi/targetextent/id/{id} — now succeeds with service down
3. DELETE /iscsi/extent/id/{id} — clean delete with no association
Fast path (force=true) is tried first and handles the normal case without
any service disruption.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Session management was only needed to prevent 422 when explicitly
deleting the targetextent. Now that we delete the extent first with
force=true (which cascades targetextent removal server-side), the
initiator session can stay up throughout — same as the original
LunCmd/FreeNAS.pm delete path which never touched iscsiadm.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Proxmox enters and allocates disk sizes in GiB (base-2) while TrueNAS
and many storage UIs display sizes in GB (base-10). This causes the
reported size to appear ~7% larger than the number entered, which is
correct and expected behaviour. Adds a reference table for common sizes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The original LunCmd/FreeNAS.pm (v2.0 path) deleted the extent with
{ force: true } and skipped the explicit targetextent DELETE entirely,
relying on TrueNAS to cascade it. Our v3.0 had the order backwards:
deleting the targetextent first always hit 422 "target in use" when
any iSCSI session was active.
New approach mirrors the original:
1. Log out initiator session
2. DELETE extent with { force: true } — TrueNAS cascades targetextent
3. If that fails (CORE 13 strict session enforcement), restart iSCSI
service and retry the extent DELETE (up to 5 times)
4. Restore session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
volume_size_info: base class routes through filesystem_path() → get_subdir()
which dies on block storage. Override to query TrueNAS API directly for
volsize.parsed so create_efidisk and other callers get the correct zvol size.
free_image retry loop: TrueNAS CORE 13 refuses targetextent deletion while any
iSCSI session is active. Single logout+restart was racy — pvedaemon workers
reconnect between the restart and DELETE when multiple disks are deleted
concurrently (e.g. VM destroy). Retry up to 5 times with fresh logout+service
restart each cycle and exponential backoff.
Remove rootdir from plugindata content types: rootdir signals LXC
container/directory storage and caused PVE to route TPM state allocation to
TrueNAS, which immediately failed since TrueNAS has no filesystem path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
parse_volname: implement for vm-/base- volume names so PVE can resolve
device paths and hotplug disks. Without this the base class falls through
to directory-volume parsing and fails with a 400 hotplug error.
free_image: TrueNAS CORE 13 holds iSCSI sessions in recovery state after
TCP disconnect, blocking targetextent deletion with 422 even seconds after
logout. Fix: log out the initiator session by SID, then restart the TrueNAS
iSCSI service to immediately clear server-side session state. Delete the
targetextent and extent, then restore the initiator session so other LUNs
on the same target remain accessible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After TrueNAS reloads its iSCSI service, the PVE host's existing session
does not automatically pick up new LUNs. Adding iscsiadm --rescan every 5s
during the device wait loop lets the kernel discover newly exported LUNs
without requiring a full session logout/login.
Fixes the 30s hotplug timeout seen when adding a disk to a running VM.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TrueNAS CORE 13.0 /pool API does not expose top-level size/free/allocated
fields (they are nested in topology.data[].stats). Switch status() to query
/pool/dataset?id=<pool> which has available.parsed + used.parsed on both
CORE and SCALE.
Add shared=1 as the default in the UI panel — iSCSI is a network block
device accessible from all cluster nodes, so it should be shared storage
by default.
Verified on pve01-hq against Tank01 (CORE 13.0-U6.7):
TrueNAS01-Tank01 active 1804599296 165936464 1638662832 9.20%
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
status() was comparing the full dataset path (e.g. tank/proxmox/vdisks)
against TrueNAS /pool names which are top-level only (e.g. tank).
Extract the first path component so pool stats resolve correctly.
Rename Pool field label to 'Pool / Dataset Path' and update its hint
to make clear it accepts the full ZFS path (matching v2.x 'pool' field).
Rename Dataset to 'Sub-dataset' with a hint that discourages filling it
unless you genuinely need an extra sub-level beyond what's in Pool.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TrueNAS CORE 13.0 does not expose /iscsi/targetgroup as a REST endpoint
(returns 404). Both CORE and SCALE include the portal group associations
inline in each target's 'groups' array from GET /iscsi/target, which is
all we need to filter targets by reachable portal IP.
Remove the /iscsi/targetgroup call entirely — use target.groups[].portal
cross-referenced against /iscsi/portal results instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PVE's sensitive-properties mechanism extracts listed keys from $param
before check_config and passes them only to on_add_hook/on_update_hook.
activate_storage reads from $cfg which never receives those values, so
the API key was always missing at runtime.
The API key now lives in storage.cfg (root-readable, mode 0640, same as
the v2.x truenas_secret field). Proper on_add_hook private-file storage
is tracked in issue #247.
Restore truenas_api_key => {} (required on create). PVE's update flow
passes $create=0 to check_config which skips absent keys, so
edit-without-changing-key still works.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
truenas_api_key must be optional in options() because PVE extracts
sensitive-properties from the POST body before calling check_config,
causing a spurious 'missing required option' 500 on storage create.
Add a guard in _api() so a missing key produces a clear error.
UI: add autocomplete="url" on host and "new-password" on API key to
prevent Firefox/Chrome from filling in PVE login credentials.
Add a reveal trigger button to show/hide the API key field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the validate-patches job (no more patch files in v3.0).
Update lint to target TrueNAS.pm instead of FreeNAS.pm.
Rebuild staging assembly: TrueNAS.pm + truenas-storage.js are the
only payload — no patch dirs, no REST-Client.pm, no triggers file.
Add $VERSION = '3.0.0' to TrueNAS.pm as the single source of truth.
Add release/3.x as a testing-channel branch alongside master.
Pin actions to @v4 (upload/download-artifact, checkout).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of diffing and patching the 50k-line pvemanagerlib.js each PVE
release, we ship truenas-storage.js as our own file and inject one
<script> line into index.html.tpl (rarely changes, ~60 lines).
truenas-storage.js adds 'truenas' to PVE.Utils.storageSchema at runtime
and defines PVE.storage.TrueNASInputPanel with all config fields:
- TrueNAS host, API key, pool, dataset (column 1)
- SSL toggle, cert verify, portal IP, target IQN (column 2)
API key field: required on create, optional on edit (only submitted if
the user types a new value).
postinst: copies TrueNAS.pm + truenas-storage.js, adds script tag
postrm: removes both files, strips script tag
Closes#225 (core interface), #226 (iSCSI lifecycle activate/deactivate),
#227 (API pool listing replaces SSH).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Package must match filename (TrueNAS.pm → PVE::Storage::Custom::TrueNAS)
so PVE's module loader finds the class when checking ISA PVE::Storage::Plugin.
api() returns 11 to match APIVER in PVE::Storage on PVE 8.4.x.
Returning 10 loaded successfully but triggered a deprecation warning.
Verified: pvedaemon loads plugin cleanly with no errors or warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full PVE::Storage::Custom implementation — zero patches to PVE system files.
Discovered automatically by Proxmox VE at runtime via Module::Load.
Implements:
- alloc_image: create zvol via TrueNAS API + wire iSCSI extent/targetextent
- free_image: tear down iSCSI association + delete zvol
- list_images: enumerate zvols under configured pool/dataset
- status: pool total/used/free via TrueNAS API (replaces SSH)
- path: resolve /dev/disk/by-path from LUN ID via API
- activate_storage: resolve target IQN + iscsiadm login
- deactivate_storage: iscsiadm logout + clear state cache
- activate_volume: ensure session + wait for block device
- volume_has_feature: declare copy and snapshot support
iSCSI target resolution supports both explicit IQN (truenas_target) and
auto-discovery from TrueNAS portal config — the field being set or blank
acts as the gate between modes.
No SSH keys required. Bearer token auth only. REST API v2.0.
Transport: CORE 13.x + SCALE <= 24.10. WebSocket (SCALE 25.04+) in v3.1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove everything that existed solely to wedge into PVE system files:
- stable-5 through stable-8 versioned patch archives
- pve-manager/js patch files (no more pvemanagerlib.js patching)
- pve-docs/api-viewer patch files (no more apidoc.js patching)
- perl5/PVE/Storage/LunCmd/ (replaced by PVE::Storage::Custom plugin)
- perl5/PVE/Storage/ZFSPlugin-*.patch (no more ZFSPlugin.pm patching)
Add perl5/PVE/Storage/Custom/FreeNAS.pm as the v3.0 starting point.
v3.0 ships one .pm file; PVE discovers it automatically — zero patches.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Basic auth (username/password) has been supported since the plugin's
origin but TrueNAS API keys have been available since TrueNAS 12 (2020).
Sending credentials on every API call is a security risk and TrueNAS
may stop accepting it in future releases.
Log a syslog(warn) on every connection attempt that uses Basic Auth so
operators see the deprecation message in their Proxmox logs. The warning
links to issue #244 which tracks removal in v3.0.0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New troubleshooting entry: SCALE 25.04 revokes existing API keys on
upgrade; users must regenerate and update truenas_secret in PVE config.
Also notes HTTPS enforcement and links to #243 for REST deprecation.
- Updated volblocksize entry: v2.4.0 auto-corrects blocksize, so the
"fix" is now informational rather than a manual step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: auto-detect and correct ZFS blocksize for TrueNAS SCALE/CORE (#241)
SCALE requires >= 16k volblocksize; CORE works with 8k. Without correction,
creating a disk on SCALE with blocksize=8k triggers a ZFS warning and wastes
space on SCALE's minimum-4k-block pool layout.
Three changes:
- freenas_get_recommended_blocksize: fixes freenas_api_connect → freenas_api_check
so product_name is actually populated before the SCALE check (was always returning
8192 before this fix)
- freenas_parse_blocksize: new helper to compare "8k"/"16k"/integer blocksize strings
- alloc_image (both 8.x and 8.4.x patches): always detect recommended blocksize for
freenas provider; if configured < recommended, override for this call AND persist
the correction back to storage.cfg via lock_storage_config
- on_add_hook (8.4.x patch only): detect at storage creation time and correct $scfg
before write_config saves it — no extra write needed
Tested on pve01-hq (PVE 8.4.19) against Tank02 (SCALE 24.10.2.1):
- Disk created with blocksize=8k → task log shows correction message, storage.cfg
updated to 16384, no volblocksize warning from TrueNAS
- Disk created with blocksize=16384 → no-op, clean TASK OK
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: add validate-patches step for ZFSPlugin PVE 8.4.x patch
ZFSPlugin-8.4.14_1.pm.patch has been in the build since v2.3.0 but was
never dry-run validated in CI. Now that we have the 8.4 orig committed
(ZFSPlugin-8.4.14_1.pm.orig from libpve-storage-perl 8.3.8), wire it up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: replace explicit return undef with bare return (perlcritic)
Subroutines::ProhibitExplicitReturnUndef violation in
freenas_get_recommended_blocksize. Bare return in list context returns
an empty list rather than a list containing undef, which is the
correct Perl idiom.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Stable releases now produce X.Y.Z-1 (e.g. 2.3.0-1) so they sort higher
than any pre-release build in dpkg. Pre-release builds now use tilde
(~beta+sha, ~alpha+sha) which sorts below the base version, ensuring
apt upgrade always selects stable over a previously installed beta.
Previously -beta+sha sorted higher than X.Y.Z causing apt to refuse
upgrades from beta to stable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
softprops/action-gh-release@v3 adds Node 24 support (v2 was Node 20).
Pin cloudsmith-io/action to v0.6.14 (latest stable) instead of @master.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ZFSPlugin's free_image deletes the zvol via SSH after calling our
run_delete_lu. Our earlier addition of freenas_delete_zvol in
run_delete_lu caused a double-delete: SSH would fail, free_image's
error recovery would call run_create_lu on the now-missing zvol,
producing a spurious "Unable to create lun (rolled back)" in the task
log even though the migration had already succeeded.
freenas_delete_zvol remains in run_create_lu's rollback path where it
correctly cleans up zvols orphaned by a failed LUN creation (#239).
Also documents ZFS blocksize requirements for TrueNAS SCALE (16k) vs
CORE (8k) in README configuration and troubleshooting sections (#241).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
remove:true in the iSCSI extent DELETE body is unreliable on TrueNAS
SCALE 24.10+ — the extent config is removed but the underlying zvol is
left behind as an orphaned dataset. Add freenas_delete_zvol() which calls
DELETE /api/v2.0/pool/dataset/id/{path}/ explicitly after every extent
removal, covering both the rollback path in run_create_lu and normal
disk deletion in run_delete_lu. Guarded to v2.0 API only using the
per-host cache to avoid stale package-global state when two storage
hosts with different API versions are active simultaneously.
Verified on TrueNAS SCALE 24.10.2.1: zvol is fully removed from
Datasets after a forced rollback test (FREENAS_TEST_ROLLBACK=1).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the ad-hoc if/rollback in run_create_lu with an eval block that
tracks both extent_id and link_id so either resource is cleaned up if
anything fails at any point during creation (#214 only covered the
link-creation step).
Also adds a FREENAS_TEST_ROLLBACK env-var trigger: set it in pvedaemon's
environment to force a rollback after a successful create, allowing
verification that orphaned extents and links are removed without needing
a real failure condition.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs caused clone/migrate to fail with 'setHost on undefined value'
followed by 'Loop recursion prevention':
1. freenas_api_check reads $freenas_server_list->{$apihost}{client} to
check if initialized. Perl autovivifies {$apihost} as an empty {} on
that read. freenas_api_connect then saw a defined (but empty) hash and
skipped initialization, leaving client undef → setHost crash.
Fix: guard also checks !defined ...{client}.
2. $ping was a local variable reset to v1.0 on each recursive call.
TrueNAS 25.04+ removed the v1.0 endpoint (returns 404), so the
v1.0→v2.0 upgrade branch looped until the runaway counter tripped.
Fix: accept $ping as optional second parameter (defaults to v1.0)
and pass it through on both recursive call sites.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two install-time failures on PVE 8.4.x nodes:
1. 'patch' utility not in Depends — causes silent patch failure on fresh
nodes; all three PVE file patches silently skip, plugin appears to
install but storage operations fail. Added 'patch' to control.j2.
2. ZFSPlugin.pm routing not applied on PVE 8.4.x — tabs→spaces reformat
and get_base($scfg) signature change in 8.4 broke hunks #3 and #4
(the freenas elsif routing branches). Nodes with a prior partial
install are doubly affected: grep idempotency check passes on partial
freenas strings, so the routing is never applied, causing:
"freenas: unknown iscsi provider" on clone/migrate operations.
New ZFSPlugin-8.4.14_1.pm.patch generated against stock PVE 8.4.19,
bundled as patches/ZFSPlugin/8.4.patch alongside existing 8.patch.
Verified clean on pve01-hq (8.4.19) and pve02-hq (8.4.14).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The initComponent anchor text was not unique in 8.4.19 — it matched
pveLxcCPUInputPanel before ZFSInputPanel, causing tnsecret/tnconfirmsecret
to be declared in the wrong scope. The ZFSInputPanel dialog then threw a
ReferenceError on open, preventing the modal from appearing.
Fixed by anchoring hunk 6 on the already-modified setValues block
(which is unique to ZFSInputPanel after hunk 5 is applied), ensuring
tnsecret/tnconfirmsecret always land in the correct initComponent scope.
Verified on 8.4.14 and 8.4.19 stock files. Tested live on pve01-hq (8.4.19).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>