Mike Frysinger | f1ba7ad | 2022-09-12 05:42:57 -0400 | [diff] [blame] | 1 | # Copyright 2012 The ChromiumOS Authors |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
Manoj Gupta | 7fad04d | 2019-06-14 20:12:25 -0700 | [diff] [blame] | 4 | |
Mike Frysinger | 2f95cfc | 2015-06-04 04:00:26 -0400 | [diff] [blame] | 5 | """Manage SDK chroots. |
| 6 | |
| 7 | This script is used for manipulating local chroot environments; creating, |
| 8 | deleting, downloading, etc. If given --enter (or no args), it defaults |
| 9 | to an interactive bash shell within the chroot. |
| 10 | |
| 11 | If given args those are passed to the chroot environment, and executed. |
| 12 | """ |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 13 | |
Mike Frysinger | 2f95cfc | 2015-06-04 04:00:26 -0400 | [diff] [blame] | 14 | import argparse |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 15 | import glob |
Chris McDonald | b55b703 | 2021-06-17 16:41:32 -0600 | [diff] [blame] | 16 | import logging |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 17 | import os |
Mike Frysinger | 23b5cf5 | 2021-06-16 23:18:00 -0400 | [diff] [blame] | 18 | from pathlib import Path |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 19 | import pwd |
Brian Norris | d37e2f7 | 2016-08-22 16:09:24 -0700 | [diff] [blame] | 20 | import re |
Mike Frysinger | 5f5c70b | 2022-07-19 12:55:21 -0400 | [diff] [blame] | 21 | import shlex |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 22 | import sys |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 23 | from typing import List |
Mike Frysinger | e852b07 | 2021-05-21 12:39:03 -0400 | [diff] [blame] | 24 | import urllib.parse |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 25 | |
Chris McDonald | b55b703 | 2021-06-17 16:41:32 -0600 | [diff] [blame] | 26 | from chromite.cbuildbot import cbuildbot_alerts |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 27 | from chromite.lib import chroot_lib |
Brian Harring | b6cf914 | 2012-09-01 20:43:17 -0700 | [diff] [blame] | 28 | from chromite.lib import commandline |
Chris McDonald | b55b703 | 2021-06-17 16:41:32 -0600 | [diff] [blame] | 29 | from chromite.lib import constants |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 30 | from chromite.lib import cros_build_lib |
Benjamin Gordon | 7464523 | 2018-05-04 17:40:42 -0600 | [diff] [blame] | 31 | from chromite.lib import cros_sdk_lib |
Mike Frysinger | 9a5124e | 2023-01-26 17:16:44 -0500 | [diff] [blame] | 32 | from chromite.lib import goma_lib |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 33 | from chromite.lib import locking |
Josh Triplett | e759b23 | 2013-03-08 13:03:43 -0800 | [diff] [blame] | 34 | from chromite.lib import namespaces |
Brian Harring | ae0a532 | 2012-09-15 01:46:51 -0700 | [diff] [blame] | 35 | from chromite.lib import osutils |
Mike Frysinger | e2d8f0d | 2014-11-01 13:09:26 -0400 | [diff] [blame] | 36 | from chromite.lib import process_util |
Mike Frysinger | 253c839 | 2023-01-27 01:12:21 -0500 | [diff] [blame] | 37 | from chromite.lib import remoteexec_util |
David James | c93e6a4d | 2014-01-13 11:37:36 -0800 | [diff] [blame] | 38 | from chromite.lib import retry_util |
Michael Mortensen | bf296fb | 2020-06-18 18:21:54 -0600 | [diff] [blame] | 39 | from chromite.lib import timeout_util |
Mike Frysinger | 8e727a3 | 2013-01-16 16:57:53 -0500 | [diff] [blame] | 40 | from chromite.lib import toolchain |
Mike Frysinger | e652ba1 | 2019-09-08 00:57:43 -0400 | [diff] [blame] | 41 | from chromite.utils import key_value_store |
| 42 | |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 43 | |
Mike Frysinger | f744d03 | 2022-05-07 20:38:39 -0400 | [diff] [blame] | 44 | # Which compression algos the SDK tarball uses. We've used xz since 2012. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 45 | COMPRESSION_PREFERENCE = ("xz",) |
Zdenek Behan | fd0efe4 | 2012-04-13 04:36:40 +0200 | [diff] [blame] | 46 | |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 47 | # Proxy simulator configuration. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 48 | PROXY_HOST_IP = "192.168.240.1" |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 49 | PROXY_PORT = 8080 |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 50 | PROXY_GUEST_IP = "192.168.240.2" |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 51 | PROXY_NETMASK = 30 |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 52 | PROXY_VETH_PREFIX = "veth" |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 53 | PROXY_CONNECT_PORTS = (80, 443, 9418) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 54 | PROXY_APACHE_FALLBACK_USERS = ("www-data", "apache", "nobody") |
| 55 | PROXY_APACHE_MPMS = ("event", "worker", "prefork") |
| 56 | PROXY_APACHE_FALLBACK_PATH = ":".join( |
| 57 | "/usr/lib/apache2/mpm-%s" % mpm for mpm in PROXY_APACHE_MPMS |
| 58 | ) |
| 59 | PROXY_APACHE_MODULE_GLOBS = ("/usr/lib*/apache2/modules", "/usr/lib*/apache2") |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 60 | |
Josh Triplett | 9a495f6 | 2013-03-15 18:06:55 -0700 | [diff] [blame] | 61 | # We need these tools to run. Very common tools (tar,..) are omitted. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 62 | NEEDED_TOOLS = ("curl", "xz") |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 63 | |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 64 | # Tools needed for --proxy-sim only. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 65 | PROXY_NEEDED_TOOLS = ("ip",) |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 66 | |
Mike Frysinger | cc83883 | 2014-05-24 13:10:30 -0400 | [diff] [blame] | 67 | |
Brian Harring | 1790ac4 | 2012-09-23 08:53:33 -0700 | [diff] [blame] | 68 | def GetArchStageTarballs(version): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 69 | """Returns the URL for a given arch/version""" |
| 70 | extension = {"xz": "tar.xz"} |
| 71 | return [ |
| 72 | toolchain.GetSdkURL( |
| 73 | suburl="cros-sdk-%s.%s" % (version, extension[compressor]) |
| 74 | ) |
| 75 | for compressor in COMPRESSION_PREFERENCE |
| 76 | ] |
Brian Harring | 1790ac4 | 2012-09-23 08:53:33 -0700 | [diff] [blame] | 77 | |
| 78 | |
Mike Frysinger | f744d03 | 2022-05-07 20:38:39 -0400 | [diff] [blame] | 79 | def FetchRemoteTarballs(storage_dir, urls): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 80 | """Fetches a tarball given by url, and place it in |storage_dir|. |
Zdenek Behan | fd0efe4 | 2012-04-13 04:36:40 +0200 | [diff] [blame] | 81 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 82 | Args: |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 83 | storage_dir: Path where to save the tarball. |
| 84 | urls: List of URLs to try to download. Download will stop on first |
| 85 | success. |
Zdenek Behan | fd0efe4 | 2012-04-13 04:36:40 +0200 | [diff] [blame] | 86 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 87 | Returns: |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 88 | Full path to the downloaded file. |
Gilad Arnold | ecc86fa | 2015-05-22 12:06:04 -0700 | [diff] [blame] | 89 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 90 | Raises: |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 91 | ValueError: None of the URLs worked. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 92 | """ |
| 93 | # Note we track content length ourselves since certain versions of curl |
| 94 | # fail if asked to resume a complete file. |
| 95 | # https://sourceforge.net/tracker/?func=detail&atid=100976&aid=3482927&group_id=976 |
| 96 | status_re = re.compile(rb"^HTTP/[0-9]+(\.[0-9]+)? 200") |
| 97 | # pylint: disable=undefined-loop-variable |
| 98 | for url in urls: |
| 99 | logging.notice("Downloading tarball %s ...", urls[0].rsplit("/", 1)[-1]) |
| 100 | parsed = urllib.parse.urlparse(url) |
| 101 | tarball_name = os.path.basename(parsed.path) |
| 102 | if parsed.scheme in ("", "file"): |
| 103 | if os.path.exists(parsed.path): |
| 104 | return parsed.path |
| 105 | continue |
| 106 | content_length = 0 |
| 107 | logging.debug("Attempting download from %s", url) |
| 108 | result = retry_util.RunCurl( |
| 109 | ["-I", url], |
| 110 | print_cmd=False, |
| 111 | debug_level=logging.NOTICE, |
| 112 | capture_output=True, |
| 113 | ) |
| 114 | successful = False |
| 115 | for header in result.stdout.splitlines(): |
| 116 | # We must walk the output to find the 200 code for use cases where |
| 117 | # a proxy is involved and may have pushed down the actual header. |
| 118 | if status_re.match(header): |
| 119 | successful = True |
| 120 | elif header.lower().startswith(b"content-length:"): |
| 121 | content_length = int(header.split(b":", 1)[-1].strip()) |
| 122 | if successful: |
| 123 | break |
Brian Harring | 1790ac4 | 2012-09-23 08:53:33 -0700 | [diff] [blame] | 124 | if successful: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 125 | break |
| 126 | else: |
| 127 | raise ValueError("No valid URLs found!") |
Zdenek Behan | fd0efe4 | 2012-04-13 04:36:40 +0200 | [diff] [blame] | 128 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 129 | tarball_dest = os.path.join(storage_dir, tarball_name) |
| 130 | current_size = 0 |
| 131 | if os.path.exists(tarball_dest): |
| 132 | current_size = os.path.getsize(tarball_dest) |
| 133 | if current_size > content_length: |
| 134 | osutils.SafeUnlink(tarball_dest) |
| 135 | current_size = 0 |
Zdenek Behan | b2fa72e | 2012-03-16 04:49:30 +0100 | [diff] [blame] | 136 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 137 | if current_size < content_length: |
| 138 | retry_util.RunCurl( |
| 139 | [ |
| 140 | "--fail", |
| 141 | "-L", |
| 142 | "-y", |
| 143 | "30", |
| 144 | "-C", |
| 145 | "-", |
| 146 | "--output", |
| 147 | tarball_dest, |
| 148 | url, |
| 149 | ], |
| 150 | print_cmd=False, |
| 151 | debug_level=logging.NOTICE, |
| 152 | ) |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 153 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 154 | # Cleanup old tarballs now since we've successfull fetched; only cleanup |
| 155 | # the tarballs for our prefix, or unknown ones. This gets a bit tricky |
| 156 | # because we might have partial overlap between known prefixes. |
| 157 | for p in Path(storage_dir).glob("cros-sdk-*"): |
| 158 | if p.name == tarball_name: |
| 159 | continue |
| 160 | logging.info("Cleaning up old tarball: %s", p) |
| 161 | osutils.SafeUnlink(p) |
Zdenek Behan | 9c644dd | 2012-04-05 06:24:02 +0200 | [diff] [blame] | 162 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 163 | return tarball_dest |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 164 | |
| 165 | |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 166 | def _SudoCommand(): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 167 | """Get the 'sudo' command, along with all needed environment variables.""" |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 168 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 169 | # Pass in the ENVIRONMENT_ALLOWLIST and ENV_PASSTHRU variables so that |
| 170 | # scripts in the chroot know what variables to pass through. |
| 171 | cmd = ["sudo"] |
| 172 | for key in constants.CHROOT_ENVIRONMENT_ALLOWLIST + constants.ENV_PASSTHRU: |
| 173 | value = os.environ.get(key) |
| 174 | if value is not None: |
| 175 | cmd += ["%s=%s" % (key, value)] |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 176 | |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 177 | # We keep PATH not for the chroot but for the re-exec & for programs we |
| 178 | # might run before we chroot into the SDK. The process that enters the SDK |
| 179 | # itself will take care of initializing PATH to the right value then. But |
| 180 | # we can't override the system's default PATH for root as that will hide |
| 181 | # /sbin. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 182 | cmd += ["CHROMEOS_SUDO_PATH=%s" % os.environ.get("PATH", "")] |
Mike Frysinger | 2bda4d1 | 2020-07-14 11:15:49 -0400 | [diff] [blame] | 183 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 184 | # Pass along current rlimit settings so we can restore them. |
Mike Frysinger | 53baf88 | 2021-06-24 23:16:50 -0400 | [diff] [blame] | 185 | cmd += [f"CHROMEOS_SUDO_RLIMITS={cros_sdk_lib.ChrootEnteror.get_rlimits()}"] |
Mike Frysinger | 12d055b | 2022-06-23 12:26:47 -0400 | [diff] [blame] | 186 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 187 | # Pass in the path to the depot_tools so that users can access them from |
| 188 | # within the chroot. |
Mike Frysinger | a95870e | 2023-03-27 15:45:34 -0400 | [diff] [blame] | 189 | cmd += [f"DEPOT_TOOLS={constants.DEPOT_TOOLS_DIR}"] |
Mike Frysinger | 749251e | 2014-01-29 05:04:27 -0500 | [diff] [blame] | 190 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 191 | return cmd |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 192 | |
| 193 | |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 194 | def _ReportMissing(missing): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 195 | """Report missing utilities, then exit. |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 196 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 197 | Args: |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 198 | missing: List of missing utilities, as returned by |
| 199 | osutils.FindMissingBinaries. If non-empty, will not return. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 200 | """ |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 201 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 202 | if missing: |
| 203 | raise SystemExit( |
| 204 | "The tool(s) %s were not found.\n" |
| 205 | "Please install the appropriate package in your host.\n" |
| 206 | "Example(ubuntu):\n" |
| 207 | " sudo apt-get install <packagename>" % ", ".join(missing) |
| 208 | ) |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 209 | |
| 210 | |
| 211 | def _ProxySimSetup(options): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 212 | """Set up proxy simulator, and return only in the child environment. |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 213 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 214 | TODO: Ideally, this should support multiple concurrent invocations of |
| 215 | cros_sdk --proxy-sim; currently, such invocations will conflict with each |
| 216 | other due to the veth device names and IP addresses. Either this code would |
| 217 | need to generate fresh, unused names for all of these before forking, or it |
| 218 | would need to support multiple concurrent cros_sdk invocations sharing one |
| 219 | proxy and allowing it to exit when unused (without counting on any local |
| 220 | service-management infrastructure on the host). |
| 221 | """ |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 222 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 223 | may_need_mpm = False |
| 224 | apache_bin = osutils.Which("apache2") |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 225 | if apache_bin is None: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 226 | apache_bin = osutils.Which("apache2", PROXY_APACHE_FALLBACK_PATH) |
| 227 | if apache_bin is None: |
| 228 | _ReportMissing(("apache2",)) |
| 229 | else: |
| 230 | may_need_mpm = True |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 231 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 232 | # Module names and .so names included for ease of grepping. |
| 233 | apache_modules = [ |
| 234 | ("proxy_module", "mod_proxy.so"), |
| 235 | ("proxy_connect_module", "mod_proxy_connect.so"), |
| 236 | ("proxy_http_module", "mod_proxy_http.so"), |
| 237 | ("proxy_ftp_module", "mod_proxy_ftp.so"), |
| 238 | ] |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 239 | |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 240 | # Find the apache module directory and make sure it has the modules we need. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 241 | module_dirs = {} |
| 242 | for g in PROXY_APACHE_MODULE_GLOBS: |
| 243 | for _, so in apache_modules: |
| 244 | for f in glob.glob(os.path.join(g, so)): |
| 245 | module_dirs.setdefault(os.path.dirname(f), []).append(so) |
| 246 | for apache_module_path, modules_found in module_dirs.items(): |
| 247 | if len(modules_found) == len(apache_modules): |
| 248 | break |
| 249 | else: |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 250 | # Appease cros lint, which doesn't understand that this else block will |
| 251 | # not fall through to the subsequent code which relies on |
| 252 | # apache_module_path. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 253 | apache_module_path = None |
| 254 | raise SystemExit( |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 255 | "Could not find apache module path containing all required " |
| 256 | "modules: %s" % ", ".join(so for mod, so in apache_modules) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 257 | ) |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 258 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 259 | def check_add_module(name): |
| 260 | so = "mod_%s.so" % name |
| 261 | if os.access(os.path.join(apache_module_path, so), os.F_OK): |
| 262 | mod = "%s_module" % name |
| 263 | apache_modules.append((mod, so)) |
| 264 | return True |
| 265 | return False |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 266 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 267 | check_add_module("authz_core") |
| 268 | if may_need_mpm: |
| 269 | for mpm in PROXY_APACHE_MPMS: |
| 270 | if check_add_module("mpm_%s" % mpm): |
| 271 | break |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 272 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 273 | veth_host = "%s-host" % PROXY_VETH_PREFIX |
| 274 | veth_guest = "%s-guest" % PROXY_VETH_PREFIX |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 275 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 276 | # Set up locks to sync the net namespace setup. We need the child to create |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 277 | # the net ns first, and then have the parent assign the guest end of the |
| 278 | # veth interface to the child's new network namespace & bring up the proxy. |
| 279 | # Only then can the child move forward and rely on the network being up. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 280 | ns_create_lock = locking.PipeLock() |
| 281 | ns_setup_lock = locking.PipeLock() |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 282 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 283 | pid = os.fork() |
| 284 | if not pid: |
| 285 | # Create our new isolated net namespace. |
| 286 | namespaces.Unshare(namespaces.CLONE_NEWNET) |
Mike Frysinger | 77bf4af | 2016-02-26 17:13:15 -0500 | [diff] [blame] | 287 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 288 | # Signal the parent the ns is ready to be configured. |
| 289 | ns_create_lock.Post() |
| 290 | del ns_create_lock |
| 291 | |
| 292 | # Wait for the parent to finish setting up the ns/proxy. |
| 293 | ns_setup_lock.Wait() |
| 294 | del ns_setup_lock |
| 295 | |
| 296 | # Set up child side of the network. |
| 297 | commands = ( |
| 298 | ("ip", "link", "set", "up", "lo"), |
| 299 | ( |
| 300 | "ip", |
| 301 | "address", |
| 302 | "add", |
| 303 | "%s/%u" % (PROXY_GUEST_IP, PROXY_NETMASK), |
| 304 | "dev", |
| 305 | veth_guest, |
| 306 | ), |
| 307 | ("ip", "link", "set", veth_guest, "up"), |
| 308 | ) |
| 309 | try: |
| 310 | for cmd in commands: |
| 311 | cros_build_lib.dbg_run(cmd) |
| 312 | except cros_build_lib.RunCommandError as e: |
| 313 | cros_build_lib.Die("Proxy setup failed!\n%s", e) |
| 314 | |
| 315 | proxy_url = "http://%s:%u" % (PROXY_HOST_IP, PROXY_PORT) |
| 316 | for proto in ("http", "https", "ftp"): |
| 317 | os.environ[proto + "_proxy"] = proxy_url |
| 318 | for v in ("all_proxy", "RSYNC_PROXY", "no_proxy"): |
| 319 | os.environ.pop(v, None) |
| 320 | return |
| 321 | |
| 322 | # Set up parent side of the network. |
| 323 | uid = int(os.environ.get("SUDO_UID", "0")) |
| 324 | gid = int(os.environ.get("SUDO_GID", "0")) |
| 325 | if uid == 0 or gid == 0: |
| 326 | for username in PROXY_APACHE_FALLBACK_USERS: |
| 327 | try: |
| 328 | pwnam = pwd.getpwnam(username) |
| 329 | uid, gid = pwnam.pw_uid, pwnam.pw_gid |
| 330 | break |
| 331 | except KeyError: |
| 332 | continue |
| 333 | if uid == 0 or gid == 0: |
| 334 | raise SystemExit("Could not find a non-root user to run Apache as") |
| 335 | |
| 336 | chroot_parent, chroot_base = os.path.split(options.chroot) |
| 337 | pid_file = os.path.join(chroot_parent, ".%s-apache-proxy.pid" % chroot_base) |
| 338 | log_file = os.path.join(chroot_parent, ".%s-apache-proxy.log" % chroot_base) |
| 339 | |
| 340 | # Wait for the child to create the net ns. |
| 341 | ns_create_lock.Wait() |
Mike Frysinger | 77bf4af | 2016-02-26 17:13:15 -0500 | [diff] [blame] | 342 | del ns_create_lock |
| 343 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 344 | apache_directives = [ |
| 345 | "User #%u" % uid, |
| 346 | "Group #%u" % gid, |
| 347 | "PidFile %s" % pid_file, |
| 348 | "ErrorLog %s" % log_file, |
| 349 | "Listen %s:%u" % (PROXY_HOST_IP, PROXY_PORT), |
| 350 | "ServerName %s" % PROXY_HOST_IP, |
| 351 | "ProxyRequests On", |
| 352 | "AllowCONNECT %s" % " ".join(str(x) for x in PROXY_CONNECT_PORTS), |
| 353 | ] + [ |
| 354 | "LoadModule %s %s" % (mod, os.path.join(apache_module_path, so)) |
| 355 | for (mod, so) in apache_modules |
| 356 | ] |
| 357 | commands = ( |
| 358 | ( |
| 359 | "ip", |
| 360 | "link", |
| 361 | "add", |
| 362 | "name", |
| 363 | veth_host, |
| 364 | "type", |
| 365 | "veth", |
| 366 | "peer", |
| 367 | "name", |
| 368 | veth_guest, |
| 369 | ), |
| 370 | ( |
| 371 | "ip", |
| 372 | "address", |
| 373 | "add", |
| 374 | "%s/%u" % (PROXY_HOST_IP, PROXY_NETMASK), |
| 375 | "dev", |
| 376 | veth_host, |
| 377 | ), |
| 378 | ("ip", "link", "set", veth_host, "up"), |
| 379 | ( |
| 380 | [apache_bin, "-f", "/dev/null"] |
| 381 | + [arg for d in apache_directives for arg in ("-C", d)] |
| 382 | ), |
| 383 | ("ip", "link", "set", veth_guest, "netns", str(pid)), |
| 384 | ) |
| 385 | cmd = None # Make cros lint happy. |
| 386 | try: |
| 387 | for cmd in commands: |
| 388 | cros_build_lib.dbg_run(cmd) |
| 389 | except cros_build_lib.RunCommandError as e: |
| 390 | # Clean up existing interfaces, if any. |
| 391 | cmd_cleanup = ("ip", "link", "del", veth_host) |
| 392 | try: |
| 393 | cros_build_lib.run(cmd_cleanup, print_cmd=False) |
| 394 | except cros_build_lib.RunCommandError: |
| 395 | logging.error("running %r failed", cmd_cleanup) |
| 396 | cros_build_lib.Die("Proxy network setup failed!\n%s", e) |
| 397 | |
| 398 | # Signal the child that the net ns/proxy is fully configured now. |
| 399 | ns_setup_lock.Post() |
Mike Frysinger | 77bf4af | 2016-02-26 17:13:15 -0500 | [diff] [blame] | 400 | del ns_setup_lock |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 401 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 402 | process_util.ExitAsStatus(os.waitpid(pid, 0)[1]) |
Josh Triplett | 472a418 | 2013-03-08 11:48:57 -0800 | [diff] [blame] | 403 | |
| 404 | |
Mike Frysinger | 5f5c70b | 2022-07-19 12:55:21 -0400 | [diff] [blame] | 405 | def _BuildReExecCommand(argv, opts) -> List[str]: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 406 | """Generate new command for self-reexec.""" |
| 407 | # Make sure to preserve the active Python executable in case the version |
| 408 | # we're running as is not the default one found via the (new) $PATH. |
| 409 | cmd = _SudoCommand() + ["--"] |
| 410 | if opts.strace: |
| 411 | cmd += ["strace"] + shlex.split(opts.strace_arguments) + ["--"] |
| 412 | return cmd + [sys.executable] + argv |
Mike Frysinger | 5f5c70b | 2022-07-19 12:55:21 -0400 | [diff] [blame] | 413 | |
| 414 | |
| 415 | def _ReExecuteIfNeeded(argv, opts): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 416 | """Re-execute cros_sdk as root. |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 417 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 418 | Also unshare the mount namespace so as to ensure that processes outside |
| 419 | the chroot can't mess with our mounts. |
| 420 | """ |
| 421 | if osutils.IsNonRootUser(): |
| 422 | cmd = _BuildReExecCommand(argv, opts) |
| 423 | logging.debug( |
| 424 | "Reexecing self via sudo:\n%s", cros_build_lib.CmdToStr(cmd) |
| 425 | ) |
| 426 | os.execvp(cmd[0], cmd) |
David James | 56e6c2c | 2012-10-24 23:54:41 -0700 | [diff] [blame] | 427 | |
| 428 | |
Mike Frysinger | 34db869 | 2013-11-11 14:54:08 -0500 | [diff] [blame] | 429 | def _CreateParser(sdk_latest_version, bootstrap_latest_version): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 430 | """Generate and return the parser with all the options.""" |
| 431 | usage = ( |
| 432 | "usage: %(prog)s [options] " |
| 433 | "[VAR1=val1 ... VAR2=val2] [--] [command [args]]" |
| 434 | ) |
| 435 | parser = commandline.ArgumentParser( |
| 436 | usage=usage, description=__doc__, caching=True |
| 437 | ) |
Brian Harring | 218e13c | 2012-10-10 16:21:26 -0700 | [diff] [blame] | 438 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 439 | # Global options. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 440 | parser.add_argument( |
| 441 | "--chroot", |
| 442 | dest="chroot", |
Brian Norris | e176045 | 2023-02-23 15:54:40 -0800 | [diff] [blame] | 443 | default=constants.DEFAULT_CHROOT_PATH, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 444 | type="path", |
| 445 | help=("SDK chroot dir name [%s]" % constants.DEFAULT_CHROOT_DIR), |
| 446 | ) |
| 447 | parser.add_argument( |
Dan Callaghan | ada9e03 | 2023-01-30 14:28:46 +1100 | [diff] [blame] | 448 | "--out-dir", |
| 449 | metavar="DIR", |
Brian Norris | e176045 | 2023-02-23 15:54:40 -0800 | [diff] [blame] | 450 | default=constants.DEFAULT_OUT_PATH, |
Dan Callaghan | ada9e03 | 2023-01-30 14:28:46 +1100 | [diff] [blame] | 451 | type=Path, |
| 452 | help="Use DIR for build state and output files", |
| 453 | ) |
| 454 | parser.add_argument( |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 455 | "--nouse-image", |
| 456 | dest="use_image", |
| 457 | action="store_false", |
| 458 | default=False, |
Brian Norris | 35a7ed0 | 2023-02-23 12:50:14 -0800 | [diff] [blame] | 459 | deprecated="--[no]use-image is no longer supported (b/266878468).", |
| 460 | help=argparse.SUPPRESS, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 461 | ) |
| 462 | parser.add_argument( |
| 463 | "--use-image", |
| 464 | dest="use_image", |
| 465 | action="store_true", |
| 466 | default=False, |
Brian Norris | 35a7ed0 | 2023-02-23 12:50:14 -0800 | [diff] [blame] | 467 | deprecated="--[no]use-image is no longer supported (b/266878468).", |
| 468 | help=argparse.SUPPRESS, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 469 | ) |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 470 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 471 | parser.add_argument( |
| 472 | "--chrome-root", |
| 473 | "--chrome_root", |
| 474 | type="path", |
| 475 | help="Mount this chrome root into the SDK chroot", |
| 476 | ) |
| 477 | parser.add_argument( |
| 478 | "--chrome_root_mount", |
| 479 | type="path", |
| 480 | help="Mount chrome into this path inside SDK chroot", |
| 481 | ) |
| 482 | parser.add_argument( |
| 483 | "--nousepkg", |
| 484 | action="store_true", |
| 485 | default=False, |
| 486 | help="Do not use binary packages when creating a chroot.", |
| 487 | ) |
| 488 | parser.add_argument( |
| 489 | "-u", |
| 490 | "--url", |
| 491 | dest="sdk_url", |
| 492 | help="Use sdk tarball located at this url. Use file:// " |
| 493 | "for local files.", |
| 494 | ) |
| 495 | parser.add_argument( |
| 496 | "--sdk-version", |
| 497 | help=( |
| 498 | "Use this sdk version. For prebuilt, current is %r" |
| 499 | ", for bootstrapping it is %r." |
| 500 | % (sdk_latest_version, bootstrap_latest_version) |
| 501 | ), |
| 502 | ) |
| 503 | parser.add_argument( |
Mike Frysinger | 8582456 | 2023-01-31 02:40:43 -0500 | [diff] [blame] | 504 | "--goma-dir", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 505 | "--goma_dir", |
Mike Frysinger | 8fc8377 | 2023-02-01 15:30:47 -0500 | [diff] [blame] | 506 | type="dir_exists", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 507 | help="Goma installed directory to mount into the chroot.", |
| 508 | ) |
| 509 | parser.add_argument( |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 510 | "--reclient-dir", |
Mike Frysinger | 8fc8377 | 2023-02-01 15:30:47 -0500 | [diff] [blame] | 511 | type="dir_exists", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 512 | help="Reclient installed directory to mount into the chroot.", |
| 513 | ) |
| 514 | parser.add_argument( |
| 515 | "--reproxy-cfg-file", |
Mike Frysinger | 8fc8377 | 2023-02-01 15:30:47 -0500 | [diff] [blame] | 516 | type="file_exists", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 517 | help="Config file for re-client's reproxy used for remoteexec.", |
| 518 | ) |
| 519 | parser.add_argument( |
| 520 | "--skip-chroot-upgrade", |
| 521 | dest="chroot_upgrade", |
| 522 | action="store_false", |
| 523 | default=True, |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 524 | help="Skip automatic SDK and toolchain upgrade when entering the " |
| 525 | "chroot. Never guaranteed to work, especially as ToT moves forward.", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 526 | ) |
Brian Norris | 872684f | 2023-08-22 15:20:20 -0700 | [diff] [blame] | 527 | parser.add_bool_argument( |
| 528 | "--delete-out-dir", |
| 529 | default=True, |
| 530 | enabled_desc="Delete the SDK build state along with the chroot. " |
| 531 | "Applies to --delete or --replace.", |
| 532 | disabled_desc="Don't delete the SDK build state along with the chroot. " |
| 533 | "Applies to --delete or --replace.", |
| 534 | ) |
Yong Hong | 84ba917 | 2018-02-07 01:37:42 +0800 | [diff] [blame] | 535 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 536 | # Use type=str instead of type='path' to prevent the given path from being |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 537 | # transferred to absolute path automatically. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 538 | parser.add_argument( |
| 539 | "--working-dir", |
Mike Frysinger | 695f2fd | 2023-02-03 20:45:14 -0500 | [diff] [blame] | 540 | type=Path, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 541 | help="Run the command in specific working directory in " |
| 542 | "chroot. If the given directory is a relative " |
| 543 | "path, this program will transfer the path to " |
| 544 | "the corresponding one inside chroot.", |
| 545 | ) |
Yong Hong | 84ba917 | 2018-02-07 01:37:42 +0800 | [diff] [blame] | 546 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 547 | parser.add_argument("commands", nargs=argparse.REMAINDER) |
Mike Frysinger | 34db869 | 2013-11-11 14:54:08 -0500 | [diff] [blame] | 548 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 549 | # Commands. |
| 550 | group = parser.add_argument_group("Commands") |
Mike Frysinger | 79024a3 | 2021-04-05 03:28:35 -0400 | [diff] [blame] | 551 | group.add_argument( |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 552 | "--enter", |
| 553 | action="store_true", |
| 554 | default=False, |
| 555 | help="Enter the SDK chroot. Implies --create.", |
| 556 | ) |
Mike Frysinger | 79024a3 | 2021-04-05 03:28:35 -0400 | [diff] [blame] | 557 | group.add_argument( |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 558 | "--create", |
| 559 | action="store_true", |
| 560 | default=False, |
Alex Klein | 22690a1 | 2022-11-17 10:56:09 -0700 | [diff] [blame] | 561 | help="Create the chroot only if it does not already exist. Downloads " |
| 562 | "the SDK only if needed, even if --download explicitly passed.", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 563 | ) |
| 564 | group.add_argument( |
| 565 | "--bootstrap", |
| 566 | action="store_true", |
| 567 | default=False, |
| 568 | help="Build everything from scratch, including the sdk. " |
| 569 | "Use this only if you need to validate a change " |
| 570 | "that affects SDK creation itself (toolchain and " |
| 571 | "build are typically the only folk who need this). " |
| 572 | "Note this will quite heavily slow down the build. " |
| 573 | "This option implies --create --nousepkg.", |
| 574 | ) |
| 575 | group.add_argument( |
| 576 | "-r", |
| 577 | "--replace", |
| 578 | action="store_true", |
| 579 | default=False, |
| 580 | help="Replace an existing SDK chroot. Basically an alias " |
| 581 | "for --delete --create.", |
| 582 | ) |
| 583 | group.add_argument( |
| 584 | "--delete", |
| 585 | action="store_true", |
| 586 | default=False, |
Brian Norris | 872684f | 2023-08-22 15:20:20 -0700 | [diff] [blame] | 587 | help="Delete the current SDK chroot and build state if they exist.", |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 588 | ) |
| 589 | group.add_argument( |
| 590 | "--force", |
| 591 | action="store_true", |
| 592 | default=False, |
Brian Norris | f624bf4 | 2023-03-02 12:57:49 -0800 | [diff] [blame] | 593 | help="Force delete of the current SDK chroot even if " |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 594 | "obtaining the write lock fails.", |
| 595 | ) |
| 596 | group.add_argument( |
| 597 | "--unmount", |
| 598 | action="store_true", |
| 599 | default=False, |
Brian Norris | f624bf4 | 2023-03-02 12:57:49 -0800 | [diff] [blame] | 600 | deprecated="loopback-image (--use-image) is no longer supported " |
| 601 | "(b/266878468). If needed, consider `cros unmount /path/to/chroot`.", |
| 602 | help=argparse.SUPPRESS, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 603 | ) |
| 604 | group.add_argument( |
| 605 | "--download", |
| 606 | action="store_true", |
| 607 | default=False, |
| 608 | help="Download the sdk.", |
| 609 | ) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 610 | commands = group |
Mike Frysinger | 80dfce9 | 2014-04-21 10:58:53 -0400 | [diff] [blame] | 611 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 612 | # Namespace options. |
| 613 | group = parser.add_argument_group("Namespaces") |
| 614 | group.add_argument( |
| 615 | "--proxy-sim", |
| 616 | action="store_true", |
| 617 | default=False, |
| 618 | help="Simulate a restrictive network requiring an outbound" " proxy.", |
| 619 | ) |
| 620 | for ns, default in (("pid", True), ("net", None)): |
| 621 | group.add_argument( |
| 622 | f"--ns-{ns}", |
| 623 | default=default, |
| 624 | action="store_true", |
| 625 | help=f"Create a new {ns} namespace.", |
| 626 | ) |
| 627 | group.add_argument( |
| 628 | f"--no-ns-{ns}", |
| 629 | dest=f"ns_{ns}", |
| 630 | action="store_false", |
| 631 | help=f"Do not create a new {ns} namespace.", |
| 632 | ) |
Mike Frysinger | 5f5c70b | 2022-07-19 12:55:21 -0400 | [diff] [blame] | 633 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 634 | # Debug options. |
| 635 | group = parser.debug_group |
| 636 | group.add_argument( |
| 637 | "--strace", |
| 638 | action="store_true", |
| 639 | help="Run cros_sdk through strace after re-exec via sudo", |
| 640 | ) |
| 641 | group.add_argument( |
| 642 | "--strace-arguments", |
| 643 | default="", |
| 644 | help="Extra strace options (shell quoting permitted)", |
| 645 | ) |
Mike Frysinger | 34db869 | 2013-11-11 14:54:08 -0500 | [diff] [blame] | 646 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 647 | # Internal options. |
| 648 | group = parser.add_argument_group( |
| 649 | "Internal Chromium OS Build Team Options", |
| 650 | "Caution: these are for meant for the Chromium OS build team only", |
| 651 | ) |
| 652 | group.add_argument( |
| 653 | "--buildbot-log-version", |
| 654 | default=False, |
| 655 | action="store_true", |
| 656 | help="Log SDK version for buildbot consumption", |
| 657 | ) |
| 658 | |
| 659 | return parser, commands |
Mike Frysinger | 34db869 | 2013-11-11 14:54:08 -0500 | [diff] [blame] | 660 | |
| 661 | |
| 662 | def main(argv): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 663 | # Turn on strict sudo checks. |
| 664 | cros_build_lib.STRICT_SUDO = True |
| 665 | conf = key_value_store.LoadFile( |
Greg Edelston | 0382ca4 | 2023-05-04 14:00:15 -0600 | [diff] [blame] | 666 | constants.SDK_VERSION_FILE_FULL_PATH, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 667 | ignore_missing=True, |
| 668 | ) |
| 669 | sdk_latest_version = conf.get("SDK_LATEST_VERSION", "<unknown>") |
| 670 | bootstrap_frozen_version = conf.get("BOOTSTRAP_FROZEN_VERSION", "<unknown>") |
Manoj Gupta | 55a6309 | 2019-06-13 11:47:13 -0700 | [diff] [blame] | 671 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 672 | # Use latest SDK for bootstrapping if requested. Use a frozen version of SDK |
| 673 | # for bootstrapping if BOOTSTRAP_FROZEN_VERSION is set. |
| 674 | bootstrap_latest_version = ( |
| 675 | sdk_latest_version |
| 676 | if bootstrap_frozen_version == "<unknown>" |
| 677 | else bootstrap_frozen_version |
| 678 | ) |
| 679 | parser, commands = _CreateParser( |
| 680 | sdk_latest_version, bootstrap_latest_version |
| 681 | ) |
| 682 | options = parser.parse_args(argv) |
Mike Frysinger | ce3d78f | 2023-08-30 10:41:33 -0400 | [diff] [blame] | 683 | options.out_dir = options.out_dir.resolve() |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 684 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 685 | # Some basic checks first, before we ask for sudo credentials. |
| 686 | cros_build_lib.AssertOutsideChroot() |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 687 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 688 | host = os.uname()[4] |
| 689 | if host != "x86_64": |
| 690 | cros_build_lib.Die( |
| 691 | "cros_sdk is currently only supported on x86_64; you're running" |
| 692 | " %s. Please find a x86_64 machine." % (host,) |
| 693 | ) |
Brian Harring | 1790ac4 | 2012-09-23 08:53:33 -0700 | [diff] [blame] | 694 | |
Brian Norris | cf03191 | 2023-02-21 15:04:27 -0800 | [diff] [blame] | 695 | goma = ( |
Brian Norris | 4f251e4 | 2023-03-09 15:53:26 -0800 | [diff] [blame] | 696 | goma_lib.Goma( |
| 697 | options.goma_dir, chroot_dir=options.chroot, out_dir=options.out_dir |
| 698 | ) |
Brian Norris | cf03191 | 2023-02-21 15:04:27 -0800 | [diff] [blame] | 699 | if options.goma_dir |
| 700 | else None |
| 701 | ) |
Mike Frysinger | 9a5124e | 2023-01-26 17:16:44 -0500 | [diff] [blame] | 702 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 703 | # Merge the outside PATH setting if we re-execed ourselves. |
| 704 | if "CHROMEOS_SUDO_PATH" in os.environ: |
| 705 | os.environ["PATH"] = "%s:%s" % ( |
| 706 | os.environ.pop("CHROMEOS_SUDO_PATH"), |
| 707 | os.environ["PATH"], |
| 708 | ) |
Mike Frysinger | 2bda4d1 | 2020-07-14 11:15:49 -0400 | [diff] [blame] | 709 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 710 | _ReportMissing(osutils.FindMissingBinaries(NEEDED_TOOLS)) |
| 711 | if options.proxy_sim: |
| 712 | _ReportMissing(osutils.FindMissingBinaries(PROXY_NEEDED_TOOLS)) |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 713 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 714 | if ( |
| 715 | sdk_latest_version == "<unknown>" |
| 716 | or bootstrap_latest_version == "<unknown>" |
| 717 | ): |
| 718 | cros_build_lib.Die( |
| 719 | "No SDK version was found. " |
| 720 | "Are you in a Chromium source tree instead of Chromium OS?\n\n" |
| 721 | "Please change to a directory inside your Chromium OS source tree\n" |
| 722 | "and retry. If you need to setup a Chromium OS source tree, see\n" |
| 723 | " https://dev.chromium.org/chromium-os/developer-guide" |
| 724 | ) |
Benjamin Gordon | 040a116 | 2017-06-29 13:44:47 -0600 | [diff] [blame] | 725 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 726 | _ReExecuteIfNeeded([sys.argv[0]] + argv, options) |
David James | 471532c | 2013-01-21 10:23:31 -0800 | [diff] [blame] | 727 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 728 | lock_path = os.path.dirname(options.chroot) |
| 729 | lock_path = os.path.join( |
| 730 | lock_path, ".%s_lock" % os.path.basename(options.chroot).lstrip(".") |
| 731 | ) |
Benjamin Gordon | abb3e37 | 2017-08-09 10:21:05 -0600 | [diff] [blame] | 732 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 733 | # Expand out the aliases... |
| 734 | if options.replace: |
| 735 | options.delete = options.create = True |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 736 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 737 | if options.bootstrap: |
| 738 | options.create = True |
Brian Harring | b938c78 | 2012-02-29 15:14:38 -0800 | [diff] [blame] | 739 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 740 | # If a command is not given, default to enter. |
| 741 | # pylint: disable=protected-access |
| 742 | # This _group_actions access sucks, but upstream decided to not include an |
| 743 | # alternative to optparse's option_list, and this is what they recommend. |
| 744 | options.enter |= not any( |
| 745 | getattr(options, x.dest) for x in commands._group_actions |
| 746 | ) |
| 747 | # pylint: enable=protected-access |
Mike Frysinger | 114a7b9 | 2023-01-26 19:08:57 -0500 | [diff] [blame] | 748 | options.enter |= bool(options.commands) |
Brian Harring | 218e13c | 2012-10-10 16:21:26 -0700 | [diff] [blame] | 749 | |
Brian Norris | 35a7ed0 | 2023-02-23 12:50:14 -0800 | [diff] [blame] | 750 | if options.delete and not options.create and options.enter: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 751 | parser.error( |
Brian Norris | 35a7ed0 | 2023-02-23 12:50:14 -0800 | [diff] [blame] | 752 | "Trying to enter the chroot when --delete " |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 753 | "was specified makes no sense." |
| 754 | ) |
Brian Harring | 218e13c | 2012-10-10 16:21:26 -0700 | [diff] [blame] | 755 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 756 | chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 757 | # Finally, flip create if necessary. |
Brian Norris | 35a7ed0 | 2023-02-23 12:50:14 -0800 | [diff] [blame] | 758 | if options.enter: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 759 | options.create |= not chroot_exists |
| 760 | |
| 761 | # Make sure we will download if we plan to create. |
| 762 | options.download |= options.create |
| 763 | |
Mike Frysinger | 6bbd3e9 | 2023-01-27 00:05:02 -0500 | [diff] [blame] | 764 | options.Freeze() |
| 765 | |
Mike Frysinger | ded1392 | 2023-02-01 15:31:59 -0500 | [diff] [blame] | 766 | if options.reclient_dir and not options.reproxy_cfg_file: |
| 767 | cros_build_lib.Die("--reclient-dir requires --reproxy-cfg-file") |
| 768 | if not options.reclient_dir and options.reproxy_cfg_file: |
| 769 | cros_build_lib.Die( |
| 770 | "--reproxy-cfg-file only makes sense with --reclient-dir" |
| 771 | ) |
| 772 | |
Mike Frysinger | 253c839 | 2023-01-27 01:12:21 -0500 | [diff] [blame] | 773 | remoteexec = ( |
| 774 | remoteexec_util.Remoteexec( |
| 775 | options.reclient_dir, options.reproxy_cfg_file |
| 776 | ) |
| 777 | if (options.reclient_dir and options.reproxy_cfg_file) |
| 778 | else None |
| 779 | ) |
| 780 | |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 781 | chroot = chroot_lib.Chroot( |
| 782 | path=options.chroot, |
Brian Norris | 2adb74c | 2023-03-29 12:20:44 -0700 | [diff] [blame] | 783 | out_path=options.out_dir, |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 784 | cache_dir=options.cache_dir, |
| 785 | chrome_root=options.chrome_root, |
| 786 | goma=goma, |
| 787 | remoteexec=remoteexec, |
| 788 | ) |
| 789 | |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 790 | # Anything that needs to manipulate the main chroot mount or communicate |
| 791 | # with LVM needs to be done here before we enter the new namespaces. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 792 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 793 | if options.delete: |
| 794 | # Set a timeout of 300 seconds when getting the lock. |
| 795 | with locking.FileLock( |
| 796 | lock_path, "chroot lock", blocking_timeout=300 |
| 797 | ) as lock: |
| 798 | try: |
| 799 | lock.write_lock() |
| 800 | except timeout_util.TimeoutError as e: |
| 801 | logging.error( |
| 802 | "Acquiring write_lock on %s failed: %s", lock_path, e |
| 803 | ) |
| 804 | if not options.force: |
| 805 | cros_build_lib.Die( |
| 806 | "Exiting; use --force to continue w/o lock." |
| 807 | ) |
| 808 | else: |
| 809 | logging.warning( |
| 810 | "cros_sdk was invoked with force option, continuing." |
| 811 | ) |
Mike Frysinger | beb40d8 | 2023-08-30 10:42:22 -0400 | [diff] [blame] | 812 | logging.notice("Deleting chroot: %s", chroot.path) |
| 813 | logging.notice( |
| 814 | "%s output dir: %s", |
| 815 | "Deleting" if options.delete_out_dir else "Keeping", |
| 816 | chroot.out_path, |
| 817 | ) |
Brian Norris | 872684f | 2023-08-22 15:20:20 -0700 | [diff] [blame] | 818 | cros_sdk_lib.CleanupChrootMount( |
| 819 | chroot, delete=True, delete_out=options.delete_out_dir |
| 820 | ) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 821 | |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 822 | # Enter a new set of namespaces. Everything after here cannot directly |
| 823 | # affect the hosts's mounts or alter LVM volumes. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 824 | namespaces.SimpleUnshare(net=options.ns_net, pid=options.ns_pid) |
Benjamin Gordon | 386b9eb | 2017-07-20 09:21:33 -0600 | [diff] [blame] | 825 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 826 | if not options.sdk_version: |
| 827 | sdk_version = ( |
| 828 | bootstrap_latest_version |
| 829 | if options.bootstrap |
| 830 | else sdk_latest_version |
| 831 | ) |
Yong Hong | 4e29b62 | 2018-02-05 14:31:10 +0800 | [diff] [blame] | 832 | else: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 833 | sdk_version = options.sdk_version |
| 834 | if options.buildbot_log_version: |
| 835 | cbuildbot_alerts.PrintBuildbotStepText(sdk_version) |
Brian Harring | 1790ac4 | 2012-09-23 08:53:33 -0700 | [diff] [blame] | 836 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 837 | # Based on selections, determine the tarball to fetch. |
Alex Klein | 22690a1 | 2022-11-17 10:56:09 -0700 | [diff] [blame] | 838 | urls = [] |
Mike Frysinger | bf47cce | 2021-01-20 13:46:30 -0500 | [diff] [blame] | 839 | if options.download: |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 840 | if options.sdk_url: |
| 841 | urls = [options.sdk_url] |
| 842 | else: |
| 843 | urls = GetArchStageTarballs(sdk_version) |
Brian Harring | 218e13c | 2012-10-10 16:21:26 -0700 | [diff] [blame] | 844 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 845 | with locking.FileLock(lock_path, "chroot lock") as lock: |
| 846 | if options.proxy_sim: |
| 847 | _ProxySimSetup(options) |
Brian Harring | 1790ac4 | 2012-09-23 08:53:33 -0700 | [diff] [blame] | 848 | |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 849 | sdk_cache = os.path.join(chroot.cache_dir, "sdks") |
| 850 | distfiles_cache = os.path.join(chroot.cache_dir, "distfiles") |
| 851 | osutils.SafeMakedirsNonRoot(chroot.cache_dir) |
Dan Callaghan | ada9e03 | 2023-01-30 14:28:46 +1100 | [diff] [blame] | 852 | osutils.SafeMakedirsNonRoot(options.out_dir) |
Brian Norris | 5e4e37b | 2023-04-03 14:38:33 -0700 | [diff] [blame] | 853 | # Create here (and not, say, in cros_sdk_lib.MountChrootPaths()) |
| 854 | # because some usages want to create tmp files here even before we've |
| 855 | # fully mounted the SDK. |
| 856 | osutils.SafeMakedirsNonRoot(options.out_dir / "tmp", mode=0o777) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 857 | |
| 858 | for target in (sdk_cache, distfiles_cache): |
| 859 | src = os.path.join(constants.SOURCE_ROOT, os.path.basename(target)) |
| 860 | if not os.path.exists(src): |
| 861 | osutils.SafeMakedirsNonRoot(target) |
| 862 | continue |
| 863 | lock.write_lock( |
| 864 | "Upgrade to %r needed but chroot is locked; please exit " |
| 865 | "all instances so this upgrade can finish." % src |
| 866 | ) |
| 867 | if not os.path.exists(src): |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 868 | # Note that while waiting for the write lock, src may've |
| 869 | # vanished; it's a rare race during the upgrade process that's a |
| 870 | # byproduct of us avoiding taking a write lock to do the src |
| 871 | # check. If we took a write lock for that check, it would |
| 872 | # effectively limit all cros_sdk for a chroot to a single |
| 873 | # instance. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 874 | osutils.SafeMakedirsNonRoot(target) |
| 875 | elif not os.path.exists(target): |
| 876 | # Upgrade occurred, but a reversion, or something whacky |
| 877 | # occurred writing to the old location. Wipe and continue. |
| 878 | os.rename(src, target) |
| 879 | else: |
| 880 | # Upgrade occurred once already, but either a reversion or |
| 881 | # some before/after separate cros_sdk usage is at play. |
| 882 | # Wipe and continue. |
| 883 | osutils.RmDir(src) |
| 884 | |
Brian Norris | c2b71e4 | 2023-03-30 15:27:36 -0700 | [diff] [blame] | 885 | cros_sdk_lib.MigrateStatePaths(chroot, lock) |
| 886 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 887 | mounted = False |
| 888 | if options.create: |
| 889 | lock.write_lock() |
Alex Klein | ef51783 | 2023-01-13 12:06:51 -0700 | [diff] [blame] | 890 | # Recheck if the chroot is set up here before creating to make sure |
Brian Norris | f624bf4 | 2023-03-02 12:57:49 -0800 | [diff] [blame] | 891 | # we account for whatever the various delete/cleanup steps above |
| 892 | # have done. |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 893 | if cros_sdk_lib.IsChrootReady(chroot.path): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 894 | logging.debug("Chroot already exists. Skipping creation.") |
| 895 | else: |
Alex Klein | 22690a1 | 2022-11-17 10:56:09 -0700 | [diff] [blame] | 896 | sdk_tarball = FetchRemoteTarballs(sdk_cache, urls) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 897 | cros_sdk_lib.CreateChroot( |
Brian Norris | 7f10df8 | 2023-08-22 13:38:54 -0700 | [diff] [blame] | 898 | chroot, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 899 | Path(sdk_tarball), |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 900 | usepkg=not options.bootstrap and not options.nousepkg, |
| 901 | chroot_upgrade=options.chroot_upgrade, |
| 902 | ) |
| 903 | mounted = True |
Alex Klein | 22690a1 | 2022-11-17 10:56:09 -0700 | [diff] [blame] | 904 | elif options.download: |
| 905 | # Allow downloading only. |
| 906 | lock.write_lock() |
| 907 | FetchRemoteTarballs(sdk_cache, urls) |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 908 | |
| 909 | if options.enter: |
| 910 | lock.read_lock() |
| 911 | if not mounted: |
Brian Norris | 7f10df8 | 2023-08-22 13:38:54 -0700 | [diff] [blame] | 912 | cros_sdk_lib.MountChrootPaths(chroot) |
Mike Frysinger | 53baf88 | 2021-06-24 23:16:50 -0400 | [diff] [blame] | 913 | ret = cros_sdk_lib.EnterChroot( |
Mike Frysinger | ec32bea | 2023-01-27 01:20:48 -0500 | [diff] [blame] | 914 | chroot, |
Mike Frysinger | 53baf88 | 2021-06-24 23:16:50 -0400 | [diff] [blame] | 915 | chrome_root_mount=options.chrome_root_mount, |
| 916 | cwd=options.working_dir, |
| 917 | cmd=options.commands, |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 918 | ) |
| 919 | sys.exit(ret.returncode) |