cbuildbot_launch: Add post-build chroot cleanup stage

The new stage unmounts the chroot and detaches the loopback device.  For
most builders that reboot after running, this doesn't make any
difference.  For builders that don't reboot between runs, this helps
reduce loopback device leaks.

BUG=chromium:752562,chromium:730144
TEST=unit tests; cros tryjob master-paladin-tryjob

Change-Id: I7f321ae0be1d5ffabcdc3a71b61246a3a65cd963
Reviewed-on: https://chromium-review.googlesource.com/907748
Commit-Ready: Benjamin Gordon <bmgordon@chromium.org>
Tested-by: Benjamin Gordon <bmgordon@chromium.org>
Reviewed-by: Don Garrett <dgarrett@chromium.org>
diff --git a/scripts/cbuildbot_launch.py b/scripts/cbuildbot_launch.py
index 71611c8..ff57c27 100644
--- a/scripts/cbuildbot_launch.py
+++ b/scripts/cbuildbot_launch.py
@@ -173,7 +173,7 @@
     logging.PrintBuildbotStepText('Unknown layout: Wiping buildroot.')
     metrics.Counter(METRIC_CLOBBER).increment(
         field(metrics_fields, reason='layout_change'))
-    chroot_dir = os.path.join(root, 'chroot')
+    chroot_dir = os.path.join(root, constants.DEFAULT_CHROOT_DIR)
     if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
       cros_build_lib.CleanupChrootMount(chroot_dir, delete_image=True)
     osutils.RmDir(root, ignore_missing=True, sudo=True)
@@ -185,7 +185,7 @@
           field(metrics_fields, old_branch=old_branch))
 
       logging.info('Remove Chroot.')
-      chroot_dir = os.path.join(repo.directory, 'chroot')
+      chroot_dir = os.path.join(repo.directory, constants.DEFAULT_CHROOT_DIR)
       if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
         cros_build_lib.CleanupChrootMount(chroot_dir, delete_image=True)
       osutils.RmDir(chroot_dir, ignore_missing=True, sudo=True)
@@ -291,6 +291,19 @@
   return result.returncode
 
 
+@StageDecorator
+def CleanupChroot(buildroot):
+  """Unmount/clean up an image-based chroot without deleting the backing image.
+
+  Args:
+    buildroot: Directory containing the chroot to be cleaned up.
+  """
+  chroot_dir = os.path.join(buildroot, constants.DEFAULT_CHROOT_DIR)
+  logging.info('Cleaning up chroot at %s', chroot_dir)
+  if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
+    cros_build_lib.CleanupChrootMount(chroot_dir, delete_image=False)
+
+
 def ConfigureGlobalEnvironment():
   """Setup process wide environmental changes."""
   # Set umask to 022 so files created by buildbot are readable.
@@ -366,6 +379,7 @@
     with metrics.SecondsTimer(METRIC_CBUILDBOT, fields=metrics_fields):
       result = RunCbuildbot(buildroot, depot_tools_path, argv)
       s_fields['success'] = (result == 0)
+      CleanupChroot(buildroot)
       return result