[tools 1/2] testbot/LibvirtTool: Reorganize the snapshot creation.

Francois Gouget fgouget at codeweavers.com
Wed Feb 16 13:10:44 CST 2022


WaitForBoot() is responsible for establishing the first connection after
the VM boots, which can take longer than usual.
PrepareVM() replaces SetupTestAgentd() and performs all the tasks
needed to make the VM ready for the tests.
CreateSnapshot() now also configures the VM before creating the
Libvirt snapshot.
And CheckBootCount() verifies that the VM did not crash at some point
during the process. It is now systematically called before creating
snapshots or declaring the VM fit for duty.

Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
---
 testbot/bin/LibvirtTool.pl | 228 ++++++++++++++++++++++---------------
 1 file changed, 135 insertions(+), 93 deletions(-)

diff --git a/testbot/bin/LibvirtTool.pl b/testbot/bin/LibvirtTool.pl
index cfdb251694..aecca4b534 100755
--- a/testbot/bin/LibvirtTool.pl
+++ b/testbot/bin/LibvirtTool.pl
@@ -454,6 +454,21 @@ sub CheckOff()
   return ChangeStatus("dirty", "off", "done");
 }
 
+sub WaitForBoot($)
+{
+  my ($TA) = @_;
+
+  Debug(Elapsed($Start), " Waiting for the VM to boot\n");
+  LogMsg "Waiting for $VMKey to boot\n";
+  my $MinTimeout = $TA->SetConnectTimeout(undef, undef, $WaitForBoot);
+  if (!$TA->GetVersion())
+  {
+    my $ErrMessage = $TA->GetLastError();
+    FatalError("Could not connect to the $VMKey TestAgent: $ErrMessage\n");
+  }
+  $TA->SetConnectTimeout(undef, undef, $MinTimeout);
+}
+
 sub WaitForSession($)
 {
   my ($TA) = @_;
@@ -478,14 +493,33 @@ sub WaitForSession($)
   }
 }
 
