mirror of
https://git.proxmox.com/git/qemu-server
synced 2025-08-16 19:52:39 +00:00
update_vm_async: new asynchronous API
This commit is contained in:
parent
d8b916fdb0
commit
5555edea95
211
PVE/API2/Qemu.pm
211
PVE/API2/Qemu.pm
@ -839,55 +839,20 @@ my $vmconfig_update_net = sub {
|
|||||||
die "error hotplug $opt" if !PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, $opt, $net);
|
die "error hotplug $opt" if !PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, $opt, $net);
|
||||||
};
|
};
|
||||||
|
|
||||||
my $vm_config_perm_list = [
|
# POST/PUT {vmid}/config implementation
|
||||||
'VM.Config.Disk',
|
#
|
||||||
'VM.Config.CDROM',
|
# The original API used PUT (idempotent) an we assumed that all operations
|
||||||
'VM.Config.CPU',
|
# are fast. But it turned out that almost any configuration change can
|
||||||
'VM.Config.Memory',
|
# involve hot-plug actions, or disk alloc/free. Such actions can take long
|
||||||
'VM.Config.Network',
|
# time to complete and have side effects (not idempotent).
|
||||||
'VM.Config.HWType',
|
#
|
||||||
'VM.Config.Options',
|
# The new implementation uses POST and forks a worker process. We added
|
||||||
];
|
# a new option 'background_delay'. If specified we wait up to
|
||||||
|
# 'background_delay' second for the worker task to complete. It returns null
|
||||||
|
# if the task is finished within that time, else we return the UPID.
|
||||||
|
|
||||||
__PACKAGE__->register_method({
|
my $update_vm_api = sub {
|
||||||
name => 'update_vm',
|
my ($param, $sync) = @_;
|
||||||
path => '{vmid}/config',
|
|
||||||
method => 'PUT',
|
|
||||||
protected => 1,
|
|
||||||
proxyto => 'node',
|
|
||||||
description => "Set virtual machine options.",
|
|
||||||
permissions => {
|
|
||||||
check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1],
|
|
||||||
},
|
|
||||||
parameters => {
|
|
||||||
additionalProperties => 0,
|
|
||||||
properties => PVE::QemuServer::json_config_properties(
|
|
||||||
{
|
|
||||||
node => get_standard_option('pve-node'),
|
|
||||||
vmid => get_standard_option('pve-vmid'),
|
|
||||||
skiplock => get_standard_option('skiplock'),
|
|
||||||
delete => {
|
|
||||||
type => 'string', format => 'pve-configid-list',
|
|
||||||
description => "A list of settings you want to delete.",
|
|
||||||
optional => 1,
|
|
||||||
},
|
|
||||||
force => {
|
|
||||||
type => 'boolean',
|
|
||||||
description => $opt_force_description,
|
|
||||||
optional => 1,
|
|
||||||
requires => 'delete',
|
|
||||||
},
|
|
||||||
digest => {
|
|
||||||
type => 'string',
|
|
||||||
description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
|
|
||||||
maxLength => 40,
|
|
||||||
optional => 1,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
returns => { type => 'null'},
|
|
||||||
code => sub {
|
|
||||||
my ($param) = @_;
|
|
||||||
|
|
||||||
my $rpcenv = PVE::RPCEnvironment::get();
|
my $rpcenv = PVE::RPCEnvironment::get();
|
||||||
|
|
||||||
@ -899,6 +864,8 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
my $digest = extract_param($param, 'digest');
|
my $digest = extract_param($param, 'digest');
|
||||||
|
|
||||||
|
my $background_delay = extract_param($param, 'background_delay');
|
||||||
|
|
||||||
my @paramarr = (); # used for log message
|
my @paramarr = (); # used for log message
|
||||||
foreach my $key (keys %$param) {
|
foreach my $key (keys %$param) {
|
||||||
push @paramarr, "-$key", $param->{$key};
|
push @paramarr, "-$key", $param->{$key};
|
||||||
@ -974,6 +941,10 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
PVE::Cluster::log_msg('info', $authuser, "update VM $vmid: " . join (' ', @paramarr));
|
PVE::Cluster::log_msg('info', $authuser, "update VM $vmid: " . join (' ', @paramarr));
|
||||||
|
|
||||||
|
my $worker = sub {
|
||||||
|
|
||||||
|
print "update VM $vmid: " . join (' ', @paramarr) . "\n";
|
||||||
|
|
||||||
foreach my $opt (@delete) { # delete
|
foreach my $opt (@delete) { # delete
|
||||||
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
||||||
&$vmconfig_delete_option($rpcenv, $authuser, $conf, $storecfg, $vmid, $opt, $force);
|
&$vmconfig_delete_option($rpcenv, $authuser, $conf, $storecfg, $vmid, $opt, $force);
|
||||||
@ -1001,7 +972,7 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
if($opt eq 'tablet' && $param->{$opt} == 1){
|
if($opt eq 'tablet' && $param->{$opt} == 1){
|
||||||
PVE::QemuServer::vm_deviceplug(undef, $conf, $vmid, $opt);
|
PVE::QemuServer::vm_deviceplug(undef, $conf, $vmid, $opt);
|
||||||
}elsif($opt eq 'tablet' && $param->{$opt} == 0){
|
} elsif($opt eq 'tablet' && $param->{$opt} == 0){
|
||||||
PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
|
PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,13 +987,147 @@ __PACKAGE__->register_method({
|
|||||||
my $balloon = $param->{'balloon'} || $conf->{memory} || $defaults->{memory};
|
my $balloon = $param->{'balloon'} || $conf->{memory} || $defaults->{memory};
|
||||||
PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
|
PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PVE::QemuServer::lock_config($vmid, $updatefn);
|
if ($sync) {
|
||||||
|
&$worker();
|
||||||
return undef;
|
return undef;
|
||||||
}});
|
} else {
|
||||||
|
my $upid = $rpcenv->fork_worker('qmconfig', $vmid, $authuser, $worker);
|
||||||
|
|
||||||
|
if ($background_delay) {
|
||||||
|
|
||||||
|
# Note: It would be better to do that in the Event based HTTPServer
|
||||||
|
# to avoid blocking call to sleep.
|
||||||
|
|
||||||
|
my $end_time = time() + $background_delay;
|
||||||
|
|
||||||
|
my $task = PVE::Tools::upid_decode($upid);
|
||||||
|
|
||||||
|
my $running = 1;
|
||||||
|
while (time() < $end_time) {
|
||||||
|
$running = PVE::ProcFSTools::check_process_running($task->{pid}, $task->{pstart});
|
||||||
|
last if !$running;
|
||||||
|
sleep(1); # this gets interrupted when child process ends
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$running) {
|
||||||
|
my $status = PVE::Tools::upid_read_status($upid);
|
||||||
|
return undef if $status eq 'OK';
|
||||||
|
die $status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $upid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return PVE::QemuServer::lock_config($vmid, $updatefn);
|
||||||
|
};
|
||||||
|
|
||||||
|
my $vm_config_perm_list = [
|
||||||
|
'VM.Config.Disk',
|
||||||
|
'VM.Config.CDROM',
|
||||||
|
'VM.Config.CPU',
|
||||||
|
'VM.Config.Memory',
|
||||||
|
'VM.Config.Network',
|
||||||
|
'VM.Config.HWType',
|
||||||
|
'VM.Config.Options',
|
||||||
|
];
|
||||||
|
|
||||||
|
__PACKAGE__->register_method({
|
||||||
|
name => 'update_vm_async',
|
||||||
|
path => '{vmid}/config',
|
||||||
|
method => 'POST',
|
||||||
|
protected => 1,
|
||||||
|
proxyto => 'node',
|
||||||
|
description => "Set virtual machine options (asynchrounous API).",
|
||||||
|
permissions => {
|
||||||
|
check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1],
|
||||||
|
},
|
||||||
|
parameters => {
|
||||||
|
additionalProperties => 0,
|
||||||
|
properties => PVE::QemuServer::json_config_properties(
|
||||||
|
{
|
||||||
|
node => get_standard_option('pve-node'),
|
||||||
|
vmid => get_standard_option('pve-vmid'),
|
||||||
|
skiplock => get_standard_option('skiplock'),
|
||||||
|
delete => {
|
||||||
|
type => 'string', format => 'pve-configid-list',
|
||||||
|
description => "A list of settings you want to delete.",
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
force => {
|
||||||
|
type => 'boolean',
|
||||||
|
description => $opt_force_description,
|
||||||
|
optional => 1,
|
||||||
|
requires => 'delete',
|
||||||
|
},
|
||||||
|
digest => {
|
||||||
|
type => 'string',
|
||||||
|
description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
|
||||||
|
maxLength => 40,
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
background_delay => {
|
||||||
|
type => 'integer',
|
||||||
|
description => "Time to wait for the task to finish. We return 'null' if the task finish within that time.",
|
||||||
|
minimum => 1,
|
||||||
|
maximum => 30,
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
returns => {
|
||||||
|
type => 'string',
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
code => $update_vm_api,
|
||||||
|
});
|
||||||
|
|
||||||
|
__PACKAGE__->register_method({
|
||||||
|
name => 'update_vm',
|
||||||
|
path => '{vmid}/config',
|
||||||
|
method => 'PUT',
|
||||||
|
protected => 1,
|
||||||
|
proxyto => '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],
|
||||||
|
},
|
||||||
|
parameters => {
|
||||||
|
additionalProperties => 0,
|
||||||
|
properties => PVE::QemuServer::json_config_properties(
|
||||||
|
{
|
||||||
|
node => get_standard_option('pve-node'),
|
||||||
|
vmid => get_standard_option('pve-vmid'),
|
||||||
|
skiplock => get_standard_option('skiplock'),
|
||||||
|
delete => {
|
||||||
|
type => 'string', format => 'pve-configid-list',
|
||||||
|
description => "A list of settings you want to delete.",
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
force => {
|
||||||
|
type => 'boolean',
|
||||||
|
description => $opt_force_description,
|
||||||
|
optional => 1,
|
||||||
|
requires => 'delete',
|
||||||
|
},
|
||||||
|
digest => {
|
||||||
|
type => 'string',
|
||||||
|
description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
|
||||||
|
maxLength => 40,
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
returns => { type => 'null' },
|
||||||
|
code => sub {
|
||||||
|
my ($param) = @_;
|
||||||
|
&$update_vm_api($param, 1);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
__PACKAGE__->register_method({
|
__PACKAGE__->register_method({
|
||||||
|
Loading…
Reference in New Issue
Block a user