[PATCH 2/3] testbot/LibvirtTool: Create live snapshots as needed.

Francois Gouget fgouget at codeweavers.com
Tue Sep 24 04:10:05 CDT 2019


Live snapshots have to save the content of the VM's memory which takes
space in the disk image. They may also be specific to the host they
are running on (e.g. AMD vs. Intel CPU). And they may need to be
recreated after QEmu upgrades.
So VMs always have a powered off snapshot as reference and backups
made from the powered off state. With VMs that are configured for
autologin and autostart of TestAgentd this patch removes the need for
the administrator to manually recreate the live snapshots.

Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
---
 testbot/bin/LibvirtTool.pl               | 85 ++++++++++++++++++++----
 testbot/lib/WineTestBot/Config.pm        |  7 +-
 testbot/lib/WineTestBot/LibvirtDomain.pm |  5 +-
 3 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/testbot/bin/LibvirtTool.pl b/testbot/bin/LibvirtTool.pl
index dd330a5ab..72075ae5e 100755
--- a/testbot/bin/LibvirtTool.pl
+++ b/testbot/bin/LibvirtTool.pl
@@ -6,7 +6,7 @@
 # network trouble, and thus are best performed in a separate process.
 #
 # Copyright 2009 Ge van Geldorp
-# Copyright 2012-2017 Francois Gouget
+# Copyright 2012-2019 Francois Gouget
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -382,6 +382,25 @@ sub SetupTestAgentd($$)
   $TA->Disconnect();
 }
 
+sub CreateSnapshot($$)
+{
+  my ($Domain, $SnapshotName) = @_;
+
+  if ($SleepAfterBoot != 0)
+  {
+    Debug(Elapsed($Start), " Sleeping for the $SnapshotName snapshot\n");
+    LogMsg "Letting $VMKey settle down for the $SnapshotName snapshot\n";
+    sleep($SleepAfterBoot);
+  }
+
+  Debug(Elapsed($Start), " Creating the $SnapshotName snapshot\n");
+  my $ErrMessage = $Domain->CreateSnapshot($SnapshotName);
+  if (defined $ErrMessage)
+  {
+    FatalError("Could not recreate the $SnapshotName snapshot on $VMKey: $ErrMessage\n");
+  }
+}
+
 sub Revert()
 {
   my $VM = CreateVMs()->GetItem($VMKey);
@@ -391,11 +410,34 @@ sub Revert()
     return 1;
   }
   $CurrentStatus = "reverting";
+  my $DomainSnapshot = $VM->IdleSnapshot;
+  my $ExtraTimeout = 0;
+  my $CreateSnapshot;
 
-  # Revert the VM (and power it on if necessary)
   my $Domain = $VM->GetDomain();
-  Debug(Elapsed($Start), " Reverting $VMKey to ", $VM->IdleSnapshot, "\n");
-  my ($ErrMessage, $Booting) = $Domain->RevertToSnapshot();
+  if (!$Domain->HasSnapshot($DomainSnapshot) and $DomainSnapshot =~ s/-live$//)
+  {
+    # Add some extra time to boot the VM and create the live snapshot
+    $ExtraTimeout += $WaitForBoot + $VMToolTimeout / 2;
+    $CreateSnapshot = 1;
+    Debug(Elapsed($Start), " $VMKey does not yet have a $DomainSnapshot-live snapshot\n");
+  }
+  if (!$Domain->HasSnapshot($DomainSnapshot))
+  {
+    FatalError("Could not find $VMKey\'s $DomainSnapshot snapshot\n");
+  }
+  if ($ExtraTimeout)
+  {
+    Debug(Elapsed($Start), " Extend the $VMKey revert deadline by $ExtraTimeout\n");
+    my $Deadline = $VM->Status eq "maintenance" ? (time() + $VMToolTimeout) :
+                                                  $VM->ChildDeadline;
+    $VM->ChildDeadline($Deadline + $ExtraTimeout);
+    $VM->Save();
+  }
+
+  # Revert the VM (and power it on if necessary)
+  Debug(Elapsed($Start), " Reverting $VMKey to $DomainSnapshot\n");
+  my ($ErrMessage, $Booting) = $Domain->RevertToSnapshot($DomainSnapshot);
   if (defined $ErrMessage)
   {
     # Libvirt/QEmu is buggy and cannot revert a running VM from one hardware
@@ -408,28 +450,45 @@ sub Revert()
       FatalError("Could not power off $VMKey: $ErrMessage\n");
     }
 
-    Debug(Elapsed($Start), " Reverting $VMKey to ", $VM->IdleSnapshot, "... again\n");
-    ($ErrMessage, $Booting) = $Domain->RevertToSnapshot();
+    Debug(Elapsed($Start), " Reverting $VMKey to $DomainSnapshot... again\n");
+    ($ErrMessage, $Booting) = $Domain->RevertToSnapshot($DomainSnapshot);
   }
   if (defined $ErrMessage)
   {
-    FatalError("Could not revert $VMKey to ". $VM->IdleSnapshot .": $ErrMessage\n");
+    FatalError("Could not revert $VMKey to $DomainSnapshot: $ErrMessage\n");
   }
 
