From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 275AC1FF0B3 for ; Fri, 25 Sep 2026 11:44:36 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 30B00218F7; Fri, 25 Sep 2026 11:42:41 +0200 (CEST) From: Arthur Bied-Charreton To: pve-devel@lists.proxmox.com Subject: [PATCH pve-manager v3 14/16] ui: sdn: apply: add control for dangling IPSet references Date: Fri, 25 Sep 2026 11:42:28 +0200 Message-ID: <20260925094230.844917-15-a.bied-charreton@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260925094230.844917-1-a.bied-charreton@proxmox.com> References: <20260925094230.844917-1-a.bied-charreton@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 AWL -0.920 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: BJMSLLGIL65PCFAAT3TVQVE4HGIM3W2K X-Message-ID-Hash: BJMSLLGIL65PCFAAT3TVQVE4HGIM3W2K X-MailFrom: abied-charreton@jett.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Applying an SDN configuration that removes a VNet also removes the four IPSets auto-generated for it [0], so rules referencing those no longer resolve and are dropped from the generated ruleset. Replace the plain confirmation message box with a window carrying the shared selector, so those rules can be disabled or deleted in the same step. The Apply button first queries the pending VNets, and the window only shows the selector if the apply actually removes one, since there is nothing to decide otherwise. [0] https://pve.proxmox.com/wiki/Software-Defined_Network#pvesdn_firewall_integration Signed-off-by: Arthur Bied-Charreton --- www/manager6/sdn/StatusView.js | 105 ++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/www/manager6/sdn/StatusView.js b/www/manager6/sdn/StatusView.js index fada5041..79ca815c 100644 --- a/www/manager6/sdn/StatusView.js +++ b/www/manager6/sdn/StatusView.js @@ -1,3 +1,74 @@ +Ext.define('PVE.sdn.ApplyWindow', { + extend: 'Proxmox.window.Edit', + alias: 'widget.pveSdnApplyWindow', + + title: gettext('Apply SDN Configuration'), + + url: '/cluster/sdn', + method: 'PUT', + isCreate: true, + submitText: gettext('Apply'), + width: 600, + + // IDs of the VNets that this apply removes, empty if it removes none + removedVnets: [], + + initComponent: function () { + let me = this; + + me.items = [ + { + xtype: 'displayfield', + value: gettext( + 'Applying pending SDN changes will also apply any pending local node network changes.', + ), + }, + ]; + + // the auto-generated IPSets of a removed VNet go away with it, so only then is there + // anything to decide about the rules referencing them + if (me.removedVnets.length !== 0) { + let removedHint = Ext.htmlEncode( + Ext.String.format( + gettext('This removes the following VNet(s): {0}.'), + me.removedVnets.join(', '), + ), + ); + let helpLink = Ext.htmlEncode( + Proxmox.Utils.get_help_link('pvesdn_firewall_integration'), + ); + let helpLabel = Ext.htmlEncode(gettext('their auto-generated IPSets')); + let refsHint = Ext.String.format( + gettext('Firewall rules referencing {0} will no longer resolve.'), + `${helpLabel}`, + ); + + me.items.push( + { + xtype: 'displayfield', + userCls: 'pmx-hint', + value: `${removedHint}
${refsHint}`, + }, + { + xtype: 'pveFirewallDanglingReferences', + name: 'dangling-ipset-references', + value: 'keep', + labelWidth: 200, + keepTip: gettext( + 'Keep referencing rules. They are dropped from the generated ruleset and shown as invalid until the VNet is recreated.', + ), + disableTip: gettext( + 'Disable referencing rules, keeping them in the firewall configuration.', + ), + dropTip: gettext('Delete referencing rules.'), + }, + ); + } + + me.callParent(); + }, +}); + Ext.define( 'PVE.sdn.StatusView', { @@ -45,26 +116,20 @@ Ext.define( { text: gettext('Apply'), handler: function () { - Ext.Msg.show({ - title: gettext('Confirm'), - icon: Ext.Msg.QUESTION, - msg: gettext( - 'Applying pending SDN changes will also apply any pending local node network changes. Proceed?', - ), - buttons: Ext.Msg.YESNO, - callback: function (btn) { - if (btn === 'yes') { - Proxmox.Utils.API2Request({ - url: '/cluster/sdn/', - method: 'PUT', - waitMsgTarget: me, - failure: (response) => - Ext.Msg.alert( - gettext('Error'), - response.htmlStatus, - ), - }); - } + Proxmox.Utils.API2Request({ + url: '/cluster/sdn/vnets', + method: 'GET', + params: { pending: 1 }, + waitMsgTarget: me, + failure: (response) => + Ext.Msg.alert(gettext('Error'), response.htmlStatus), + success: function (response) { + Ext.create('PVE.sdn.ApplyWindow', { + removedVnets: response.result.data + .filter((vnet) => vnet.state === 'deleted') + .map((vnet) => vnet.vnet), + autoShow: true, + }); }, }); }, -- 2.47.3