def testExistingChroot(self): # Chroot version file exists in the chroot. # Should return True without running any commands. osutils.Touch(os.path.join(self.chroot_path, 'etc', 'cros_chroot_version'), makedirs=True) success = cros_sdk_lib.MountChroot(self.chroot_path, create=False) self.assertTrue(success) success = cros_sdk_lib.MountChroot(self.chroot_path, create=True) self.assertTrue(success)
def testBadMount(self): # Chroot with something else mounted on it. # Should return False without running any commands. proc_mounts = os.path.join(self.tempdir, 'proc_mounts') with open(proc_mounts, 'w') as f: f.write('/dev/sda1 %s ext4 rw 0 0\n' % self.chroot_path) success = cros_sdk_lib.MountChroot(self.chroot_path, create=False, proc_mounts=proc_mounts) self.assertFalse(success) success = cros_sdk_lib.MountChroot(self.chroot_path, create=True, proc_mounts=proc_mounts) self.assertFalse(success)
def testImagePresentOnlyVgSetup(self): # Mount an image that is present, attached to a loopback device, and has a # VG, but doesn't have anything else set up. This can't arise in normal # usage, but could happen if cros_sdk crashes in the middle of setup. # Should call losetup, vgs, vgchange, lvs, lvcreate, mke2fs, mount self._makeImageFile(self.chroot_img) m = self._mockFindVolumeGroupForDevice() m2 = self._mockDeviceFromFile('/dev/loop0') with cros_test_lib.RunCommandMock() as rc_mock: rc_mock.AddCmdResult(self._VGS_LOOKUP, returncode=self._LVM_SUCCESS_CODE) rc_mock.AddCmdResult(self._VGCHANGE) rc_mock.AddCmdResult(self._LVS_LOOKUP, returncode=self._LVM_FAILURE_CODE) rc_mock.AddCmdResult(self._LVCREATE) rc_mock.AddCmdResult(self._MKE2FS) rc_mock.AddCmdResult(self._MOUNT) success = cros_sdk_lib.MountChroot(self.chroot_path) self.assertTrue(success) m.assert_called_with(self.chroot_path, '/dev/loop0') m2.assert_called_with(self.chroot_img)
def testImagePresentNotSetup(self): # Mount an image that is present but doesn't have anything set up. This # can't arise in normal usage, but could happen if cros_sdk crashes in the # middle of setup. # Should call losetup -j, losetup -f, vgs, vgcreate, lvs, lvcreate, mke2fs, # mount self._makeImageFile(self.chroot_img) m = self._mockFindVolumeGroupForDevice() m2 = self._mockAttachDeviceToFile() m3 = self._mockDeviceFromFile('') with cros_test_lib.RunCommandMock() as rc_mock: rc_mock.AddCmdResult(self._VGS_LOOKUP, returncode=self._LVM_FAILURE_CODE) rc_mock.AddCmdResult(self._VGCREATE) rc_mock.AddCmdResult(self._LVS_LOOKUP, returncode=self._LVM_FAILURE_CODE) rc_mock.AddCmdResult(self._LVCREATE) rc_mock.AddCmdResult(self._MKE2FS) rc_mock.AddCmdResult(self._MOUNT) success = cros_sdk_lib.MountChroot(self.chroot_path) self.assertTrue(success) m.assert_called_with(self.chroot_path, '/dev/loop0') m2.assert_called_with(self.chroot_img) m3.assert_called_with(self.chroot_img)
def testEmptyChroot(self): # Chroot mounted from proper image but without the version file present, # e.g. if cros_sdk fails in the middle of populating the chroot. # Should return True without running any commands. proc_mounts = os.path.join(self.tempdir, 'proc_mounts') with open(proc_mounts, 'w') as f: f.write('/dev/mapper/cros_test_000-chroot %s ext4 rw 0 0\n' % self.chroot_path) success = cros_sdk_lib.MountChroot(self.chroot_path, create=False, proc_mounts=proc_mounts) self.assertTrue(success) success = cros_sdk_lib.MountChroot(self.chroot_path, create=True, proc_mounts=proc_mounts) self.assertTrue(success)
def setUp(self): with sudo.SudoKeepAlive(): # Create just enough of a chroot to fool cros_sdk into accepting it. self.chroot = os.path.join(self.tempdir, 'chroot') cros_sdk_lib.MountChroot(self.chroot, create=True) logging.debug('Chroot mounted on %s', self.chroot) chroot_etc = os.path.join(self.chroot, 'etc') osutils.SafeMakedirsNonRoot(chroot_etc) self.chroot_version_file = os.path.join(chroot_etc, 'cros_chroot_version') osutils.Touch(self.chroot_version_file, makedirs=True)
def testRestoreSnapshot(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) code, _ = self._crosSdk(['--snapshot-restore', 'test']) self.assertEqual(code, 0) self.assertTrue(cros_sdk_lib.MountChroot(self.chroot, create=False)) self.assertExists(test_file) code, output = self._crosSdk(['--snapshot-list']) self.assertEqual(code, 0) self.assertEqual(output, '')
def testFromScratch(self): # Create the whole setup from nothing. # Should call losetup, vgs, vgcreate, lvs, lvcreate, mke2fs, mount m = self._mockFindVolumeGroupForDevice() m2 = self._mockAttachDeviceToFile() with cros_test_lib.RunCommandMock() as rc_mock: rc_mock.AddCmdResult(self._VGS_LOOKUP, returncode=self._LVM_FAILURE_CODE) rc_mock.AddCmdResult(self._VGCREATE, output='') rc_mock.AddCmdResult(self._LVS_LOOKUP, returncode=self._LVM_FAILURE_CODE) rc_mock.AddCmdResult(self._LVCREATE) rc_mock.AddCmdResult(self._MKE2FS) rc_mock.AddCmdResult(self._MOUNT) success = cros_sdk_lib.MountChroot(self.chroot_path) self.assertTrue(success) m.assert_called_with(self.chroot_path, '/dev/loop0') m2.assert_called_with(self.chroot_img)
def Run(self): """Perfrom the cros flash command.""" self.options.Freeze() if (self.options.device.scheme == commandline.DEVICE_SCHEME_SSH and not cros_build_lib.IsInsideChroot()): chroot_dir = os.path.join(constants.SOURCE_ROOT, constants.DEFAULT_CHROOT_DIR) if not cros_sdk_lib.MountChroot(chroot=chroot_dir, create=False): raise Exception('Unable to find chroot.') try: flash.Flash( self.options.device, self.options.image, board=self.options.board, install=self.options.install, src_image_to_delta=self.options.src_image_to_delta, rootfs_update=self.options.rootfs_update, stateful_update=self.options.stateful_update, clobber_stateful=self.options.clobber_stateful, reboot=self.options.reboot, wipe=self.options.wipe, ssh_private_key=self.options.private_key, ping=self.options.ping, disable_rootfs_verification=self.options.disable_rootfs_verification, clear_cache=self.options.clear_cache, yes=self.options.yes, force=self.options.force, debug=self.options.debug, send_payload_in_parallel=self.options.send_payload_in_parallel, experimental_au=self.options.experimental_au) logging.notice('cros flash completed successfully.') except dev_server_wrapper.ImagePathError: logging.error('To get the latest remote image, please run:\n' 'cros flash --board=%s %s remote/latest', self.options.board, self.options.device.raw) raise
def testMissingMount(self): # Re-mount an image that has a loopback and VG active but isn't mounted. # This can happen if the person unmounts the chroot or calls # osutils.UmountTree() on the path. # Should call losetup, vgchange, lvs, mount self._makeImageFile(self.chroot_img) m = self._mockFindVolumeGroupForDevice() m2 = self._mockDeviceFromFile('/dev/loop1') with cros_test_lib.RunCommandMock() as rc_mock: rc_mock.AddCmdResult(self._VGS_LOOKUP, returncode=self._LVM_SUCCESS_CODE) rc_mock.AddCmdResult(self._VGCHANGE) rc_mock.AddCmdResult(self._LVS_LOOKUP, returncode=self._LVM_SUCCESS_CODE) rc_mock.AddCmdResult(self._MOUNT) success = cros_sdk_lib.MountChroot(self.chroot_path) self.assertTrue(success) m.assert_called_with(self.chroot_path, '/dev/loop1') m2.assert_called_with(self.chroot_img)
def testImageAfterReboot(self): # Re-mount an image that has everything setup, but doesn't have anything # attached, e.g. after reboot. # Should call losetup -j, losetup -f, vgs, vgchange, lvs, lvchange, mount self._makeImageFile(self.chroot_img) m = self._mockFindVolumeGroupForDevice() m2 = self._mockDeviceFromFile('') m3 = self._mockAttachDeviceToFile('loop1') with cros_test_lib.RunCommandMock() as rc_mock: rc_mock.AddCmdResult(self._VGS_LOOKUP, returncode=self._LVM_SUCCESS_CODE) rc_mock.AddCmdResult(self._VGCHANGE) rc_mock.AddCmdResult(self._LVS_LOOKUP, returncode=self._LVM_SUCCESS_CODE) rc_mock.AddCmdResult(self._MOUNT) success = cros_sdk_lib.MountChroot(self.chroot_path) self.assertTrue(success) m.assert_called_with(self.chroot_path, '/dev/loop1') m2.assert_called_with(self.chroot_img) m3.assert_called_with(self.chroot_img)
def testMissingNoCreate(self): # Chroot image isn't present, but create is False. # Should return False without running any commands. success = cros_sdk_lib.MountChroot(self.chroot_path, create=False) self.assertFalse(success)
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 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)