feat: add TrueNAS UI panel via injected JS — no pvemanagerlib.js patch
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>
This commit is contained in:
parent
f6ca0c9ef5
commit
8a487ef4a8
|
|
@ -1,11 +1,14 @@
|
|||
#!/bin/bash
|
||||
# postinst: freenas-proxmox v3.x install/upgrade script
|
||||
# Installs the TrueNAS custom storage plugin for Proxmox VE.
|
||||
# No patches, no internet access required.
|
||||
# Installs the TrueNAS custom storage plugin and UI panel for Proxmox VE.
|
||||
# No patches to PVE core files — only adds our own files and one <script> line.
|
||||
set -e
|
||||
|
||||
PLUGIN_SRC="/usr/share/freenas-proxmox/TrueNAS.pm"
|
||||
INSTALL_DIR="/usr/share/freenas-proxmox"
|
||||
PLUGIN_DST="/usr/share/perl5/PVE/Storage/Custom/TrueNAS.pm"
|
||||
JS_DST="/usr/share/pve-manager/js/truenas-storage.js"
|
||||
TPL="/usr/share/pve-manager/index.html.tpl"
|
||||
SCRIPT_TAG=' <script type="text/javascript" src="/pve2/js/truenas-storage.js?ver=[% version %]"></script>'
|
||||
LOG_FILE="/var/log/freenas-proxmox-install.log"
|
||||
|
||||
log() {
|
||||
|
|
@ -15,21 +18,34 @@ log() {
|
|||
install_plugin() {
|
||||
log "Installing ${PLUGIN_DST}"
|
||||
mkdir -p "$(dirname "$PLUGIN_DST")"
|
||||
cp "$PLUGIN_SRC" "$PLUGIN_DST"
|
||||
log "Plugin installed"
|
||||
cp "${INSTALL_DIR}/TrueNAS.pm" "$PLUGIN_DST"
|
||||
}
|
||||
|
||||
install_ui() {
|
||||
log "Installing ${JS_DST}"
|
||||
cp "${INSTALL_DIR}/truenas-storage.js" "$JS_DST"
|
||||
|
||||
if grep -qF 'truenas-storage.js' "$TPL" 2>/dev/null; then
|
||||
log "index.html.tpl already has truenas-storage.js — skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Adding <script> tag to ${TPL}"
|
||||
sed -i "/pvemanagerlib\.js/a\\${SCRIPT_TAG}" "$TPL"
|
||||
}
|
||||
|
||||
restart_pve_services() {
|
||||
log "Restarting Proxmox VE services ..."
|
||||
pvedaemon restart && log "pvedaemon restarted"
|
||||
pveproxy restart && log "pveproxy restarted"
|
||||
log "Done. Refresh your Proxmox browser tab to load the updated UI."
|
||||
log "Done. Refresh your Proxmox browser tab."
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
log "Configuring freenas-proxmox (previous version: ${2:-none})"
|
||||
install_plugin
|
||||
install_ui
|
||||
restart_pve_services
|
||||
;;
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,25 @@
|
|||
#!/bin/bash
|
||||
# postrm: freenas-proxmox v3.x removal script
|
||||
# Removes the TrueNAS custom storage plugin for Proxmox VE.
|
||||
set -e
|
||||
|
||||
PLUGIN_DST="/usr/share/perl5/PVE/Storage/Custom/TrueNAS.pm"
|
||||
JS_DST="/usr/share/pve-manager/js/truenas-storage.js"
|
||||
TPL="/usr/share/pve-manager/index.html.tpl"
|
||||
LOG_FILE="/var/log/freenas-proxmox-install.log"
|
||||
|
||||
log() {
|
||||
echo "[freenas-proxmox] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
remove_ui() {
|
||||
rm -f "$JS_DST" && log "Removed ${JS_DST}"
|
||||
|
||||
if [ -f "$TPL" ] && grep -qF 'truenas-storage.js' "$TPL"; then
|
||||
log "Removing <script> tag from ${TPL}"
|
||||
sed -i '/truenas-storage\.js/d' "$TPL"
|
||||
fi
|
||||
}
|
||||
|
||||
restart_pve_services() {
|
||||
log "Restarting Proxmox VE services ..."
|
||||
pvedaemon restart && log "pvedaemon restarted"
|
||||
|
|
@ -19,15 +29,15 @@ restart_pve_services() {
|
|||
case "$1" in
|
||||
remove)
|
||||
log "Removing freenas-proxmox ..."
|
||||
rm -f "$PLUGIN_DST"
|
||||
log "Plugin removed"
|
||||
rm -f "$PLUGIN_DST" && log "Removed ${PLUGIN_DST}"
|
||||
remove_ui
|
||||
restart_pve_services
|
||||
log "freenas-proxmox removed. Refresh your Proxmox browser tab."
|
||||
;;
|
||||
purge)
|
||||
log "Purging freenas-proxmox ..."
|
||||
rm -f "$PLUGIN_DST"
|
||||
rm -f "$LOG_FILE"
|
||||
rm -f "$PLUGIN_DST" "$JS_DST" "$LOG_FILE"
|
||||
[ -f "$TPL" ] && sed -i '/truenas-storage\.js/d' "$TPL"
|
||||
;;
|
||||
upgrade|failed-upgrade|disappear|abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
// TrueNAS Custom Storage Plugin — Proxmox VE UI
|
||||
//
|
||||
// Registers the 'truenas' storage type in PVE's UI schema and defines the
|
||||
// configuration panel shown when adding or editing TrueNAS storage.
|
||||
//
|
||||
// Loaded by index.html.tpl after pvemanagerlib.js, so PVE.Utils is available.
|
||||
|
||||
// Register TrueNAS in the storage type dropdown
|
||||
PVE.Utils.storageSchema.truenas = {
|
||||
name: 'TrueNAS (ZFS/iSCSI)',
|
||||
ipanel: 'TrueNASInputPanel',
|
||||
faIcon: 'database',
|
||||
backups: false,
|
||||
};
|
||||
|
||||
Ext.define('PVE.storage.TrueNASInputPanel', {
|
||||
extend: 'PVE.panel.StorageBase',
|
||||
|
||||
initComponent: function () {
|
||||
let me = this;
|
||||
|
||||
// Column 1 — identity and credentials (left side)
|
||||
me.column1 = [
|
||||
{
|
||||
xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
|
||||
fieldLabel: gettext('TrueNAS Host'),
|
||||
name: 'truenas_host',
|
||||
allowBlank: false,
|
||||
emptyText: gettext('hostname or IP address'),
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
fieldLabel: gettext('API Key'),
|
||||
name: 'truenas_api_key',
|
||||
inputType: 'password',
|
||||
allowBlank: !me.isCreate,
|
||||
emptyText: me.isCreate
|
||||
? gettext('Paste API key from TrueNAS UI')
|
||||
: gettext('unchanged — paste new key to change'),
|
||||
listeners: {
|
||||
// On edit: don't submit unless the user types a new value
|
||||
afterrender: function (field) {
|
||||
if (!me.isCreate) {
|
||||
field.submitValue = false;
|
||||
}
|
||||
},
|
||||
change: function (field, value) {
|
||||
if (!me.isCreate) {
|
||||
field.submitValue = (value && value.length > 0);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
|
||||
fieldLabel: gettext('Pool'),
|
||||
name: 'truenas_pool',
|
||||
allowBlank: false,
|
||||
emptyText: gettext('ZFS pool name (e.g. tank)'),
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
fieldLabel: gettext('Dataset'),
|
||||
name: 'truenas_dataset',
|
||||
allowBlank: true,
|
||||
emptyText: gettext('Optional (e.g. proxmox)'),
|
||||
deleteEmpty: !me.isCreate,
|
||||
},
|
||||
];
|
||||
|
||||
// Column 2 — connection options (right side)
|
||||
// Note: Nodes selector and Enable checkbox are prepended by StorageBase
|
||||
me.column2 = [
|
||||
{
|
||||
xtype: 'proxmoxcheckbox',
|
||||
fieldLabel: gettext('Use SSL'),
|
||||
name: 'truenas_ssl',
|
||||
checked: true,
|
||||
uncheckedValue: 0,
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxcheckbox',
|
||||
fieldLabel: gettext('Verify SSL Certificate'),
|
||||
name: 'truenas_ssl_verify',
|
||||
checked: false,
|
||||
uncheckedValue: 0,
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
fieldLabel: gettext('Portal IP'),
|
||||
name: 'truenas_portal_ip',
|
||||
allowBlank: true,
|
||||
emptyText: gettext('Optional — defaults to TrueNAS host'),
|
||||
deleteEmpty: !me.isCreate,
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
fieldLabel: gettext('Target IQN'),
|
||||
name: 'truenas_target',
|
||||
allowBlank: true,
|
||||
emptyText: gettext('Optional — auto-discovered if blank'),
|
||||
deleteEmpty: !me.isCreate,
|
||||
},
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
},
|
||||
});
|
||||
Loading…
Reference in New Issue