-sub SetupTestAgentd($$$)
+sub CheckBootCount($)
+{
+  my ($TA) = @_;
+
+  # Check that TestAgentd is not displaying the "Has Windows rebooted?" warning.
+  my $Count = $TA->GetProperties("start.count");
+  if (defined $Count and $Count > 1)
+  {
+    FatalError("$VMKey has been rebooted too many times: start.count=$Count > 1\n");
+  }
+}
+
+sub ResetBootCount($)
+{
+  my ($TA) = @_;
+
+  # Check the boot count before resetting it
+  CheckBootCount($TA);
+  $TA->SetProperty("start.count", 0);
+}
+
+sub PrepareVM($)
 {
-  my ($Booting, $UpgradeTestAgentd, $ResetStartCount) = @_;
+  my ($TA) = @_;
 
   Debug(Elapsed($Start), " Setting up the $VMKey TestAgent server\n");
   LogMsg "Setting up the $VMKey TestAgent server\n";
-  my $TA = $VM->GetAgent();
-  $TA->SetConnectTimeout(undef, undef, $WaitForBoot) if ($Booting);
   my $Version = $TA->GetVersion();
   if (!$Version)
   {
@@ -493,9 +527,58 @@ sub SetupTestAgentd($$$)
     FatalError("Could not connect to the $VMKey TestAgent: $ErrMessage\n");
   }
 
-  # Upgrade TestAgentd
-  if ($UpgradeTestAgentd and ($VM->Type eq "win32" or $VM->Type eq "win64"))
+  # Always update the guest's system time
+  # This is needed not only for the tests (date is important when checking
+  # HTTPS certificates), but also for the build (if the time moves forward
+  # during the build some ccache versions will return a compilation error).
+  my $PTA = GetPrivilegedTA($TA);
+  FatalError("$VMKey has no privileged TestAgent server\n") if (!$PTA);
+  if (!$PTA->SetTime())
+  {
+    FatalError("Setting the $VMKey system time failed: ". $PTA->GetLastError() ."\n");
+  }
+}
+
+sub GetSnapshotConfig($)
+{
+  my ($Config) = @_;
+
+  # Don't stack snapshots. For instance assume the snapshot name is
+  # 'test-live-fr-FR-tsign' and that 'test-live-fr-FR' already exists
+  # (typically because it is used by another VM):
+  # - It's probably better if snapshots are independent from each other.
+  # - Applying the 'tsign' flag on top of the existing snapshot requires a
+  #   Windows reboot. But format locale changes may not stick across reboots.
+  # - Stopping the snapshot name parsing when finding an existing snapshot name
+  #   would lose the 'live' flag resulting in an error (or the wrong type of
+  #   snapshot. Avoiding this issue would result in more complexity.
+  # - Finally snapshot stacking does not seem that useful.
+  # - A consequence is that the base snapshot should be called 'test' and not
+  #   'test-live'.
+  while (1)
+  {
+    if ($Config->{base} =~ s/-([a-z]{2}-[A-Z]{2})$//)
+    {
+      $Config->{locale} ||= $1; # take only the last match
+    }
+    elsif ($Config->{base} =~ s/-(live)$//)
+    {
+      $Config->{$1} = 1;
+    }
+    else
+    {
+      last;
+    }
+  }
+}
+
+sub CreateSnapshot($$$$)
+{
+  my ($Domain, $TA, $Config, $Booting) = @_;
+
+  if ($VM->Type =~ /^win(?:32|64)$/)
   {
+    my $Version = $TA->GetVersion();
     Debug(Elapsed($Start), " Upgrading the $VMKey TestAgent server from $Version\n");
     LogMsg "Upgrading the $VMKey TestAgent server from $Version\n";
     if ($Version !~ / ([0-9]+)\.([0-9]+)$/)
@@ -532,76 +615,41 @@ sub SetupTestAgentd($$$)
     # A side effect is that it will force TestAgentd.exe.old to stay around.
   }
 
-  # Always update the guest's system time
-  # This is needed not only for the tests (date is important when checking
-  # HTTPS certificates), but also for the build (if the time moves forward
-  # during the build some ccache versions will return a compilation error).
-  my $PTA = GetPrivilegedTA($TA);
-  FatalError("Cannot set the $VMKey VM system time\n") if (!$PTA);
-  if (!$PTA->SetTime())
+  if ($Config->{locale})
   {
-    FatalError("Setting the $VMKey VM system time failed: ". $PTA->GetLastError() ."\n");
-  }
-
-  WaitForSession($TA) if ($Booting);
+    Debug(Elapsed($Start), " Setting up the $Config->{locale} locale on $VMKey\n");
+    # SetWinLocale --default performs a reboot and WaitForBoot()
+    ResetBootCount($TA);
+    $TA->Disconnect();
+    $Booting = 1;
 
-  if ($ResetStartCount)
-  {
-    # If SetProperty() is not supported neither is --show-restarts.
-    # So it all works out.
-    $TA->SetProperty("start.count", 0);
-  }
-  elsif ($Booting)
-  {
-    # Check that TestAgentd is not displaying the "Has Windows rebooted?"
-    # warning.
-    my $Count = $TA->GetProperties("start.count");
-    if (defined $Count and $Count > 1)
+    my @Cmd = ("$BinDir/SetWinLocale", $VM->Hostname, "--default", $Config->{locale});
+    push @Cmd, "--debug" if ($Debug);
+    Debug("Running: ", join(" ", @Cmd), "\n");
+    if (system(@Cmd))
     {
-      FatalError("$VMKey has been rebooted too many times: start.count=$Count > 1");
+      FatalError("Could not set the $VMKey locale to $Config->{locale}\n");
     }
   }
-  $PTA->Disconnect();
-  $TA->Disconnect();
-}
-
-sub GetSnapshotConfig($)
-{
-  my ($Config) = @_;
 
-  while (1)
+  if ($Booting)
   {
-    if ($Config->{base} =~ s/-([a-z]{2}-[A-Z]{2})$//)
-    {
-      $Config->{locale} = $1;
-    }
-    elsif ($Config->{base} =~ s/-(live)$//)
-    {
-      $Config->{$1} = 1;
-    }
-    else
+    WaitForSession($TA);
+    if ($SleepAfterBoot)
     {
-      last;
+      Debug(Elapsed($Start), " Sleeping ${SleepAfterBoot}s for the $Config->{snapshot} snapshot\n");
+      LogMsg "Letting $VMKey settle down for the $Config->{snapshot} snapshot\n";
+      sleep($SleepAfterBoot);
     }
   }
-}
-
-sub CreateSnapshot($$)
-{
-  my ($Domain, $SnapshotName) = @_;
-
-  if ($SleepAfterBoot != 0)
-  {
-    Debug(Elapsed($Start), " Sleeping ${SleepAfterBoot}s for the $SnapshotName snapshot\n");
-    LogMsg "Letting $VMKey settle down for the $SnapshotName snapshot\n";
-    sleep($SleepAfterBoot);
-  }
+  CheckBootCount($TA);
 
-  Debug(Elapsed($Start), " Creating the $SnapshotName snapshot\n");
-  my $ErrMessage = $Domain->CreateSnapshot($SnapshotName);
+  $TA->Disconnect(); # disconnect before taking the snapshot
+  Debug(Elapsed($Start), " Creating the $Config->{snapshot} snapshot\n");
+  my $ErrMessage = $Domain->CreateSnapshot($Config->{snapshot});
   if (defined $ErrMessage)
   {
-    FatalError("Could not recreate the $SnapshotName snapshot on $VMKey: $ErrMessage\n");
+    FatalError("Could not create the $Config->{snapshot} snapshot on $VMKey: $ErrMessage\n");
   }
 }
 
@@ -613,13 +661,17 @@ sub Revert()
     return 1;
   }
   $CurrentStatus = "reverting";
-  my $Config = { base => $VM->IdleSnapshot };
+  my $Config = {
+    base => $VM->IdleSnapshot,
+    snapshot => $VM->IdleSnapshot,
+  };
 
   my $Domain = $VM->GetDomain();
   if (!$Domain->HasSnapshot($Config->{base}))
   {
     $Config->{create} = 1;
     GetSnapshotConfig($Config);
+    Debug(join(" ", Elapsed($Start), "Config:", map { "$_=$Config->{$_}" } sort keys %$Config), "\n");
     if ($Config->{locale} and $VM->Type !~ /^win(?:32|64)$/)
     {
       FatalError("Creating locale snapshots ($Config->{locale}) is not supported for ". $VM->Type ." VMs ($VMKey)\n");
@@ -655,8 +707,8 @@ sub Revert()
   if (defined $ErrMessage)
   {
     # Libvirt/QEmu is buggy and cannot revert a running VM from one hardware
-    # configuration to another. So try again after powering off the VM, though
-    # this can be much slower.
+    # configuration to another. So try again after forcefully powering off
+    # the VM, though this can be much slower.
     Debug(Elapsed($Start), " Powering off the VM\n");
     $ErrMessage = $Domain->PowerOff();
     if (defined $ErrMessage)
@@ -672,33 +724,22 @@ sub Revert()
     FatalError("Could not revert $VMKey to $Config->{base}: $ErrMessage\n");
   }
 
-  # Mark the VM as sleeping which allows the scheduler to abort the revert in
-  # favor of higher priority tasks. But don't allow interruptions in the
-  # middle of snapshot creation!
   if (!$Config->{create})
   {
+    # Mark the VM as sleeping which allows the scheduler to abort the revert in
+    # favor of higher priority tasks. But don't allow interruptions in the
+    # middle of snapshot creation!
     return 1 if (ChangeStatus("reverting", "sleeping"));
   }
 
-  # Set up the TestAgent server. Note that setting the locale will require a
-  # reboot so reset start.count in that case.
-  SetupTestAgentd($Booting, $Config->{create}, $Config->{locale});
-
-  # Set up the VM locale
-  if ($Config->{locale})
-  {
-    Debug(Elapsed($Start), " Setting up the $Config->{locale} locale on $VMKey\n");
-    my @Cmd = ("$BinDir/SetWinLocale", $VM->Hostname, "--default", $Config->{locale});
-    push @Cmd, "--debug" if ($Debug);
-    if (system(@Cmd))
-    {
-      FatalError("Could not set the $VMKey locale to $Config->{locale}\n");
-    }
-  }
+  my $TA = $VM->GetAgent();
+  WaitForBoot($TA) if ($Booting);
+  PrepareVM($TA);
 
   if ($Config->{create})
   {
-    CreateSnapshot($Domain, $VM->IdleSnapshot);
+    CreateSnapshot($Domain, $TA, $Config, $Booting);
+    $Booting = 0;
 
     if ($VM->Type eq "build" or $VM->Type eq "wine")
     {
@@ -721,15 +762,16 @@ sub Revert()
     # The activity monitor does not like it when VMs skip the sleeping step
     return 1 if (ChangeStatus("reverting", "sleeping"));
   }
-  else
-  {
-    my $Sleep = ($Booting and $SleepAfterBoot > $SleepAfterRevert) ?
-                $SleepAfterBoot : $SleepAfterRevert;
-    Debug(Elapsed($Start), " Sleeping ${Sleep}s\n");
-    LogMsg "Letting $VMKey settle down for ${Sleep}s\n";
-    sleep($Sleep);
-  }
 
+  WaitForSession($TA) if ($Booting);
+
+  my $Sleep = ($Booting and $SleepAfterBoot > $SleepAfterRevert) ?
+              $SleepAfterBoot : $SleepAfterRevert;
+  Debug(Elapsed($Start), " Sleeping ${Sleep}s\n");
+  LogMsg "Letting $VMKey settle down for ${Sleep}s\n";
+  sleep($Sleep);
+
+  CheckBootCount($TA);
   return ChangeStatus($CurrentStatus, "idle", "done");
 }
 
-- 
2.30.2




More information about the wine-devel mailing list