* [pve-devel] [PATCH-SERIES v2 pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback @ 2023-06-01 6:50 Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 1/2] api2: add /guests path Alexandre Derumier ` (2 more replies) 0 siblings, 3 replies; 5+ messages in thread From: Alexandre Derumier @ 2023-06-01 6:50 UTC (permalink / raw) To: pve-devel Hi, Currently, to manage qemu && lxc vms, we always need to specify nodename in uri. This is a problem with automation tools like terraform, where is node is registered in the state of terraform. (That mean, than if we move the vm on another node, terraform don't known it, and try to create the vm again or can't delete the vm,...) https://github.com/Telmate/terraform-provider-proxmox/issues/168 This can also be a potential problem with race, if we need to query /cluster/ressources to find the node, then another query on the vm. I have some discussion with fabian about it: https://bugzilla.proxmox.com/show_bug.cgi?id=4689 This patch series, find the nodename with proxyto_callback. a new api endpoint /guests/ is defined: /guests/(qemu|lxc)/vmid This patch series currently implement callback for api2::qemu todo (if this patch serie is ok for you): api2::qemu::agent (/guest/qemu/vmid/agent) api2::lxc (/guest/lxc/vmid) api2::lxc::config (/guest/lxc/vmid/config) api2::lxc::status (/guest/lxc/vmid/status) api2::lxc::snapshot (/guest/lxc/vmid/snapshot) api2::firewall:vm (/guest/(qemu|lxc)/vmid/firewall ) changelog v2: - fix pvesh param sending to proxyto_callback pve-manager: Alexandre Derumier (2): api2: add /guests path pvesh: send params to check_proxyto like httpserver PVE/API2.pm | 6 +++++ PVE/API2/Guests.pm | 55 ++++++++++++++++++++++++++++++++++++++++++++++ PVE/API2/Makefile | 1 + PVE/CLI/pvesh.pm | 13 ++++++----- 4 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 PVE/API2/Guests.pm qemu-server: Alexandre Derumier (1): api2: qemu: add proxyto_callback to find node if not defined PVE/API2/Qemu.pm | 157 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 48 deletions(-) -- 2.30.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH pve-manager 1/2] api2: add /guests path 2023-06-01 6:50 [pve-devel] [PATCH-SERIES v2 pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback Alexandre Derumier @ 2023-06-01 6:50 ` Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 2/2] pvesh: send params to check_proxyto like httpserver Alexandre Derumier 2 siblings, 0 replies; 5+ messages in thread From: Alexandre Derumier @ 2023-06-01 6:50 UTC (permalink / raw) To: pve-devel Signed-off-by: Alexandre Derumier <aderumier@odiso.com> --- PVE/API2.pm | 6 +++++ PVE/API2/Guests.pm | 55 ++++++++++++++++++++++++++++++++++++++++++++++ PVE/API2/Makefile | 1 + 3 files changed, 62 insertions(+) create mode 100644 PVE/API2/Guests.pm diff --git a/PVE/API2.pm b/PVE/API2.pm index 42941fd2..092c6df7 100644 --- a/PVE/API2.pm +++ b/PVE/API2.pm @@ -17,6 +17,7 @@ use PVE::API2::Nodes; use PVE::API2::Pool; use PVE::API2::AccessControl; use PVE::API2::Storage::Config; +use PVE::API2::Guests; __PACKAGE__->register_method ({ subclass => "PVE::API2::Cluster", @@ -38,6 +39,11 @@ __PACKAGE__->register_method ({ path => 'access', }); +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Guests", + path => 'guests', +}); + __PACKAGE__->register_method ({ subclass => "PVE::API2::Pool", path => 'pools', diff --git a/PVE/API2/Guests.pm b/PVE/API2/Guests.pm new file mode 100644 index 00000000..9be96393 --- /dev/null +++ b/PVE/API2/Guests.pm @@ -0,0 +1,55 @@ +package PVE::API2::Guests; + +use strict; +use warnings; + +use PVE::RESTHandler; + +use base qw(PVE::RESTHandler); + +# preload classes +use PVE::API2::Qemu; +use PVE::API2::LXC; + + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Qemu", + path => 'qemu', +}); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::LXC", + path => 'lxc', +}); + +__PACKAGE__->register_method ({ + name => 'index', + path => '', + method => 'GET', + permissions => { user => 'all' }, + description => "Directory index.", + parameters => { + additionalProperties => 0, + properties => {}, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => { + subdir => { type => 'string' }, + }, + }, + links => [ { rel => 'child', href => "{subdir}" } ], + }, + code => sub { + my ($param) = @_; + + my $res = [ + { subdir => 'qemu' }, + { subdir => 'lxc' }, + ]; + + return $res; + }}); +1; diff --git a/PVE/API2/Makefile b/PVE/API2/Makefile index 97f1cc20..b1ece7d6 100644 --- a/PVE/API2/Makefile +++ b/PVE/API2/Makefile @@ -12,6 +12,7 @@ PERLSOURCE = \ Ceph.pm \ Certificates.pm \ Cluster.pm \ + Guests.pm \ HAConfig.pm \ Hardware.pm \ Network.pm \ -- 2.30.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined 2023-06-01 6:50 [pve-devel] [PATCH-SERIES v2 pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 1/2] api2: add /guests path Alexandre Derumier @ 2023-06-01 6:50 ` Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 2/2] pvesh: send params to check_proxyto like httpserver Alexandre Derumier 2 siblings, 0 replies; 5+ messages in thread From: Alexandre Derumier @ 2023-06-01 6:50 UTC (permalink / raw) To: pve-devel Signed-off-by: Alexandre Derumier <aderumier@odiso.com> --- PVE/API2/Qemu.pm | 157 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 48 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 587bb22..53df317 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -59,6 +59,19 @@ use base qw(PVE::RESTHandler); my $opt_force_description = "Force physical removal. Without this, we simple remove the disk from the config file and create an additional configuration entry called 'unused[n]', which contains the volume ID. Unlink of unused[n] always cause physical removal."; +my $find_vm_node = sub { + my ($rpcenv, $proxyto, $param) = @_; + return $param->{node} if $param->{node}; + # proxy to the node where the guest resides + my $vmid = $param->{vmid}; + return 'localhost' if !$vmid; + + my $vms = PVE::Cluster::get_vmlist(); + + return 'localhost' if !$vms->{ids}->{$vmid}; + return $vms->{ids}->{$vmid}->{node}; +}; + my $resolve_cdrom_alias = sub { my $param = shift; @@ -659,11 +672,12 @@ __PACKAGE__->register_method({ user => 'all', }, proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, # qemu pid files are only readable by root parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), full => { type => 'boolean', optional => 1, @@ -684,8 +698,20 @@ __PACKAGE__->register_method({ my $rpcenv = PVE::RPCEnvironment::get(); my $authuser = $rpcenv->get_user(); + my $vmstatus = undef; - my $vmstatus = PVE::QemuServer::vmstatus(undef, $param->{full}); + if (!$param->{node}) { + my $vmlist = PVE::Cluster::get_vmlist()->{ids}; + my $rrd = PVE::Cluster::rrd_dump(); + for my $vmid (sort keys %$vmlist) { + my $data = $vmlist->{$vmid}; + next if $data->{type} ne 'qemu'; + my $entry = PVE::API2Tools::extract_vm_stats($vmid, $data, $rrd); + $vmstatus->{$vmid} = $entry; + } + } else { + $vmstatus = PVE::QemuServer::vmstatus(undef, $param->{full}); + } my $res = []; foreach my $vmid (keys %$vmstatus) { @@ -733,11 +759,12 @@ __PACKAGE__->register_method({ }, protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, parameters => { additionalProperties => 0, properties => PVE::QemuServer::json_config_properties( { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::Cluster::complete_next_vmid }), archive => { description => "The backup archive. Either the file system path to a .tar or .vma file (use '-' to pipe data from stdin) or a proxmox storage backup volume identifier.", @@ -878,7 +905,6 @@ __PACKAGE__->register_method({ &$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param); &$check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param); - &$check_cpu_model_access($rpcenv, $authuser, $param); $check_drive_param->($param, $storecfg); @@ -1053,6 +1079,7 @@ __PACKAGE__->register_method({ path => '{vmid}', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Directory index", permissions => { user => 'all', @@ -1060,7 +1087,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -1125,7 +1152,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), timeframe => { description => "Specify the time frame you are interested in.", @@ -1171,7 +1198,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), timeframe => { description => "Specify the time frame you are interested in.", @@ -1200,12 +1227,12 @@ __PACKAGE__->register_method({ "pve2-vm/$param->{vmid}", $param->{timeframe}, $param->{cf}); }}); - __PACKAGE__->register_method({ name => 'vm_config', path => '{vmid}/config', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get the virtual machine configuration with pending configuration " . "changes applied. Set the 'current' parameter to get the current configuration instead.", permissions => { @@ -1214,7 +1241,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), current => { description => "Get current values (instead of pending values).", @@ -1265,6 +1292,7 @@ __PACKAGE__->register_method({ path => '{vmid}/pending', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get the virtual machine configuration with both current and pending values.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], @@ -1272,7 +1300,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), }, }, @@ -1324,6 +1352,7 @@ __PACKAGE__->register_method({ path => '{vmid}/cloudinit', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get the cloudinit configuration with both current and pending values.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], @@ -1331,7 +1360,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), }, }, @@ -1396,6 +1425,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Regenerate and change cloudinit config drive.", permissions => { check => ['perm', '/vms/{vmid}', 'VM.Config.Cloudinit'], @@ -1403,7 +1433,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -1873,6 +1903,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Set virtual machine options (asynchrounous API).", permissions => { check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1], @@ -1881,7 +1912,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => PVE::QemuServer::json_config_properties( { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), skiplock => get_standard_option('skiplock'), delete => { @@ -1930,6 +1961,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Set virtual machine options (synchrounous API) - You should consider using the POST method instead for any actions involving hotplug or storage allocation.", permissions => { check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1], @@ -1938,7 +1970,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => PVE::QemuServer::json_config_properties( { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), skiplock => get_standard_option('skiplock'), delete => { @@ -1981,6 +2013,7 @@ __PACKAGE__->register_method({ method => 'DELETE', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Destroy the VM and all used/owned volumes. Removes any VM specific permissions" ." and firewall rules", permissions => { @@ -1989,7 +2022,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_stopped }), skiplock => get_standard_option('skiplock'), purge => { @@ -2089,6 +2122,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Unlink/delete disk images.", permissions => { check => [ 'perm', '/vms/{vmid}', ['VM.Config.Disk']], @@ -2096,7 +2130,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), idlist => { type => 'string', format => 'pve-configid-list', @@ -2151,7 +2185,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), websocket => { optional => 1, @@ -2313,7 +2347,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), serial=> { optional => 1, @@ -2409,7 +2443,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), vncticket => { description => "Ticket from previous call to vncproxy.", @@ -2461,6 +2495,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]], }, @@ -2468,7 +2503,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), proxy => get_standard_option('spice-proxy', { optional => 1 }), }, @@ -2505,6 +2540,7 @@ __PACKAGE__->register_method({ path => '{vmid}/status', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Directory index", permissions => { user => 'all', @@ -2512,7 +2548,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -2550,6 +2586,7 @@ __PACKAGE__->register_method({ path => '{vmid}/status/current', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, # qemu pid files are only readable by root description => "Get virtual machine status.", permissions => { @@ -2558,7 +2595,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -2610,6 +2647,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Start virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -2617,7 +2655,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_stopped }), skiplock => get_standard_option('skiplock'), @@ -2775,6 +2813,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Stop virtual machine. The qemu process will exit immediately. This" . "is akin to pulling the power plug of a running computer and may damage the VM data", permissions => { @@ -2783,7 +2822,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -2864,6 +2903,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Reset virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -2871,7 +2911,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -2914,6 +2954,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Shutdown virtual machine. This is similar to pressing the power button on a physical machine." . "This will send an ACPI event for the guest OS, which should then proceed to a clean shutdown.", permissions => { @@ -2922,7 +2963,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3022,6 +3063,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Reboot the VM by shutting it down, and starting it again. Applies pending changes.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -3029,7 +3071,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), timeout => { @@ -3073,6 +3115,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Suspend virtual machine.", permissions => { description => "You need 'VM.PowerMgmt' on /vms/{vmid}, and if you have set 'todisk',". @@ -3083,7 +3126,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3167,6 +3210,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Resume virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -3174,7 +3218,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3241,6 +3285,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Send key event to virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]], @@ -3248,7 +3293,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3284,6 +3329,7 @@ __PACKAGE__->register_method({ path => '{vmid}/feature', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, description => "Check if feature for virtual machine is available.", permissions => { @@ -3292,7 +3338,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), feature => { description => "Feature to check.", @@ -3351,6 +3397,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Create a copy of virtual machine/template.", permissions => { description => "You need 'VM.Clone' permissions on /vms/{vmid}, and 'VM.Allocate' permissions " . @@ -3368,7 +3415,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), newid => get_standard_option('pve-vmid', { completion => \&PVE::Cluster::complete_next_vmid, @@ -3708,6 +3755,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Move volume to different storage or to a different VM.", permissions => { description => "You need 'VM.Config.Disk' permissions on /vms/{vmid}, " . @@ -3718,7 +3766,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), 'target-vmid' => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid, @@ -4170,6 +4218,7 @@ __PACKAGE__->register_method({ method => 'GET', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get preconditions for migration.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]], @@ -4177,7 +4226,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), target => get_standard_option('pve-node', { description => "Target node.", @@ -4271,6 +4320,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Migrate virtual machine. Creates a new migration task.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]], @@ -4278,7 +4328,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), target => get_standard_option('pve-node', { description => "Target node.", @@ -4436,6 +4486,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Migrate virtual machine to a remote cluster. Creates a new migration task. EXPERIMENTAL feature!", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]], @@ -4443,7 +4494,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), 'target-vmid' => get_standard_option('pve-vmid', { optional => 1 }), 'target-endpoint' => get_standard_option('proxmox-remote', { @@ -4601,6 +4652,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Execute QEMU monitor commands.", permissions => { description => "Sys.Modify is required for (sub)commands which are not read-only ('info *' and 'help')", @@ -4609,7 +4661,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), command => { type => 'string', @@ -4652,6 +4704,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Extend volume size.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Config.Disk' ]], @@ -4659,7 +4712,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), skiplock => get_standard_option('skiplock'), disk => { @@ -4780,12 +4833,13 @@ __PACKAGE__->register_method({ check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], }, proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, # qemu pid files are only readable by root parameters => { additionalProperties => 0, properties => { vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), }, }, returns => { @@ -4864,6 +4918,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Snapshot a VM.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]], @@ -4871,7 +4926,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), snapname => get_standard_option('pve-snapshot-name'), vmstate => { @@ -4930,7 +4985,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { vmid => get_standard_option('pve-vmid'), - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), snapname => get_standard_option('pve-snapshot-name'), }, }, @@ -4959,6 +5014,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Update snapshot metadata.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]], @@ -4966,7 +5022,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), snapname => get_standard_option('pve-snapshot-name'), description => { @@ -5015,6 +5071,7 @@ __PACKAGE__->register_method({ path => '{vmid}/snapshot/{snapname}/config', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get snapshot configuration", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback', 'VM.Audit' ], any => 1], @@ -5022,7 +5079,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), snapname => get_standard_option('pve-snapshot-name'), }, @@ -5054,6 +5111,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Rollback VM state to specified snapshot.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback' ], any => 1], @@ -5061,7 +5119,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), snapname => get_standard_option('pve-snapshot-name'), start => { @@ -5113,6 +5171,7 @@ __PACKAGE__->register_method({ method => 'DELETE', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Delete a VM snapshot.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]], @@ -5120,7 +5179,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), snapname => get_standard_option('pve-snapshot-name'), force => { @@ -5175,6 +5234,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Create a Template.", permissions => { description => "You need 'VM.Allocate' permissions on /vms/{vmid}", @@ -5183,7 +5243,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_stopped }), disk => { optional => 1, @@ -5249,6 +5309,7 @@ __PACKAGE__->register_method({ path => '{vmid}/cloudinit/dump', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get automatically generated cloudinit config.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], @@ -5256,7 +5317,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), type => { description => 'Config type.', @@ -5294,7 +5355,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), storages => { type => 'string', -- 2.30.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH pve-manager 2/2] pvesh: send params to check_proxyto like httpserver 2023-06-01 6:50 [pve-devel] [PATCH-SERIES v2 pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 1/2] api2: add /guests path Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined Alexandre Derumier @ 2023-06-01 6:50 ` Alexandre Derumier 2 siblings, 0 replies; 5+ messages in thread From: Alexandre Derumier @ 2023-06-01 6:50 UTC (permalink / raw) To: pve-devel Currently only url_params are send to check_proxyto, the behaviour is different than httpserver. for example, so we can't retreive "pvesh create ... --node" param in proxyto_callback Signed-off-by: Alexandre Derumier <aderumier@odiso.com> --- PVE/CLI/pvesh.pm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/PVE/CLI/pvesh.pm b/PVE/CLI/pvesh.pm index 9acf292a..f83e05aa 100755 --- a/PVE/CLI/pvesh.pm +++ b/PVE/CLI/pvesh.pm @@ -300,16 +300,19 @@ sub call_api_method { die "no '$cmd' handler for '$path'\n"; } + for my $p (sort keys %{$param}) { + if (defined($uri_param->{$p}) && $uri_param->{$p} ne $param->{$p}) { + die "duplicate parameter $p (already defined in URI) with conflicting values!\n"; + } + $uri_param->{$p} = $param->{$p}; + } + my $data; my ($node, $remip) = check_proxyto($info, $uri_param); if ($node) { $data = proxy_handler($node, $remip, $path, $cmd, $param); } else { - foreach my $p (keys %$uri_param) { - $param->{$p} = $uri_param->{$p}; - } - - $data = $handler->handle($info, $param); + $data = $handler->handle($info, $uri_param); } return if $opt_nooutput || $stdopts->{quiet}; -- 2.30.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH-SERIES pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback @ 2023-05-31 22:28 Alexandre Derumier 2023-05-31 22:28 ` [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined Alexandre Derumier 0 siblings, 1 reply; 5+ messages in thread From: Alexandre Derumier @ 2023-05-31 22:28 UTC (permalink / raw) To: pve-devel Hi, Currently, to manage qemu && lxc vms, we always need to specify nodename in uri. This is a problem with automation tools like terraform, where is node is registered in the state of terraform. (That mean, than if we move the vm on another node, terraform don't known it, and try to create the vm again or can't delete the vm,...) https://github.com/Telmate/terraform-provider-proxmox/issues/168 This can also be a potential problem with race, if we need to query /cluster/ressources to find the node, then another query on the vm. I have some discussion with fabian about it: https://bugzilla.proxmox.com/show_bug.cgi?id=4689 This patch series, find the nodename with proxyto_callback. a new api endpoint /guests/ is defined: /guests/(qemu|lxc)/vmid This patch series currently implement callback for api2::qemu I'm not sure how to create vm_create when vmid && nodename is not defined. Currently the callback return localhost, so the vm is created on the called node. todo (if this patch serie is ok for you): api2::qemu::agent (/guest/qemu/vmid/agent) api2::lxc (/guest/lxc/vmid) api2::lxc::config (/guest/lxc/vmid/config) api2::lxc::status (/guest/lxc/vmid/status) api2::lxc::snapshot (/guest/lxc/vmid/snapshot) api2::firewall:vm (/guest/(qemu|lxc)/vmid/firewall ) Alexandre Derumier (1): api2: add /guests path PVE/API2.pm | 6 +++++ PVE/API2/Guests.pm | 55 ++++++++++++++++++++++++++++++++++++++++++++++ PVE/API2/Makefile | 1 + 3 files changed, 62 insertions(+) create mode 100644 PVE/API2/Guests.pm Alexandre Derumier (1): api2: qemu: add proxyto_callback to find node if not defined PVE/API2/Qemu.pm | 157 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 48 deletions(-) -- 2.30.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined 2023-05-31 22:28 [pve-devel] [PATCH-SERIES pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback Alexandre Derumier @ 2023-05-31 22:28 ` Alexandre Derumier 0 siblings, 0 replies; 5+ messages in thread From: Alexandre Derumier @ 2023-05-31 22:28 UTC (permalink / raw) To: pve-devel Signed-off-by: Alexandre Derumier <aderumier@odiso.com> --- PVE/API2/Qemu.pm | 157 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 48 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 587bb22..52daf5a 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -59,6 +59,19 @@ use base qw(PVE::RESTHandler); my $opt_force_description = "Force physical removal. Without this, we simple remove the disk from the config file and create an additional configuration entry called 'unused[n]', which contains the volume ID. Unlink of unused[n] always cause physical removal."; +my $find_vm_node = sub { + my ($rpcenv, $proxyto, $param) = @_; + return $param->{node} if $param->{node}; + # proxy to the node where the guest resides + my $vmid = $param->{vmid}; + return 'localhost' if !$vmid; + + my $vms = PVE::Cluster::get_vmlist(); + + return 'localhost' if !$vms->{ids}->{$vmid}; + return $vms->{ids}->{$vmid}->{node}; +}; + my $resolve_cdrom_alias = sub { my $param = shift; @@ -659,11 +672,12 @@ __PACKAGE__->register_method({ user => 'all', }, proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, # qemu pid files are only readable by root parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), full => { type => 'boolean', optional => 1, @@ -684,8 +698,20 @@ __PACKAGE__->register_method({ my $rpcenv = PVE::RPCEnvironment::get(); my $authuser = $rpcenv->get_user(); + my $vmstatus = undef; - my $vmstatus = PVE::QemuServer::vmstatus(undef, $param->{full}); + if (!$param->{node}) { + my $vmlist = PVE::Cluster::get_vmlist()->{ids}; + my $rrd = PVE::Cluster::rrd_dump(); + for my $vmid (sort keys %$vmlist) { + my $data = $vmlist->{$vmid}; + next if $data->{type} ne 'qemu'; + my $entry = PVE::API2Tools::extract_vm_stats($vmid, $data, $rrd); + $vmstatus->{$vmid} = $entry; + } + } else { + $vmstatus = PVE::QemuServer::vmstatus(undef, $param->{full}); + } my $res = []; foreach my $vmid (keys %$vmstatus) { @@ -733,11 +759,12 @@ __PACKAGE__->register_method({ }, protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, parameters => { additionalProperties => 0, properties => PVE::QemuServer::json_config_properties( { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::Cluster::complete_next_vmid }), archive => { description => "The backup archive. Either the file system path to a .tar or .vma file (use '-' to pipe data from stdin) or a proxmox storage backup volume identifier.", @@ -878,7 +905,6 @@ __PACKAGE__->register_method({ &$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param); &$check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param); - &$check_cpu_model_access($rpcenv, $authuser, $param); $check_drive_param->($param, $storecfg); @@ -1053,6 +1079,7 @@ __PACKAGE__->register_method({ path => '{vmid}', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Directory index", permissions => { user => 'all', @@ -1060,7 +1087,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -1125,7 +1152,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), timeframe => { description => "Specify the time frame you are interested in.", @@ -1171,7 +1198,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), timeframe => { description => "Specify the time frame you are interested in.", @@ -1200,12 +1227,12 @@ __PACKAGE__->register_method({ "pve2-vm/$param->{vmid}", $param->{timeframe}, $param->{cf}); }}); - __PACKAGE__->register_method({ name => 'vm_config', path => '{vmid}/config', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get the virtual machine configuration with pending configuration " . "changes applied. Set the 'current' parameter to get the current configuration instead.", permissions => { @@ -1214,7 +1241,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), current => { description => "Get current values (instead of pending values).", @@ -1265,6 +1292,7 @@ __PACKAGE__->register_method({ path => '{vmid}/pending', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get the virtual machine configuration with both current and pending values.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], @@ -1272,7 +1300,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), }, }, @@ -1324,6 +1352,7 @@ __PACKAGE__->register_method({ path => '{vmid}/cloudinit', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get the cloudinit configuration with both current and pending values.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], @@ -1331,7 +1360,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), }, }, @@ -1396,6 +1425,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Regenerate and change cloudinit config drive.", permissions => { check => ['perm', '/vms/{vmid}', 'VM.Config.Cloudinit'], @@ -1403,7 +1433,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -1873,6 +1903,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Set virtual machine options (asynchrounous API).", permissions => { check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1], @@ -1881,7 +1912,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => PVE::QemuServer::json_config_properties( { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), skiplock => get_standard_option('skiplock'), delete => { @@ -1930,6 +1961,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Set virtual machine options (synchrounous API) - You should consider using the POST method instead for any actions involving hotplug or storage allocation.", permissions => { check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1], @@ -1938,7 +1970,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => PVE::QemuServer::json_config_properties( { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), skiplock => get_standard_option('skiplock'), delete => { @@ -1981,6 +2013,7 @@ __PACKAGE__->register_method({ method => 'DELETE', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Destroy the VM and all used/owned volumes. Removes any VM specific permissions" ." and firewall rules", permissions => { @@ -1989,7 +2022,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_stopped }), skiplock => get_standard_option('skiplock'), purge => { @@ -2089,6 +2122,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Unlink/delete disk images.", permissions => { check => [ 'perm', '/vms/{vmid}', ['VM.Config.Disk']], @@ -2096,7 +2130,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), idlist => { type => 'string', format => 'pve-configid-list', @@ -2151,7 +2185,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), websocket => { optional => 1, @@ -2313,7 +2347,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), serial=> { optional => 1, @@ -2409,7 +2443,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), vncticket => { description => "Ticket from previous call to vncproxy.", @@ -2461,6 +2495,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]], }, @@ -2468,7 +2503,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), proxy => get_standard_option('spice-proxy', { optional => 1 }), }, @@ -2505,6 +2540,7 @@ __PACKAGE__->register_method({ path => '{vmid}/status', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Directory index", permissions => { user => 'all', @@ -2512,7 +2548,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -2550,6 +2586,7 @@ __PACKAGE__->register_method({ path => '{vmid}/status/current', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, # qemu pid files are only readable by root description => "Get virtual machine status.", permissions => { @@ -2558,7 +2595,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), }, }, @@ -2610,6 +2647,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Start virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -2617,7 +2655,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_stopped }), skiplock => get_standard_option('skiplock'), @@ -2775,6 +2813,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Stop virtual machine. The qemu process will exit immediately. This" . "is akin to pulling the power plug of a running computer and may damage the VM data", permissions => { @@ -2783,7 +2822,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -2864,6 +2903,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Reset virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -2871,7 +2911,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -2914,6 +2954,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Shutdown virtual machine. This is similar to pressing the power button on a physical machine." . "This will send an ACPI event for the guest OS, which should then proceed to a clean shutdown.", permissions => { @@ -2922,7 +2963,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3022,6 +3063,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Reboot the VM by shutting it down, and starting it again. Applies pending changes.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -3029,7 +3071,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), timeout => { @@ -3073,6 +3115,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Suspend virtual machine.", permissions => { description => "You need 'VM.PowerMgmt' on /vms/{vmid}, and if you have set 'todisk',". @@ -3083,7 +3126,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3167,6 +3210,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Resume virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]], @@ -3174,7 +3218,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3241,6 +3285,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Send key event to virtual machine.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]], @@ -3248,7 +3293,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }), skiplock => get_standard_option('skiplock'), @@ -3284,6 +3329,7 @@ __PACKAGE__->register_method({ path => '{vmid}/feature', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, description => "Check if feature for virtual machine is available.", permissions => { @@ -3292,7 +3338,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), feature => { description => "Feature to check.", @@ -3351,6 +3397,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Create a copy of virtual machine/template.", permissions => { description => "You need 'VM.Clone' permissions on /vms/{vmid}, and 'VM.Allocate' permissions " . @@ -3368,7 +3415,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), newid => get_standard_option('pve-vmid', { completion => \&PVE::Cluster::complete_next_vmid, @@ -3708,6 +3755,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Move volume to different storage or to a different VM.", permissions => { description => "You need 'VM.Config.Disk' permissions on /vms/{vmid}, " . @@ -3718,7 +3766,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), 'target-vmid' => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid, @@ -4170,6 +4218,7 @@ __PACKAGE__->register_method({ method => 'GET', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get preconditions for migration.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]], @@ -4177,7 +4226,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), target => get_standard_option('pve-node', { description => "Target node.", @@ -4271,6 +4320,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Migrate virtual machine. Creates a new migration task.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]], @@ -4278,7 +4328,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), target => get_standard_option('pve-node', { description => "Target node.", @@ -4436,6 +4486,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Migrate virtual machine to a remote cluster. Creates a new migration task. EXPERIMENTAL feature!", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]], @@ -4443,7 +4494,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), 'target-vmid' => get_standard_option('pve-vmid', { optional => 1 }), 'target-endpoint' => get_standard_option('proxmox-remote', { @@ -4601,6 +4652,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Execute QEMU monitor commands.", permissions => { description => "Sys.Modify is required for (sub)commands which are not read-only ('info *' and 'help')", @@ -4609,7 +4661,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), command => { type => 'string', @@ -4652,6 +4704,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Extend volume size.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Config.Disk' ]], @@ -4659,7 +4712,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), skiplock => get_standard_option('skiplock'), disk => { @@ -4780,12 +4833,13 @@ __PACKAGE__->register_method({ check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], }, proxyto => 'node', + proxyto_callback => \&$find_vm_node, protected => 1, # qemu pid files are only readable by root parameters => { additionalProperties => 0, properties => { vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), }, }, returns => { @@ -4864,6 +4918,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Snapshot a VM.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]], @@ -4871,7 +4926,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), snapname => get_standard_option('pve-snapshot-name'), vmstate => { @@ -4930,7 +4985,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { vmid => get_standard_option('pve-vmid'), - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), snapname => get_standard_option('pve-snapshot-name'), }, }, @@ -4959,6 +5014,7 @@ __PACKAGE__->register_method({ method => 'PUT', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Update snapshot metadata.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]], @@ -4966,7 +5022,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), snapname => get_standard_option('pve-snapshot-name'), description => { @@ -5015,6 +5071,7 @@ __PACKAGE__->register_method({ path => '{vmid}/snapshot/{snapname}/config', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get snapshot configuration", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback', 'VM.Audit' ], any => 1], @@ -5022,7 +5079,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), snapname => get_standard_option('pve-snapshot-name'), }, @@ -5054,6 +5111,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Rollback VM state to specified snapshot.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback' ], any => 1], @@ -5061,7 +5119,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), snapname => get_standard_option('pve-snapshot-name'), start => { @@ -5113,6 +5171,7 @@ __PACKAGE__->register_method({ method => 'DELETE', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Delete a VM snapshot.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot' ]], @@ -5120,7 +5179,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), snapname => get_standard_option('pve-snapshot-name'), force => { @@ -5175,6 +5234,7 @@ __PACKAGE__->register_method({ method => 'POST', protected => 1, proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Create a Template.", permissions => { description => "You need 'VM.Allocate' permissions on /vms/{vmid}", @@ -5183,7 +5243,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_stopped }), disk => { optional => 1, @@ -5249,6 +5309,7 @@ __PACKAGE__->register_method({ path => '{vmid}/cloudinit/dump', method => 'GET', proxyto => 'node', + proxyto_callback => \&$find_vm_node, description => "Get automatically generated cloudinit config.", permissions => { check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], @@ -5256,7 +5317,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }), type => { description => 'Config type.', @@ -5294,7 +5355,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - node => get_standard_option('pve-node'), + node => get_standard_option('pve-node', { optional => 1}), vmid => get_standard_option('pve-vmid'), storages => { type => 'string', -- 2.30.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-06-01 6:51 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2023-06-01 6:50 [pve-devel] [PATCH-SERIES v2 pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 1/2] api2: add /guests path Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined Alexandre Derumier 2023-06-01 6:50 ` [pve-devel] [PATCH pve-manager 2/2] pvesh: send params to check_proxyto like httpserver Alexandre Derumier -- strict thread matches above, loose matches on Subject: below -- 2023-05-31 22:28 [pve-devel] [PATCH-SERIES pve-manager/qemu-server] fix#4689 autofind node with proxyto_callback Alexandre Derumier 2023-05-31 22:28 ` [pve-devel] [PATCH qemu-server 1/1] api2: qemu: add proxyto_callback to find node if not defined Alexandre Derumier
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox