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')
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)
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)
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)
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')
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'])
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, '')
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')
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')
def tearDown(self): with sudo.SudoKeepAlive(): cros_sdk_lib.CleanupChrootMount(self.chroot, delete_image=True)
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)
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)
def CleanupChroot(chroot_path): """Unmounts a chroot and cleans up any associated devices.""" cros_sdk_lib.CleanupChrootMount(chroot_path, delete=False)
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)