Exemple #1
0
    def testMountedCleanupWithDelete(self):
        m = self.PatchObject(osutils, 'UmountTree')
        m2 = self.PatchObject(osutils, 'SafeUnlink')
        m3 = self.PatchObject(osutils, 'RmDir')
        m4 = self.PatchObject(cros_sdk_lib, '_RescanDeviceLvmMetadata')

        proc_mounts = os.path.join(self.tempdir, 'proc_mounts')
        with open(proc_mounts, 'w') as f:
            f.write('/dev/mapper/cros_vg_name-chroot %s ext4 rw 0 0\n' %
                    self.chroot_path)

        with cros_test_lib.RunCommandMock() as rc_mock:
            rc_mock.AddCmdResult(self._VGS_DEV_LOOKUP, output='  /dev/loop0')
            rc_mock.AddCmdResult(self._VGCHANGE_N)
            rc_mock.AddCmdResult(self._LOSETUP_DETACH)

            cros_sdk_lib.CleanupChrootMount(self.chroot_path,
                                            None,
                                            delete=True,
                                            proc_mounts=proc_mounts)

        m.assert_called_with(self.chroot_path)
        m2.assert_called_with(self.chroot_img)
        m3.assert_called_with(self.chroot_path, ignore_missing=True, sudo=True)
        m4.assert_called_with('/dev/loop0')
Exemple #2
0
    def testNothingCleanupWithDelete(self):
        m = self.PatchObject(osutils, 'UmountTree')
        m2 = self.PatchObject(cros_sdk_lib, 'FindVolumeGroupForDevice')
        m2.return_value = 'cros_chroot_001'
        m3 = self.PatchObject(osutils, 'SafeUnlink')
        m4 = self.PatchObject(osutils, 'RmDir')

        proc_mounts = os.path.join(self.tempdir, 'proc_mounts')
        with open(proc_mounts, 'w') as f:
            f.write('sysfs /sys sysfs rw 0 0\n')

        with cros_test_lib.RunCommandMock() as rc_mock:
            rc_mock.AddCmdResult(self._LOSETUP_FIND, returncode=1)
            rc_mock.AddCmdResult(self._VGS_VG_LOOKUP,
                                 returncode=self._LVM_FAILURE_CODE)

            cros_sdk_lib.CleanupChrootMount(self.chroot_path,
                                            None,
                                            delete=True,
                                            proc_mounts=proc_mounts)

        m.assert_called_with(self.chroot_path)
        m2.assert_called_with(self.chroot_path, None)
        m3.assert_called_with(self.chroot_img)
        m4.assert_called_with(self.chroot_path, ignore_missing=True, sudo=True)
Exemple #3
0
 def _DeleteChroot(self):
     logging.info('Deleting chroot.')
     chroot = os.path.join(self._build_root, constants.DEFAULT_CHROOT_DIR)
     if os.path.exists(chroot) or os.path.exists(chroot + '.img'):
         # At this stage, it's not safe to run the cros_sdk inside the buildroot
         # itself because we haven't sync'd yet, and the version of the chromite
         # in there might be broken. Since we've already unmounted everything in
         # there, we can just remove it using rm -rf.
         cros_sdk_lib.CleanupChrootMount(chroot, delete=True)
Exemple #4
0
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_sdk_lib.CleanupChrootMount(chroot_dir, delete_image=False)
Exemple #5
0
  def testCreateSnapshotMountsAsNeeded(self):
    with sudo.SudoKeepAlive():
      cros_sdk_lib.CleanupChrootMount(self.chroot)

    code, _ = self._crosSdk(['--snapshot-create', 'test'])
    self.assertEqual(code, 0)
    self.assertExists(self.chroot_version_file)

    code, output = self._crosSdk(['--snapshot-list'])
    self.assertEqual(code, 0)
    self.assertEqual(output.strip(), 'test')
Exemple #6
0
    def _CleanWorkspace(self):
        logging.info('Cleaning up workspace checkout.')
        assert self._run.options.workspace
        workspace = self._run.options.workspace

        logging.info('Remove Chroot.')
        chroot_dir = os.path.join(workspace, constants.DEFAULT_CHROOT_DIR)
        if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
            cros_sdk_lib.CleanupChrootMount(chroot_dir, delete=True)

        logging.info('Remove all workspace files except .repo.')
        repository.ClearBuildRoot(workspace, ['.repo'])
