diff --git a/frontend-modern/src/components/Settings/NodeModal.tsx b/frontend-modern/src/components/Settings/NodeModal.tsx index 09e3cb8c5..089ac6e9b 100644 --- a/frontend-modern/src/components/Settings/NodeModal.tsx +++ b/frontend-modern/src/components/Settings/NodeModal.tsx @@ -35,6 +35,7 @@ export const NodeModal: Component = (props) => { monitorContainers: true, monitorStorage: true, monitorBackups: true, + enableBackupManagement: true, // New field for backup write permissions // PBS specific monitorDatastores: true, monitorSyncJobs: true, @@ -62,6 +63,7 @@ export const NodeModal: Component = (props) => { monitorContainers: (node.type === 'pve' && 'monitorContainers' in node ? node.monitorContainers : true) ?? true, monitorStorage: (node.type === 'pve' && 'monitorStorage' in node ? node.monitorStorage : true) ?? true, monitorBackups: (node.type === 'pve' && 'monitorBackups' in node ? node.monitorBackups : true) ?? true, + enableBackupManagement: true, // Default to true for existing nodes monitorDatastores: (node.type === 'pbs' && 'monitorDatastores' in node ? node.monitorDatastores : true) ?? true, monitorSyncJobs: (node.type === 'pbs' && 'monitorSyncJobs' in node ? node.monitorSyncJobs : true) ?? true, monitorVerifyJobs: (node.type === 'pbs' && 'monitorVerifyJobs' in node ? node.monitorVerifyJobs : true) ?? true, @@ -85,6 +87,7 @@ export const NodeModal: Component = (props) => { monitorContainers: true, monitorStorage: true, monitorBackups: true, + enableBackupManagement: true, monitorDatastores: true, monitorSyncJobs: true, monitorVerifyJobs: true, @@ -407,6 +410,26 @@ export const NodeModal: Component = (props) => { {/* Quick Setup Tab */} + {/* Backup Management Checkbox */} +
+ +

+ {formData().enableBackupManagement + ? 'Allows Pulse to manage PVE backups (create, delete, etc.) and display them in the Storage tab' + : 'Pulse will have read-only access. PVE backups will not appear in the Storage tab'} +

+
+

Run this single command on your Proxmox VE server:

{/* One-liner command */} @@ -417,7 +440,8 @@ export const NodeModal: Component = (props) => { const hostValue = formData().host || ''; const encodedHost = encodeURIComponent(hostValue); const pulseUrl = encodeURIComponent(window.location.origin); - const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}`; + const backupPerms = formData().enableBackupManagement ? '&backup_perms=true' : ''; + const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}${backupPerms}`; const command = `curl -sSL "${scriptUrl}" | bash`; if (await copyToClipboard(command)) { showSuccess('Command copied! Run it on your server.'); @@ -437,7 +461,8 @@ export const NodeModal: Component = (props) => { const hostValue = formData().host || ''; const encodedHost = encodeURIComponent(hostValue); const pulseUrl = encodeURIComponent(window.location.origin); - const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}`; + const backupPerms = formData().enableBackupManagement ? '&backup_perms=true' : ''; + const scriptUrl = `${window.location.origin}/api/setup-script?type=pve&host=${encodedHost}&pulse_url=${pulseUrl}${backupPerms}`; const command = `curl -sSL "${scriptUrl}" | bash`; return ( <> @@ -462,7 +487,8 @@ export const NodeModal: Component = (props) => { ✨ New: The script now automatically configures Pulse - no manual token copying needed!

- Permissions granted: PVEAuditor (read-only) on root + PVEDatastoreAdmin (read/write for backups) on /storage + Permissions granted: PVEAuditor (read-only) on root + {formData().enableBackupManagement && ' + PVEDatastoreAdmin (read/write for backups) on /storage'}

diff --git a/internal/api/config_handlers.go b/internal/api/config_handlers.go index e0495b4e4..7e7cbaaae 100644 --- a/internal/api/config_handlers.go +++ b/internal/api/config_handlers.go @@ -1484,6 +1484,7 @@ func (h *ConfigHandlers) HandleSetupScript(w http.ResponseWriter, r *http.Reques serverType := query.Get("type") // "pve" or "pbs" serverHost := query.Get("host") pulseURL := query.Get("pulse_url") // URL of the Pulse server for auto-registration + backupPerms := query.Get("backup_perms") == "true" // Whether to add backup management permissions // Default to PVE if not specified if serverType == "" { @@ -1518,6 +1519,12 @@ func (h *ConfigHandlers) HandleSetupScript(w http.ResponseWriter, r *http.Reques var script string if serverType == "pve" { + // Build storage permissions command if needed + storagePerms := "" + if backupPerms { + storagePerms = "\npveum aclmod /storage -user pulse-monitor@pam -role PVEDatastoreAdmin" + } + script = fmt.Sprintf(`#!/bin/bash # Pulse Monitoring Setup Script for %s # Generated: %s @@ -1619,8 +1626,7 @@ fi # Set up permissions echo "Setting up permissions..." -pveum aclmod / -user pulse-monitor@pam -role PVEAuditor -pveum aclmod /storage -user pulse-monitor@pam -role PVEDatastoreAdmin +pveum aclmod / -user pulse-monitor@pam -role PVEAuditor%s echo "" echo "✅ Setup complete!" @@ -1634,7 +1640,7 @@ else fi echo " Host URL: %s" echo "" -`, serverName, time.Now().Format("2006-01-02 15:04:05"), pulseURL, serverHost, serverHost) +`, serverName, time.Now().Format("2006-01-02 15:04:05"), pulseURL, serverHost, storagePerms, serverHost) } else { // PBS script = fmt.Sprintf(`#!/bin/bash