[pve-devel] [PATCH qemu-server 5/8] migrate: allow arbitrary source->target storage maps
Fabian Grünbichler
f.gruenbichler at proxmox.com
Mon Mar 30 13:41:33 CEST 2020
the syntax is backwards compatible, providing a single storage ID or '1'
works like before. the new helper ensures consistent behaviour at all
call sites.
Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---
Notes:
needs a versioned dep on pve-common with the new format and parse_idmap
PVE/API2/Qemu.pm | 41 ++++++++++++++++++++++++++++-------------
PVE/QemuMigrate.pm | 24 +++++++++++-------------
PVE/QemuServer.pm | 34 ++++++++++++++++++++++++++++------
3 files changed, 67 insertions(+), 32 deletions(-)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 788db93..6eba8d0 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -2024,11 +2024,7 @@ __PACKAGE__->register_method({
optional => 1,
},
machine => get_standard_option('pve-qemu-machine'),
- targetstorage => {
- description => "Target storage for the migration. (Can be '1' to use the same storage id as on the source node.)",
- type => 'string',
- optional => 1
- },
+ targetstorage => get_standard_option('pve-targetstorage'),
timeout => {
description => "Wait maximal timeout seconds.",
type => 'integer',
@@ -2067,8 +2063,15 @@ __PACKAGE__->register_method({
my $migration_network = $get_root_param->('migration_network');
my $targetstorage = $get_root_param->('targetstorage');
- raise_param_exc({ targetstorage => "targetstorage can only by used with migratedfrom." })
- if $targetstorage && !$migratedfrom;
+ my $storagemap;
+
+ if ($targetstorage) {
+ raise_param_exc({ targetstorage => "targetstorage can only by used with migratedfrom." })
+ if !$migratedfrom;
+ $storagemap = eval { PVE::JSONSchema::parse_idmap($targetstorage, 'pve-storage-id') };
+ raise_param_exc({ targetstorage => "failed to parse targetstorage map: $@" })
+ if $@;
+ }
# read spice ticket from STDIN
my $spice_ticket;
@@ -2119,7 +2122,7 @@ __PACKAGE__->register_method({
spice_ticket => $spice_ticket,
network => $migration_network,
type => $migration_type,
- targetstorage => $targetstorage,
+ storagemap => $storagemap,
nbd_proto_version => $nbd_protocol_version,
replicated_volumes => $replicated_volumes,
};
@@ -3385,9 +3388,7 @@ __PACKAGE__->register_method({
description => "Enable live storage migration for local disk",
optional => 1,
},
- targetstorage => get_standard_option('pve-storage-id', {
- description => "Default target storage.",
- optional => 1,
+ targetstorage => get_standard_option('pve-targetstorage', {
completion => \&PVE::QemuServer::complete_migration_storage,
}),
bwlimit => {
@@ -3451,8 +3452,22 @@ __PACKAGE__->register_method({
my $storecfg = PVE::Storage::config();
- if( $param->{targetstorage}) {
- PVE::Storage::storage_check_node($storecfg, $param->{targetstorage}, $target);
+ if (my $targetstorage = $param->{targetstorage}) {
+ my $storagemap = eval { PVE::JSONSchema::parse_idmap($targetstorage, 'pve-storage-id') };
+ raise_param_exc({ targetstorage => "failed to parse targetstorage map: $@" })
+ if $@;
+
+ foreach my $source (keys %{$storagemap->{entries}}) {
+ PVE::Storage::storage_check_node($storecfg, $storagemap->{entries}->{$source}, $target);
+ }
+
+ PVE::Storage::storage_check_node($storecfg, $storagemap->{default}, $target)
+ if $storagemap->{default};
+
+ PVE::QemuServer::check_storage_availability($storecfg, $conf, $target)
+ if $storagemap->{identity};
+
+ $param->{storagemap} = $storagemap;
} else {
PVE::QemuServer::check_storage_availability($storecfg, $conf, $target);
}
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index 579be0e..1546d87 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -244,7 +244,7 @@ sub prepare {
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
# check if storage is available on both nodes
- my $targetsid = $self->{opts}->{targetstorage} // $sid;
+ my $targetsid = PVE::QemuServer::map_storage($self->{opts}->{storagemap}, $sid);
my $scfg = PVE::Storage::storage_check_node($self->{storecfg}, $sid);
PVE::Storage::storage_check_node($self->{storecfg}, $targetsid, $self->{node});
@@ -281,14 +281,6 @@ sub sync_disks {
$self->{volumes} = [];
my $storecfg = $self->{storecfg};
- my $override_targetsid = $self->{opts}->{targetstorage};
-
- if (defined($override_targetsid)) {
- my $scfg = PVE::Storage::storage_config($storecfg, $override_targetsid);
- die "content type 'images' is not available on storage '$override_targetsid'\n"
- if !$scfg->{content}->{images};
- }
-
eval {
# found local volumes and their origin
@@ -319,11 +311,17 @@ sub sync_disks {
next if @{$dl->{$storeid}} == 0;
- my $targetsid = $override_targetsid // $storeid;
-
+ my $targetsid = PVE::QemuServer::map_storage($self->{opts}->{storagemap}, $storeid);
# check if storage is available on target node
PVE::Storage::storage_check_node($storecfg, $targetsid, $self->{node});
+ # grandfather in existing mismatches
+ if ($targetsid ne $storeid) {
+ my $target_scfg = PVE::Storage::storage_config($storecfg, $targetsid);
+ die "content type 'images' is not available on storage '$targetsid'\n"
+ if !$target_scfg->{content}->{images};
+ }
+
PVE::Storage::foreach_volid($dl, sub {
my ($volid, $sid, $volinfo) = @_;
@@ -368,7 +366,7 @@ sub sync_disks {
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
- my $targetsid = $override_targetsid // $sid;
+ my $targetsid = PVE::QemuServer::map_storage($self->{opts}->{storagemap}, $sid);
# check if storage is available on both nodes
my $scfg = PVE::Storage::storage_check_node($storecfg, $sid);
PVE::Storage::storage_check_node($storecfg, $targetsid, $self->{node});
@@ -518,7 +516,7 @@ sub sync_disks {
foreach my $volid (keys %$local_volumes) {
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
- my $targetsid = $override_targetsid // $sid;
+ my $targetsid = PVE::QemuServer::map_storage($self->{opts}->{storagemap}, $sid);
my $ref = $local_volumes->{$volid}->{ref};
if ($self->{running} && $ref eq 'config') {
push @{$self->{online_local_volumes}}, $volid;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 1ac8643..cd534f4 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -97,6 +97,28 @@ PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
optional => 1,
});
+
+sub map_storage {
+ my ($map, $source) = @_;
+
+ return $source if !defined($map);
+
+ return $map->{entries}->{$source}
+ if defined($map->{entries}) && $map->{entries}->{$source};
+
+ return $map->{default} if $map->{default};
+
+ # identity (fallback)
+ return $source;
+}
+
+PVE::JSONSchema::register_standard_option('pve-targetstorage', {
+ description => "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
+ type => 'string',
+ format => 'storagepair-list',
+ optional => 1,
+});
+
#no warnings 'redefine';
sub cgroups_write {
@@ -4711,7 +4733,7 @@ sub vmconfig_update_disk {
# called in locked context by incoming migration
sub vm_migrate_alloc_nbd_disks {
- my ($storecfg, $vmid, $conf, $targetstorage, $replicated_volumes) = @_;
+ my ($storecfg, $vmid, $conf, $storagemap, $replicated_volumes) = @_;
my $local_volumes = {};
foreach_drive($conf, sub {
@@ -4746,8 +4768,8 @@ sub vm_migrate_alloc_nbd_disks {
# If a remote storage is specified and the format of the original
# volume is not available there, fall back to the default format.
# Otherwise use the same format as the original.
- if ($targetstorage && $targetstorage ne "1") {
- $storeid = $targetstorage;
+ if (!$storagemap->{identity}) {
+ $storeid = map_storage($storagemap, $storeid);
my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
my $fileFormat = qemu_img_format($scfg, $volname);
@@ -4772,7 +4794,7 @@ sub vm_migrate_alloc_nbd_disks {
# see vm_start_nolock for parameters, additionally:
# migrate_opts:
-# targetstorage = storageid/'1' - target storage for disks migrated over NBD
+# storagemap = parsed storage map for allocating NBD disks
sub vm_start {
my ($storecfg, $vmid, $params, $migrate_opts) = @_;
@@ -4788,8 +4810,8 @@ sub vm_start {
die "VM $vmid already running\n" if check_running($vmid, undef, $migrate_opts->{migratedfrom});
- $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $conf, $migrate_opts->{targetstorage}, $migrate_opts->{replicated_volumes})
- if $migrate_opts->{targetstorage};
+ $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $conf, $migrate_opts->{storagemap}, $migrate_opts->{replicated_volumes})
+ if $migrate_opts->{storagemap};
vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
});
--
2.20.1
More information about the pve-devel
mailing list