Exemple #7
0
  def testRestoreSnapshotMountsAsNeeded(self):
    with sudo.SudoKeepAlive():
      test_file = os.path.join(self.chroot, 'etc', 'test_file')
      osutils.Touch(test_file)

      code, _ = self._crosSdk(['--snapshot-create', 'test'])
      self.assertEqual(code, 0)

      osutils.SafeUnlink(test_file)

      cros_sdk_lib.CleanupChrootMount(self.chroot)

      code, _ = self._crosSdk(['--snapshot-restore', 'test'])
      self.assertEqual(code, 0)
      self.assertExists(test_file)

      code, output = self._crosSdk(['--snapshot-list'])
      self.assertEqual(code, 0)
      self.assertEqual(output, '')
Exemple #8
0
    def testMountedCleanupByBuildroot(self):
        m = self.PatchObject(osutils, 'UmountTree')
        m2 = self.PatchObject(cros_sdk_lib, '_RescanDeviceLvmMetadata')

        proc_mounts = os.path.join(self.tempdir, 'proc_mounts')
        with open(proc_mounts, 'w') as f:
            f.write('/dev/mapper/cros_vg_name-chroot %s ext4 rw 0 0\n' %
                    self.chroot_path)

        with cros_test_lib.RunCommandMock() as rc_mock:
            rc_mock.AddCmdResult(self._VGS_DEV_LOOKUP, output='  /dev/loop0')
            rc_mock.AddCmdResult(self._VGCHANGE_N)
            rc_mock.AddCmdResult(self._LOSETUP_DETACH)

            cros_sdk_lib.CleanupChrootMount(None,
                                            self.tempdir,
                                            proc_mounts=proc_mounts)

        m.assert_called_with(self.chroot_path)
        m2.assert_called_with('/dev/loop0')
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'):
        try:
            cros_sdk_lib.CleanupChrootMount(chroot_dir, delete=False)
        except timeout_util.TimeoutError:
            logging.exception('Cleaning up chroot timed out')
            # Dump debug info to help https://crbug.com/1000034.
            cros_build_lib.run(['mount'], error_code_ok=False)
            cros_build_lib.run(['uname', '-a'], error_code_ok=False)
            cros_build_lib.sudo_run(['losetup', '-a'], error_code_ok=False)
            cros_build_lib.run(['dmesg'], error_code_ok=False)
            logging.warning(
                'Assuming the bot is going to reboot, so ignoring this '
                'failure; see https://crbug.com/1000034')
Exemple #10
0
    def testDevOnlyCleanup(self):
        m = self.PatchObject(osutils, 'UmountTree')
        m2 = self.PatchObject(cros_sdk_lib, 'FindVolumeGroupForDevice')
        m2.return_value = 'cros_chroot_001'
        m3 = self.PatchObject(cros_sdk_lib, '_RescanDeviceLvmMetadata')

        proc_mounts = os.path.join(self.tempdir, 'proc_mounts')
        with open(proc_mounts, 'w') as f:
            f.write('sysfs /sys sysfs rw 0 0\n')

        with cros_test_lib.RunCommandMock() as rc_mock:
            rc_mock.AddCmdResult(self._LOSETUP_FIND, output='/dev/loop1')
            rc_mock.AddCmdResult(self._VGS_VG_LOOKUP,
                                 returncode=self._LVM_FAILURE_CODE)
            rc_mock.AddCmdResult(self._LOSETUP_DETACH)

            cros_sdk_lib.CleanupChrootMount(self.chroot_path,
                                            None,
                                            proc_mounts=proc_mounts)

        m.assert_called_with(self.chroot_path)
        m2.assert_called_with(self.chroot_path, '/dev/loop1')
        m3.assert_called_with('/dev/loop1')
Exemple #11
0
 def tearDown(self):
   with sudo.SudoKeepAlive():
     cros_sdk_lib.CleanupChrootMount(self.chroot, delete_image=True)
Exemple #12
0
    def PerformStage(self):
        if (not (self._run.options.buildbot or self._run.options.remote_trybot)
                and self._run.options.clobber):
            if not commands.ValidateClobber(self._build_root):
                cros_build_lib.Die('--clobber in local mode must be approved.')

        # If we can't get a manifest out of it, then it's not usable and must be
        # clobbered.
        manifest = None
        delete_chroot = False
        if not self._run.options.clobber:
            try:
                manifest = git.ManifestCheckout.Cached(self._build_root,
                                                       search=False)
            except (KeyboardInterrupt, MemoryError, SystemExit):
                raise
            except Exception as e:
                # Either there is no repo there, or the manifest isn't usable.  If the
                # directory exists, log the exception for debugging reasons.  Either
                # way, the checkout needs to be wiped since it's in an unknown
                # state.
                if os.path.exists(self._build_root):
                    logging.warning('ManifestCheckout at %s is unusable: %s',
                                    self._build_root, e)
                delete_chroot = True

        # Clean mount points first to be safe about deleting.
        chroot_path = os.path.join(self._build_root,
                                   constants.DEFAULT_CHROOT_DIR)
        cros_sdk_lib.CleanupChrootMount(chroot=chroot_path)
        osutils.UmountTree(self._build_root)

        if not delete_chroot:
            delete_chroot = not self.CanReuseChroot(chroot_path)

        # If we're going to delete the chroot and we can use a snapshot instead,
        # try to revert.  If the revert succeeds, we don't need to delete after all.
        if delete_chroot and self.CanUseChrootSnapshotToDelete(chroot_path):
            delete_chroot = not self._RevertChrootToCleanSnapshot()

        # Re-mount chroot image if it exists so that subsequent steps can clean up
        # inside.
        if not delete_chroot and self._run.config.chroot_use_image:
            try:
                cros_sdk_lib.MountChroot(chroot=chroot_path, create=False)
            except cros_build_lib.RunCommandError as e:
                logging.error(
                    'Unable to mount chroot under %s.  Deleting chroot.  '
                    'Error: %s', self._build_root, e)
                delete_chroot = True

        if manifest is None:
            self._DeleteChroot()
            repository.ClearBuildRoot(self._build_root,
                                      self._run.options.preserve_paths)
        else:
            tasks = [
                self._BuildRootGitCleanup, self._WipeOldOutput,
                self._DeleteArchivedTrybotImages,
                self._DeleteArchivedPerfResults,
                self._DeleteAutotestSitePackages
            ]
            if self._run.options.chrome_root:
                tasks.append(self._DeleteChromeBuildOutput)
            if delete_chroot:
                tasks.append(self._DeleteChroot)
            else:
                tasks.append(self._CleanChroot)
            if self._run.options.workspace:
                tasks.append(self._CleanWorkspace)

            # CancelObsoleteSlaveBuilds, if there are slave builds to cancel.
            if self._run.config.slave_configs:
                tasks.append(self.CancelObsoleteSlaveBuilds)

            parallel.RunParallelSteps(tasks)

        # If chroot.img still exists after everything is cleaned up, it means we're
        # planning to reuse it. This chroot was created by the previous run, so its
        # creation isn't affected by any potential changes in the current run.
        # Therefore, if this run fails, having the subsequent run revert to this
        # snapshot will still produce a clean chroot.  If this run succeeds, the
        # next run will reuse the chroot without needing to revert it.  Thus, taking
        # a snapshot now should be correct regardless of whether this run will
        # ultimately succeed or not.
        if os.path.exists(chroot_path + '.img'):
            self._CreateCleanSnapshot()