-  # The VM is now sleeping which may allow some tasks to run
-  return 1 if (ChangeStatus("reverting", "sleeping"));
+  # 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 (!$CreateSnapshot)
+  {
+    return 1 if (ChangeStatus("reverting", "sleeping"));
+  }
 
   # Set up the TestAgent server
   SetupTestAgentd($VM, $Booting);
 
-  if ($SleepAfterRevert != 0)
+  if ($CreateSnapshot)
   {
+    CreateSnapshot($Domain, $VM->IdleSnapshot);
+  }
+  else
+  {
+    my $Sleep = ($Booting and $SleepAfterBoot > $SleepAfterRevert) ?
+                $SleepAfterBoot : $SleepAfterRevert;
     Debug(Elapsed($Start), " Sleeping\n");
-    LogMsg "Letting ". $VM->Name  ." settle down for ${SleepAfterRevert}s\n";
-    sleep($SleepAfterRevert);
+    LogMsg "Letting $VMKey settle down for ${Sleep}s\n";
+    sleep($Sleep);
+  }
+
+  if ($CreateSnapshot)
+  {
+    # The activity monitor does not like it when VMs skip the sleeping step
+    return 1 if (ChangeStatus("reverting", "sleeping"));
   }
 
-  return ChangeStatus("sleeping", "idle", "done");
+  return ChangeStatus($CurrentStatus, "idle", "done");
 }
 
 
diff --git a/testbot/lib/WineTestBot/Config.pm b/testbot/lib/WineTestBot/Config.pm
index 3496c310e..bcfa9ae82 100644
--- a/testbot/lib/WineTestBot/Config.pm
+++ b/testbot/lib/WineTestBot/Config.pm
@@ -28,7 +28,7 @@ WineTestBot::Config - Site-independent configuration settings
 use vars qw (@ISA @EXPORT @EXPORT_OK $UseSSL $LogDir $DataDir $BinDir
              %RepoURLs $DbDataSource $DbUsername $DbPassword $MaxRevertingVMs
              $MaxRevertsWhileRunningVMs $MaxActiveVMs $MaxRunningVMs
-             $MaxVMsWhenIdle $SleepAfterRevert $WaitForBoot
+             $MaxVMsWhenIdle $WaitForBoot $SleepAfterBoot $SleepAfterRevert
              $VMToolTimeout $MaxVMErrors $MaxTaskTries $AdminEMail $RobotEMail
              $WinePatchToOverride $WinePatchCc
              $ExeBuildNativeTimeout $ExeBuildTestTimeout $ExeModuleTimeout
@@ -44,7 +44,8 @@ require Exporter;
 @ISA = qw(Exporter);
 @EXPORT = qw($UseSSL $LogDir $DataDir $BinDir %RepoURLs
              $MaxRevertingVMs $MaxRevertsWhileRunningVMs $MaxActiveVMs
-             $MaxRunningVMs $MaxVMsWhenIdle $SleepAfterRevert $WaitForBoot
+             $MaxRunningVMs $MaxVMsWhenIdle $WaitForBoot $SleepAfterBoot
+             $SleepAfterRevert
              $VMToolTimeout $MaxVMErrors $MaxTaskTries $AdminEMail
              $RobotEMail $WinePatchToOverride $WinePatchCc $SuiteTimeout
              $ExeBuildNativeTimeout $ExeBuildTestTimeout $ExeModuleTimeout
@@ -92,6 +93,8 @@ $MaxVMsWhenIdle = undef;
 
 # How long to attempt to connect to the TestAgent while the VM is booting.
 $WaitForBoot = 90;
+# How long to let the VM settle down after booting it before taking a snapshot.
+$SleepAfterBoot = 30;
 # How long to let the VM settle down after a revert before starting a task on
 # it (in seconds).
 $SleepAfterRevert = 0;
diff --git a/testbot/lib/WineTestBot/LibvirtDomain.pm b/testbot/lib/WineTestBot/LibvirtDomain.pm
index dbb2a39ea..207dc6d45 100644
--- a/testbot/lib/WineTestBot/LibvirtDomain.pm
+++ b/testbot/lib/WineTestBot/LibvirtDomain.pm
@@ -309,11 +309,10 @@ sub GetSnapshotName($)
   return (undef, $SnapshotName);
 }
 
-sub RevertToSnapshot($)
+sub RevertToSnapshot($$)
 {
-  my ($self) = @_;
+  my ($self, $SnapshotName) = @_;
 
-  my $SnapshotName = $self->{VM}->IdleSnapshot;
   my ($ErrMessage, $Domain, $Snapshot) = $self->_GetSnapshot($SnapshotName);
   return ($ErrMessage, undef) if (defined $ErrMessage);
 
-- 
2.20.1




More information about the wine-devel mailing list