migrate: send updated TPM state volid to target node

The volid may change if local-storage migration is involved, we need
to tell the target node the new one and update the in-memory config
for starting the target VM accordingly.

Reported here: https://forum.proxmox.com/threads/99906/#post-431345

this possibly breaks migration new -> old iff
- spice is not used (else the explicit ticket wins because it comes
  later)
- a local TPM state volume is used
- that local TPM state volume has a different volume id on the target
  node (switched storage, volname already taken, ..)

because the target node will then mis-interpret the tpmstate0 line as
spice ticket and set it accordingly. if the old tpm state volume ID does
not exist on the target node, migration will fail. if it exists by
chance, it might work albeit with a wrong spice ticket (new because of
this patch) and tpm state volume (pre-existing breakage).

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
Fabian Grünbichler 2021-11-22 11:30:11 +01:00 committed by Thomas Lamprecht
parent 399ca0d66e
commit fd95d780a2
3 changed files with 21 additions and 1 deletions

View File

@ -2319,6 +2319,7 @@ __PACKAGE__->register_method({
my $spice_ticket;
my $nbd_protocol_version = 0;
my $replicated_volumes = {};
my $tpmstate_vol;
if ($stateuri && ($stateuri eq 'tcp' || $stateuri eq 'unix') && $migratedfrom && ($rpcenv->{type} eq 'cli')) {
while (defined(my $line = <STDIN>)) {
chomp $line;
@ -2328,6 +2329,8 @@ __PACKAGE__->register_method({
$nbd_protocol_version = $1;
} elsif ($line =~ m/^replicated_volume: (.*)$/) {
$replicated_volumes->{$1} = 1;
} elsif ($line =~ m/^tpmstate0: (.*)$/) {
$tpmstate_vol = $1;
} elsif (!$spice_ticket) {
# fallback for old source node
$spice_ticket = $line;
@ -2369,6 +2372,7 @@ __PACKAGE__->register_method({
storagemap => $storagemap,
nbd_proto_version => $nbd_protocol_version,
replicated_volumes => $replicated_volumes,
tpmstate_vol => $tpmstate_vol,
};
my $params = {

View File

@ -870,6 +870,14 @@ sub phase2 {
# version > 0 for unix socket support
my $nbd_protocol_version = 1;
my $input = "nbd_protocol_version: $nbd_protocol_version\n";
if ($conf->{tpmstate0}) {
my $tpmdrive = PVE::QemuServer::parse_drive('tpmstate0', $conf->{tpmstate0});
my $tpmvol = $tpmdrive->{file};
$input .= "tpmstate0: $self->{volume_map}->{$tpmvol}"
if $self->{volume_map}->{$tpmvol} && $tpmvol ne $self->{volume_map}->{$tpmvol};
}
$input .= "spice_ticket: $spice_ticket\n" if $spice_ticket;
my @online_replicated_volumes = $self->filter_local_volumes('online', 1);

View File

@ -5370,7 +5370,8 @@ sub vm_start {
# network => CIDR of migration network
# type => secure/insecure - tunnel over encrypted connection or plain-text
# nbd_proto_version => int, 0 for TCP, 1 for UNIX
# replicated_volumes = which volids should be re-used with bitmaps for nbd migration
# replicated_volumes => which volids should be re-used with bitmaps for nbd migration
# tpmstate_vol => new volid of tpmstate0, not yet contained in config
sub vm_start_nolock {
my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
@ -5395,6 +5396,13 @@ sub vm_start_nolock {
# this way we can reuse the old ISO with the correct config
PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid) if !$migratedfrom;
# override TPM state vol if migrated, conf is out of date still
if (my $tpmvol = $migrate_opts->{tpmstate_vol}) {
my $parsed = parse_drive("tpmstate0", $conf->{tpmstate0});
$parsed->{file} = $tpmvol;
$conf->{tpmstate0} = print_drive($parsed);
}
my $defaults = load_defaults();
# set environment variable useful inside network script