mirror of
git://git.proxmox.com/git/qemu-server.git
synced 2025-03-10 12:58:25 +03:00
vm_start: apply pending changes
I move related helper methods into PVE::QemuServer. Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
3900164009
commit
055d554dfa
111
PVE/API2/Qemu.pm
111
PVE/API2/Qemu.pm
@ -37,26 +37,12 @@ my $resolve_cdrom_alias = sub {
|
||||
}
|
||||
};
|
||||
|
||||
my $vm_is_volid_owner = sub {
|
||||
my ($storecfg, $vmid, $volid) =@_;
|
||||
|
||||
if ($volid !~ m|^/|) {
|
||||
my ($path, $owner);
|
||||
eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
|
||||
if ($owner && ($owner == $vmid)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
};
|
||||
|
||||
my $test_deallocate_drive = sub {
|
||||
my ($storecfg, $vmid, $key, $drive, $force) = @_;
|
||||
|
||||
if (!PVE::QemuServer::drive_is_cdrom($drive)) {
|
||||
my $volid = $drive->{file};
|
||||
if (&$vm_is_volid_owner($storecfg, $vmid, $volid)) {
|
||||
if ( PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
|
||||
if ($force || $key =~ m/^unused/) {
|
||||
my $sid = PVE::Storage::parse_volume_id($volid);
|
||||
return $sid;
|
||||
@ -67,44 +53,6 @@ my $test_deallocate_drive = sub {
|
||||
return undef;
|
||||
};
|
||||
|
||||
my $pending_delete_option = sub {
|
||||
my ($conf, $key) = @_;
|
||||
|
||||
delete $conf->{pending}->{$key};
|
||||
my $pending_delete_hash = { $key => 1 };
|
||||
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
|
||||
$pending_delete_hash->{$opt} = 1;
|
||||
}
|
||||
$conf->{pending}->{delete} = join(',', keys %$pending_delete_hash);
|
||||
};
|
||||
|
||||
my $pending_undelete_option = sub {
|
||||
my ($conf, $key) = @_;
|
||||
|
||||
my $pending_delete_hash = {};
|
||||
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
|
||||
$pending_delete_hash->{$opt} = 1;
|
||||
}
|
||||
delete $pending_delete_hash->{$key};
|
||||
|
||||
my @keylist = keys %$pending_delete_hash;
|
||||
if (scalar(@keylist)) {
|
||||
$conf->{pending}->{delete} = join(',', @keylist);
|
||||
} else {
|
||||
delete $conf->{pending}->{delete};
|
||||
}
|
||||
};
|
||||
|
||||
my $register_unused_drive = sub {
|
||||
my ($storecfg, $vmid, $conf, $drive) = @_;
|
||||
if (!PVE::QemuServer::drive_is_cdrom($drive)) {
|
||||
my $volid = $drive->{file};
|
||||
if (&$vm_is_volid_owner($storecfg, $vmid, $volid)) {
|
||||
PVE::QemuServer::add_unused_volume($conf, $volid, $vmid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
my $check_storage_access = sub {
|
||||
my ($rpcenv, $authuser, $storecfg, $vmid, $settings, $default_storage) = @_;
|
||||
|
||||
@ -712,7 +660,7 @@ my $delete_drive = sub {
|
||||
if (!PVE::QemuServer::drive_is_cdrom($drive)) {
|
||||
my $volid = $drive->{file};
|
||||
|
||||
if (&$vm_is_volid_owner($storecfg, $vmid, $volid)) {
|
||||
if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
|
||||
if ($force || $key =~ m/^unused/) {
|
||||
eval {
|
||||
# check if the disk is really unused
|
||||
@ -905,48 +853,6 @@ my $vmconfig_update_net = sub {
|
||||
die "error hotplug $opt" if !PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, $opt, $net);
|
||||
};
|
||||
|
||||
my $vmconfig_apply_pending = sub {
|
||||
my ($vmid, $conf, $storecfg, $running) = @_;
|
||||
|
||||
my @delete = PVE::Tools::split_list($conf->{pending}->{delete});
|
||||
foreach my $opt (@delete) { # delete
|
||||
die "internal error" if $opt =~ m/^unused/;
|
||||
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
||||
if (!defined($conf->{$opt})) {
|
||||
&$pending_undelete_option($conf, $opt);
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
} elsif (PVE::QemuServer::valid_drivename($opt)) {
|
||||
&$register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{$opt}));
|
||||
&$pending_undelete_option($conf, $opt);
|
||||
delete $conf->{$opt};
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
} else {
|
||||
&$pending_undelete_option($conf, $opt);
|
||||
delete $conf->{$opt};
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
||||
|
||||
foreach my $opt (keys %{$conf->{pending}}) { # add/change
|
||||
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
||||
|
||||
if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
|
||||
# skip if nothing changed
|
||||
} elsif (PVE::QemuServer::valid_drivename($opt)) {
|
||||
&$register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{$opt}))
|
||||
if defined($conf->{$opt});
|
||||
$conf->{$opt} = $conf->{pending}->{$opt};
|
||||
} else {
|
||||
$conf->{$opt} = $conf->{pending}->{$opt};
|
||||
}
|
||||
|
||||
delete $conf->{pending}->{$opt};
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
}
|
||||
};
|
||||
|
||||
# POST/PUT {vmid}/config implementation
|
||||
#
|
||||
# The original API used PUT (idempotent) an we assumed that all operations
|
||||
@ -1068,12 +974,12 @@ my $update_vm_api = sub {
|
||||
}
|
||||
} elsif (PVE::QemuServer::valid_drivename($opt)) {
|
||||
$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
|
||||
&$register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
|
||||
PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
|
||||
if defined($conf->{pending}->{$opt});
|
||||
&$pending_delete_option($conf, $opt);
|
||||
PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt);
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
} else {
|
||||
&$pending_delete_option($conf, $opt);
|
||||
PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt);
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
}
|
||||
}
|
||||
@ -1089,14 +995,14 @@ my $update_vm_api = sub {
|
||||
} else {
|
||||
$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
|
||||
}
|
||||
&$register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
|
||||
PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
|
||||
if defined($conf->{pending}->{$opt});
|
||||
|
||||
&$create_disks($rpcenv, $authuser, $conf->{pending}, $storecfg, $vmid, undef, {$opt => $param->{$opt}});
|
||||
} else {
|
||||
$conf->{pending}->{$opt} = $param->{$opt};
|
||||
}
|
||||
&$pending_undelete_option($conf, $opt);
|
||||
PVE::QemuServer::vmconfig_undelete_pending_option($conf, $opt);
|
||||
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||
}
|
||||
|
||||
@ -1114,12 +1020,11 @@ my $update_vm_api = sub {
|
||||
return if !scalar(keys %{$conf->{pending}});
|
||||
|
||||
my $running = PVE::QemuServer::check_running($vmid);
|
||||
die "implement me - vm is running" if $running; # fixme: if $conf->{hotplug};
|
||||
|
||||
# apply pending changes
|
||||
|
||||
$conf = PVE::QemuServer::load_config($vmid); # update/reload
|
||||
&$vmconfig_apply_pending($vmid, $conf, $storecfg, $running);
|
||||
PVE::QemuServer::vmconfig_apply_pending($vmid, $conf, $storecfg, $running);
|
||||
|
||||
return; # TODO: remove old code below
|
||||
|
||||
|
@ -1433,6 +1433,59 @@ sub add_unused_volume {
|
||||
return $key;
|
||||
}
|
||||
|
||||
sub vm_is_volid_owner {
|
||||
my ($storecfg, $vmid, $volid) = @_;
|
||||
|
||||
if ($volid !~ m|^/|) {
|
||||
my ($path, $owner);
|
||||
eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
|
||||
if ($owner && ($owner == $vmid)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub vmconfig_delete_pending_option {
|
||||
my ($conf, $key) = @_;
|
||||
|
||||
delete $conf->{pending}->{$key};
|
||||
my $pending_delete_hash = { $key => 1 };
|
||||
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
|
||||
$pending_delete_hash->{$opt} = 1;
|
||||
}
|
||||
$conf->{pending}->{delete} = join(',', keys %$pending_delete_hash);
|
||||
}
|
||||
|
||||
sub vmconfig_undelete_pending_option {
|
||||
my ($conf, $key) = @_;
|
||||
|
||||
my $pending_delete_hash = {};
|
||||
foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
|
||||
$pending_delete_hash->{$opt} = 1;
|
||||
}
|
||||
delete $pending_delete_hash->{$key};
|
||||
|
||||
my @keylist = keys %$pending_delete_hash;
|
||||
if (scalar(@keylist)) {
|
||||
$conf->{pending}->{delete} = join(',', @keylist);
|
||||
} else {
|
||||
delete $conf->{pending}->{delete};
|
||||
}
|
||||
}
|
||||
|
||||
sub vmconfig_register_unused_drive {
|
||||
my ($storecfg, $vmid, $conf, $drive) = @_;
|
||||
|
||||
if (!drive_is_cdrom($drive)) {
|
||||
my $volid = $drive->{file};
|
||||
if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
|
||||
add_unused_volume($conf, $volid, $vmid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $valid_smbios1_options = {
|
||||
manufacturer => '\S+',
|
||||
product => '\S+',
|
||||
@ -3494,6 +3547,51 @@ sub set_migration_caps {
|
||||
vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
|
||||
}
|
||||
|
||||
|
||||
sub vmconfig_apply_pending {
|
||||
my ($vmid, $conf, $storecfg, $running) = @_;
|
||||
|
||||
die "implement me - vm is running" if $running; # fixme: if $conf->{hotplug};
|
||||
|
||||
my @delete = PVE::Tools::split_list($conf->{pending}->{delete});
|
||||
foreach my $opt (@delete) { # delete
|
||||
die "internal error" if $opt =~ m/^unused/;
|
||||
$conf = load_config($vmid); # update/reload
|
||||
if (!defined($conf->{$opt})) {
|
||||
vmconfig_undelete_pending_option($conf, $opt);
|
||||
update_config_nolock($vmid, $conf, 1);
|
||||
} elsif (valid_drivename($opt)) {
|
||||
vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}));
|
||||
vmconfig_undelete_pending_option($conf, $opt);
|
||||
delete $conf->{$opt};
|
||||
update_config_nolock($vmid, $conf, 1);
|
||||
} else {
|
||||
vmconfig_undelete_pending_option($conf, $opt);
|
||||
delete $conf->{$opt};
|
||||
update_config_nolock($vmid, $conf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$conf = load_config($vmid); # update/reload
|
||||
|
||||
foreach my $opt (keys %{$conf->{pending}}) { # add/change
|
||||
$conf = load_config($vmid); # update/reload
|
||||
|
||||
if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
|
||||
# skip if nothing changed
|
||||
} elsif (valid_drivename($opt)) {
|
||||
vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
|
||||
if defined($conf->{$opt});
|
||||
$conf->{$opt} = $conf->{pending}->{$opt};
|
||||
} else {
|
||||
$conf->{$opt} = $conf->{pending}->{$opt};
|
||||
}
|
||||
|
||||
delete $conf->{pending}->{$opt};
|
||||
update_config_nolock($vmid, $conf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
sub vm_start {
|
||||
my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine, $spice_ticket) = @_;
|
||||
|
||||
@ -3506,6 +3604,11 @@ sub vm_start {
|
||||
|
||||
die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
|
||||
|
||||
if (!$statefile && scalar(keys %{$conf->{pending}})) {
|
||||
vmconfig_apply_pending($vmid, $conf, $storecfg, 0);
|
||||
$conf = load_config($vmid); # update/reload
|
||||
}
|
||||
|
||||
my $defaults = load_defaults();
|
||||
|
||||
# set environment variable useful inside network script
|
||||
|
Loading…
x
Reference in New Issue
Block a user