mirror of
git://git.proxmox.com/git/qemu-server.git
synced 2025-01-08 21:18:03 +03:00
migrate: allow arbitrary source->target storage maps
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@proxmox.com>
This commit is contained in:
parent
c05f1b33ea
commit
bf8fc5a307
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user