* [PATCH common/manager 0/3] fix #7803: 'localhost' alias handling in node-specific endpoints
@ 2026-07-14 14:50 Elias Huhsovitz
2026-07-14 14:50 ` [PATCH common 1/3] inotify: add helper to resolve 'localhost' node alias Elias Huhsovitz
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Elias Huhsovitz @ 2026-07-14 14:50 UTC (permalink / raw)
To: pve-devel; +Cc: Elias Huhsovitz
This series fixes bug #7803, where API endpoints like
/nodes/localhost/config and /nodes/localhost/certificates/info return
empty data or fail, while the same endpoints work correctly when using
the actual node name (e.g., /nodes/node1/config).
The API routing layer correctly proxies
'localhost' to the local node, but the endpoint handlers use the literal
string 'localhost' to construct file paths in the cluster filesystem.
Since no node directory named 'localhost' exists, the file
lookups fail.
To resolve this, the first patch introduces a
PVE::INotify::resolve_nodename() helper in pve-common to centralize the
alias resolution. The subsequent patches apply this helper to the
affected endpoints in pve-manager (NodeConfig, Certificates, RRD,
migrateall) and refactor existing inline resolutions in the bulk
operation endpoints (startall, stopall, suspendall) for consistency.
Note: The pve-common patch (1/3) must be applied and built before the
pve-manager patches, as the API changes depend on the new helper
function.
pve-common:
Elias Huhsovitz (1):
inotify: add helper to resolve 'localhost' node alias
src/PVE/INotify.pm | 5 +++++
1 file changed, 5 insertions(+)
pve-manager:
Elias Huhsovitz (2):
fix #7803: api: nodes: resolve 'localhost' alias in node-specific
endpoints
api: nodes: use resolve_nodename helper for bulk operation
PVE/API2/Ceph/MDS.pm | 3 +--
PVE/API2/Certificates.pm | 8 +++++---
PVE/API2/NodeConfig.pm | 6 ++++--
PVE/API2/Nodes.pm | 22 +++++++++-------------
4 files changed, 19 insertions(+), 20 deletions(-)
Summary over all repositories:
5 files changed, 24 insertions(+), 20 deletions(-)
--
Generated by murpp 0.12.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH common 1/3] inotify: add helper to resolve 'localhost' node alias 2026-07-14 14:50 [PATCH common/manager 0/3] fix #7803: 'localhost' alias handling in node-specific endpoints Elias Huhsovitz @ 2026-07-14 14:50 ` Elias Huhsovitz 2026-07-14 14:50 ` [PATCH manager 2/3] fix #7803: api: nodes: resolve 'localhost' alias in node-specific endpoints Elias Huhsovitz 2026-07-14 14:50 ` [PATCH manager 3/3] api: nodes: use resolve_nodename helper for bulk operation Elias Huhsovitz 2 siblings, 0 replies; 5+ messages in thread From: Elias Huhsovitz @ 2026-07-14 14:50 UTC (permalink / raw) To: pve-devel; +Cc: Elias Huhsovitz Several API endpoints accept 'localhost' as a valid node alias via the API routing layer. However, the endpoint handlers often use the literal string 'localhost' to construct file paths in the cluster filesystem (e.g., /etc/pve/nodes/localhost/config), which fails because no actual node directory with that name exists. Add a PVE::INotify::resolve_nodename() helper to centralize the translation of 'localhost' to the actual node name. This ensures consistent behavior. across multiple API handlers. Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> --- src/PVE/INotify.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm index 53b4e21..25ea0b8 100644 --- a/src/PVE/INotify.pm +++ b/src/PVE/INotify.pm @@ -533,6 +533,11 @@ sub nodename { return $cached_nodename; } +sub resolve_nodename { + my ($node) = @_; + return $node eq 'localhost' ? nodename() : $node; +} + sub read_etc_hostname { my ($filename, $fd) = @_; -- 2.47.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH manager 2/3] fix #7803: api: nodes: resolve 'localhost' alias in node-specific endpoints 2026-07-14 14:50 [PATCH common/manager 0/3] fix #7803: 'localhost' alias handling in node-specific endpoints Elias Huhsovitz 2026-07-14 14:50 ` [PATCH common 1/3] inotify: add helper to resolve 'localhost' node alias Elias Huhsovitz @ 2026-07-14 14:50 ` Elias Huhsovitz 2026-07-14 14:57 ` Shannon Sterz 2026-07-14 14:50 ` [PATCH manager 3/3] api: nodes: use resolve_nodename helper for bulk operation Elias Huhsovitz 2 siblings, 1 reply; 5+ messages in thread From: Elias Huhsovitz @ 2026-07-14 14:50 UTC (permalink / raw) To: pve-devel; +Cc: Elias Huhsovitz When 'localhost' is used as the node parameter, the API proxy correctly routes the request to the local node. However, several endpoint handlers used the literal string 'localhost' to construct file paths or validate cluster nodes, resulting in empty data or validation errors. Use the new PVE::INotify::resolve_nodename() helper to correctly resolve the alias before accessing the cluster filesystem or checking node existence. This fixes the following endpoints: - NodeConfig (get_config, set_options) - Certificates (info, upload_custom_cert, remove_custom_cert) - Nodes (rrd, rrddata, migrateall) Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> --- PVE/API2/Certificates.pm | 8 +++++--- PVE/API2/NodeConfig.pm | 6 ++++-- PVE/API2/Nodes.pm | 13 ++++++------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/PVE/API2/Certificates.pm b/PVE/API2/Certificates.pm index de8762c5..d567939c 100644 --- a/PVE/API2/Certificates.pm +++ b/PVE/API2/Certificates.pm @@ -7,6 +7,7 @@ use PVE::API2::ACME; use PVE::Certificate; use PVE::CertHelpers; use PVE::Exception qw(raise_param_exc); +use PVE::INotify; use PVE::JSONSchema qw(get_standard_option); use PVE::Tools qw(extract_param file_get_contents file_set_contents); @@ -66,7 +67,8 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $node_path = "/etc/pve/nodes/$param->{node}"; + my $node = PVE::INotify::resolve_nodename($param->{node}); + my $node_path = "/etc/pve/nodes/$node"; my $res = []; my $cert_paths = [ @@ -125,7 +127,7 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $node = extract_param($param, 'node'); + my $node = PVE::INotify::resolve_nodename(extract_param($param, 'node')); my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node); my $certs = extract_param($param, 'certificates'); @@ -188,7 +190,7 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $node = extract_param($param, 'node'); + my $node = PVE::INotify::resolve_nodename(extract_param($param, 'node')); my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node); my $code = sub { diff --git a/PVE/API2/NodeConfig.pm b/PVE/API2/NodeConfig.pm index cc726dac..cad81c3e 100644 --- a/PVE/API2/NodeConfig.pm +++ b/PVE/API2/NodeConfig.pm @@ -3,6 +3,7 @@ package PVE::API2::NodeConfig; use strict; use warnings; +use PVE::INotify; use PVE::JSONSchema qw(get_standard_option); use PVE::NodeConfig; use PVE::Tools qw(extract_param); @@ -61,7 +62,8 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $config = PVE::NodeConfig::load_config($param->{node}); + my $node = PVE::INotify::resolve_nodename($param->{node}); + my $config = PVE::NodeConfig::load_config($node); if (defined(my $prop = $param->{property})) { return {} if !exists $config->{$prop}; @@ -91,7 +93,7 @@ __PACKAGE__->register_method({ my ($param) = @_; my $delete = extract_param($param, 'delete'); - my $node = extract_param($param, 'node'); + my $node = PVE::INotify::resolve_nodename(extract_param($param, 'node')); my $digest = extract_param($param, 'digest'); my $code = sub { diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm index dfe3b4cf..90ce3c10 100644 --- a/PVE/API2/Nodes.pm +++ b/PVE/API2/Nodes.pm @@ -830,9 +830,9 @@ __PACKAGE__->register_method({ }, code => sub { my ($param) = @_; - + my $node = PVE::INotify::resolve_nodename($param->{node}); return PVE::RRD::create_rrd_graph( - "pve-node-9.0/$param->{node}", $param->{timeframe}, $param->{ds}, $param->{cf}, + "pve-node-9.0/$node", $param->{timeframe}, $param->{ds}, $param->{cf}, ); }, @@ -873,9 +873,9 @@ __PACKAGE__->register_method({ }, code => sub { my ($param) = @_; - + my $node = PVE::INotify::resolve_nodename($param->{node}); return PVE::RRD::create_rrd_data( - "pve-node-9.0/$param->{node}", $param->{timeframe}, $param->{cf}, + "pve-node-9.0/$node", $param->{timeframe}, $param->{cf}, ); }, }); @@ -2718,10 +2718,9 @@ __PACKAGE__->register_method({ } } - my $nodename = $param->{node}; - $nodename = PVE::INotify::nodename() if $nodename eq 'localhost'; + my $nodename = PVE::INotify::resolve_nodename($param->{node}); - my $target = $param->{target}; + my $target = PVE::INotify::resolve_nodename($param->{target}); my $with_local_disks = $param->{'with-local-disks'}; raise_param_exc({ target => "target is local node." }) if $target eq $nodename; -- 2.47.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH manager 2/3] fix #7803: api: nodes: resolve 'localhost' alias in node-specific endpoints 2026-07-14 14:50 ` [PATCH manager 2/3] fix #7803: api: nodes: resolve 'localhost' alias in node-specific endpoints Elias Huhsovitz @ 2026-07-14 14:57 ` Shannon Sterz 0 siblings, 0 replies; 5+ messages in thread From: Shannon Sterz @ 2026-07-14 14:57 UTC (permalink / raw) To: Elias Huhsovitz, pve-devel On Tue Jul 14, 2026 at 4:50 PM CEST, Elias Huhsovitz wrote: > When 'localhost' is used as the node parameter, the API proxy correctly > routes the request to the local node. However, several endpoint handlers > used the literal string 'localhost' to construct file paths or validate > cluster nodes, resulting in empty data or validation errors. > > Use the new PVE::INotify::resolve_nodename() helper to correctly resolve > the alias before accessing the cluster filesystem or checking node > existence. This fixes the following endpoints: > - NodeConfig (get_config, set_options) > - Certificates (info, upload_custom_cert, remove_custom_cert) > - Nodes (rrd, rrddata, migrateall) > > Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> > --- > PVE/API2/Certificates.pm | 8 +++++--- > PVE/API2/NodeConfig.pm | 6 ++++-- > PVE/API2/Nodes.pm | 13 ++++++------- > 3 files changed, 15 insertions(+), 12 deletions(-) > > diff --git a/PVE/API2/Certificates.pm b/PVE/API2/Certificates.pm > index de8762c5..d567939c 100644 > --- a/PVE/API2/Certificates.pm > +++ b/PVE/API2/Certificates.pm > @@ -7,6 +7,7 @@ use PVE::API2::ACME; > use PVE::Certificate; > use PVE::CertHelpers; > use PVE::Exception qw(raise_param_exc); > +use PVE::INotify; > use PVE::JSONSchema qw(get_standard_option); > use PVE::Tools qw(extract_param file_get_contents file_set_contents); > > @@ -66,7 +67,8 @@ __PACKAGE__->register_method({ > code => sub { > my ($param) = @_; > > - my $node_path = "/etc/pve/nodes/$param->{node}"; > + my $node = PVE::INotify::resolve_nodename($param->{node}); > + my $node_path = "/etc/pve/nodes/$node"; this hunk overlaps with my commit in the tls rotation series [1]. since your series tackles this problem in a more complete fashion, the commit in my series can simply be dropped if your patches make it in first. just thought i'd mention it here :) [1]: https://lore.proxmox.com/pdm-devel/20260611120327.257523-4-s.sterz@proxmox.com/ > > my $res = []; > my $cert_paths = [ > @@ -125,7 +127,7 @@ __PACKAGE__->register_method({ > code => sub { > my ($param) = @_; > > - my $node = extract_param($param, 'node'); > + my $node = PVE::INotify::resolve_nodename(extract_param($param, 'node')); > my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node); > > my $certs = extract_param($param, 'certificates'); > @@ -188,7 +190,7 @@ __PACKAGE__->register_method({ > code => sub { > my ($param) = @_; > > - my $node = extract_param($param, 'node'); > + my $node = PVE::INotify::resolve_nodename(extract_param($param, 'node')); > my $cert_prefix = PVE::CertHelpers::cert_path_prefix($node); > > my $code = sub { > diff --git a/PVE/API2/NodeConfig.pm b/PVE/API2/NodeConfig.pm > index cc726dac..cad81c3e 100644 > --- a/PVE/API2/NodeConfig.pm > +++ b/PVE/API2/NodeConfig.pm > @@ -3,6 +3,7 @@ package PVE::API2::NodeConfig; > use strict; > use warnings; > > +use PVE::INotify; > use PVE::JSONSchema qw(get_standard_option); > use PVE::NodeConfig; > use PVE::Tools qw(extract_param); > @@ -61,7 +62,8 @@ __PACKAGE__->register_method({ > code => sub { > my ($param) = @_; > > - my $config = PVE::NodeConfig::load_config($param->{node}); > + my $node = PVE::INotify::resolve_nodename($param->{node}); > + my $config = PVE::NodeConfig::load_config($node); > > if (defined(my $prop = $param->{property})) { > return {} if !exists $config->{$prop}; > @@ -91,7 +93,7 @@ __PACKAGE__->register_method({ > my ($param) = @_; > > my $delete = extract_param($param, 'delete'); > - my $node = extract_param($param, 'node'); > + my $node = PVE::INotify::resolve_nodename(extract_param($param, 'node')); > my $digest = extract_param($param, 'digest'); > > my $code = sub { > diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm > index dfe3b4cf..90ce3c10 100644 > --- a/PVE/API2/Nodes.pm > +++ b/PVE/API2/Nodes.pm > @@ -830,9 +830,9 @@ __PACKAGE__->register_method({ > }, > code => sub { > my ($param) = @_; > - > + my $node = PVE::INotify::resolve_nodename($param->{node}); > return PVE::RRD::create_rrd_graph( > - "pve-node-9.0/$param->{node}", $param->{timeframe}, $param->{ds}, $param->{cf}, > + "pve-node-9.0/$node", $param->{timeframe}, $param->{ds}, $param->{cf}, > ); > > }, > @@ -873,9 +873,9 @@ __PACKAGE__->register_method({ > }, > code => sub { > my ($param) = @_; > - > + my $node = PVE::INotify::resolve_nodename($param->{node}); > return PVE::RRD::create_rrd_data( > - "pve-node-9.0/$param->{node}", $param->{timeframe}, $param->{cf}, > + "pve-node-9.0/$node", $param->{timeframe}, $param->{cf}, > ); > }, > }); > @@ -2718,10 +2718,9 @@ __PACKAGE__->register_method({ > } > } > > - my $nodename = $param->{node}; > - $nodename = PVE::INotify::nodename() if $nodename eq 'localhost'; > + my $nodename = PVE::INotify::resolve_nodename($param->{node}); > > - my $target = $param->{target}; > + my $target = PVE::INotify::resolve_nodename($param->{target}); > my $with_local_disks = $param->{'with-local-disks'}; > raise_param_exc({ target => "target is local node." }) if $target eq $nodename; > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH manager 3/3] api: nodes: use resolve_nodename helper for bulk operation 2026-07-14 14:50 [PATCH common/manager 0/3] fix #7803: 'localhost' alias handling in node-specific endpoints Elias Huhsovitz 2026-07-14 14:50 ` [PATCH common 1/3] inotify: add helper to resolve 'localhost' node alias Elias Huhsovitz 2026-07-14 14:50 ` [PATCH manager 2/3] fix #7803: api: nodes: resolve 'localhost' alias in node-specific endpoints Elias Huhsovitz @ 2026-07-14 14:50 ` Elias Huhsovitz 2 siblings, 0 replies; 5+ messages in thread From: Elias Huhsovitz @ 2026-07-14 14:50 UTC (permalink / raw) To: pve-devel; +Cc: Elias Huhsovitz The startall, stopall, and suspendall endpoints already contained inline logic to resolve the 'localhost' alias to the actual node name. Refactor these endpoints to use the new PVE::INotify::resolve_nodename() helper, improving consistency. Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> --- PVE/API2/Ceph/MDS.pm | 3 +-- PVE/API2/Nodes.pm | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/PVE/API2/Ceph/MDS.pm b/PVE/API2/Ceph/MDS.pm index 31b6fb7e..f9986d03 100644 --- a/PVE/API2/Ceph/MDS.pm +++ b/PVE/API2/Ceph/MDS.pm @@ -167,8 +167,7 @@ __PACKAGE__->register_method({ my $rpcenv = PVE::RPCEnvironment::get(); my $authuser = $rpcenv->get_user(); - my $nodename = $param->{node}; - $nodename = INotify::nodename() if $nodename eq 'localhost'; + my $nodename = PVE::INotify::resolve_nodename($param->{node}); my $mds_id = $param->{name} // $nodename; diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm index 90ce3c10..143da68a 100644 --- a/PVE/API2/Nodes.pm +++ b/PVE/API2/Nodes.pm @@ -2182,8 +2182,7 @@ __PACKAGE__->register_method({ } } - my $nodename = $param->{node}; - $nodename = PVE::INotify::nodename() if $nodename eq 'localhost'; + my $nodename = PVE::INotify::resolve_nodename($param->{node}); my $force = $param->{force}; @@ -2380,8 +2379,7 @@ __PACKAGE__->register_method({ } } - my $nodename = $param->{node}; - $nodename = PVE::INotify::nodename() if $nodename eq 'localhost'; + my $nodename = PVE::INotify::resolve_nodename($param->{node}); my $code = sub { @@ -2518,8 +2516,7 @@ __PACKAGE__->register_method({ } } - my $nodename = $param->{node}; - $nodename = PVE::INotify::nodename() if $nodename eq 'localhost'; + my $nodename = PVE::INotify::resolve_nodename($param->{node}); my $code = sub { -- 2.47.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-14 14:58 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-14 14:50 [PATCH common/manager 0/3] fix #7803: 'localhost' alias handling in node-specific endpoints Elias Huhsovitz 2026-07-14 14:50 ` [PATCH common 1/3] inotify: add helper to resolve 'localhost' node alias Elias Huhsovitz 2026-07-14 14:50 ` [PATCH manager 2/3] fix #7803: api: nodes: resolve 'localhost' alias in node-specific endpoints Elias Huhsovitz 2026-07-14 14:57 ` Shannon Sterz 2026-07-14 14:50 ` [PATCH manager 3/3] api: nodes: use resolve_nodename helper for bulk operation Elias Huhsovitz
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.