VMAUWorker: change handling of VM disk images

This CL makes two changes to how we handle VM disk images:
- VMAUWorker takes responsibility for making a private copy of
  the VM disk image, instead of leaving that to cros_vm_lib.sh
- If the update failed, or if verification of the image failed,
  move the private copy of the VM disk image to the |fail_directory|.

These two changes work in concert with CL:175329, to archive VM
disk images when a VMTest fails.

The rationale for having VMAUWorker make the private copy is two-fold:
- If cros_vm_lib.sh makes the copy, then we need to communicate
  the disk image name back to VMAUWorker (so that the disk image
  can be archived properly).
- We eliminate a possible problem with "--persist" and copying.
  Previously, if we ran UpdateImage, and then stopped the VM
  before running VerifyImage, then VerifyImage would run with a
  fresh copy of the VM disk image. Now, we know that UpdateImage
  and VerifyImage will use the same disk image.

BUG=chromium:311837
CQ-DEPEND=CL:175329
TEST=See test stanza in CL:175329

Change-Id: Ia2040e6a2494cb21e73fc5ca2d60ce0b43aaa549
Reviewed-on: https://chromium-review.googlesource.com/177133
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
Commit-Queue: mukesh agrawal <quiche@chromium.org>
diff --git a/au_test_harness/vm_au_worker.py b/au_test_harness/vm_au_worker.py
index 42eb41c..8d95c63 100644
--- a/au_test_harness/vm_au_worker.py
+++ b/au_test_harness/vm_au_worker.py
@@ -6,8 +6,10 @@
 
 import os
 import shutil
+import tempfile
 
 import constants
+from chromite.buildbot import constants as buildbot_constants
 from chromite.lib import cros_build_lib
 from crostestutils.au_test_harness import au_worker
 from crostestutils.au_test_harness import update_exception
@@ -38,18 +40,36 @@
 
   def PrepareBase(self, image_path, signed_base=False):
     """Creates an update-able VM based on base image."""
-    return self.PrepareVMBase(image_path, signed_base)
+    original_image_path = self.PrepareVMBase(image_path, signed_base)
+    # This worker may be running in parallel with other VMAUWorkers, as
+    # well as the archive stage of cbuildbot. Make a private copy of
+    # the VM image, to avoid any conflict.
+    _, private_image_path = tempfile.mkstemp(
+        prefix="%s." % buildbot_constants.VM_IMAGE_PREFIX)
+    shutil.copy(self.vm_image_path, private_image_path)
+    self.TestInfo('Copied shared disk image %s to %s.' %
+                  (self.vm_image_path, private_image_path))
+    self.vm_image_path = private_image_path
+    # Although we will run the VM with |private_image_path|, we return
+    # |original_image_path|, because our return value is used to find the
+    # update files. And the update files are shared across the tests
+    # that share the original image.
+    return original_image_path
 
-  @staticmethod
-  def _HandleFail(log_directory, fail_directory):
+  def _HandleFail(self, log_directory, fail_directory):
     parent_dir = os.path.dirname(fail_directory)
     if not os.path.isdir(parent_dir):
       os.makedirs(parent_dir)
 
     try:
+      # Copy logs. Must be done before moving image, as this creates
+      # |fail_directory|.
       shutil.copytree(log_directory, fail_directory)
+      self._KillExistingVM(self._kvm_pid_file)
+      shutil.move(self.vm_image_path, fail_directory)
     except shutil.Error as e:
-      cros_build_lib.Warning('Ignoring errors %s', e)
+      cros_build_lib.Warning(
+          'Ignoring errors while copying logs or VM disk image: %s', e)
 
   def UpdateImage(self, image_path, src_image_path='', stateful_change='old',
                   proxy_port='', private_key_path=None):
@@ -59,7 +79,6 @@
     cmd = ['%s/bin/cros_run_vm_update' % constants.CROSUTILS_DIR,
            '--vm_image_path=%s' % self.vm_image_path,
            '--update_log=%s' % os.path.join(log_directory, 'update_engine.log'),
-           '--copy',
            self.graphics_flag,
            '--persist',
            '--kvm_pid=%s' % self._kvm_pid_file,
@@ -85,7 +104,6 @@
            '--payload=%s' % update_path,
            '--vm_image_path=%s' % self.vm_image_path,
            '--update_log=%s' % os.path.join(log_directory, 'update_engine.log'),
-           '--copy',
            self.graphics_flag,
            '--persist',
            '--kvm_pid=%s' % self._kvm_pid_file,
@@ -128,7 +146,6 @@
     command = ['./bin/cros_run_vm_test',
                '--board=%s' % self.board,
                '--image_path=%s' % self.vm_image_path,
-               '--copy',
                '--persist',
                '--kvm_pid=%s' % self._kvm_pid_file,
                '--ssh_port=%s' % self._ssh_port,