blob: 1b192f38a3f423fcd27b54665b6799e7f46cb2b6 [file] [log] [blame]
Mike Frysinger2de7f042012-07-10 04:45:03 -04001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Brian Harringb938c782012-02-29 15:14:38 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Mike Frysinger2f95cfc2015-06-04 04:00:26 -04005"""Manage SDK chroots.
6
7This script is used for manipulating local chroot environments; creating,
8deleting, downloading, etc. If given --enter (or no args), it defaults
9to an interactive bash shell within the chroot.
10
11If given args those are passed to the chroot environment, and executed.
12"""
Brian Harringb938c782012-02-29 15:14:38 -080013
Mike Frysinger383367e2014-09-16 15:06:17 -040014from __future__ import print_function
15
Mike Frysinger2f95cfc2015-06-04 04:00:26 -040016import argparse
Josh Triplett472a4182013-03-08 11:48:57 -080017import glob
Brian Harringb938c782012-02-29 15:14:38 -080018import os
Josh Triplett472a4182013-03-08 11:48:57 -080019import pwd
Brian Norrisd37e2f72016-08-22 16:09:24 -070020import re
Ting-Yuan Huangf56d9af2017-06-19 16:08:32 -070021import resource
David James56e6c2c2012-10-24 23:54:41 -070022import sys
Brian Harringb938c782012-02-29 15:14:38 -080023import urlparse
24
Aviv Keshetb7519e12016-10-04 00:50:00 -070025from chromite.lib import constants
Brian Harringcfe762a2012-02-29 13:03:53 -080026from chromite.lib import cgroups
Brian Harringb6cf9142012-09-01 20:43:17 -070027from chromite.lib import commandline
Brian Harringb938c782012-02-29 15:14:38 -080028from chromite.lib import cros_build_lib
Ralph Nathan59900422015-03-24 10:41:17 -070029from chromite.lib import cros_logging as logging
Brian Harringb938c782012-02-29 15:14:38 -080030from chromite.lib import locking
Josh Triplette759b232013-03-08 13:03:43 -080031from chromite.lib import namespaces
Brian Harringae0a5322012-09-15 01:46:51 -070032from chromite.lib import osutils
Mike Frysingere2d8f0d2014-11-01 13:09:26 -040033from chromite.lib import process_util
David Jamesc93e6a4d2014-01-13 11:37:36 -080034from chromite.lib import retry_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050035from chromite.lib import toolchain
Brian Harringb938c782012-02-29 15:14:38 -080036
37cros_build_lib.STRICT_SUDO = True
38
39
Zdenek Behanaa52cea2012-05-30 01:31:11 +020040COMPRESSION_PREFERENCE = ('xz', 'bz2')
Zdenek Behanfd0efe42012-04-13 04:36:40 +020041
Brian Harringb938c782012-02-29 15:14:38 -080042# TODO(zbehan): Remove the dependency on these, reimplement them in python
Mike Frysinger648ba2d2013-01-08 14:19:34 -050043MAKE_CHROOT = [os.path.join(constants.SOURCE_ROOT,
44 'src/scripts/sdk_lib/make_chroot.sh')]
45ENTER_CHROOT = [os.path.join(constants.SOURCE_ROOT,
46 'src/scripts/sdk_lib/enter_chroot.sh')]
Brian Harringb938c782012-02-29 15:14:38 -080047
Josh Triplett472a4182013-03-08 11:48:57 -080048# Proxy simulator configuration.
49PROXY_HOST_IP = '192.168.240.1'
50PROXY_PORT = 8080
51PROXY_GUEST_IP = '192.168.240.2'
52PROXY_NETMASK = 30
53PROXY_VETH_PREFIX = 'veth'
54PROXY_CONNECT_PORTS = (80, 443, 9418)
55PROXY_APACHE_FALLBACK_USERS = ('www-data', 'apache', 'nobody')
56PROXY_APACHE_MPMS = ('event', 'worker', 'prefork')
57PROXY_APACHE_FALLBACK_PATH = ':'.join(
58 '/usr/lib/apache2/mpm-%s' % mpm for mpm in PROXY_APACHE_MPMS
59)
60PROXY_APACHE_MODULE_GLOBS = ('/usr/lib*/apache2/modules', '/usr/lib*/apache2')
61
Josh Triplett9a495f62013-03-15 18:06:55 -070062# We need these tools to run. Very common tools (tar,..) are omitted.
Josh Triplette759b232013-03-08 13:03:43 -080063NEEDED_TOOLS = ('curl', 'xz')
Brian Harringb938c782012-02-29 15:14:38 -080064
Josh Triplett472a4182013-03-08 11:48:57 -080065# Tools needed for --proxy-sim only.
66PROXY_NEEDED_TOOLS = ('ip',)
Brian Harringb938c782012-02-29 15:14:38 -080067
Benjamin Gordon386b9eb2017-07-20 09:21:33 -060068# Tools needed when use_image is true (the default).
69IMAGE_NEEDED_TOOLS = ('losetup', 'lvchange', 'lvcreate', 'lvs', 'mke2fs',
Benjamin Gordoncfa9c162017-08-03 13:49:29 -060070 'pvscan', 'thin_check', 'vgchange', 'vgcreate', 'vgs')
Benjamin Gordon386b9eb2017-07-20 09:21:33 -060071
Mike Frysingercc838832014-05-24 13:10:30 -040072
Brian Harring1790ac42012-09-23 08:53:33 -070073def GetArchStageTarballs(version):
Brian Harringb938c782012-02-29 15:14:38 -080074 """Returns the URL for a given arch/version"""
Brian Harring1790ac42012-09-23 08:53:33 -070075 extension = {'bz2':'tbz2', 'xz':'tar.xz'}
Mike Frysinger8e727a32013-01-16 16:57:53 -050076 return [toolchain.GetSdkURL(suburl='cros-sdk-%s.%s'
77 % (version, extension[compressor]))
Brian Harring1790ac42012-09-23 08:53:33 -070078 for compressor in COMPRESSION_PREFERENCE]
79
80
81def GetStage3Urls(version):
Mike Frysinger8e727a32013-01-16 16:57:53 -050082 return [toolchain.GetSdkURL(suburl='stage3-amd64-%s.tar.%s' % (version, ext))
Brian Harring1790ac42012-09-23 08:53:33 -070083 for ext in COMPRESSION_PREFERENCE]
Brian Harringb938c782012-02-29 15:14:38 -080084
85
Gilad Arnold6a8f0452015-06-04 11:25:18 -070086def GetToolchainsOverlayUrls(version, toolchains):
87 """Returns the URL(s) for a toolchains SDK overlay.
Gilad Arnoldecc86fa2015-05-22 12:06:04 -070088
89 Args:
90 version: The SDK version used, e.g. 2015.05.27.145939. We use the year and
91 month components to point to a subdirectory on the SDK bucket where
Gilad Arnold6a8f0452015-06-04 11:25:18 -070092 overlays are stored (.../2015/05/ in this case).
93 toolchains: Iterable of toolchain target strings (e.g. 'i686-pc-linux-gnu').
Gilad Arnoldecc86fa2015-05-22 12:06:04 -070094
95 Returns:
Gilad Arnold6a8f0452015-06-04 11:25:18 -070096 List of alternative download URLs for an SDK overlay tarball that contains
97 the given toolchains.
Gilad Arnoldecc86fa2015-05-22 12:06:04 -070098 """
Gilad Arnold6a8f0452015-06-04 11:25:18 -070099 toolchains_desc = '-'.join(sorted(toolchains))
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700100 suburl_template = os.path.join(
101 *(version.split('.')[:2] +
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700102 ['cros-sdk-overlay-toolchains-%s-%s.tar.%%s' %
103 (toolchains_desc, version)]))
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700104 return [toolchain.GetSdkURL(suburl=suburl_template % ext)
105 for ext in COMPRESSION_PREFERENCE]
106
107
108def FetchRemoteTarballs(storage_dir, urls, desc, allow_none=False):
Mike Frysinger34db8692013-11-11 14:54:08 -0500109 """Fetches a tarball given by url, and place it in |storage_dir|.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200110
111 Args:
Mike Frysinger34db8692013-11-11 14:54:08 -0500112 storage_dir: Path where to save the tarball.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200113 urls: List of URLs to try to download. Download will stop on first success.
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700114 desc: A string describing what tarball we're downloading (for logging).
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700115 allow_none: Don't fail if none of the URLs worked.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200116
117 Returns:
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700118 Full path to the downloaded file, or None if |allow_none| and no URL worked.
119
120 Raises:
121 ValueError: If |allow_none| is False and none of the URLs worked.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200122 """
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200123
Brian Harring1790ac42012-09-23 08:53:33 -0700124 # Note we track content length ourselves since certain versions of curl
125 # fail if asked to resume a complete file.
126 # pylint: disable=C0301,W0631
127 # https://sourceforge.net/tracker/?func=detail&atid=100976&aid=3482927&group_id=976
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700128 logging.notice('Downloading %s tarball...', desc)
Brian Norriscf8aef42016-09-27 10:43:39 -0700129 status_re = re.compile(r'^HTTP/[0-9]+(\.[0-9]+)? 200')
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200130 for url in urls:
Brian Harring1790ac42012-09-23 08:53:33 -0700131 # http://www.logilab.org/ticket/8766
132 # pylint: disable=E1101
133 parsed = urlparse.urlparse(url)
134 tarball_name = os.path.basename(parsed.path)
135 if parsed.scheme in ('', 'file'):
136 if os.path.exists(parsed.path):
137 return parsed.path
138 continue
139 content_length = 0
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700140 logging.debug('Attempting download from %s', url)
David Jamesc93e6a4d2014-01-13 11:37:36 -0800141 result = retry_util.RunCurl(
Hidehiko Abee55af7f2017-05-01 18:38:04 +0900142 ['-I', url], print_cmd=False, debug_level=logging.NOTICE,
143 capture_output=True)
Brian Harring1790ac42012-09-23 08:53:33 -0700144 successful = False
145 for header in result.output.splitlines():
Brian Norrisd37e2f72016-08-22 16:09:24 -0700146 # We must walk the output to find the 200 code for use cases where
Brian Harring1790ac42012-09-23 08:53:33 -0700147 # a proxy is involved and may have pushed down the actual header.
Brian Norrisd37e2f72016-08-22 16:09:24 -0700148 if status_re.match(header):
Brian Harring1790ac42012-09-23 08:53:33 -0700149 successful = True
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500150 elif header.lower().startswith('content-length:'):
151 content_length = int(header.split(':', 1)[-1].strip())
Brian Harring1790ac42012-09-23 08:53:33 -0700152 if successful:
153 break
154 if successful:
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200155 break
156 else:
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700157 if allow_none:
158 return None
159 raise ValueError('No valid URLs found!')
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200160
Brian Harringae0a5322012-09-15 01:46:51 -0700161 tarball_dest = os.path.join(storage_dir, tarball_name)
Brian Harring1790ac42012-09-23 08:53:33 -0700162 current_size = 0
163 if os.path.exists(tarball_dest):
164 current_size = os.path.getsize(tarball_dest)
165 if current_size > content_length:
David James56e6c2c2012-10-24 23:54:41 -0700166 osutils.SafeUnlink(tarball_dest)
Brian Harring1790ac42012-09-23 08:53:33 -0700167 current_size = 0
Zdenek Behanb2fa72e2012-03-16 04:49:30 +0100168
Brian Harring1790ac42012-09-23 08:53:33 -0700169 if current_size < content_length:
David Jamesc93e6a4d2014-01-13 11:37:36 -0800170 retry_util.RunCurl(
Hidehiko Abee55af7f2017-05-01 18:38:04 +0900171 ['--fail', '-L', '-y', '30', '-C', '-', '--output', tarball_dest, url],
172 print_cmd=False, debug_level=logging.NOTICE)
Brian Harringb938c782012-02-29 15:14:38 -0800173
Brian Harring1790ac42012-09-23 08:53:33 -0700174 # Cleanup old tarballs now since we've successfull fetched; only cleanup
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700175 # the tarballs for our prefix, or unknown ones. This gets a bit tricky
176 # because we might have partial overlap between known prefixes.
177 my_prefix = tarball_name.rsplit('-', 1)[0] + '-'
178 all_prefixes = ('stage3-amd64-', 'cros-sdk-', 'cros-sdk-overlay-')
179 ignored_prefixes = [prefix for prefix in all_prefixes if prefix != my_prefix]
Brian Harring1790ac42012-09-23 08:53:33 -0700180 for filename in os.listdir(storage_dir):
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700181 if (filename == tarball_name or
182 any([(filename.startswith(p) and
183 not (len(my_prefix) > len(p) and filename.startswith(my_prefix)))
184 for p in ignored_prefixes])):
Brian Harring1790ac42012-09-23 08:53:33 -0700185 continue
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700186 logging.info('Cleaning up old tarball: %s', filename)
David James56e6c2c2012-10-24 23:54:41 -0700187 osutils.SafeUnlink(os.path.join(storage_dir, filename))
Zdenek Behan9c644dd2012-04-05 06:24:02 +0200188
Brian Harringb938c782012-02-29 15:14:38 -0800189 return tarball_dest
190
191
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700192def CreateChroot(chroot_path, sdk_tarball, toolchains_overlay_tarball,
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600193 cache_dir, nousepkg=False):
194 """Creates a new chroot from a given SDK.
195
196 Args:
197 chroot_path: Path where the new chroot will be created.
198 sdk_tarball: Path to a downloaded Gentoo Stage3 or Chromium OS SDK tarball.
199 toolchains_overlay_tarball: Optional path to a second tarball that will be
200 unpacked into the chroot on top of the SDK tarball.
201 cache_dir: Path to a directory that will be used for caching portage files,
202 etc.
203 nousepkg: If True, pass --nousepkg to cros_setup_toolchains inside the
204 chroot.
205 """
Brian Harringb938c782012-02-29 15:14:38 -0800206
Brian Harring1790ac42012-09-23 08:53:33 -0700207 cmd = MAKE_CHROOT + ['--stage3_path', sdk_tarball,
Brian Harringae0a5322012-09-15 01:46:51 -0700208 '--chroot', chroot_path,
209 '--cache_dir', cache_dir]
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700210
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700211 if toolchains_overlay_tarball:
212 cmd.extend(['--toolchains_overlay_path', toolchains_overlay_tarball])
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700213
Mike Frysinger2de7f042012-07-10 04:45:03 -0400214 if nousepkg:
215 cmd.append('--nousepkg')
Brian Harringb938c782012-02-29 15:14:38 -0800216
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700217 logging.notice('Creating chroot. This may take a few minutes...')
Brian Harringb938c782012-02-29 15:14:38 -0800218 try:
219 cros_build_lib.RunCommand(cmd, print_cmd=False)
220 except cros_build_lib.RunCommandError:
Brian Harring98b54902012-03-23 04:05:42 -0700221 raise SystemExit('Running %r failed!' % cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800222
223
224def DeleteChroot(chroot_path):
225 """Deletes an existing chroot"""
226 cmd = MAKE_CHROOT + ['--chroot', chroot_path,
227 '--delete']
228 try:
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700229 logging.notice('Deleting chroot.')
Brian Harringb938c782012-02-29 15:14:38 -0800230 cros_build_lib.RunCommand(cmd, print_cmd=False)
231 except cros_build_lib.RunCommandError:
Brian Harring98b54902012-03-23 04:05:42 -0700232 raise SystemExit('Running %r failed!' % cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800233
234
Brian Harringae0a5322012-09-15 01:46:51 -0700235def EnterChroot(chroot_path, cache_dir, chrome_root, chrome_root_mount,
Hidehiko Abeb5daf2f2017-03-02 17:57:43 +0900236 workspace, goma_dir, goma_client_json, additional_args):
Brian Harringb938c782012-02-29 15:14:38 -0800237 """Enters an existing SDK chroot"""
Mike Frysingere5456972013-06-13 00:07:23 -0400238 st = os.statvfs(os.path.join(chroot_path, 'usr', 'bin', 'sudo'))
239 # The os.ST_NOSUID constant wasn't added until python-3.2.
240 if st.f_flag & 0x2:
241 cros_build_lib.Die('chroot cannot be in a nosuid mount')
242
Brian Harringae0a5322012-09-15 01:46:51 -0700243 cmd = ENTER_CHROOT + ['--chroot', chroot_path, '--cache_dir', cache_dir]
Brian Harringb938c782012-02-29 15:14:38 -0800244 if chrome_root:
245 cmd.extend(['--chrome_root', chrome_root])
246 if chrome_root_mount:
247 cmd.extend(['--chrome_root_mount', chrome_root_mount])
Don Garrett230d1b22015-03-09 16:21:19 -0700248 if workspace:
249 cmd.extend(['--workspace_root', workspace])
Hidehiko Abeb5daf2f2017-03-02 17:57:43 +0900250 if goma_dir:
251 cmd.extend(['--goma_dir', goma_dir])
252 if goma_client_json:
253 cmd.extend(['--goma_client_json', goma_client_json])
Don Garrett230d1b22015-03-09 16:21:19 -0700254
Brian Harringb938c782012-02-29 15:14:38 -0800255 if len(additional_args) > 0:
256 cmd.append('--')
257 cmd.extend(additional_args)
Brian Harring7199e7d2012-03-23 04:10:08 -0700258
Ting-Yuan Huangf56d9af2017-06-19 16:08:32 -0700259 # ThinLTO opens lots of files at the same time.
260 resource.setrlimit(resource.RLIMIT_NOFILE, (32768, 32768))
Ralph Nathan549d3502015-03-26 17:38:42 -0700261 ret = cros_build_lib.RunCommand(cmd, print_cmd=False, error_code_ok=True,
262 mute_output=False)
Brian Harring7199e7d2012-03-23 04:10:08 -0700263 # If we were in interactive mode, ignore the exit code; it'll be whatever
264 # they last ran w/in the chroot and won't matter to us one way or another.
265 # Note this does allow chroot entrance to fail and be ignored during
266 # interactive; this is however a rare case and the user will immediately
267 # see it (nor will they be checking the exit code manually).
268 if ret.returncode != 0 and additional_args:
Richard Barnette5c728a42015-03-18 11:50:21 -0700269 raise SystemExit(ret.returncode)
Brian Harringb938c782012-02-29 15:14:38 -0800270
271
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600272def _ImageFileForChroot(chroot):
273 """Find the image file that should be associated with |chroot|.
274
275 This function does not check if the image exists; it simply returns the
276 filename that would be used.
277
278 Args:
279 chroot: Path to the chroot.
280
281 Returns:
282 Path to an image file that would be associated with chroot.
283 """
284 return chroot.rstrip('/') + '.img'
285
286
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600287def _FindSubmounts(*args):
288 """Find all mounts matching each of the paths in |args| and any submounts.
289
290 Returns:
291 A list of all matching mounts in the order found in /proc/mounts.
292 """
293 mounts = []
294 paths = [p.rstrip('/') for p in args]
295 for mtab in osutils.IterateMountPoints():
296 for path in paths:
297 if mtab.destination == path or mtab.destination.startswith(path + '/'):
298 mounts.append(mtab.destination)
299 break
300
301 return mounts
302
303
David James56e6c2c2012-10-24 23:54:41 -0700304def _SudoCommand():
305 """Get the 'sudo' command, along with all needed environment variables."""
306
David James5a73b4d2013-03-07 10:23:40 -0800307 # Pass in the ENVIRONMENT_WHITELIST and ENV_PASSTHRU variables so that
308 # scripts in the chroot know what variables to pass through.
David James56e6c2c2012-10-24 23:54:41 -0700309 cmd = ['sudo']
David James5a73b4d2013-03-07 10:23:40 -0800310 for key in constants.CHROOT_ENVIRONMENT_WHITELIST + constants.ENV_PASSTHRU:
David James56e6c2c2012-10-24 23:54:41 -0700311 value = os.environ.get(key)
312 if value is not None:
313 cmd += ['%s=%s' % (key, value)]
314
315 # Pass in the path to the depot_tools so that users can access them from
316 # within the chroot.
Mike Frysinger08e75f12014-08-13 01:30:09 -0400317 cmd += ['DEPOT_TOOLS=%s' % constants.DEPOT_TOOLS_DIR]
Mike Frysinger749251e2014-01-29 05:04:27 -0500318
David James56e6c2c2012-10-24 23:54:41 -0700319 return cmd
320
321
Josh Triplett472a4182013-03-08 11:48:57 -0800322def _ReportMissing(missing):
323 """Report missing utilities, then exit.
324
325 Args:
326 missing: List of missing utilities, as returned by
327 osutils.FindMissingBinaries. If non-empty, will not return.
328 """
329
330 if missing:
331 raise SystemExit(
332 'The tool(s) %s were not found.\n'
333 'Please install the appropriate package in your host.\n'
334 'Example(ubuntu):\n'
335 ' sudo apt-get install <packagename>'
336 % ', '.join(missing))
337
338
339def _ProxySimSetup(options):
340 """Set up proxy simulator, and return only in the child environment.
341
342 TODO: Ideally, this should support multiple concurrent invocations of
343 cros_sdk --proxy-sim; currently, such invocations will conflict with each
344 other due to the veth device names and IP addresses. Either this code would
345 need to generate fresh, unused names for all of these before forking, or it
346 would need to support multiple concurrent cros_sdk invocations sharing one
347 proxy and allowing it to exit when unused (without counting on any local
348 service-management infrastructure on the host).
349 """
350
351 may_need_mpm = False
352 apache_bin = osutils.Which('apache2')
353 if apache_bin is None:
354 apache_bin = osutils.Which('apache2', PROXY_APACHE_FALLBACK_PATH)
355 if apache_bin is None:
356 _ReportMissing(('apache2',))
357 else:
358 may_need_mpm = True
359
360 # Module names and .so names included for ease of grepping.
361 apache_modules = [('proxy_module', 'mod_proxy.so'),
362 ('proxy_connect_module', 'mod_proxy_connect.so'),
363 ('proxy_http_module', 'mod_proxy_http.so'),
364 ('proxy_ftp_module', 'mod_proxy_ftp.so')]
365
366 # Find the apache module directory, and make sure it has the modules we need.
367 module_dirs = {}
368 for g in PROXY_APACHE_MODULE_GLOBS:
369 for mod, so in apache_modules:
370 for f in glob.glob(os.path.join(g, so)):
371 module_dirs.setdefault(os.path.dirname(f), []).append(so)
372 for apache_module_path, modules_found in module_dirs.iteritems():
373 if len(modules_found) == len(apache_modules):
374 break
375 else:
376 # Appease cros lint, which doesn't understand that this else block will not
377 # fall through to the subsequent code which relies on apache_module_path.
378 apache_module_path = None
379 raise SystemExit(
380 'Could not find apache module path containing all required modules: %s'
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500381 % ', '.join(so for mod, so in apache_modules))
Josh Triplett472a4182013-03-08 11:48:57 -0800382
383 def check_add_module(name):
384 so = 'mod_%s.so' % name
385 if os.access(os.path.join(apache_module_path, so), os.F_OK):
386 mod = '%s_module' % name
387 apache_modules.append((mod, so))
388 return True
389 return False
390
391 check_add_module('authz_core')
392 if may_need_mpm:
393 for mpm in PROXY_APACHE_MPMS:
394 if check_add_module('mpm_%s' % mpm):
395 break
396
397 veth_host = '%s-host' % PROXY_VETH_PREFIX
398 veth_guest = '%s-guest' % PROXY_VETH_PREFIX
399
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500400 # Set up locks to sync the net namespace setup. We need the child to create
401 # the net ns first, and then have the parent assign the guest end of the veth
402 # interface to the child's new network namespace & bring up the proxy. Only
403 # then can the child move forward and rely on the network being up.
404 ns_create_lock = locking.PipeLock()
405 ns_setup_lock = locking.PipeLock()
Josh Triplett472a4182013-03-08 11:48:57 -0800406
407 pid = os.fork()
408 if not pid:
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500409 # Create our new isolated net namespace.
Josh Triplett472a4182013-03-08 11:48:57 -0800410 namespaces.Unshare(namespaces.CLONE_NEWNET)
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500411
412 # Signal the parent the ns is ready to be configured.
413 ns_create_lock.Post()
414 del ns_create_lock
415
416 # Wait for the parent to finish setting up the ns/proxy.
417 ns_setup_lock.Wait()
418 del ns_setup_lock
Josh Triplett472a4182013-03-08 11:48:57 -0800419
420 # Set up child side of the network.
421 commands = (
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500422 ('ip', 'link', 'set', 'up', 'lo'),
423 ('ip', 'address', 'add',
424 '%s/%u' % (PROXY_GUEST_IP, PROXY_NETMASK),
425 'dev', veth_guest),
426 ('ip', 'link', 'set', veth_guest, 'up'),
Josh Triplett472a4182013-03-08 11:48:57 -0800427 )
428 try:
429 for cmd in commands:
430 cros_build_lib.RunCommand(cmd, print_cmd=False)
431 except cros_build_lib.RunCommandError:
432 raise SystemExit('Running %r failed!' % (cmd,))
433
434 proxy_url = 'http://%s:%u' % (PROXY_HOST_IP, PROXY_PORT)
435 for proto in ('http', 'https', 'ftp'):
436 os.environ[proto + '_proxy'] = proxy_url
437 for v in ('all_proxy', 'RSYNC_PROXY', 'no_proxy'):
438 os.environ.pop(v, None)
439 return
440
Josh Triplett472a4182013-03-08 11:48:57 -0800441 # Set up parent side of the network.
442 uid = int(os.environ.get('SUDO_UID', '0'))
443 gid = int(os.environ.get('SUDO_GID', '0'))
444 if uid == 0 or gid == 0:
445 for username in PROXY_APACHE_FALLBACK_USERS:
446 try:
447 pwnam = pwd.getpwnam(username)
448 uid, gid = pwnam.pw_uid, pwnam.pw_gid
449 break
450 except KeyError:
451 continue
452 if uid == 0 or gid == 0:
453 raise SystemExit('Could not find a non-root user to run Apache as')
454
455 chroot_parent, chroot_base = os.path.split(options.chroot)
456 pid_file = os.path.join(chroot_parent, '.%s-apache-proxy.pid' % chroot_base)
457 log_file = os.path.join(chroot_parent, '.%s-apache-proxy.log' % chroot_base)
458
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500459 # Wait for the child to create the net ns.
460 ns_create_lock.Wait()
461 del ns_create_lock
462
Josh Triplett472a4182013-03-08 11:48:57 -0800463 apache_directives = [
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500464 'User #%u' % uid,
465 'Group #%u' % gid,
466 'PidFile %s' % pid_file,
467 'ErrorLog %s' % log_file,
468 'Listen %s:%u' % (PROXY_HOST_IP, PROXY_PORT),
469 'ServerName %s' % PROXY_HOST_IP,
470 'ProxyRequests On',
471 'AllowCONNECT %s' % ' '.join(map(str, PROXY_CONNECT_PORTS)),
Josh Triplett472a4182013-03-08 11:48:57 -0800472 ] + [
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500473 'LoadModule %s %s' % (mod, os.path.join(apache_module_path, so))
474 for (mod, so) in apache_modules
Josh Triplett472a4182013-03-08 11:48:57 -0800475 ]
476 commands = (
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500477 ('ip', 'link', 'add', 'name', veth_host,
478 'type', 'veth', 'peer', 'name', veth_guest),
479 ('ip', 'address', 'add',
480 '%s/%u' % (PROXY_HOST_IP, PROXY_NETMASK),
481 'dev', veth_host),
482 ('ip', 'link', 'set', veth_host, 'up'),
483 ([apache_bin, '-f', '/dev/null'] +
484 [arg for d in apache_directives for arg in ('-C', d)]),
485 ('ip', 'link', 'set', veth_guest, 'netns', str(pid)),
Josh Triplett472a4182013-03-08 11:48:57 -0800486 )
487 cmd = None # Make cros lint happy.
488 try:
489 for cmd in commands:
490 cros_build_lib.RunCommand(cmd, print_cmd=False)
491 except cros_build_lib.RunCommandError:
492 # Clean up existing interfaces, if any.
493 cmd_cleanup = ('ip', 'link', 'del', veth_host)
494 try:
495 cros_build_lib.RunCommand(cmd_cleanup, print_cmd=False)
496 except cros_build_lib.RunCommandError:
Ralph Nathan59900422015-03-24 10:41:17 -0700497 logging.error('running %r failed', cmd_cleanup)
Josh Triplett472a4182013-03-08 11:48:57 -0800498 raise SystemExit('Running %r failed!' % (cmd,))
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500499
500 # Signal the child that the net ns/proxy is fully configured now.
501 ns_setup_lock.Post()
502 del ns_setup_lock
Josh Triplett472a4182013-03-08 11:48:57 -0800503
Mike Frysingere2d8f0d2014-11-01 13:09:26 -0400504 process_util.ExitAsStatus(os.waitpid(pid, 0)[1])
Josh Triplett472a4182013-03-08 11:48:57 -0800505
506
Mike Frysingera78a56e2012-11-20 06:02:30 -0500507def _ReExecuteIfNeeded(argv):
David James56e6c2c2012-10-24 23:54:41 -0700508 """Re-execute cros_sdk as root.
509
510 Also unshare the mount namespace so as to ensure that processes outside
511 the chroot can't mess with our mounts.
512 """
513 if os.geteuid() != 0:
Mike Frysingera78a56e2012-11-20 06:02:30 -0500514 cmd = _SudoCommand() + ['--'] + argv
515 os.execvp(cmd[0], cmd)
Mike Frysingera78a56e2012-11-20 06:02:30 -0500516 else:
Mike Frysinger80dfce92014-04-21 10:58:53 -0400517 # We must set up the cgroups mounts before we enter our own namespace.
518 # This way it is a shared resource in the root mount namespace.
Josh Triplette759b232013-03-08 13:03:43 -0800519 cgroups.Cgroup.InitSystem()
David James56e6c2c2012-10-24 23:54:41 -0700520
521
Mike Frysinger34db8692013-11-11 14:54:08 -0500522def _CreateParser(sdk_latest_version, bootstrap_latest_version):
523 """Generate and return the parser with all the options."""
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400524 usage = ('usage: %(prog)s [options] '
525 '[VAR1=val1 ... VAR2=val2] [--] [command [args]]')
526 parser = commandline.ArgumentParser(usage=usage, description=__doc__,
527 caching=True)
Brian Harring218e13c2012-10-10 16:21:26 -0700528
Mike Frysinger34db8692013-11-11 14:54:08 -0500529 # Global options.
Mike Frysinger648ba2d2013-01-08 14:19:34 -0500530 default_chroot = os.path.join(constants.SOURCE_ROOT,
531 constants.DEFAULT_CHROOT_DIR)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400532 parser.add_argument(
Brian Harring218e13c2012-10-10 16:21:26 -0700533 '--chroot', dest='chroot', default=default_chroot, type='path',
534 help=('SDK chroot dir name [%s]' % constants.DEFAULT_CHROOT_DIR))
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600535 parser.add_argument('--nouse-image', dest='use_image', action='store_false',
536 default=True,
537 help='Do not mount the chroot on a loopback image; '
538 'instead, create it directly in a directory.')
Brian Harringb938c782012-02-29 15:14:38 -0800539
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400540 parser.add_argument('--chrome_root', type='path',
541 help='Mount this chrome root into the SDK chroot')
542 parser.add_argument('--chrome_root_mount', type='path',
543 help='Mount chrome into this path inside SDK chroot')
544 parser.add_argument('--nousepkg', action='store_true', default=False,
545 help='Do not use binary packages when creating a chroot.')
546 parser.add_argument('-u', '--url', dest='sdk_url',
547 help='Use sdk tarball located at this url. Use file:// '
548 'for local files.')
549 parser.add_argument('--sdk-version',
550 help=('Use this sdk version. For prebuilt, current is %r'
551 ', for bootstrapping it is %r.'
552 % (sdk_latest_version, bootstrap_latest_version)))
553 parser.add_argument('--workspace',
554 help='Workspace directory to mount into the chroot.')
Hidehiko Abeb5daf2f2017-03-02 17:57:43 +0900555 parser.add_argument('--goma_dir', type='path',
556 help='Goma installed directory to mount into the chroot.')
557 parser.add_argument('--goma_client_json', type='path',
558 help='Service account json file to use goma on bot. '
559 'Mounted into the chroot.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400560 parser.add_argument('commands', nargs=argparse.REMAINDER)
Mike Frysinger34db8692013-11-11 14:54:08 -0500561
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700562 # SDK overlay tarball options (mutually exclusive).
563 group = parser.add_mutually_exclusive_group()
564 group.add_argument('--toolchains',
565 help=('Comma-separated list of toolchains we expect to be '
566 'using on the chroot. Used for downloading a '
567 'corresponding SDK toolchains group (if one is '
568 'found), which may speed up chroot initialization '
569 'when building for the first time. Otherwise this '
570 'has no effect and will not restrict the chroot in '
571 'any way. Ignored if using --bootstrap.'))
572 group.add_argument('--board',
573 help=('The board we intend to be building in the chroot. '
574 'Used for deriving the list of required toolchains '
575 '(see --toolchains).'))
576
Mike Frysinger34db8692013-11-11 14:54:08 -0500577 # Commands.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400578 group = parser.add_argument_group('Commands')
579 group.add_argument(
Mike Frysinger34db8692013-11-11 14:54:08 -0500580 '--enter', action='store_true', default=False,
581 help='Enter the SDK chroot. Implies --create.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400582 group.add_argument(
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500583 '--create', action='store_true', default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500584 help='Create the chroot only if it does not already exist. '
585 'Implies --download.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400586 group.add_argument(
Mike Frysinger34db8692013-11-11 14:54:08 -0500587 '--bootstrap', action='store_true', default=False,
588 help='Build everything from scratch, including the sdk. '
589 'Use this only if you need to validate a change '
590 'that affects SDK creation itself (toolchain and '
591 'build are typically the only folk who need this). '
592 'Note this will quite heavily slow down the build. '
593 'This option implies --create --nousepkg.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400594 group.add_argument(
Mike Frysinger34db8692013-11-11 14:54:08 -0500595 '-r', '--replace', action='store_true', default=False,
596 help='Replace an existing SDK chroot. Basically an alias '
597 'for --delete --create.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400598 group.add_argument(
Mike Frysinger34db8692013-11-11 14:54:08 -0500599 '--delete', action='store_true', default=False,
600 help='Delete the current SDK chroot if it exists.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400601 group.add_argument(
Mike Frysinger34db8692013-11-11 14:54:08 -0500602 '--download', action='store_true', default=False,
603 help='Download the sdk.')
604 commands = group
605
Mike Frysinger80dfce92014-04-21 10:58:53 -0400606 # Namespace options.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400607 group = parser.add_argument_group('Namespaces')
608 group.add_argument('--proxy-sim', action='store_true', default=False,
609 help='Simulate a restrictive network requiring an outbound'
610 ' proxy.')
611 group.add_argument('--no-ns-pid', dest='ns_pid',
612 default=True, action='store_false',
613 help='Do not create a new PID namespace.')
Mike Frysinger80dfce92014-04-21 10:58:53 -0400614
Mike Frysinger34db8692013-11-11 14:54:08 -0500615 # Internal options.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400616 group = parser.add_argument_group(
Mike Frysinger34db8692013-11-11 14:54:08 -0500617 'Internal Chromium OS Build Team Options',
618 'Caution: these are for meant for the Chromium OS build team only')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400619 group.add_argument('--buildbot-log-version', default=False,
620 action='store_true',
621 help='Log SDK version for buildbot consumption')
Mike Frysinger34db8692013-11-11 14:54:08 -0500622
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400623 return parser, commands
Mike Frysinger34db8692013-11-11 14:54:08 -0500624
625
626def main(argv):
627 conf = cros_build_lib.LoadKeyValueFile(
628 os.path.join(constants.SOURCE_ROOT, constants.SDK_VERSION_FILE),
629 ignore_missing=True)
630 sdk_latest_version = conf.get('SDK_LATEST_VERSION', '<unknown>')
631 bootstrap_latest_version = conf.get('BOOTSTRAP_LATEST_VERSION', '<unknown>')
632 parser, commands = _CreateParser(sdk_latest_version, bootstrap_latest_version)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400633 options = parser.parse_args(argv)
634 chroot_command = options.commands
Brian Harringb938c782012-02-29 15:14:38 -0800635
636 # Some sanity checks first, before we ask for sudo credentials.
Mike Frysinger8fd67dc2012-12-03 23:51:18 -0500637 cros_build_lib.AssertOutsideChroot()
Brian Harringb938c782012-02-29 15:14:38 -0800638
Brian Harring1790ac42012-09-23 08:53:33 -0700639 host = os.uname()[4]
Brian Harring1790ac42012-09-23 08:53:33 -0700640 if host != 'x86_64':
Benjamin Gordon040a1162017-06-29 13:44:47 -0600641 cros_build_lib.Die(
Brian Harring1790ac42012-09-23 08:53:33 -0700642 "cros_sdk is currently only supported on x86_64; you're running"
643 " %s. Please find a x86_64 machine." % (host,))
644
Josh Triplett472a4182013-03-08 11:48:57 -0800645 _ReportMissing(osutils.FindMissingBinaries(NEEDED_TOOLS))
646 if options.proxy_sim:
647 _ReportMissing(osutils.FindMissingBinaries(PROXY_NEEDED_TOOLS))
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600648 missing_image_tools = osutils.FindMissingBinaries(IMAGE_NEEDED_TOOLS)
Brian Harringb938c782012-02-29 15:14:38 -0800649
Benjamin Gordon040a1162017-06-29 13:44:47 -0600650 if (sdk_latest_version == '<unknown>' or
651 bootstrap_latest_version == '<unknown>'):
652 cros_build_lib.Die(
653 'No SDK version was found. '
654 'Are you in a Chromium source tree instead of Chromium OS?\n\n'
655 'Please change to a directory inside your Chromium OS source tree\n'
656 'and retry. If you need to setup a Chromium OS source tree, see\n'
657 ' http://www.chromium.org/chromium-os/developer-guide')
658
David James471532c2013-01-21 10:23:31 -0800659 _ReExecuteIfNeeded([sys.argv[0]] + argv)
660
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600661 lock_path = os.path.dirname(options.chroot)
662 lock_path = os.path.join(
663 lock_path, '.%s_lock' % os.path.basename(options.chroot).lstrip('.'))
664
Brian Harring218e13c2012-10-10 16:21:26 -0700665 # Expand out the aliases...
666 if options.replace:
667 options.delete = options.create = True
Brian Harringb938c782012-02-29 15:14:38 -0800668
Brian Harring218e13c2012-10-10 16:21:26 -0700669 if options.bootstrap:
670 options.create = True
Brian Harringb938c782012-02-29 15:14:38 -0800671
Brian Harring218e13c2012-10-10 16:21:26 -0700672 # If a command is not given, default to enter.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400673 # pylint: disable=protected-access
674 # This _group_actions access sucks, but upstream decided to not include an
675 # alternative to optparse's option_list, and this is what they recommend.
Brian Harring218e13c2012-10-10 16:21:26 -0700676 options.enter |= not any(getattr(options, x.dest)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400677 for x in commands._group_actions)
678 # pylint: enable=protected-access
Brian Harring218e13c2012-10-10 16:21:26 -0700679 options.enter |= bool(chroot_command)
680
681 if options.enter and options.delete and not options.create:
682 parser.error("Trying to enter the chroot when --delete "
683 "was specified makes no sense.")
684
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600685 # Clean up potential leftovers from previous interrupted builds.
686 # TODO(bmgordon): Remove this at the end of 2017. That should be long enough
687 # to get rid of them all.
688 chroot_build_path = options.chroot + '.build'
689 if options.use_image and os.path.exists(chroot_build_path):
690 try:
691 with cgroups.SimpleContainChildren('cros_sdk'):
692 with locking.FileLock(lock_path, 'chroot lock') as lock:
693 logging.notice('Cleaning up leftover build directory %s',
694 chroot_build_path)
695 lock.write_lock()
696 osutils.UmountTree(chroot_build_path)
697 osutils.RmDir(chroot_build_path)
698 except cros_build_lib.RunCommandError as e:
699 logging.warning("Unable to remove %s: %s", chroot_build_path, e)
700
Benjamin Gordon35194f12017-07-19 10:26:22 -0600701 # Discern if we need to create the chroot.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600702 chroot_ver_file = os.path.join(options.chroot, 'etc', 'cros_chroot_version')
703 chroot_exists = os.path.exists(chroot_ver_file)
704 if (options.use_image and not chroot_exists and not options.delete and
705 not missing_image_tools and
706 os.path.exists(_ImageFileForChroot(options.chroot))):
707 # Try to re-mount an existing image in case the user has rebooted.
708 with cgroups.SimpleContainChildren('cros_sdk'):
709 with locking.FileLock(lock_path, 'chroot lock') as lock:
710 logging.debug('Checking if existing chroot image can be mounted.')
711 lock.write_lock()
712 cros_build_lib.MountChroot(options.chroot, create=False)
713 chroot_exists = os.path.exists(chroot_ver_file)
714 if chroot_exists:
715 logging.notice('Mounted existing image %s on chroot',
716 _ImageFileForChroot(options.chroot))
Brian Harring218e13c2012-10-10 16:21:26 -0700717 if options.create or options.enter:
718 # Only create if it's being wiped, or if it doesn't exist.
719 if not options.delete and chroot_exists:
720 options.create = False
721 else:
722 options.download = True
723
724 # Finally, flip create if necessary.
725 if options.enter:
726 options.create |= not chroot_exists
Brian Harringb938c782012-02-29 15:14:38 -0800727
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600728 # If we're going to delete, also make sure the chroot isn't mounted
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600729 # before we enter the new mount namespace. We do this regardless of
730 # the use_image flag so that a previously-created loopback chroot can
731 # also be cleaned up.
732 # TODO(bmgordon): See if the DeleteChroot call below can be removed in
733 # favor of this block.
734 chroot_deleted = False
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600735 if options.delete:
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600736 with cgroups.SimpleContainChildren('cros_sdk'):
737 with locking.FileLock(lock_path, 'chroot lock') as lock:
738 lock.write_lock()
739 if missing_image_tools:
740 logging.notice('Unmounting chroot.')
741 osutils.UmountTree(options.chroot)
742 else:
743 logging.notice('Deleting chroot.')
744 cros_build_lib.CleanupChrootMount(options.chroot, delete_image=True)
745 osutils.RmDir(options.chroot, ignore_missing=True)
746 chroot_deleted = True
747
748 # If we're going to create a new chroot, set it up before we change
749 # mount namespaces so that it will be visible to processes other than
750 # cros_sdk's children.
751 if options.create and options.use_image:
752 if missing_image_tools:
753 raise SystemExit(
754 '''The tool(s) %s were not found.
755Please make sure the lvm2 and thin-provisioning-tools packages
756are installed on your host.
757Example(ubuntu):
758 sudo apt-get install lvm2 thin-provisioning-tools
759
760If you want to run without lvm2, pass --nouse-image (chroot
761snapshots will be unavailable).''' % ', '.join(missing_image_tools))
762 logging.debug('Making sure chroot image is mounted.')
763 with cgroups.SimpleContainChildren('cros_sdk'):
764 with locking.FileLock(lock_path, 'chroot lock') as lock:
765 lock.write_lock()
766 if not cros_build_lib.MountChroot(options.chroot, create=True):
767 cros_build_lib.Die('Unable to mount %s on chroot',
768 _ImageFileForChroot(options.chroot))
769 logging.notice('Mounted %s on chroot',
770 _ImageFileForChroot(options.chroot))
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600771
772 namespaces.SimpleUnshare()
773 if options.ns_pid:
774 first_pid = namespaces.CreatePidNs()
775 else:
776 first_pid = None
777
Brian Harringb938c782012-02-29 15:14:38 -0800778 if not options.sdk_version:
Brian Harring1790ac42012-09-23 08:53:33 -0700779 sdk_version = (bootstrap_latest_version if options.bootstrap
780 else sdk_latest_version)
Brian Harringb938c782012-02-29 15:14:38 -0800781 else:
782 sdk_version = options.sdk_version
Mike Frysinger34db8692013-11-11 14:54:08 -0500783 if options.buildbot_log_version:
Prathmesh Prabhu17f07422015-07-17 11:40:40 -0700784 logging.PrintBuildbotStepText(sdk_version)
Brian Harringb938c782012-02-29 15:14:38 -0800785
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700786 # Based on selections, determine the tarball to fetch.
Brian Harring1790ac42012-09-23 08:53:33 -0700787 if options.sdk_url:
788 urls = [options.sdk_url]
789 elif options.bootstrap:
790 urls = GetStage3Urls(sdk_version)
791 else:
792 urls = GetArchStageTarballs(sdk_version)
793
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700794 # Get URLs for the toolchains overlay, if one is to be used.
795 toolchains_overlay_urls = None
796 if not options.bootstrap:
797 toolchains = None
798 if options.toolchains:
799 toolchains = options.toolchains.split(',')
800 elif options.board:
801 toolchains = toolchain.GetToolchainsForBoard(options.board).keys()
802
803 if toolchains:
804 toolchains_overlay_urls = GetToolchainsOverlayUrls(sdk_version,
805 toolchains)
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700806
Mike Frysinger80dfce92014-04-21 10:58:53 -0400807 with cgroups.SimpleContainChildren('cros_sdk', pid=first_pid):
David James56e6c2c2012-10-24 23:54:41 -0700808 with locking.FileLock(lock_path, 'chroot lock') as lock:
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700809 toolchains_overlay_tarball = None
Brian Harring1790ac42012-09-23 08:53:33 -0700810
Josh Triplett472a4182013-03-08 11:48:57 -0800811 if options.proxy_sim:
812 _ProxySimSetup(options)
813
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600814 if (options.delete and not chroot_deleted and
815 (os.path.exists(options.chroot) or
816 os.path.exists(_ImageFileForChroot(options.chroot)))):
David James56e6c2c2012-10-24 23:54:41 -0700817 lock.write_lock()
818 DeleteChroot(options.chroot)
Brian Harringb938c782012-02-29 15:14:38 -0800819
David James56e6c2c2012-10-24 23:54:41 -0700820 sdk_cache = os.path.join(options.cache_dir, 'sdks')
821 distfiles_cache = os.path.join(options.cache_dir, 'distfiles')
Yu-Ju Hong2c066762013-10-28 14:05:08 -0700822 osutils.SafeMakedirsNonRoot(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -0700823
David James56e6c2c2012-10-24 23:54:41 -0700824 for target in (sdk_cache, distfiles_cache):
Mike Frysinger648ba2d2013-01-08 14:19:34 -0500825 src = os.path.join(constants.SOURCE_ROOT, os.path.basename(target))
David James56e6c2c2012-10-24 23:54:41 -0700826 if not os.path.exists(src):
Prathmesh Prabhu06a50562016-10-22 01:41:44 -0700827 osutils.SafeMakedirsNonRoot(target)
David James56e6c2c2012-10-24 23:54:41 -0700828 continue
829 lock.write_lock(
830 "Upgrade to %r needed but chroot is locked; please exit "
831 "all instances so this upgrade can finish." % src)
832 if not os.path.exists(src):
833 # Note that while waiting for the write lock, src may've vanished;
834 # it's a rare race during the upgrade process that's a byproduct
835 # of us avoiding taking a write lock to do the src check. If we
836 # took a write lock for that check, it would effectively limit
837 # all cros_sdk for a chroot to a single instance.
Prathmesh Prabhu06a50562016-10-22 01:41:44 -0700838 osutils.SafeMakedirsNonRoot(target)
David James56e6c2c2012-10-24 23:54:41 -0700839 elif not os.path.exists(target):
840 # Upgrade occurred, but a reversion, or something whacky
841 # occurred writing to the old location. Wipe and continue.
842 os.rename(src, target)
843 else:
844 # Upgrade occurred once already, but either a reversion or
845 # some before/after separate cros_sdk usage is at play.
846 # Wipe and continue.
847 osutils.RmDir(src)
Brian Harringae0a5322012-09-15 01:46:51 -0700848
David James56e6c2c2012-10-24 23:54:41 -0700849 if options.download:
850 lock.write_lock()
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700851 sdk_tarball = FetchRemoteTarballs(
852 sdk_cache, urls, 'stage3' if options.bootstrap else 'SDK')
853 if toolchains_overlay_urls:
854 toolchains_overlay_tarball = FetchRemoteTarballs(
855 sdk_cache, toolchains_overlay_urls, 'SDK toolchains overlay',
856 allow_none=True)
Brian Harring218e13c2012-10-10 16:21:26 -0700857
David James56e6c2c2012-10-24 23:54:41 -0700858 if options.create:
859 lock.write_lock()
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700860 CreateChroot(options.chroot, sdk_tarball, toolchains_overlay_tarball,
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700861 options.cache_dir,
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600862 nousepkg=(options.bootstrap or options.nousepkg))
Brian Harring1790ac42012-09-23 08:53:33 -0700863
David James56e6c2c2012-10-24 23:54:41 -0700864 if options.enter:
865 lock.read_lock()
866 EnterChroot(options.chroot, options.cache_dir, options.chrome_root,
Don Garrett230d1b22015-03-09 16:21:19 -0700867 options.chrome_root_mount, options.workspace,
Hidehiko Abeb5daf2f2017-03-02 17:57:43 +0900868 options.goma_dir, options.goma_client_json,
Don Garrett230d1b22015-03-09 16:21:19 -0700869 chroot_command)