From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <pve-devel-bounces@lists.proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
	by lore.proxmox.com (Postfix) with ESMTPS id 581E71FF191
	for <inbox@lore.proxmox.com>; Mon,  2 Jun 2025 18:17:16 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
	by firstgate.proxmox.com (Proxmox) with ESMTP id E282E8164;
	Mon,  2 Jun 2025 18:17:31 +0200 (CEST)
To: pve-devel@lists.proxmox.com
Date: Mon,  2 Jun 2025 17:10:52 +0100
In-Reply-To: <20250602161052.170879-1-joao.sousa@eurotux.com>
References: <20250602161052.170879-1-joao.sousa@eurotux.com>
MIME-Version: 1.0
Message-ID: <mailman.181.1748881051.395.pve-devel@lists.proxmox.com>
List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com>
List-Post: <mailto:pve-devel@lists.proxmox.com>
From: Tiago Sousa via pve-devel <pve-devel@lists.proxmox.com>
Precedence: list
Cc: Tiago Sousa <joao.sousa@eurotux.com>
X-Mailman-Version: 2.1.29
X-BeenThere: pve-devel@lists.proxmox.com
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/>
Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>
List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help>
Subject: [pve-devel] [RFC pve-manager 1/1] add ha node maintenance mode to
 the UI and API
Content-Type: multipart/mixed; boundary="===============7652666341752393970=="
Errors-To: pve-devel-bounces@lists.proxmox.com
Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com>

--===============7652666341752393970==
Content-Type: message/rfc822
Content-Disposition: inline

Return-Path: <joao.sousa@eurotux.com>
X-Original-To: pve-devel@lists.proxmox.com
Delivered-To: pve-devel@lists.proxmox.com
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits))
	(No client certificate requested)
	by lists.proxmox.com (Postfix) with ESMTPS id C2C31CB332
	for <pve-devel@lists.proxmox.com>; Mon,  2 Jun 2025 18:17:30 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
	by firstgate.proxmox.com (Proxmox) with ESMTP id 9BBFF811A
	for <pve-devel@lists.proxmox.com>; Mon,  2 Jun 2025 18:17:00 +0200 (CEST)
Received: from eurotux.com (mail.eurotux.com [185.98.249.9])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(No client certificate requested)
	by firstgate.proxmox.com (Proxmox) with ESMTPS
	for <pve-devel@lists.proxmox.com>; Mon,  2 Jun 2025 18:16:59 +0200 (CEST)
Received: from localhost (localhost [127.0.0.1])
	by eurotux.com (Postfix) with ESMTP id B169A30C6F8B;
	Mon,  2 Jun 2025 17:11:11 +0100 (WEST)
Authentication-Results: mail.prd.eurotux.pt (amavisd-new);
 dkim=pass (2048-bit key) reason="pass (just generated, assumed good)"
 header.d=eurotux.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=eurotux.com; h=
	content-transfer-encoding:mime-version:references:in-reply-to
	:x-mailer:message-id:date:date:subject:subject:from:from; s=
	default; t=1748880671; x=1750695072; bh=6uig9CF6gl8tHS6lqwSIaXdM
	YxLyS1t3+kp1Fob4Nbw=; b=SY7cgin58Ti+27dH+R317Ps7CUMEiFIEPEEHUel0
	cq+glCcj20Erw+nZd64vOakhmbc10sMCau4GYu/jRMoO2GYMlYfTd959A1+k1HxK
	Tmxhjatqz6FHVc+qTXRGgih2ncpOaFmjmaOguZYVnBLcjPdic9orwvrknmiN2gQ7
	BLQlp96rItyQJ+KAbKbbPhUCc1MlbrAY/UKrtEtIaRtDihwMoYvhZp2PRTbzzzbU
	JAcb3GYD8JblYj7dlK8xHzvE8E88YX4gTrFMh1Vy08EUoUXKK2aUepV/1eI5fKGQ
	IWafBzXKMeuzeL5LqCmkFoKJPraw6fscztVZDv2uTy+AVw==
