blob: 0e0fb71f9999aeec5d4dc9f2f41e720a50fb44b7 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Mike Frysinger2de7f042012-07-10 04:45:03 -04002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Brian Harringb938c782012-02-29 15:14:38 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
Manoj Gupta7fad04d2019-06-14 20:12:25 -07005
Mike Frysinger2f95cfc2015-06-04 04:00:26 -04006"""Manage SDK chroots.
7
8This script is used for manipulating local chroot environments; creating,
9deleting, downloading, etc. If given --enter (or no args), it defaults
10to an interactive bash shell within the chroot.
11
12If given args those are passed to the chroot environment, and executed.
13"""
Brian Harringb938c782012-02-29 15:14:38 -080014
Mike Frysinger383367e2014-09-16 15:06:17 -040015from __future__ import print_function
16
Mike Frysinger2f95cfc2015-06-04 04:00:26 -040017import argparse
Josh Triplett472a4182013-03-08 11:48:57 -080018import glob
Brian Harringb938c782012-02-29 15:14:38 -080019import os
Josh Triplett472a4182013-03-08 11:48:57 -080020import pwd
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060021import random
Brian Norrisd37e2f72016-08-22 16:09:24 -070022import re
Ting-Yuan Huangf56d9af2017-06-19 16:08:32 -070023import resource
David James56e6c2c2012-10-24 23:54:41 -070024import sys
Mike Frysinger3dcacee2019-08-23 17:09:11 -040025
26from six.moves import urllib
Brian Harringb938c782012-02-29 15:14:38 -080027
Aviv Keshetb7519e12016-10-04 00:50:00 -070028from chromite.lib import constants
Brian Harringcfe762a2012-02-29 13:03:53 -080029from chromite.lib import cgroups
Brian Harringb6cf9142012-09-01 20:43:17 -070030from chromite.lib import commandline
Brian Harringb938c782012-02-29 15:14:38 -080031from chromite.lib import cros_build_lib
Ralph Nathan59900422015-03-24 10:41:17 -070032from chromite.lib import cros_logging as logging
Benjamin Gordon74645232018-05-04 17:40:42 -060033from chromite.lib import cros_sdk_lib
Brian Harringb938c782012-02-29 15:14:38 -080034from chromite.lib import locking
Josh Triplette759b232013-03-08 13:03:43 -080035from chromite.lib import namespaces
Brian Harringae0a5322012-09-15 01:46:51 -070036from chromite.lib import osutils
Yong Hong84ba9172018-02-07 01:37:42 +080037from chromite.lib import path_util
Mike Frysingere2d8f0d2014-11-01 13:09:26 -040038from chromite.lib import process_util
David Jamesc93e6a4d2014-01-13 11:37:36 -080039from chromite.lib import retry_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050040from chromite.lib import toolchain
Mike Frysingere652ba12019-09-08 00:57:43 -040041from chromite.utils import key_value_store
42
Brian Harringb938c782012-02-29 15:14:38 -080043
44cros_build_lib.STRICT_SUDO = True
45
Zdenek Behanaa52cea2012-05-30 01:31:11 +020046COMPRESSION_PREFERENCE = ('xz', 'bz2')
Zdenek Behanfd0efe42012-04-13 04:36:40 +020047
Brian Harringb938c782012-02-29 15:14:38 -080048# TODO(zbehan): Remove the dependency on these, reimplement them in python
Manoj Guptab12f7302019-06-03 16:40:14 -070049MAKE_CHROOT = [
50 os.path.join(constants.SOURCE_ROOT, 'src/scripts/sdk_lib/make_chroot.sh')
51]
52ENTER_CHROOT = [
53 os.path.join(constants.SOURCE_ROOT, 'src/scripts/sdk_lib/enter_chroot.sh')
54]
Brian Harringb938c782012-02-29 15:14:38 -080055
Josh Triplett472a4182013-03-08 11:48:57 -080056# Proxy simulator configuration.
57PROXY_HOST_IP = '192.168.240.1'
58PROXY_PORT = 8080
59PROXY_GUEST_IP = '192.168.240.2'
60PROXY_NETMASK = 30
61PROXY_VETH_PREFIX = 'veth'
62PROXY_CONNECT_PORTS = (80, 443, 9418)
63PROXY_APACHE_FALLBACK_USERS = ('www-data', 'apache', 'nobody')
64PROXY_APACHE_MPMS = ('event', 'worker', 'prefork')
65PROXY_APACHE_FALLBACK_PATH = ':'.join(
Manoj Guptab12f7302019-06-03 16:40:14 -070066 '/usr/lib/apache2/mpm-%s' % mpm for mpm in PROXY_APACHE_MPMS)
Josh Triplett472a4182013-03-08 11:48:57 -080067PROXY_APACHE_MODULE_GLOBS = ('/usr/lib*/apache2/modules', '/usr/lib*/apache2')
68
Josh Triplett9a495f62013-03-15 18:06:55 -070069# We need these tools to run. Very common tools (tar,..) are omitted.
Josh Triplette759b232013-03-08 13:03:43 -080070NEEDED_TOOLS = ('curl', 'xz')
Brian Harringb938c782012-02-29 15:14:38 -080071
Josh Triplett472a4182013-03-08 11:48:57 -080072# Tools needed for --proxy-sim only.
73PROXY_NEEDED_TOOLS = ('ip',)
Brian Harringb938c782012-02-29 15:14:38 -080074
Benjamin Gordon386b9eb2017-07-20 09:21:33 -060075# Tools needed when use_image is true (the default).
76IMAGE_NEEDED_TOOLS = ('losetup', 'lvchange', 'lvcreate', 'lvs', 'mke2fs',
Benjamin Gordoncfa9c162017-08-03 13:49:29 -060077 'pvscan', 'thin_check', 'vgchange', 'vgcreate', 'vgs')
Benjamin Gordon386b9eb2017-07-20 09:21:33 -060078
Benjamin Gordone3d5bd12017-11-16 15:42:28 -070079# As space is used inside the chroot, the empty space in chroot.img is
80# allocated. Deleting files inside the chroot doesn't automatically return the
81# used space to the OS. Over time, this tends to make the sparse chroot.img
82# less sparse even if the chroot contents don't currently need much space. We
83# can recover most of this unused space with fstrim, but that takes too much
84# time to run it every time. Instead, check the used space against the image
85# size after mounting the chroot and only call fstrim if it looks like we could
86# recover at least this many GiB.
87MAX_UNUSED_IMAGE_GBS = 20
88
Mike Frysingercc838832014-05-24 13:10:30 -040089
Brian Harring1790ac42012-09-23 08:53:33 -070090def GetArchStageTarballs(version):
Brian Harringb938c782012-02-29 15:14:38 -080091 """Returns the URL for a given arch/version"""
Manoj Guptab12f7302019-06-03 16:40:14 -070092 extension = {'bz2': 'tbz2', 'xz': 'tar.xz'}
93 return [
94 toolchain.GetSdkURL(
95 suburl='cros-sdk-%s.%s' % (version, extension[compressor]))
96 for compressor in COMPRESSION_PREFERENCE
97 ]
Brian Harring1790ac42012-09-23 08:53:33 -070098
99
Mike Frysingerdaf57b82019-11-23 17:26:51 -0500100def FetchRemoteTarballs(storage_dir, urls, desc):
Mike Frysinger34db8692013-11-11 14:54:08 -0500101 """Fetches a tarball given by url, and place it in |storage_dir|.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200102
103 Args:
Mike Frysinger34db8692013-11-11 14:54:08 -0500104 storage_dir: Path where to save the tarball.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200105 urls: List of URLs to try to download. Download will stop on first success.
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700106 desc: A string describing what tarball we're downloading (for logging).
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200107
108 Returns:
Mike Frysingerdaf57b82019-11-23 17:26:51 -0500109 Full path to the downloaded file.
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700110
111 Raises:
Mike Frysingerdaf57b82019-11-23 17:26:51 -0500112 ValueError: None of the URLs worked.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200113 """
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200114
Brian Harring1790ac42012-09-23 08:53:33 -0700115 # Note we track content length ourselves since certain versions of curl
116 # fail if asked to resume a complete file.
Brian Harring1790ac42012-09-23 08:53:33 -0700117 # https://sourceforge.net/tracker/?func=detail&atid=100976&aid=3482927&group_id=976
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700118 logging.notice('Downloading %s tarball...', desc)
Mike Frysingerdaf57b82019-11-23 17:26:51 -0500119 status_re = re.compile(br'^HTTP/[0-9]+(\.[0-9]+)? 200')
Mike Frysinger27e21b72018-07-12 14:20:21 -0400120 # pylint: disable=undefined-loop-variable
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200121 for url in urls:
Mike Frysinger3dcacee2019-08-23 17:09:11 -0400122 parsed = urllib.parse.urlparse(url)
Brian Harring1790ac42012-09-23 08:53:33 -0700123 tarball_name = os.path.basename(parsed.path)
124 if parsed.scheme in ('', 'file'):
125 if os.path.exists(parsed.path):
126 return parsed.path
127 continue
128 content_length = 0
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700129 logging.debug('Attempting download from %s', url)
Manoj Guptab12f7302019-06-03 16:40:14 -0700130 result = retry_util.RunCurl(['-I', url],
131 print_cmd=False,
132 debug_level=logging.NOTICE,
133 capture_output=True)
Brian Harring1790ac42012-09-23 08:53:33 -0700134 successful = False
135 for header in result.output.splitlines():
Brian Norrisd37e2f72016-08-22 16:09:24 -0700136 # We must walk the output to find the 200 code for use cases where
Brian Harring1790ac42012-09-23 08:53:33 -0700137 # a proxy is involved and may have pushed down the actual header.
Brian Norrisd37e2f72016-08-22 16:09:24 -0700138 if status_re.match(header):
Brian Harring1790ac42012-09-23 08:53:33 -0700139 successful = True
Mike Frysingerdaf57b82019-11-23 17:26:51 -0500140 elif header.lower().startswith(b'content-length:'):
141 content_length = int(header.split(b':', 1)[-1].strip())
Brian Harring1790ac42012-09-23 08:53:33 -0700142 if successful:
143 break
144 if successful:
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200145 break
146 else:
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700147 raise ValueError('No valid URLs found!')
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200148
Brian Harringae0a5322012-09-15 01:46:51 -0700149 tarball_dest = os.path.join(storage_dir, tarball_name)
Brian Harring1790ac42012-09-23 08:53:33 -0700150 current_size = 0
151 if os.path.exists(tarball_dest):
152 current_size = os.path.getsize(tarball_dest)
153 if current_size > content_length:
David James56e6c2c2012-10-24 23:54:41 -0700154 osutils.SafeUnlink(tarball_dest)
Brian Harring1790ac42012-09-23 08:53:33 -0700155 current_size = 0
Zdenek Behanb2fa72e2012-03-16 04:49:30 +0100156
Brian Harring1790ac42012-09-23 08:53:33 -0700157 if current_size < content_length:
David Jamesc93e6a4d2014-01-13 11:37:36 -0800158 retry_util.RunCurl(
Hidehiko Abee55af7f2017-05-01 18:38:04 +0900159 ['--fail', '-L', '-y', '30', '-C', '-', '--output', tarball_dest, url],
Manoj Guptab12f7302019-06-03 16:40:14 -0700160 print_cmd=False,
161 debug_level=logging.NOTICE)
Brian Harringb938c782012-02-29 15:14:38 -0800162
Brian Harring1790ac42012-09-23 08:53:33 -0700163 # Cleanup old tarballs now since we've successfull fetched; only cleanup
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700164 # the tarballs for our prefix, or unknown ones. This gets a bit tricky
165 # because we might have partial overlap between known prefixes.
166 my_prefix = tarball_name.rsplit('-', 1)[0] + '-'
167 all_prefixes = ('stage3-amd64-', 'cros-sdk-', 'cros-sdk-overlay-')
168 ignored_prefixes = [prefix for prefix in all_prefixes if prefix != my_prefix]
Brian Harring1790ac42012-09-23 08:53:33 -0700169 for filename in os.listdir(storage_dir):
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700170 if (filename == tarball_name or
171 any([(filename.startswith(p) and
172 not (len(my_prefix) > len(p) and filename.startswith(my_prefix)))
173 for p in ignored_prefixes])):
Brian Harring1790ac42012-09-23 08:53:33 -0700174 continue
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700175 logging.info('Cleaning up old tarball: %s', filename)
David James56e6c2c2012-10-24 23:54:41 -0700176 osutils.SafeUnlink(os.path.join(storage_dir, filename))
Zdenek Behan9c644dd2012-04-05 06:24:02 +0200177
Brian Harringb938c782012-02-29 15:14:38 -0800178 return tarball_dest
179
180
Benjamin Gordon589873b2018-05-31 14:30:56 -0600181def CreateChroot(chroot_path, sdk_tarball, cache_dir, nousepkg=False):
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600182 """Creates a new chroot from a given SDK.
183
184 Args:
185 chroot_path: Path where the new chroot will be created.
186 sdk_tarball: Path to a downloaded Gentoo Stage3 or Chromium OS SDK tarball.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600187 cache_dir: Path to a directory that will be used for caching portage files,
188 etc.
189 nousepkg: If True, pass --nousepkg to cros_setup_toolchains inside the
190 chroot.
191 """
Brian Harringb938c782012-02-29 15:14:38 -0800192
Manoj Guptab12f7302019-06-03 16:40:14 -0700193 cmd = MAKE_CHROOT + [
194 '--stage3_path', sdk_tarball, '--chroot', chroot_path, '--cache_dir',
195 cache_dir
196 ]
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700197
Mike Frysinger2de7f042012-07-10 04:45:03 -0400198 if nousepkg:
199 cmd.append('--nousepkg')
Brian Harringb938c782012-02-29 15:14:38 -0800200
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700201 logging.notice('Creating chroot. This may take a few minutes...')
Brian Harringb938c782012-02-29 15:14:38 -0800202 try:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500203 cros_build_lib.dbg_run(cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800204 except cros_build_lib.RunCommandError:
Brian Harring98b54902012-03-23 04:05:42 -0700205 raise SystemExit('Running %r failed!' % cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800206
207
208def DeleteChroot(chroot_path):
209 """Deletes an existing chroot"""
Manoj Guptab12f7302019-06-03 16:40:14 -0700210 cmd = MAKE_CHROOT + ['--chroot', chroot_path, '--delete']
Brian Harringb938c782012-02-29 15:14:38 -0800211 try:
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700212 logging.notice('Deleting chroot.')
Mike Frysinger3e8de442020-02-14 16:46:28 -0500213 cros_build_lib.dbg_run(cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800214 except cros_build_lib.RunCommandError:
Brian Harring98b54902012-03-23 04:05:42 -0700215 raise SystemExit('Running %r failed!' % cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800216
217
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600218def CleanupChroot(chroot_path):
219 """Unmounts a chroot and cleans up any associated devices."""
Don Garrett36650112018-06-28 15:54:34 -0700220 cros_sdk_lib.CleanupChrootMount(chroot_path, delete=False)
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600221
222
Brian Harringae0a5322012-09-15 01:46:51 -0700223def EnterChroot(chroot_path, cache_dir, chrome_root, chrome_root_mount,
Mike Frysinger0b2d9ee2019-02-28 17:05:47 -0500224 goma_dir, goma_client_json, working_dir, additional_args):
Brian Harringb938c782012-02-29 15:14:38 -0800225 """Enters an existing SDK chroot"""
Mike Frysingere5456972013-06-13 00:07:23 -0400226 st = os.statvfs(os.path.join(chroot_path, 'usr', 'bin', 'sudo'))
227 # The os.ST_NOSUID constant wasn't added until python-3.2.
228 if st.f_flag & 0x2:
229 cros_build_lib.Die('chroot cannot be in a nosuid mount')
230
Brian Harringae0a5322012-09-15 01:46:51 -0700231 cmd = ENTER_CHROOT + ['--chroot', chroot_path, '--cache_dir', cache_dir]
Brian Harringb938c782012-02-29 15:14:38 -0800232 if chrome_root:
233 cmd.extend(['--chrome_root', chrome_root])
234 if chrome_root_mount:
235 cmd.extend(['--chrome_root_mount', chrome_root_mount])
Hidehiko Abeb5daf2f2017-03-02 17:57:43 +0900236 if goma_dir:
237 cmd.extend(['--goma_dir', goma_dir])
238 if goma_client_json:
239 cmd.extend(['--goma_client_json', goma_client_json])
Yong Hong84ba9172018-02-07 01:37:42 +0800240 if working_dir is not None:
241 cmd.extend(['--working_dir', working_dir])
Don Garrett230d1b22015-03-09 16:21:19 -0700242
Mike Frysinger53ffaae2019-08-27 16:30:27 -0400243 if additional_args:
Brian Harringb938c782012-02-29 15:14:38 -0800244 cmd.append('--')
245 cmd.extend(additional_args)
Brian Harring7199e7d2012-03-23 04:10:08 -0700246
Ting-Yuan Huangf56d9af2017-06-19 16:08:32 -0700247 # ThinLTO opens lots of files at the same time.
248 resource.setrlimit(resource.RLIMIT_NOFILE, (32768, 32768))
Mike Frysinger3e8de442020-02-14 16:46:28 -0500249 ret = cros_build_lib.dbg_run(cmd, check=False, mute_output=False)
Brian Harring7199e7d2012-03-23 04:10:08 -0700250 # If we were in interactive mode, ignore the exit code; it'll be whatever
251 # they last ran w/in the chroot and won't matter to us one way or another.
252 # Note this does allow chroot entrance to fail and be ignored during
253 # interactive; this is however a rare case and the user will immediately
254 # see it (nor will they be checking the exit code manually).
255 if ret.returncode != 0 and additional_args:
Richard Barnette5c728a42015-03-18 11:50:21 -0700256 raise SystemExit(ret.returncode)
Brian Harringb938c782012-02-29 15:14:38 -0800257
258
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600259def _ImageFileForChroot(chroot):
260 """Find the image file that should be associated with |chroot|.
261
262 This function does not check if the image exists; it simply returns the
263 filename that would be used.
264
265 Args:
266 chroot: Path to the chroot.
267
268 Returns:
269 Path to an image file that would be associated with chroot.
270 """
271 return chroot.rstrip('/') + '.img'
272
273
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600274def CreateChrootSnapshot(snapshot_name, chroot_vg, chroot_lv):
275 """Create a snapshot for the specified chroot VG/LV.
276
277 Args:
278 snapshot_name: The name of the new snapshot.
279 chroot_vg: The name of the VG containing the origin LV.
280 chroot_lv: The name of the origin LV.
281
282 Returns:
283 True if the snapshot was created, or False if a snapshot with the same
284 name already exists.
285
286 Raises:
287 SystemExit: The lvcreate command failed.
288 """
289 if snapshot_name in ListChrootSnapshots(chroot_vg, chroot_lv):
Manoj Guptab12f7302019-06-03 16:40:14 -0700290 logging.error(
291 'Cannot create snapshot %s: A volume with that name already '
292 'exists.', snapshot_name)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600293 return False
294
Manoj Guptab12f7302019-06-03 16:40:14 -0700295 cmd = [
296 'lvcreate', '-s', '--name', snapshot_name,
297 '%s/%s' % (chroot_vg, chroot_lv)
298 ]
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600299 try:
300 logging.notice('Creating snapshot %s from %s in VG %s.', snapshot_name,
301 chroot_lv, chroot_vg)
Mike Frysinger3e8de442020-02-14 16:46:28 -0500302 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600303 return True
304 except cros_build_lib.RunCommandError:
305 raise SystemExit('Running %r failed!' % cmd)
306
307
308def DeleteChrootSnapshot(snapshot_name, chroot_vg, chroot_lv):
309 """Delete the named snapshot from the specified chroot VG.
310
311 If the requested snapshot is not found, nothing happens. The main chroot LV
312 and internal thinpool LV cannot be deleted with this function.
313
314 Args:
315 snapshot_name: The name of the snapshot to delete.
316 chroot_vg: The name of the VG containing the origin LV.
317 chroot_lv: The name of the origin LV.
318
319 Raises:
320 SystemExit: The lvremove command failed.
321 """
Benjamin Gordon74645232018-05-04 17:40:42 -0600322 if snapshot_name in (cros_sdk_lib.CHROOT_LV_NAME,
323 cros_sdk_lib.CHROOT_THINPOOL_NAME):
Manoj Guptab12f7302019-06-03 16:40:14 -0700324 logging.error(
325 'Cannot remove LV %s as a snapshot. Use cros_sdk --delete '
326 'if you want to remove the whole chroot.', snapshot_name)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600327 return
328
329 if snapshot_name not in ListChrootSnapshots(chroot_vg, chroot_lv):
330 return
331
332 cmd = ['lvremove', '-f', '%s/%s' % (chroot_vg, snapshot_name)]
333 try:
334 logging.notice('Deleting snapshot %s in VG %s.', snapshot_name, chroot_vg)
Mike Frysinger3e8de442020-02-14 16:46:28 -0500335 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600336 except cros_build_lib.RunCommandError:
337 raise SystemExit('Running %r failed!' % cmd)
338
339
340def RestoreChrootSnapshot(snapshot_name, chroot_vg, chroot_lv):
341 """Restore the chroot to an existing snapshot.
342
343 This is done by renaming the original |chroot_lv| LV to a temporary name,
344 renaming the snapshot named |snapshot_name| to |chroot_lv|, and deleting the
345 now unused LV. If an error occurs, attempts to rename the original snapshot
346 back to |chroot_lv| to leave the chroot unchanged.
347
348 The chroot must be unmounted before calling this function, and will be left
349 unmounted after this function returns.
350
351 Args:
352 snapshot_name: The name of the snapshot to restore. This snapshot will no
353 longer be accessible at its original name after this function finishes.
354 chroot_vg: The VG containing the chroot LV and snapshot LV.
355 chroot_lv: The name of the original chroot LV.
356
357 Returns:
358 True if the chroot was restored to the requested snapshot, or False if
359 the snapshot wasn't found or isn't valid.
360
361 Raises:
362 SystemExit: Any of the LVM commands failed.
363 """
364 valid_snapshots = ListChrootSnapshots(chroot_vg, chroot_lv)
Benjamin Gordon74645232018-05-04 17:40:42 -0600365 if (snapshot_name in (cros_sdk_lib.CHROOT_LV_NAME,
366 cros_sdk_lib.CHROOT_THINPOOL_NAME) or
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600367 snapshot_name not in valid_snapshots):
368 logging.error('Chroot cannot be restored to %s. Valid snapshots: %s',
369 snapshot_name, ', '.join(valid_snapshots))
370 return False
371
372 backup_chroot_name = 'chroot-bak-%d' % random.randint(0, 1000)
373 cmd = ['lvrename', chroot_vg, chroot_lv, backup_chroot_name]
374 try:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500375 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600376 except cros_build_lib.RunCommandError:
377 raise SystemExit('Running %r failed!' % cmd)
378
379 cmd = ['lvrename', chroot_vg, snapshot_name, chroot_lv]
380 try:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500381 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600382 except cros_build_lib.RunCommandError:
383 cmd = ['lvrename', chroot_vg, backup_chroot_name, chroot_lv]
384 try:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500385 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600386 except cros_build_lib.RunCommandError:
387 raise SystemExit('Failed to rename %s to chroot and failed to restore '
388 '%s back to chroot. Failed command: %r' %
389 (snapshot_name, backup_chroot_name, cmd))
Manoj Guptab12f7302019-06-03 16:40:14 -0700390 raise SystemExit(
391 'Failed to rename %s to chroot. Original chroot LV has '
392 'been restored. Failed command: %r' % (snapshot_name, cmd))
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600393
394 # Some versions of LVM set snapshots to be skipped at auto-activate time.
395 # Other versions don't have this flag at all. We run lvchange to try
396 # disabling auto-skip and activating the volume, but ignore errors. Versions
397 # that don't have the flag should be auto-activated.
398 chroot_lv_path = '%s/%s' % (chroot_vg, chroot_lv)
399 cmd = ['lvchange', '-kn', chroot_lv_path]
Mike Frysinger45602c72019-09-22 02:15:11 -0400400 cros_build_lib.run(
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500401 cmd, print_cmd=False, capture_output=True, check=False)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600402
403 # Activate the LV in case the lvchange above was needed. Activating an LV
404 # that is already active shouldn't do anything, so this is safe to run even if
405 # the -kn wasn't needed.
406 cmd = ['lvchange', '-ay', chroot_lv_path]
Mike Frysinger3e8de442020-02-14 16:46:28 -0500407 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600408
409 cmd = ['lvremove', '-f', '%s/%s' % (chroot_vg, backup_chroot_name)]
410 try:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500411 cros_build_lib.dbg_run(cmd, capture_output=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600412 except cros_build_lib.RunCommandError:
413 raise SystemExit('Failed to remove backup LV %s/%s. Failed command: %r' %
414 (chroot_vg, backup_chroot_name, cmd))
415
416 return True
417
418
419def ListChrootSnapshots(chroot_vg, chroot_lv):
420 """Return all snapshots in |chroot_vg| regardless of origin volume.
421
422 Args:
423 chroot_vg: The name of the VG containing the chroot.
424 chroot_lv: The name of the chroot LV.
425
426 Returns:
427 A (possibly-empty) list of snapshot LVs found in |chroot_vg|.
428
429 Raises:
430 SystemExit: The lvs command failed.
431 """
432 if not chroot_vg or not chroot_lv:
433 return []
434
Manoj Guptab12f7302019-06-03 16:40:14 -0700435 cmd = [
436 'lvs', '-o', 'lv_name,pool_lv,lv_attr', '-O', 'lv_name', '--noheadings',
437 '--separator', '\t', chroot_vg
438 ]
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600439 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400440 result = cros_build_lib.run(
Mike Frysinger0282d222019-12-17 17:15:48 -0500441 cmd, print_cmd=False, stdout=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600442 except cros_build_lib.RunCommandError:
443 raise SystemExit('Running %r failed!' % cmd)
444
445 # Once the thin origin volume has been deleted, there's no way to tell a
446 # snapshot apart from any other volume. Since this VG is created and managed
447 # by cros_sdk, we'll assume that all volumes that share the same thin pool are
448 # valid snapshots.
449 snapshots = []
450 snapshot_attrs = re.compile(r'^V.....t.{2,}') # Matches a thin volume.
451 for line in result.output.splitlines():
452 lv_name, pool_lv, lv_attr = line.lstrip().split('\t')
Manoj Guptab12f7302019-06-03 16:40:14 -0700453 if (lv_name == chroot_lv or lv_name == cros_sdk_lib.CHROOT_THINPOOL_NAME or
Benjamin Gordon74645232018-05-04 17:40:42 -0600454 pool_lv != cros_sdk_lib.CHROOT_THINPOOL_NAME or
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600455 not snapshot_attrs.match(lv_attr)):
456 continue
457 snapshots.append(lv_name)
458 return snapshots
459
460
David James56e6c2c2012-10-24 23:54:41 -0700461def _SudoCommand():
462 """Get the 'sudo' command, along with all needed environment variables."""
463
David James5a73b4d2013-03-07 10:23:40 -0800464 # Pass in the ENVIRONMENT_WHITELIST and ENV_PASSTHRU variables so that
Mike Frysinger9dabf3d2020-02-14 01:00:08 -0500465 # scripts in the chroot know what variables to pass through. We keep PATH
466 # not for the chroot but for the re-exec & for programs we might run before
467 # we chroot into the SDK. The process that enters the SDK itself will take
468 # care of initializing PATH to the right value then.
David James56e6c2c2012-10-24 23:54:41 -0700469 cmd = ['sudo']
Mike Frysinger9dabf3d2020-02-14 01:00:08 -0500470 for key in (constants.CHROOT_ENVIRONMENT_WHITELIST + constants.ENV_PASSTHRU +
471 ('PATH',)):
David James56e6c2c2012-10-24 23:54:41 -0700472 value = os.environ.get(key)
473 if value is not None:
474 cmd += ['%s=%s' % (key, value)]
475
476 # Pass in the path to the depot_tools so that users can access them from
477 # within the chroot.
Mike Frysinger08e75f12014-08-13 01:30:09 -0400478 cmd += ['DEPOT_TOOLS=%s' % constants.DEPOT_TOOLS_DIR]
Mike Frysinger749251e2014-01-29 05:04:27 -0500479
David James56e6c2c2012-10-24 23:54:41 -0700480 return cmd
481
482
Josh Triplett472a4182013-03-08 11:48:57 -0800483def _ReportMissing(missing):
484 """Report missing utilities, then exit.
485
486 Args:
487 missing: List of missing utilities, as returned by
488 osutils.FindMissingBinaries. If non-empty, will not return.
489 """
490
491 if missing:
492 raise SystemExit(
493 'The tool(s) %s were not found.\n'
494 'Please install the appropriate package in your host.\n'
495 'Example(ubuntu):\n'
Manoj Guptab12f7302019-06-03 16:40:14 -0700496 ' sudo apt-get install <packagename>' % ', '.join(missing))
Josh Triplett472a4182013-03-08 11:48:57 -0800497
498
499def _ProxySimSetup(options):
500 """Set up proxy simulator, and return only in the child environment.
501
502 TODO: Ideally, this should support multiple concurrent invocations of
503 cros_sdk --proxy-sim; currently, such invocations will conflict with each
504 other due to the veth device names and IP addresses. Either this code would
505 need to generate fresh, unused names for all of these before forking, or it
506 would need to support multiple concurrent cros_sdk invocations sharing one
507 proxy and allowing it to exit when unused (without counting on any local
508 service-management infrastructure on the host).
509 """
510
511 may_need_mpm = False
512 apache_bin = osutils.Which('apache2')
513 if apache_bin is None:
514 apache_bin = osutils.Which('apache2', PROXY_APACHE_FALLBACK_PATH)
515 if apache_bin is None:
516 _ReportMissing(('apache2',))
517 else:
518 may_need_mpm = True
519
520 # Module names and .so names included for ease of grepping.
521 apache_modules = [('proxy_module', 'mod_proxy.so'),
522 ('proxy_connect_module', 'mod_proxy_connect.so'),
523 ('proxy_http_module', 'mod_proxy_http.so'),
524 ('proxy_ftp_module', 'mod_proxy_ftp.so')]
525
526 # Find the apache module directory, and make sure it has the modules we need.
527 module_dirs = {}
528 for g in PROXY_APACHE_MODULE_GLOBS:
529 for mod, so in apache_modules:
530 for f in glob.glob(os.path.join(g, so)):
531 module_dirs.setdefault(os.path.dirname(f), []).append(so)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400532 for apache_module_path, modules_found in module_dirs.items():
Josh Triplett472a4182013-03-08 11:48:57 -0800533 if len(modules_found) == len(apache_modules):
534 break
535 else:
536 # Appease cros lint, which doesn't understand that this else block will not
537 # fall through to the subsequent code which relies on apache_module_path.
538 apache_module_path = None
539 raise SystemExit(
540 'Could not find apache module path containing all required modules: %s'
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500541 % ', '.join(so for mod, so in apache_modules))
Josh Triplett472a4182013-03-08 11:48:57 -0800542
543 def check_add_module(name):
544 so = 'mod_%s.so' % name
545 if os.access(os.path.join(apache_module_path, so), os.F_OK):
546 mod = '%s_module' % name
547 apache_modules.append((mod, so))
548 return True
549 return False
550
551 check_add_module('authz_core')
552 if may_need_mpm:
553 for mpm in PROXY_APACHE_MPMS:
554 if check_add_module('mpm_%s' % mpm):
555 break
556
557 veth_host = '%s-host' % PROXY_VETH_PREFIX
558 veth_guest = '%s-guest' % PROXY_VETH_PREFIX
559
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500560 # Set up locks to sync the net namespace setup. We need the child to create
561 # the net ns first, and then have the parent assign the guest end of the veth
562 # interface to the child's new network namespace & bring up the proxy. Only
563 # then can the child move forward and rely on the network being up.
564 ns_create_lock = locking.PipeLock()
565 ns_setup_lock = locking.PipeLock()
Josh Triplett472a4182013-03-08 11:48:57 -0800566
567 pid = os.fork()
568 if not pid:
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500569 # Create our new isolated net namespace.
Josh Triplett472a4182013-03-08 11:48:57 -0800570 namespaces.Unshare(namespaces.CLONE_NEWNET)
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500571
572 # Signal the parent the ns is ready to be configured.
573 ns_create_lock.Post()
574 del ns_create_lock
575
576 # Wait for the parent to finish setting up the ns/proxy.
577 ns_setup_lock.Wait()
578 del ns_setup_lock
Josh Triplett472a4182013-03-08 11:48:57 -0800579
580 # Set up child side of the network.
581 commands = (
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500582 ('ip', 'link', 'set', 'up', 'lo'),
Manoj Guptab12f7302019-06-03 16:40:14 -0700583 ('ip', 'address', 'add', '%s/%u' % (PROXY_GUEST_IP, PROXY_NETMASK),
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500584 'dev', veth_guest),
585 ('ip', 'link', 'set', veth_guest, 'up'),
Josh Triplett472a4182013-03-08 11:48:57 -0800586 )
587 try:
588 for cmd in commands:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500589 cros_build_lib.dbg_run(cmd)
Josh Triplett472a4182013-03-08 11:48:57 -0800590 except cros_build_lib.RunCommandError:
591 raise SystemExit('Running %r failed!' % (cmd,))
592
593 proxy_url = 'http://%s:%u' % (PROXY_HOST_IP, PROXY_PORT)
594 for proto in ('http', 'https', 'ftp'):
595 os.environ[proto + '_proxy'] = proxy_url
596 for v in ('all_proxy', 'RSYNC_PROXY', 'no_proxy'):
597 os.environ.pop(v, None)
598 return
599
Josh Triplett472a4182013-03-08 11:48:57 -0800600 # Set up parent side of the network.
601 uid = int(os.environ.get('SUDO_UID', '0'))
602 gid = int(os.environ.get('SUDO_GID', '0'))
603 if uid == 0 or gid == 0:
604 for username in PROXY_APACHE_FALLBACK_USERS:
605 try:
606 pwnam = pwd.getpwnam(username)
607 uid, gid = pwnam.pw_uid, pwnam.pw_gid
608 break
609 except KeyError:
610 continue
611 if uid == 0 or gid == 0:
612 raise SystemExit('Could not find a non-root user to run Apache as')
613
614 chroot_parent, chroot_base = os.path.split(options.chroot)
615 pid_file = os.path.join(chroot_parent, '.%s-apache-proxy.pid' % chroot_base)
616 log_file = os.path.join(chroot_parent, '.%s-apache-proxy.log' % chroot_base)
617
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500618 # Wait for the child to create the net ns.
619 ns_create_lock.Wait()
620 del ns_create_lock
621
Josh Triplett472a4182013-03-08 11:48:57 -0800622 apache_directives = [
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500623 'User #%u' % uid,
624 'Group #%u' % gid,
625 'PidFile %s' % pid_file,
626 'ErrorLog %s' % log_file,
627 'Listen %s:%u' % (PROXY_HOST_IP, PROXY_PORT),
628 'ServerName %s' % PROXY_HOST_IP,
629 'ProxyRequests On',
Mike Frysinger66ce4132019-07-17 22:52:52 -0400630 'AllowCONNECT %s' % ' '.join(str(x) for x in PROXY_CONNECT_PORTS),
Josh Triplett472a4182013-03-08 11:48:57 -0800631 ] + [
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500632 'LoadModule %s %s' % (mod, os.path.join(apache_module_path, so))
633 for (mod, so) in apache_modules
Josh Triplett472a4182013-03-08 11:48:57 -0800634 ]
635 commands = (
Manoj Guptab12f7302019-06-03 16:40:14 -0700636 ('ip', 'link', 'add', 'name', veth_host, 'type', 'veth', 'peer', 'name',
637 veth_guest),
638 ('ip', 'address', 'add', '%s/%u' % (PROXY_HOST_IP, PROXY_NETMASK), 'dev',
639 veth_host),
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500640 ('ip', 'link', 'set', veth_host, 'up'),
641 ([apache_bin, '-f', '/dev/null'] +
642 [arg for d in apache_directives for arg in ('-C', d)]),
643 ('ip', 'link', 'set', veth_guest, 'netns', str(pid)),
Josh Triplett472a4182013-03-08 11:48:57 -0800644 )
Manoj Guptab12f7302019-06-03 16:40:14 -0700645 cmd = None # Make cros lint happy.
Josh Triplett472a4182013-03-08 11:48:57 -0800646 try:
647 for cmd in commands:
Mike Frysinger3e8de442020-02-14 16:46:28 -0500648 cros_build_lib.dbg_run(cmd)
Josh Triplett472a4182013-03-08 11:48:57 -0800649 except cros_build_lib.RunCommandError:
650 # Clean up existing interfaces, if any.
651 cmd_cleanup = ('ip', 'link', 'del', veth_host)
652 try:
Mike Frysinger45602c72019-09-22 02:15:11 -0400653 cros_build_lib.run(cmd_cleanup, print_cmd=False)
Josh Triplett472a4182013-03-08 11:48:57 -0800654 except cros_build_lib.RunCommandError:
Ralph Nathan59900422015-03-24 10:41:17 -0700655 logging.error('running %r failed', cmd_cleanup)
Josh Triplett472a4182013-03-08 11:48:57 -0800656 raise SystemExit('Running %r failed!' % (cmd,))
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500657
658 # Signal the child that the net ns/proxy is fully configured now.
659 ns_setup_lock.Post()
660 del ns_setup_lock
Josh Triplett472a4182013-03-08 11:48:57 -0800661
Mike Frysingere2d8f0d2014-11-01 13:09:26 -0400662 process_util.ExitAsStatus(os.waitpid(pid, 0)[1])
Josh Triplett472a4182013-03-08 11:48:57 -0800663
664
Mike Frysingera78a56e2012-11-20 06:02:30 -0500665def _ReExecuteIfNeeded(argv):
David James56e6c2c2012-10-24 23:54:41 -0700666 """Re-execute cros_sdk as root.
667
668 Also unshare the mount namespace so as to ensure that processes outside
669 the chroot can't mess with our mounts.
670 """
671 if os.geteuid() != 0:
Mike Frysingera78a56e2012-11-20 06:02:30 -0500672 cmd = _SudoCommand() + ['--'] + argv
Mike Frysinger3e8de442020-02-14 16:46:28 -0500673 logging.debug('Reexecing self via sudo:\n%s', cros_build_lib.CmdToStr(cmd))
Mike Frysingera78a56e2012-11-20 06:02:30 -0500674 os.execvp(cmd[0], cmd)
Mike Frysingera78a56e2012-11-20 06:02:30 -0500675 else:
Mike Frysinger80dfce92014-04-21 10:58:53 -0400676 # We must set up the cgroups mounts before we enter our own namespace.
677 # This way it is a shared resource in the root mount namespace.
Josh Triplette759b232013-03-08 13:03:43 -0800678 cgroups.Cgroup.InitSystem()
David James56e6c2c2012-10-24 23:54:41 -0700679
680
Mike Frysinger34db8692013-11-11 14:54:08 -0500681def _CreateParser(sdk_latest_version, bootstrap_latest_version):
682 """Generate and return the parser with all the options."""
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400683 usage = ('usage: %(prog)s [options] '
684 '[VAR1=val1 ... VAR2=val2] [--] [command [args]]')
Manoj Guptab12f7302019-06-03 16:40:14 -0700685 parser = commandline.ArgumentParser(
686 usage=usage, description=__doc__, caching=True)
Brian Harring218e13c2012-10-10 16:21:26 -0700687
Mike Frysinger34db8692013-11-11 14:54:08 -0500688 # Global options.
Mike Frysinger648ba2d2013-01-08 14:19:34 -0500689 default_chroot = os.path.join(constants.SOURCE_ROOT,
690 constants.DEFAULT_CHROOT_DIR)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400691 parser.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700692 '--chroot',
693 dest='chroot',
694 default=default_chroot,
695 type='path',
Brian Harring218e13c2012-10-10 16:21:26 -0700696 help=('SDK chroot dir name [%s]' % constants.DEFAULT_CHROOT_DIR))
Manoj Guptab12f7302019-06-03 16:40:14 -0700697 parser.add_argument(
698 '--nouse-image',
699 dest='use_image',
700 action='store_false',
701 default=True,
702 help='Do not mount the chroot on a loopback image; '
703 'instead, create it directly in a directory.')
Brian Harringb938c782012-02-29 15:14:38 -0800704
Manoj Guptab12f7302019-06-03 16:40:14 -0700705 parser.add_argument(
Alex Klein5e4b1bc2019-07-02 12:27:06 -0600706 '--chrome-root',
Manoj Guptab12f7302019-06-03 16:40:14 -0700707 '--chrome_root',
708 type='path',
709 help='Mount this chrome root into the SDK chroot')
710 parser.add_argument(
711 '--chrome_root_mount',
712 type='path',
713 help='Mount chrome into this path inside SDK chroot')
714 parser.add_argument(
715 '--nousepkg',
716 action='store_true',
717 default=False,
718 help='Do not use binary packages when creating a chroot.')
719 parser.add_argument(
720 '-u',
721 '--url',
722 dest='sdk_url',
723 help='Use sdk tarball located at this url. Use file:// '
724 'for local files.')
725 parser.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700726 '--sdk-version',
727 help=('Use this sdk version. For prebuilt, current is %r'
728 ', for bootstrapping it is %r.' % (sdk_latest_version,
729 bootstrap_latest_version)))
730 parser.add_argument(
731 '--goma_dir',
732 type='path',
733 help='Goma installed directory to mount into the chroot.')
734 parser.add_argument(
735 '--goma_client_json',
736 type='path',
737 help='Service account json file to use goma on bot. '
738 'Mounted into the chroot.')
Yong Hong84ba9172018-02-07 01:37:42 +0800739
740 # Use type=str instead of type='path' to prevent the given path from being
741 # transfered to absolute path automatically.
Manoj Guptab12f7302019-06-03 16:40:14 -0700742 parser.add_argument(
743 '--working-dir',
744 type=str,
745 help='Run the command in specific working directory in '
746 'chroot. If the given directory is a relative '
747 'path, this program will transfer the path to '
748 'the corresponding one inside chroot.')
Yong Hong84ba9172018-02-07 01:37:42 +0800749
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400750 parser.add_argument('commands', nargs=argparse.REMAINDER)
Mike Frysinger34db8692013-11-11 14:54:08 -0500751
752 # Commands.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400753 group = parser.add_argument_group('Commands')
754 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700755 '--enter',
756 action='store_true',
757 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500758 help='Enter the SDK chroot. Implies --create.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400759 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700760 '--create',
761 action='store_true',
762 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500763 help='Create the chroot only if it does not already exist. '
764 'Implies --download.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400765 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700766 '--bootstrap',
767 action='store_true',
768 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500769 help='Build everything from scratch, including the sdk. '
770 'Use this only if you need to validate a change '
771 'that affects SDK creation itself (toolchain and '
772 'build are typically the only folk who need this). '
773 'Note this will quite heavily slow down the build. '
774 'This option implies --create --nousepkg.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400775 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700776 '-r',
777 '--replace',
778 action='store_true',
779 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500780 help='Replace an existing SDK chroot. Basically an alias '
781 'for --delete --create.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400782 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700783 '--delete',
784 action='store_true',
785 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500786 help='Delete the current SDK chroot if it exists.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400787 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700788 '--unmount',
789 action='store_true',
790 default=False,
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600791 help='Unmount and clean up devices associated with the '
792 'SDK chroot if it exists. This does not delete the '
793 'backing image file, so the same chroot can be later '
794 're-mounted for reuse. To fully delete the chroot, use '
795 '--delete. This is primarily useful for working on '
796 'cros_sdk or the chroot setup; you should not need it '
797 'under normal circumstances.')
798 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700799 '--download',
800 action='store_true',
801 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500802 help='Download the sdk.')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600803 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700804 '--snapshot-create',
805 metavar='SNAPSHOT_NAME',
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600806 help='Create a snapshot of the chroot. Requires that the chroot was '
Manoj Guptab12f7302019-06-03 16:40:14 -0700807 'created without the --nouse-image option.')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600808 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700809 '--snapshot-restore',
810 metavar='SNAPSHOT_NAME',
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600811 help='Restore the chroot to a previously created snapshot.')
812 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700813 '--snapshot-delete',
814 metavar='SNAPSHOT_NAME',
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600815 help='Delete a previously created snapshot. Deleting a snapshot that '
Manoj Guptab12f7302019-06-03 16:40:14 -0700816 'does not exist is not an error.')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600817 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700818 '--snapshot-list',
819 action='store_true',
820 default=False,
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600821 help='List existing snapshots of the chroot and exit.')
Mike Frysinger34db8692013-11-11 14:54:08 -0500822 commands = group
823
Mike Frysinger80dfce92014-04-21 10:58:53 -0400824 # Namespace options.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400825 group = parser.add_argument_group('Namespaces')
Manoj Guptab12f7302019-06-03 16:40:14 -0700826 group.add_argument(
827 '--proxy-sim',
828 action='store_true',
829 default=False,
830 help='Simulate a restrictive network requiring an outbound'
831 ' proxy.')
832 group.add_argument(
833 '--no-ns-pid',
834 dest='ns_pid',
835 default=True,
836 action='store_false',
837 help='Do not create a new PID namespace.')
Mike Frysinger80dfce92014-04-21 10:58:53 -0400838
Mike Frysinger34db8692013-11-11 14:54:08 -0500839 # Internal options.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400840 group = parser.add_argument_group(
Mike Frysinger34db8692013-11-11 14:54:08 -0500841 'Internal Chromium OS Build Team Options',
842 'Caution: these are for meant for the Chromium OS build team only')
Manoj Guptab12f7302019-06-03 16:40:14 -0700843 group.add_argument(
844 '--buildbot-log-version',
845 default=False,
846 action='store_true',
847 help='Log SDK version for buildbot consumption')
Mike Frysinger34db8692013-11-11 14:54:08 -0500848
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400849 return parser, commands
Mike Frysinger34db8692013-11-11 14:54:08 -0500850
851
852def main(argv):
Mike Frysingere652ba12019-09-08 00:57:43 -0400853 conf = key_value_store.LoadFile(
Mike Frysinger34db8692013-11-11 14:54:08 -0500854 os.path.join(constants.SOURCE_ROOT, constants.SDK_VERSION_FILE),
855 ignore_missing=True)
856 sdk_latest_version = conf.get('SDK_LATEST_VERSION', '<unknown>')
Manoj Gupta01927c12019-05-13 17:33:14 -0700857 bootstrap_frozen_version = conf.get('BOOTSTRAP_FROZEN_VERSION', '<unknown>')
Manoj Gupta55a63092019-06-13 11:47:13 -0700858
859 # Use latest SDK for bootstrapping if requested. Use a frozen version of SDK
860 # for bootstrapping if BOOTSTRAP_FROZEN_VERSION is set.
861 bootstrap_latest_version = (
862 sdk_latest_version
863 if bootstrap_frozen_version == '<unknown>' else bootstrap_frozen_version)
Mike Frysinger34db8692013-11-11 14:54:08 -0500864 parser, commands = _CreateParser(sdk_latest_version, bootstrap_latest_version)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400865 options = parser.parse_args(argv)
866 chroot_command = options.commands
Brian Harringb938c782012-02-29 15:14:38 -0800867
868 # Some sanity checks first, before we ask for sudo credentials.
Mike Frysinger8fd67dc2012-12-03 23:51:18 -0500869 cros_build_lib.AssertOutsideChroot()
Brian Harringb938c782012-02-29 15:14:38 -0800870
Brian Harring1790ac42012-09-23 08:53:33 -0700871 host = os.uname()[4]
Brian Harring1790ac42012-09-23 08:53:33 -0700872 if host != 'x86_64':
Benjamin Gordon040a1162017-06-29 13:44:47 -0600873 cros_build_lib.Die(
Brian Harring1790ac42012-09-23 08:53:33 -0700874 "cros_sdk is currently only supported on x86_64; you're running"
Mike Frysinger80de5012019-08-01 14:10:53 -0400875 ' %s. Please find a x86_64 machine.' % (host,))
Brian Harring1790ac42012-09-23 08:53:33 -0700876
Josh Triplett472a4182013-03-08 11:48:57 -0800877 _ReportMissing(osutils.FindMissingBinaries(NEEDED_TOOLS))
878 if options.proxy_sim:
879 _ReportMissing(osutils.FindMissingBinaries(PROXY_NEEDED_TOOLS))
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600880 missing_image_tools = osutils.FindMissingBinaries(IMAGE_NEEDED_TOOLS)
Brian Harringb938c782012-02-29 15:14:38 -0800881
Benjamin Gordon040a1162017-06-29 13:44:47 -0600882 if (sdk_latest_version == '<unknown>' or
883 bootstrap_latest_version == '<unknown>'):
884 cros_build_lib.Die(
885 'No SDK version was found. '
886 'Are you in a Chromium source tree instead of Chromium OS?\n\n'
887 'Please change to a directory inside your Chromium OS source tree\n'
888 'and retry. If you need to setup a Chromium OS source tree, see\n'
Mike Frysingerdcad4e02018-08-03 16:20:02 -0400889 ' https://dev.chromium.org/chromium-os/developer-guide')
Benjamin Gordon040a1162017-06-29 13:44:47 -0600890
Manoj Guptab12f7302019-06-03 16:40:14 -0700891 any_snapshot_operation = (
892 options.snapshot_create or options.snapshot_restore or
893 options.snapshot_delete or options.snapshot_list)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600894 if any_snapshot_operation and not options.use_image:
895 cros_build_lib.Die('Snapshot operations are not compatible with '
896 '--nouse-image.')
897
Manoj Guptab12f7302019-06-03 16:40:14 -0700898 if (options.snapshot_delete and
899 options.snapshot_delete == options.snapshot_restore):
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600900 parser.error('Cannot --snapshot_delete the same snapshot you are '
901 'restoring with --snapshot_restore.')
902
David James471532c2013-01-21 10:23:31 -0800903 _ReExecuteIfNeeded([sys.argv[0]] + argv)
904
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600905 lock_path = os.path.dirname(options.chroot)
906 lock_path = os.path.join(
907 lock_path, '.%s_lock' % os.path.basename(options.chroot).lstrip('.'))
908
Brian Harring218e13c2012-10-10 16:21:26 -0700909 # Expand out the aliases...
910 if options.replace:
911 options.delete = options.create = True
Brian Harringb938c782012-02-29 15:14:38 -0800912
Brian Harring218e13c2012-10-10 16:21:26 -0700913 if options.bootstrap:
914 options.create = True
Brian Harringb938c782012-02-29 15:14:38 -0800915
Brian Harring218e13c2012-10-10 16:21:26 -0700916 # If a command is not given, default to enter.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400917 # pylint: disable=protected-access
918 # This _group_actions access sucks, but upstream decided to not include an
919 # alternative to optparse's option_list, and this is what they recommend.
Manoj Guptab12f7302019-06-03 16:40:14 -0700920 options.enter |= not any(
921 getattr(options, x.dest) for x in commands._group_actions)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400922 # pylint: enable=protected-access
Brian Harring218e13c2012-10-10 16:21:26 -0700923 options.enter |= bool(chroot_command)
924
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600925 if (options.delete and not options.create and
926 (options.enter or any_snapshot_operation)):
Mike Frysinger80de5012019-08-01 14:10:53 -0400927 parser.error('Trying to enter or snapshot the chroot when --delete '
928 'was specified makes no sense.')
Brian Harring218e13c2012-10-10 16:21:26 -0700929
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600930 if (options.unmount and
931 (options.create or options.enter or any_snapshot_operation)):
932 parser.error('--unmount cannot be specified with other chroot actions.')
933
Yong Hong84ba9172018-02-07 01:37:42 +0800934 if options.working_dir is not None and not os.path.isabs(options.working_dir):
935 options.working_dir = path_util.ToChrootPath(options.working_dir)
936
Benjamin Gordon35194f12017-07-19 10:26:22 -0600937 # Discern if we need to create the chroot.
Benjamin Gordon7b44bef2018-06-08 08:13:59 -0600938 chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot)
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600939 if (options.use_image and not chroot_exists and not options.delete and
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600940 not options.unmount and not missing_image_tools and
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600941 os.path.exists(_ImageFileForChroot(options.chroot))):
942 # Try to re-mount an existing image in case the user has rebooted.
943 with cgroups.SimpleContainChildren('cros_sdk'):
944 with locking.FileLock(lock_path, 'chroot lock') as lock:
945 logging.debug('Checking if existing chroot image can be mounted.')
946 lock.write_lock()
Benjamin Gordon74645232018-05-04 17:40:42 -0600947 cros_sdk_lib.MountChroot(options.chroot, create=False)
Benjamin Gordon7b44bef2018-06-08 08:13:59 -0600948 chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot)
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600949 if chroot_exists:
950 logging.notice('Mounted existing image %s on chroot',
951 _ImageFileForChroot(options.chroot))
Brian Harring218e13c2012-10-10 16:21:26 -0700952
953 # Finally, flip create if necessary.
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600954 if options.enter or options.snapshot_create:
Brian Harring218e13c2012-10-10 16:21:26 -0700955 options.create |= not chroot_exists
Brian Harringb938c782012-02-29 15:14:38 -0800956
Benjamin Gordon7b44bef2018-06-08 08:13:59 -0600957 # Make sure we will download if we plan to create.
958 options.download |= options.create
959
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600960 # Anything that needs to manipulate the main chroot mount or communicate with
961 # LVM needs to be done here before we enter the new namespaces.
962
963 # If deleting, do it regardless of the use_image flag so that a
964 # previously-created loopback chroot can also be cleaned up.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600965 # TODO(bmgordon): See if the DeleteChroot call below can be removed in
966 # favor of this block.
967 chroot_deleted = False
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600968 if options.delete:
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600969 with cgroups.SimpleContainChildren('cros_sdk'):
970 with locking.FileLock(lock_path, 'chroot lock') as lock:
971 lock.write_lock()
972 if missing_image_tools:
973 logging.notice('Unmounting chroot.')
974 osutils.UmountTree(options.chroot)
975 else:
976 logging.notice('Deleting chroot.')
Don Garrett36650112018-06-28 15:54:34 -0700977 cros_sdk_lib.CleanupChrootMount(options.chroot, delete=True)
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600978 chroot_deleted = True
979
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600980 # If cleanup was requested, we have to do it while we're still in the original
981 # namespace. Since cleaning up the mount will interfere with any other
982 # commands, we exit here. The check above should have made sure that no other
983 # action was requested, anyway.
984 if options.unmount:
985 with locking.FileLock(lock_path, 'chroot lock') as lock:
986 lock.write_lock()
987 CleanupChroot(options.chroot)
988 sys.exit(0)
989
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600990 # Make sure the main chroot mount is visible. Contents will be filled in
991 # below if needed.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600992 if options.create and options.use_image:
993 if missing_image_tools:
Mike Frysinger80de5012019-08-01 14:10:53 -0400994 raise SystemExit("""The tool(s) %s were not found.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600995Please make sure the lvm2 and thin-provisioning-tools packages
996are installed on your host.
997Example(ubuntu):
998 sudo apt-get install lvm2 thin-provisioning-tools
999
1000If you want to run without lvm2, pass --nouse-image (chroot
Mike Frysinger80de5012019-08-01 14:10:53 -04001001snapshots will be unavailable).""" % ', '.join(missing_image_tools))
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001002
Benjamin Gordonabb3e372017-08-09 10:21:05 -06001003 logging.debug('Making sure chroot image is mounted.')
1004 with cgroups.SimpleContainChildren('cros_sdk'):
1005 with locking.FileLock(lock_path, 'chroot lock') as lock:
1006 lock.write_lock()
Benjamin Gordon74645232018-05-04 17:40:42 -06001007 if not cros_sdk_lib.MountChroot(options.chroot, create=True):
Benjamin Gordonabb3e372017-08-09 10:21:05 -06001008 cros_build_lib.Die('Unable to mount %s on chroot',
1009 _ImageFileForChroot(options.chroot))
1010 logging.notice('Mounted %s on chroot',
1011 _ImageFileForChroot(options.chroot))
Benjamin Gordon386b9eb2017-07-20 09:21:33 -06001012
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001013 # Snapshot operations will always need the VG/LV, but other actions won't.
1014 if any_snapshot_operation:
1015 with cgroups.SimpleContainChildren('cros_sdk'):
1016 with locking.FileLock(lock_path, 'chroot lock') as lock:
Benjamin Gordon74645232018-05-04 17:40:42 -06001017 chroot_vg, chroot_lv = cros_sdk_lib.FindChrootMountSource(
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001018 options.chroot)
1019 if not chroot_vg or not chroot_lv:
1020 cros_build_lib.Die('Unable to find VG/LV for chroot %s',
1021 options.chroot)
1022
1023 # Delete snapshot before creating a new one. This allows the user to
1024 # throw out old state, create a new snapshot, and enter the chroot in a
1025 # single call to cros_sdk. Since restore involves deleting, also do it
1026 # before creating.
1027 if options.snapshot_restore:
1028 lock.write_lock()
1029 valid_snapshots = ListChrootSnapshots(chroot_vg, chroot_lv)
1030 if options.snapshot_restore not in valid_snapshots:
Manoj Guptab12f7302019-06-03 16:40:14 -07001031 cros_build_lib.Die(
1032 '%s is not a valid snapshot to restore to. '
1033 'Valid snapshots: %s', options.snapshot_restore,
1034 ', '.join(valid_snapshots))
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001035 osutils.UmountTree(options.chroot)
1036 if not RestoreChrootSnapshot(options.snapshot_restore, chroot_vg,
1037 chroot_lv):
1038 cros_build_lib.Die('Unable to restore chroot to snapshot.')
Benjamin Gordon74645232018-05-04 17:40:42 -06001039 if not cros_sdk_lib.MountChroot(options.chroot, create=False):
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001040 cros_build_lib.Die('Unable to mount restored snapshot onto chroot.')
1041
1042 # Use a read lock for snapshot delete and create even though they modify
1043 # the filesystem, because they don't modify the mounted chroot itself.
1044 # The underlying LVM commands take their own locks, so conflicting
1045 # concurrent operations here may crash cros_sdk, but won't corrupt the
1046 # chroot image. This tradeoff seems worth it to allow snapshot
1047 # operations on chroots that have a process inside.
1048 if options.snapshot_delete:
1049 lock.read_lock()
1050 DeleteChrootSnapshot(options.snapshot_delete, chroot_vg, chroot_lv)
1051
1052 if options.snapshot_create:
1053 lock.read_lock()
1054 if not CreateChrootSnapshot(options.snapshot_create, chroot_vg,
1055 chroot_lv):
1056 cros_build_lib.Die('Unable to create snapshot.')
1057
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001058 img_path = _ImageFileForChroot(options.chroot)
1059 if (options.use_image and os.path.exists(options.chroot) and
1060 os.path.exists(img_path)):
1061 img_stat = os.stat(img_path)
1062 img_used_bytes = img_stat.st_blocks * 512
1063
1064 mount_stat = os.statvfs(options.chroot)
Manoj Guptab12f7302019-06-03 16:40:14 -07001065 mount_used_bytes = mount_stat.f_frsize * (
1066 mount_stat.f_blocks - mount_stat.f_bfree)
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001067
Mike Frysinger93e8ffa2019-07-03 20:24:18 -04001068 extra_gbs = (img_used_bytes - mount_used_bytes) // 2**30
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001069 if extra_gbs > MAX_UNUSED_IMAGE_GBS:
1070 logging.notice('%s is using %s GiB more than needed. Running '
1071 'fstrim.', img_path, extra_gbs)
1072 cmd = ['fstrim', options.chroot]
1073 try:
Mike Frysinger3e8de442020-02-14 16:46:28 -05001074 cros_build_lib.dbg_run(cmd)
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001075 except cros_build_lib.RunCommandError as e:
Manoj Guptab12f7302019-06-03 16:40:14 -07001076 logging.warning(
1077 'Running fstrim failed. Consider running fstrim on '
1078 'your chroot manually.\nError: %s', e)
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001079
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001080 # Enter a new set of namespaces. Everything after here cannot directly affect
1081 # the hosts's mounts or alter LVM volumes.
Benjamin Gordon386b9eb2017-07-20 09:21:33 -06001082 namespaces.SimpleUnshare()
1083 if options.ns_pid:
1084 first_pid = namespaces.CreatePidNs()
1085 else:
1086 first_pid = None
1087
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001088 if options.snapshot_list:
1089 for snap in ListChrootSnapshots(chroot_vg, chroot_lv):
1090 print(snap)
1091 sys.exit(0)
1092
Brian Harringb938c782012-02-29 15:14:38 -08001093 if not options.sdk_version:
Manoj Guptab12f7302019-06-03 16:40:14 -07001094 sdk_version = (
1095 bootstrap_latest_version if options.bootstrap else sdk_latest_version)
Brian Harringb938c782012-02-29 15:14:38 -08001096 else:
1097 sdk_version = options.sdk_version
Mike Frysinger34db8692013-11-11 14:54:08 -05001098 if options.buildbot_log_version:
Prathmesh Prabhu17f07422015-07-17 11:40:40 -07001099 logging.PrintBuildbotStepText(sdk_version)
Brian Harringb938c782012-02-29 15:14:38 -08001100
Gilad Arnoldecc86fa2015-05-22 12:06:04 -07001101 # Based on selections, determine the tarball to fetch.
Yong Hong4e29b622018-02-05 14:31:10 +08001102 if options.download:
1103 if options.sdk_url:
1104 urls = [options.sdk_url]
Yong Hong4e29b622018-02-05 14:31:10 +08001105 else:
1106 urls = GetArchStageTarballs(sdk_version)
Brian Harring1790ac42012-09-23 08:53:33 -07001107
Mike Frysinger80dfce92014-04-21 10:58:53 -04001108 with cgroups.SimpleContainChildren('cros_sdk', pid=first_pid):
David James56e6c2c2012-10-24 23:54:41 -07001109 with locking.FileLock(lock_path, 'chroot lock') as lock:
Josh Triplett472a4182013-03-08 11:48:57 -08001110 if options.proxy_sim:
1111 _ProxySimSetup(options)
1112
Benjamin Gordonabb3e372017-08-09 10:21:05 -06001113 if (options.delete and not chroot_deleted and
1114 (os.path.exists(options.chroot) or
1115 os.path.exists(_ImageFileForChroot(options.chroot)))):
David James56e6c2c2012-10-24 23:54:41 -07001116 lock.write_lock()
1117 DeleteChroot(options.chroot)
Brian Harringb938c782012-02-29 15:14:38 -08001118
David James56e6c2c2012-10-24 23:54:41 -07001119 sdk_cache = os.path.join(options.cache_dir, 'sdks')
1120 distfiles_cache = os.path.join(options.cache_dir, 'distfiles')
Yu-Ju Hong2c066762013-10-28 14:05:08 -07001121 osutils.SafeMakedirsNonRoot(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -07001122
David James56e6c2c2012-10-24 23:54:41 -07001123 for target in (sdk_cache, distfiles_cache):
Mike Frysinger648ba2d2013-01-08 14:19:34 -05001124 src = os.path.join(constants.SOURCE_ROOT, os.path.basename(target))
David James56e6c2c2012-10-24 23:54:41 -07001125 if not os.path.exists(src):
Prathmesh Prabhu06a50562016-10-22 01:41:44 -07001126 osutils.SafeMakedirsNonRoot(target)
David James56e6c2c2012-10-24 23:54:41 -07001127 continue
1128 lock.write_lock(
Mike Frysinger80de5012019-08-01 14:10:53 -04001129 'Upgrade to %r needed but chroot is locked; please exit '
1130 'all instances so this upgrade can finish.' % src)
David James56e6c2c2012-10-24 23:54:41 -07001131 if not os.path.exists(src):
1132 # Note that while waiting for the write lock, src may've vanished;
1133 # it's a rare race during the upgrade process that's a byproduct
1134 # of us avoiding taking a write lock to do the src check. If we
1135 # took a write lock for that check, it would effectively limit
1136 # all cros_sdk for a chroot to a single instance.
Prathmesh Prabhu06a50562016-10-22 01:41:44 -07001137 osutils.SafeMakedirsNonRoot(target)
David James56e6c2c2012-10-24 23:54:41 -07001138 elif not os.path.exists(target):
1139 # Upgrade occurred, but a reversion, or something whacky
1140 # occurred writing to the old location. Wipe and continue.
1141 os.rename(src, target)
1142 else:
1143 # Upgrade occurred once already, but either a reversion or
1144 # some before/after separate cros_sdk usage is at play.
1145 # Wipe and continue.
1146 osutils.RmDir(src)
Brian Harringae0a5322012-09-15 01:46:51 -07001147
David James56e6c2c2012-10-24 23:54:41 -07001148 if options.download:
1149 lock.write_lock()
Gilad Arnold6a8f0452015-06-04 11:25:18 -07001150 sdk_tarball = FetchRemoteTarballs(
1151 sdk_cache, urls, 'stage3' if options.bootstrap else 'SDK')
Brian Harring218e13c2012-10-10 16:21:26 -07001152
David James56e6c2c2012-10-24 23:54:41 -07001153 if options.create:
1154 lock.write_lock()
Benjamin Gordon7b44bef2018-06-08 08:13:59 -06001155 # Recheck if the chroot is set up here before creating to make sure we
1156 # account for whatever the various delete/unmount/remount steps above
1157 # have done.
1158 if cros_sdk_lib.IsChrootReady(options.chroot):
1159 logging.debug('Chroot already exists. Skipping creation.')
1160 else:
Manoj Guptab12f7302019-06-03 16:40:14 -07001161 CreateChroot(
1162 options.chroot,
1163 sdk_tarball,
1164 options.cache_dir,
1165 nousepkg=(options.bootstrap or options.nousepkg))
Brian Harring1790ac42012-09-23 08:53:33 -07001166
David James56e6c2c2012-10-24 23:54:41 -07001167 if options.enter:
1168 lock.read_lock()
1169 EnterChroot(options.chroot, options.cache_dir, options.chrome_root,
Mike Frysinger0b2d9ee2019-02-28 17:05:47 -05001170 options.chrome_root_mount, options.goma_dir,
1171 options.goma_client_json, options.working_dir,
1172 chroot_command)