def CleanBuildRoot(root, repo, cache_dir, build_state):
    """Some kinds of branch transitions break builds.

  This method ensures that cbuildbot's buildroot is a clean checkout on the
  given branch when it starts. If necessary (a branch transition) it will wipe
  assorted state that cannot be safely reused from the previous build.

  Args:
    root: Root directory owned by cbuildbot_launch.
    repo: repository.RepoRepository instance.
    cache_dir: Cache directory.
    build_state: BuildSummary object containing the current build state that
        will be saved into the cleaned root.  The distfiles_ts property will
        be updated if the distfiles cache is cleaned.
  """
    previous_state = GetLastBuildState(root)
    SetLastBuildState(root, build_state)
    SanitizeCacheDir(cache_dir)
    build_state.distfiles_ts = _MaybeCleanDistfiles(
        cache_dir, previous_state.distfiles_ts)

    if previous_state.buildroot_layout != BUILDROOT_BUILDROOT_LAYOUT:
        logging.PrintBuildbotStepText('Unknown layout: Wiping buildroot.')
        metrics.Counter(METRIC_CLOBBER).increment(
            fields=field({}, reason='layout_change'))
        chroot_dir = os.path.join(root, constants.DEFAULT_CHROOT_DIR)
        if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
            cros_sdk_lib.CleanupChrootMount(chroot_dir, delete=True)
        osutils.RmDir(root, ignore_missing=True, sudo=True)
        osutils.RmDir(cache_dir, ignore_missing=True, sudo=True)
    else:
        if previous_state.branch != repo.branch:
            logging.PrintBuildbotStepText('Branch change: Cleaning buildroot.')
            logging.info('Unmatched branch: %s -> %s', previous_state.branch,
                         repo.branch)
            metrics.Counter(METRIC_BRANCH_CLEANUP).increment(
                fields=field({}, old_branch=previous_state.branch))

            logging.info('Remove 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_sdk_lib.CleanupChrootMount(chroot_dir, delete=True)

            logging.info('Remove Chrome checkout.')
            osutils.RmDir(os.path.join(repo.directory, '.cache', 'distfiles'),
                          ignore_missing=True,
                          sudo=True)

    try:
        # If there is any failure doing the cleanup, wipe everything.
        # The previous run might have been killed in the middle leaving stale git
        # locks. Clean those up, first.
        repo.PreLoad()

        # If the previous build didn't exit normally, run an expensive step to
        # cleanup abandoned git locks.
        if previous_state.status not in (constants.BUILDER_STATUS_FAILED,
                                         constants.BUILDER_STATUS_PASSED):
            repo.CleanStaleLocks()

        repo.BuildRootGitCleanup(prune_all=True)
    except Exception:
        logging.info('Checkout cleanup failed, wiping buildroot:',
                     exc_info=True)
        metrics.Counter(METRIC_CLOBBER).increment(
            fields=field({}, reason='repo_cleanup_failure'))
        repository.ClearBuildRoot(repo.directory)

    # Ensure buildroot exists. Save the state we are prepped for.
    osutils.SafeMakedirs(repo.directory)
    SetLastBuildState(root, build_state)
Exemple #14
0
def main(argv):
    # Turn on strict sudo checks.
    cros_build_lib.STRICT_SUDO = True
    conf = key_value_store.LoadFile(os.path.join(constants.SOURCE_ROOT,
                                                 constants.SDK_VERSION_FILE),
                                    ignore_missing=True)
    sdk_latest_version = conf.get('SDK_LATEST_VERSION', '<unknown>')
    bootstrap_frozen_version = conf.get('BOOTSTRAP_FROZEN_VERSION',
                                        '<unknown>')

    # Use latest SDK for bootstrapping if requested. Use a frozen version of SDK
    # for bootstrapping if BOOTSTRAP_FROZEN_VERSION is set.
    bootstrap_latest_version = (sdk_latest_version if bootstrap_frozen_version
                                == '<unknown>' else bootstrap_frozen_version)
    parser, commands = _CreateParser(sdk_latest_version,
                                     bootstrap_latest_version)
    options = parser.parse_args(argv)
    chroot_command = options.commands

    # Some sanity checks first, before we ask for sudo credentials.
    cros_build_lib.AssertOutsideChroot()

    host = os.uname()[4]
    if host != 'x86_64':
        cros_build_lib.Die(
            "cros_sdk is currently only supported on x86_64; you're running"
            ' %s.  Please find a x86_64 machine.' % (host, ))

    # Merge the outside PATH setting if we re-execed ourselves.
    if 'CHROMEOS_SUDO_PATH' in os.environ:
        os.environ['PATH'] = '%s:%s' % (os.environ.pop('CHROMEOS_SUDO_PATH'),
                                        os.environ['PATH'])

    _ReportMissing(osutils.FindMissingBinaries(NEEDED_TOOLS))
    if options.proxy_sim:
        _ReportMissing(osutils.FindMissingBinaries(PROXY_NEEDED_TOOLS))
    missing_image_tools = osutils.FindMissingBinaries(IMAGE_NEEDED_TOOLS)

    if (sdk_latest_version == '<unknown>'
            or bootstrap_latest_version == '<unknown>'):
        cros_build_lib.Die(
            'No SDK version was found. '
            'Are you in a Chromium source tree instead of Chromium OS?\n\n'
            'Please change to a directory inside your Chromium OS source tree\n'
            'and retry.  If you need to setup a Chromium OS source tree, see\n'
            '  https://dev.chromium.org/chromium-os/developer-guide')

    any_snapshot_operation = (options.snapshot_create
                              or options.snapshot_restore
                              or options.snapshot_delete
                              or options.snapshot_list)
    if any_snapshot_operation and not options.use_image:
        cros_build_lib.Die('Snapshot operations are not compatible with '
                           '--nouse-image.')

    if (options.snapshot_delete
            and options.snapshot_delete == options.snapshot_restore):
        parser.error('Cannot --snapshot_delete the same snapshot you are '
                     'restoring with --snapshot_restore.')

    _ReExecuteIfNeeded([sys.argv[0]] + argv)

    lock_path = os.path.dirname(options.chroot)
    lock_path = os.path.join(
        lock_path, '.%s_lock' % os.path.basename(options.chroot).lstrip('.'))

    # Expand out the aliases...
    if options.replace:
        options.delete = options.create = True

    if options.bootstrap:
        options.create = True

    # If a command is not given, default to enter.
    # pylint: disable=protected-access
    # This _group_actions access sucks, but upstream decided to not include an
    # alternative to optparse's option_list, and this is what they recommend.
    options.enter |= not any(
        getattr(options, x.dest) for x in commands._group_actions)
    # pylint: enable=protected-access
    options.enter |= bool(chroot_command)

    if (options.delete and not options.create
            and (options.enter or any_snapshot_operation)):
        parser.error('Trying to enter or snapshot the chroot when --delete '
                     'was specified makes no sense.')

    if (options.unmount
            and (options.create or options.enter or any_snapshot_operation)):
        parser.error(
            '--unmount cannot be specified with other chroot actions.')

    if options.working_dir is not None and not os.path.isabs(
            options.working_dir):
        options.working_dir = path_util.ToChrootPath(options.working_dir)

    # Discern if we need to create the chroot.
    chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot)
    if (options.use_image and not chroot_exists and not options.delete
            and not options.unmount and not missing_image_tools
            and os.path.exists(_ImageFileForChroot(options.chroot))):
        # Try to re-mount an existing image in case the user has rebooted.
        with cgroups.SimpleContainChildren('cros_sdk'):
            with locking.FileLock(lock_path, 'chroot lock') as lock:
                logging.debug(
                    'Checking if existing chroot image can be mounted.')
                lock.write_lock()
                cros_sdk_lib.MountChroot(options.chroot, create=False)
                chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot)
                if chroot_exists:
                    logging.notice('Mounted existing image %s on chroot',
                                   _ImageFileForChroot(options.chroot))

    # Finally, flip create if necessary.
    if options.enter or options.snapshot_create:
        options.create |= not chroot_exists

    # Make sure we will download if we plan to create.
    options.download |= options.create

    # Anything that needs to manipulate the main chroot mount or communicate with
    # LVM needs to be done here before we enter the new namespaces.

    # If deleting, do it regardless of the use_image flag so that a
    # previously-created loopback chroot can also be cleaned up.
    # TODO(bmgordon): See if the DeleteChroot call below can be removed in
    # favor of this block.
    chroot_deleted = False
    if options.delete:
        with cgroups.SimpleContainChildren('cros_sdk'):
            # Set a timeout of 300 seconds when getting the lock.
            with locking.FileLock(lock_path,
                                  'chroot lock',
                                  blocking_timeout=300) as lock:
                try:
                    lock.write_lock()
                except timeout_util.TimeoutError as e:
                    logging.error('Acquiring write_lock on %s failed: %s',
                                  lock_path, e)
                    if not options.force:
                        cros_build_lib.Die(
                            'Exiting; use --force to continue w/o lock.')
                    else:
                        logging.warning(
                            'cros_sdk was invoked with force option, continuing.'
                        )
                if missing_image_tools:
                    logging.notice('Unmounting chroot.')
                    osutils.UmountTree(options.chroot)
                else:
                    logging.notice('Deleting chroot.')
                    cros_sdk_lib.CleanupChrootMount(options.chroot,
                                                    delete=True)
                    chroot_deleted = True

    # If cleanup was requested, we have to do it while we're still in the original
    # namespace.  Since cleaning up the mount will interfere with any other
    # commands, we exit here.  The check above should have made sure that no other
    # action was requested, anyway.
    if options.unmount:
        # Set a timeout of 300 seconds when getting the lock.
        with locking.FileLock(lock_path, 'chroot lock',
                              blocking_timeout=300) as lock:
            try:
                lock.write_lock()
            except timeout_util.TimeoutError as e:
                logging.error('Acquiring write_lock on %s failed: %s',
                              lock_path, e)
                logging.warning(
                    'Continuing with CleanupChroot(%s), which will umount the tree.',
                    options.chroot)
            # We can call CleanupChroot (which calls cros_sdk_lib.CleanupChrootMount)
            # even if we don't get the lock because it will attempt to unmount the
            # tree and will print diagnostic information from 'fuser', 'lsof', and
            # 'ps'.
            CleanupChroot(options.chroot)
            sys.exit(0)

    # Make sure the main chroot mount is visible.  Contents will be filled in
    # below if needed.
    if options.create and options.use_image:
        if missing_image_tools:
            raise SystemExit("""The tool(s) %s were not found.
Please make sure the lvm2 and thin-provisioning-tools packages
are installed on your host.
Example(ubuntu):
  sudo apt-get install lvm2 thin-provisioning-tools

If you want to run without lvm2, pass --nouse-image (chroot
snapshots will be unavailable).""" % ', '.join(missing_image_tools))

        logging.debug('Making sure chroot image is mounted.')
        with cgroups.SimpleContainChildren('cros_sdk'):
            with locking.FileLock(lock_path, 'chroot lock') as lock:
                lock.write_lock()
                if not cros_sdk_lib.MountChroot(options.chroot, create=True):
                    cros_build_lib.Die('Unable to mount %s on chroot',
                                       _ImageFileForChroot(options.chroot))
                logging.notice('Mounted %s on chroot',
                               _ImageFileForChroot(options.chroot))

    # Snapshot operations will always need the VG/LV, but other actions won't.
    if any_snapshot_operation:
        with cgroups.SimpleContainChildren('cros_sdk'):
            with locking.FileLock(lock_path, 'chroot lock') as lock:
                chroot_vg, chroot_lv = cros_sdk_lib.FindChrootMountSource(
                    options.chroot)
                if not chroot_vg or not chroot_lv:
                    cros_build_lib.Die('Unable to find VG/LV for chroot %s',
                                       options.chroot)

                # Delete snapshot before creating a new one.  This allows the user to
                # throw out old state, create a new snapshot, and enter the chroot in a
                # single call to cros_sdk.  Since restore involves deleting, also do it
                # before creating.
                if options.snapshot_restore:
                    lock.write_lock()
                    valid_snapshots = ListChrootSnapshots(chroot_vg, chroot_lv)
                    if options.snapshot_restore not in valid_snapshots:
                        cros_build_lib.Die(
                            '%s is not a valid snapshot to restore to. '
                            'Valid snapshots: %s', options.snapshot_restore,
                            ', '.join(valid_snapshots))
                    osutils.UmountTree(options.chroot)
                    if not RestoreChrootSnapshot(options.snapshot_restore,
                                                 chroot_vg, chroot_lv):
                        cros_build_lib.Die(
                            'Unable to restore chroot to snapshot.')
                    if not cros_sdk_lib.MountChroot(options.chroot,
                                                    create=False):
                        cros_build_lib.Die(
                            'Unable to mount restored snapshot onto chroot.')

                # Use a read lock for snapshot delete and create even though they modify
                # the filesystem, because they don't modify the mounted chroot itself.
                # The underlying LVM commands take their own locks, so conflicting
                # concurrent operations here may crash cros_sdk, but won't corrupt the
                # chroot image.  This tradeoff seems worth it to allow snapshot
                # operations on chroots that have a process inside.
                if options.snapshot_delete:
                    lock.read_lock()
                    DeleteChrootSnapshot(options.snapshot_delete, chroot_vg,
                                         chroot_lv)

                if options.snapshot_create:
                    lock.read_lock()
                    if not CreateChrootSnapshot(options.snapshot_create,
                                                chroot_vg, chroot_lv):
                        cros_build_lib.Die('Unable to create snapshot.')

    img_path = _ImageFileForChroot(options.chroot)
    if (options.use_image and os.path.exists(options.chroot)
            and os.path.exists(img_path)):
        img_stat = os.stat(img_path)
        img_used_bytes = img_stat.st_blocks * 512

        mount_stat = os.statvfs(options.chroot)
        mount_used_bytes = mount_stat.f_frsize * (mount_stat.f_blocks -
                                                  mount_stat.f_bfree)

        extra_gbs = (img_used_bytes - mount_used_bytes) // 2**30
        if extra_gbs > MAX_UNUSED_IMAGE_GBS:
            logging.notice(
                '%s is using %s GiB more than needed.  Running '
                'fstrim.', img_path, extra_gbs)
            cmd = ['fstrim', options.chroot]
            try:
                cros_build_lib.dbg_run(cmd)
            except cros_build_lib.RunCommandError as e:
                logging.warning(
                    'Running fstrim failed. Consider running fstrim on '
                    'your chroot manually.\n%s', e)

    # Enter a new set of namespaces.  Everything after here cannot directly affect
    # the hosts's mounts or alter LVM volumes.
    namespaces.SimpleUnshare()
    if options.ns_pid:
        first_pid = namespaces.CreatePidNs()
    else:
        first_pid = None

    if options.snapshot_list:
        for snap in ListChrootSnapshots(chroot_vg, chroot_lv):
            print(snap)
        sys.exit(0)

    if not options.sdk_version:
        sdk_version = (bootstrap_latest_version
                       if options.bootstrap else sdk_latest_version)
    else:
        sdk_version = options.sdk_version
    if options.buildbot_log_version:
        logging.PrintBuildbotStepText(sdk_version)

    # Based on selections, determine the tarball to fetch.
    if options.download:
        if options.sdk_url:
            urls = [options.sdk_url]
        else:
            urls = GetArchStageTarballs(sdk_version)

    with cgroups.SimpleContainChildren('cros_sdk', pid=first_pid):
        with locking.FileLock(lock_path, 'chroot lock') as lock:
            if options.proxy_sim:
                _ProxySimSetup(options)

            if (options.delete and not chroot_deleted and
                (os.path.exists(options.chroot)
                 or os.path.exists(_ImageFileForChroot(options.chroot)))):
                lock.write_lock()
                DeleteChroot(options.chroot)

            sdk_cache = os.path.join(options.cache_dir, 'sdks')
            distfiles_cache = os.path.join(options.cache_dir, 'distfiles')
            osutils.SafeMakedirsNonRoot(options.cache_dir)

            for target in (sdk_cache, distfiles_cache):
                src = os.path.join(constants.SOURCE_ROOT,
                                   os.path.basename(target))
                if not os.path.exists(src):
                    osutils.SafeMakedirsNonRoot(target)
                    continue
                lock.write_lock(
                    'Upgrade to %r needed but chroot is locked; please exit '
                    'all instances so this upgrade can finish.' % src)
                if not os.path.exists(src):
                    # Note that while waiting for the write lock, src may've vanished;
                    # it's a rare race during the upgrade process that's a byproduct
                    # of us avoiding taking a write lock to do the src check.  If we
                    # took a write lock for that check, it would effectively limit
                    # all cros_sdk for a chroot to a single instance.
                    osutils.SafeMakedirsNonRoot(target)
                elif not os.path.exists(target):
                    # Upgrade occurred, but a reversion, or something whacky
                    # occurred writing to the old location.  Wipe and continue.
                    os.rename(src, target)
                else:
                    # Upgrade occurred once already, but either a reversion or
                    # some before/after separate cros_sdk usage is at play.
                    # Wipe and continue.
                    osutils.RmDir(src)

            if options.download:
                lock.write_lock()
                sdk_tarball = FetchRemoteTarballs(
                    sdk_cache, urls, 'stage3' if options.bootstrap else 'SDK')

            if options.create:
                lock.write_lock()
                # Recheck if the chroot is set up here before creating to make sure we
                # account for whatever the various delete/unmount/remount steps above
                # have done.
                if cros_sdk_lib.IsChrootReady(options.chroot):
                    logging.debug('Chroot already exists.  Skipping creation.')
                else:
                    CreateChroot(options.chroot,
                                 sdk_tarball,
                                 options.cache_dir,
                                 nousepkg=(options.bootstrap
                                           or options.nousepkg))

            if options.enter:
                lock.read_lock()
                EnterChroot(options.chroot, options.cache_dir,
                            options.chrome_root, options.chrome_root_mount,
                            options.goma_dir, options.goma_client_json,
                            options.working_dir, chroot_command)
