mirror of
https://git.proxmox.com/git/qemu-server
synced 2025-08-16 04:21:07 +00:00
update_vm_async: new asynchronous API
This commit is contained in:
parent
d8b916fdb0
commit
5555edea95
209
PVE/API2/Qemu.pm
209
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);
|
||||
};
|
||||
|
||||
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',
|
||||
];
|
||||
# POST/PUT {vmid}/config implementation
|
||||
#
|
||||
# The original API used PUT (idempotent) an we assumed that all operations
|
||||
# are fast. But it turned out that almost any configuration change can
|
||||
# involve hot-plug actions, or disk alloc/free. Such actions can take long
|
||||
# time to complete and have side effects (not idempotent).
|
||||
#
|
||||
# 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({
|
||||
name => 'update_vm',
|
||||
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 $update_vm_api = sub {
|
||||
my ($param, $sync) = @_;
|
||||
|
||||
my $rpcenv = PVE::RPCEnvironment::get();
|
||||
|
||||
@ -899,6 +864,8 @@ __PACKAGE__->register_method({
|
||||
|
||||
my $digest = extract_param($param, 'digest');
|
||||
|
||||
my $background_delay = extract_param($param, 'background_delay');
|
||||
|
||||
my @paramarr = (); # used for log message
|
||||
foreach my $key (keys %$param) {
|
||||
push @paramarr, "-$key", $param->{$key};
|
||||
@ -974,6 +941,10 @@ __PACKAGE__->register_method({
|
||||
|
||||
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
|
||||
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
||||
&$vmconfig_delete_option($rpcenv, $authuser, $conf, $storecfg, $vmid, $opt, $force);
|
||||
@ -1016,13 +987,147 @@ __PACKAGE__->register_method({
|
||||
my $balloon = $param->{'balloon'} || $conf->{memory} || $defaults->{memory};
|
||||
PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PVE::QemuServer::lock_config($vmid, $updatefn);
|
||||
|
||||
if ($sync) {
|
||||
&$worker();
|
||||
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({
|
||||
|
Loading…
Reference in New Issue
Block a user