[RFC pve-manager 1/1] add ha node maintenance mode to the UI and API
Tiago Sousa
joao.sousa at eurotux.com
Mon Jun 2 18:10:52 CEST 2025
Signed-off-by: Tiago Sousa <joao.sousa at 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 => 'vncshell' },
{ name => 'vzdump' },
{ name => 'wakeonlan' },
+ { name => 'node-maintenance-set' },
];
push @$result, { name => 'sdn' } if $have_sdn;
@@ -802,6 +804,49 @@ __PACKAGE__->register_method({
return $wol_config->{mac};
}});
+__PACKAGE__->register_method({
+ name => 'node-maintenance-set',
+ path => 'node-maintenance-set',
+ method => 'POST',
+ permissions => {
+ check => ['perm', '/nodes/{node}', [ 'Sys.PowerMgmt' ]],
+ },
+ protected => 1,
+ description => "Set node maintenance mode (enable or disable)",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ disable => {
+ description => "Requests disabling or enabling maintenance-mode.",
+ type => 'boolean',
+ },
+ },
+ },
+ returns => {
+ type => 'string',
+ format => 'string',
+ description => '',
+ },
+ code => sub {
+ my ($param) = @_;
+ my $node = $param->{node};
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+ PVE::Cluster::check_node_exists($node);
+ my $state = $param->{disable} ? 'disable' : 'enable';
+ my $hacmd = sub {
+ my $upid = shift;
+ print "Requesting to $state HA node maintenance for node $node\n";
+ my $cmd = ['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 => 'rrd',
path => '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 = this.up('menu').nodename;
+ Proxmox.Utils.API2Request({
+ url: `/nodes/${nodename}/node-maintenance-set`,
+ params: { disable: 0 },
+ method: 'POST',
+ failure: (response, opts) => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
+ });
+ },
+ },
+ {
+ text: gettext('Exit Maintenance Mode'),
+ itemId: 'exitmaintenance',
+ iconCls: 'fa fa-fw fa-building',
+ handler: function() {
+ let nodename = this.up('menu').nodename;
+ Proxmox.Utils.API2Request({
+ url: `/nodes/${nodename}/node-maintenance-set`,
+ params: { disable: 1 },
+ method: 'POST',
+ failure: (response, opts) => Ext.Msg.alert(gettext('Error'), response.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 === '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);
}
--
2.39.5
More information about the pve-devel
mailing list