Exemple #15
0
def CleanupChroot(chroot_path):
    """Unmounts a chroot and cleans up any associated devices."""
    cros_sdk_lib.CleanupChrootMount(chroot_path, delete=False)
Exemple #16
0
def CleanBuildRoot(root, repo, metrics_fields, build_state):
    """Some kinds of branch transitions break builds.

  This method ensures that cbuildbot's buildroot is a clean checkout on the
  given branch when it starts. If necessary (a branch transition) it will wipe
  assorted state that cannot be safely reused from the previous build.

  Args:
    root: Root directory owned by cbuildbot_launch.
    repo: repository.RepoRepository instance.
    metrics_fields: Dictionary of fields to include in metrics.
    build_state: BuildSummary object containing the current build state that
        will be saved into the cleaned root.  The distfiles_ts property will
        be updated if the distfiles cache is cleaned.
  """
    previous_state = GetLastBuildState(root)
    build_state.distfiles_ts = _MaybeCleanDistfiles(
        repo, previous_state.distfiles_ts, metrics_fields)

    if previous_state.buildroot_layout != BUILDROOT_BUILDROOT_LAYOUT:
        logging.PrintBuildbotStepText('Unknown layout: Wiping buildroot.')
        metrics.Counter(METRIC_CLOBBER).increment(
            field(metrics_fields, reason='layout_change'))
        chroot_dir = os.path.join(root, constants.DEFAULT_CHROOT_DIR)
        if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
            cros_sdk_lib.CleanupChrootMount(chroot_dir, delete_image=True)
        osutils.RmDir(root, ignore_missing=True, sudo=True)
    else:
        if previous_state.branch != repo.branch:
            logging.PrintBuildbotStepText('Branch change: Cleaning buildroot.')
            logging.info('Unmatched branch: %s -> %s', previous_state.branch,
                         repo.branch)
            metrics.Counter(METRIC_BRANCH_CLEANUP).increment(
                field(metrics_fields, old_branch=previous_state.branch))

            logging.info('Remove 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_sdk_lib.CleanupChrootMount(chroot_dir, delete_image=True)
            osutils.RmDir(chroot_dir, ignore_missing=True, sudo=True)

            logging.info('Remove Chrome checkout.')
            osutils.RmDir(os.path.join(repo.directory, '.cache', 'distfiles'),
                          ignore_missing=True,
                          sudo=True)

        try:
            # If there is any failure doing the cleanup, wipe everything.
            repo.BuildRootGitCleanup(prune_all=True)
        except Exception:
            logging.info('Checkout cleanup failed, wiping buildroot:',
                         exc_info=True)
            metrics.Counter(METRIC_CLOBBER).increment(
                field(metrics_fields, reason='repo_cleanup_failure'))
            repository.ClearBuildRoot(repo.directory)

    # Ensure buildroot exists. Save the state we are prepped for.
    osutils.SafeMakedirs(repo.directory)
    if not build_state.distfiles_ts:
        build_state.distfiles_ts = time.time()
    SetLastBuildState(root, build_state)