X-Virus-Scanned: amavisd-new at mail.prd.eurotux.pt
Received: from eurotux.com ([127.0.0.1])
 by localhost (mail.prd.eurotux.pt [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id Cvz0S8GBbINz; Mon,  2 Jun 2025 17:11:11 +0100 (WEST)
Received: from proxmox.example (brg.eurotux.com [185.98.249.5])
	(Authenticated sender: joao.sousa@eurotux.com)
	by eurotux.com (Postfix) with ESMTPSA id F103830C6F8A;
	Mon,  2 Jun 2025 17:11:10 +0100 (WEST)
From: Tiago Sousa <joao.sousa@eurotux.com>
To: pve-devel@lists.proxmox.com
Subject: [RFC pve-manager 1/1] add ha node maintenance mode to the UI and API
Date: Mon,  2 Jun 2025 17:10:52 +0100
Message-Id: <20250602161052.170879-2-joao.sousa@eurotux.com>
X-Mailer: git-send-email 2.39.5
In-Reply-To: <20250602161052.170879-1-joao.sousa@eurotux.com>
References: <20250602161052.170879-1-joao.sousa@eurotux.com>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
X-SPAM-LEVEL: Spam detection results:  0
	AWL                     0.150 Adjusted score from AWL reputation of From: address
	BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
	DKIM_SIGNED               0.1 Message has a DKIM or DK signature, not necessarily valid
	DKIM_VALID               -0.1 Message has at least one valid DKIM or DK signature
	DKIM_VALID_AU            -0.1 Message has a valid DKIM or DK signature from author's domain
	DKIM_VALID_EF            -0.1 Message has a valid DKIM or DK signature from envelope-from domain
	DMARC_PASS               -0.1 DMARC pass policy
	RCVD_IN_MSPIKE_H2       0.001 Average reputation (+2)
	SPF_HELO_PASS          -0.001 SPF: HELO matches SPF record
	SPF_PASS               -0.001 SPF: sender matches SPF record

Signed-off-by: Tiago Sousa <joao.sousa@eurotux.com>
---
 PVE/API2/Nodes.pm            | 45 ++++++++++++++++++++++++++++++++++++
 www/manager6/Utils.js        |  1 +
 www/manager6/node/CmdMenu.js | 36 +++++++++++++++++++++++++++--
 3 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm
index 791d2dec..f2365e59 100644
--- a/PVE/API2/Nodes.pm
+++ b/PVE/API2/Nodes.pm
@@ -21,6 +21,7 @@ use PVE::DataCenterConfig;
 use PVE::Exception qw(raise raise_perm_exc raise_param_exc);
 use PVE::Firewall;
 use PVE::HA::Config;
+use PVE::HA::Usage;
 use PVE::HA::Env::PVE2;
 use PVE::INotify;
 use PVE::JSONSchema qw(get_standard_option);
@@ -300,6 +301,7 @@ __PACKAGE__->register_method ({
 	    { name =3D> 'vncshell' },
 	    { name =3D> 'vzdump' },
 	    { name =3D> 'wakeonlan' },
+	    { name =3D> 'node-maintenance-set' },
 	];
=20
 	push @$result, { name =3D> 'sdn' } if $have_sdn;
@@ -802,6 +804,49 @@ __PACKAGE__->register_method({
 	return $wol_config->{mac};
     }});
=20
+__PACKAGE__->register_method({
+    name =3D> 'node-maintenance-set',
+    path =3D> 'node-maintenance-set',
+    method =3D> 'POST',
+    permissions =3D> {
+	check =3D> ['perm', '/nodes/{node}', [ 'Sys.PowerMgmt' ]],
+    },
+    protected =3D> 1,
+    description =3D> "Set node maintenance mode (enable or disable)",
+    parameters =3D> {
+	additionalProperties =3D> 0,
+	properties =3D> {
+        node =3D> get_standard_option('pve-node'),
+        disable =3D> {
+        description =3D> "Requests disabling or enabling maintenance-mod=
e.",
+        type =3D> 'boolean',
+        },
+	},
+    },
+    returns =3D> {
+	type =3D> 'string',
+	format =3D> 'string',
+	description =3D> '',
+    },
+    code =3D> sub {
+	my ($param) =3D @_;
+	my $node =3D $param->{node};
+	my $rpcenv =3D PVE::RPCEnvironment::get();
+	my $authuser =3D $rpcenv->get_user();
+
+	PVE::Cluster::check_node_exists($node);
+	my $state =3D $param->{disable} ? 'disable' : 'enable';
+    my $hacmd =3D sub {
+    my $upid =3D shift;
+    print "Requesting to $state HA node maintenance for node $node\n";
+    my $cmd =3D ['ha-manager', 'crm-command', 'node-maintenance', $state=
, $node];
+    PVE::Tools::run_command($cmd);
+    return;
+    };
+
+	return $rpcenv->fork_worker('hamaintenance', undef, $authuser, $hacmd);
+    }});
+
 __PACKAGE__->register_method({
     name =3D> 'rrd',
     path =3D> 'rrd',
diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index 1f6778cd..48dac090 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -2034,6 +2034,7 @@ Ext.define('PVE.Utils', {
 	    hamigrate: ['HA', gettext('Migrate')],
 	    hashutdown: ['HA', gettext('Shutdown')],
 	    hastart: ['HA', gettext('Start')],
+	    hamaintenance: ['HA', gettext('Node Maintenance')],
 	    hastop: ['HA', gettext('Stop')],
 	    imgcopy: ['', gettext('Copy data')],
 	    imgdel: ['', gettext('Erase data')],
diff --git a/www/manager6/node/CmdMenu.js b/www/manager6/node/CmdMenu.js
index 7bdfebc5..0a8dc008 100644
--- a/www/manager6/node/CmdMenu.js
+++ b/www/manager6/node/CmdMenu.js
@@ -94,6 +94,34 @@ Ext.define('PVE.node.CmdMenu', {
 		PVE.Utils.openDefaultConsoleWindow(true, 'shell', undefined, nodename,=
 undefined);
 	    },
 	},
+	{
+	    text: gettext('Enter Maintenance Mode'),
+	    itemId: 'entermaintenance',
+	    iconCls: 'fa fa-fw fa-building',
+	    handler: function() {
+		let nodename =3D this.up('menu').nodename;
+		Proxmox.Utils.API2Request({
+		    url: `/nodes/${nodename}/node-maintenance-set`,
+            params: { disable: 0 },
+		    method: 'POST',
+		    failure: (response, opts) =3D> Ext.Msg.alert(gettext('Error'), res=
ponse.htmlStatus),
+		});
+	    },
+	},
+	{
+	    text: gettext('Exit Maintenance Mode'),
+	    itemId: 'exitmaintenance',
+	    iconCls: 'fa fa-fw fa-building',
+	    handler: function() {
+		let nodename =3D this.up('menu').nodename;
+		Proxmox.Utils.API2Request({
+		    url: `/nodes/${nodename}/node-maintenance-set`,
+            params: { disable: 1 },
+		    method: 'POST',
+		    failure: (response, opts) =3D> Ext.Msg.alert(gettext('Error'), res=
ponse.htmlStatus),
+		});
+	    },
+	},
 	{ xtype: 'menuseparator' },
 	{
 	    text: gettext('Wake-on-LAN'),
@@ -150,11 +178,15 @@ Ext.define('PVE.node.CmdMenu', {
 	}
 	if (!caps.nodes['Sys.Console']) {
 	    me.getComponent('shell').setDisabled(true);
-	}
+    }
+    if (me.pveSelNode.data.hastate =3D=3D=3D 'maintenance') {
+	    me.getComponent('entermaintenance').setVisible(false);
+    } else {
+	    me.getComponent('exitmaintenance').setVisible(false);
+    }
 	if (me.pveSelNode.data.running) {
 	    me.getComponent('wakeonlan').setDisabled(true);
 	}
-
 	if (PVE.Utils.isStandaloneNode()) {
 	    me.getComponent('bulkmigrate').setVisible(false);
 	}
--=20
2.39.5



--===============7652666341752393970==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

--===============7652666341752393970==--