Mike Frysinger | e58c0e2 | 2017-10-04 15:43:30 -0400 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 2 | # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """ChromeOS image pusher (from cbuildbot to signer). |
| 7 | |
| 8 | This pushes files from the archive bucket to the signer bucket and marks |
| 9 | artifacts for signing (which a signing process will look for). |
| 10 | """ |
| 11 | |
| 12 | from __future__ import print_function |
| 13 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 14 | import getpass |
| 15 | import os |
| 16 | import re |
Mike Frysinger | 09fe012 | 2014-02-09 02:44:05 -0500 | [diff] [blame] | 17 | import textwrap |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 18 | |
Mike Frysinger | b43142e | 2019-08-27 17:50:44 -0400 | [diff] [blame] | 19 | from six.moves import configparser |
Mike Frysinger | fd54457 | 2019-09-06 16:35:50 -0400 | [diff] [blame] | 20 | from six.moves import StringIO |
Mike Frysinger | b43142e | 2019-08-27 17:50:44 -0400 | [diff] [blame] | 21 | |
Aviv Keshet | b7519e1 | 2016-10-04 00:50:00 -0700 | [diff] [blame] | 22 | from chromite.lib import constants |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 23 | from chromite.lib import commandline |
| 24 | from chromite.lib import cros_build_lib |
Ralph Nathan | 5a582ff | 2015-03-20 18:18:30 -0700 | [diff] [blame] | 25 | from chromite.lib import cros_logging as logging |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 26 | from chromite.lib import gs |
| 27 | from chromite.lib import osutils |
| 28 | from chromite.lib import signing |
| 29 | |
| 30 | |
| 31 | # This will split a fully qualified ChromeOS version string up. |
| 32 | # R34-5126.0.0 will break into "34" and "5126.0.0". |
| 33 | VERSION_REGEX = r'^R([0-9]+)-([^-]+)' |
| 34 | |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 35 | # The test signers will scan this dir looking for test work. |
| 36 | # Keep it in sync with the signer config files [gs_test_buckets]. |
| 37 | TEST_SIGN_BUCKET_BASE = 'gs://chromeos-throw-away-bucket/signer-tests' |
| 38 | |
David Riley | f820512 | 2015-09-04 13:46:36 -0700 | [diff] [blame] | 39 | # Keysets that are only valid in the above test bucket. |
| 40 | TEST_KEYSET_PREFIX = 'test-keys' |
| 41 | TEST_KEYSETS = set(( |
| 42 | 'mp', |
| 43 | 'premp', |
| 44 | 'nvidia-premp', |
| 45 | )) |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 46 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 47 | # Supported image types for signing. |
| 48 | _SUPPORTED_IMAGE_TYPES = ( |
| 49 | constants.IMAGE_TYPE_RECOVERY, |
| 50 | constants.IMAGE_TYPE_FACTORY, |
| 51 | constants.IMAGE_TYPE_FIRMWARE, |
David Riley | a04d19d | 2015-09-04 16:11:50 -0700 | [diff] [blame] | 52 | constants.IMAGE_TYPE_NV_LP0_FIRMWARE, |
Vincent Palatin | d599c66 | 2015-10-26 09:51:41 -0700 | [diff] [blame] | 53 | constants.IMAGE_TYPE_ACCESSORY_USBPD, |
| 54 | constants.IMAGE_TYPE_ACCESSORY_RWSIG, |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 55 | constants.IMAGE_TYPE_BASE, |
LaMont Jones | 7d6c98f | 2019-09-27 12:37:33 -0600 | [diff] [blame] | 56 | constants.IMAGE_TYPE_CR50_FIRMWARE, |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 57 | ) |
| 58 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 59 | |
Mike Frysinger | 4495b03 | 2014-03-05 17:24:03 -0500 | [diff] [blame] | 60 | class PushError(Exception): |
| 61 | """When an (unknown) error happened while trying to push artifacts.""" |
| 62 | |
| 63 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 64 | class MissingBoardInstructions(Exception): |
| 65 | """Raised when a board lacks any signer instructions.""" |
| 66 | |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 67 | def __init__(self, board, image_type, input_insns): |
| 68 | Exception.__init__(self, 'Board %s lacks insns for %s image: %s not found' % |
| 69 | (board, image_type, input_insns)) |
| 70 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 71 | |
| 72 | class InputInsns(object): |
| 73 | """Object to hold settings for a signable board. |
| 74 | |
| 75 | Note: The format of the instruction file pushimage outputs (and the signer |
| 76 | reads) is not exactly the same as the instruction file pushimage reads. |
| 77 | """ |
| 78 | |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 79 | def __init__(self, board, image_type=None, buildroot=None): |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 80 | """Initialization. |
| 81 | |
| 82 | Args: |
| 83 | board: The board to look up details. |
| 84 | image_type: The type of image we will be signing (see --sign-types). |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 85 | buildroot: Buildroot in which to look for signing instructions. |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 86 | """ |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 87 | self.board = board |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 88 | self.buildroot = buildroot or constants.SOURCE_ROOT |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 89 | |
Mike Frysinger | b43142e | 2019-08-27 17:50:44 -0400 | [diff] [blame] | 90 | config = configparser.ConfigParser() |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 91 | config.readfp(open(self.GetInsnFile('DEFAULT'))) |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 92 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 93 | # What pushimage internally refers to as 'recovery', are the basic signing |
| 94 | # instructions in practice, and other types are stacked on top. |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 95 | if image_type is None: |
| 96 | image_type = constants.IMAGE_TYPE_RECOVERY |
| 97 | self.image_type = image_type |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 98 | input_insns = self.GetInsnFile(constants.IMAGE_TYPE_RECOVERY) |
| 99 | if not os.path.exists(input_insns): |
| 100 | # This board doesn't have any signing instructions. |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 101 | raise MissingBoardInstructions(self.board, image_type, input_insns) |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 102 | config.readfp(open(input_insns)) |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 103 | |
| 104 | if image_type is not None: |
| 105 | input_insns = self.GetInsnFile(image_type) |
| 106 | if not os.path.exists(input_insns): |
| 107 | # This type doesn't have any signing instructions. |
| 108 | raise MissingBoardInstructions(self.board, image_type, input_insns) |
| 109 | |
| 110 | self.image_type = image_type |
| 111 | config.readfp(open(input_insns)) |
| 112 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 113 | self.cfg = config |
| 114 | |
| 115 | def GetInsnFile(self, image_type): |
| 116 | """Find the signer instruction files for this board/image type. |
| 117 | |
| 118 | Args: |
| 119 | image_type: The type of instructions to load. It can be a common file |
| 120 | (like "DEFAULT"), or one of the --sign-types. |
| 121 | |
| 122 | Returns: |
| 123 | Full path to the instruction file using |image_type| and |self.board|. |
| 124 | """ |
| 125 | if image_type == image_type.upper(): |
| 126 | name = image_type |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 127 | elif image_type in (constants.IMAGE_TYPE_RECOVERY, |
| 128 | constants.IMAGE_TYPE_BASE): |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 129 | name = self.board |
| 130 | else: |
| 131 | name = '%s.%s' % (self.board, image_type) |
| 132 | |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 133 | return os.path.join( |
| 134 | self.buildroot, signing.INPUT_INSN_DIR_REL, '%s.instructions' % name) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 135 | |
| 136 | @staticmethod |
| 137 | def SplitCfgField(val): |
| 138 | """Split a string into multiple elements. |
| 139 | |
| 140 | This centralizes our convention for multiple elements in the input files |
| 141 | being delimited by either a space or comma. |
| 142 | |
| 143 | Args: |
| 144 | val: The string to split. |
| 145 | |
| 146 | Returns: |
| 147 | The list of elements from having done split the string. |
| 148 | """ |
| 149 | return val.replace(',', ' ').split() |
| 150 | |
| 151 | def GetChannels(self): |
| 152 | """Return the list of channels to sign for this board. |
| 153 | |
| 154 | If the board-specific config doesn't specify a preference, we'll use the |
| 155 | common settings. |
| 156 | """ |
| 157 | return self.SplitCfgField(self.cfg.get('insns', 'channel')) |
| 158 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 159 | def GetKeysets(self, insns_merge=None): |
| 160 | """Return the list of keysets to sign for this board. |
| 161 | |
| 162 | Args: |
| 163 | insns_merge: The additional section to look at over [insns]. |
| 164 | """ |
| 165 | # First load the default value from [insns.keyset] if available. |
| 166 | sections = ['insns'] |
| 167 | # Then overlay the [insns.xxx.keyset] if requested. |
| 168 | if insns_merge is not None: |
| 169 | sections += [insns_merge] |
| 170 | |
| 171 | keyset = '' |
| 172 | for section in sections: |
| 173 | try: |
| 174 | keyset = self.cfg.get(section, 'keyset') |
Mike Frysinger | b43142e | 2019-08-27 17:50:44 -0400 | [diff] [blame] | 175 | except (configparser.NoSectionError, configparser.NoOptionError): |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 176 | pass |
| 177 | |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 178 | # We do not perturb the order (e.g. using sorted() or making a set()) |
| 179 | # because we want the behavior stable, and we want the input insns to |
| 180 | # explicitly control the order (since it has an impact on naming). |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 181 | return self.SplitCfgField(keyset) |
| 182 | |
| 183 | def GetAltInsnSets(self): |
| 184 | """Return the list of alternative insn sections.""" |
| 185 | # We do not perturb the order (e.g. using sorted() or making a set()) |
| 186 | # because we want the behavior stable, and we want the input insns to |
| 187 | # explicitly control the order (since it has an impact on naming). |
| 188 | ret = [x for x in self.cfg.sections() if x.startswith('insns.')] |
| 189 | return ret if ret else [None] |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 190 | |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 191 | @staticmethod |
| 192 | def CopyConfigParser(config): |
| 193 | """Return a copy of a ConfigParser object. |
| 194 | |
Thiemo Nagel | 9fb9972 | 2017-05-26 16:26:40 +0200 | [diff] [blame] | 195 | The python folks broke the ability to use something like deepcopy: |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 196 | https://bugs.python.org/issue16058 |
| 197 | """ |
| 198 | # Write the current config to a string io object. |
Mike Frysinger | fd54457 | 2019-09-06 16:35:50 -0400 | [diff] [blame] | 199 | data = StringIO() |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 200 | config.write(data) |
| 201 | data.seek(0) |
| 202 | |
| 203 | # Create a new ConfigParser from the serialized data. |
Mike Frysinger | b43142e | 2019-08-27 17:50:44 -0400 | [diff] [blame] | 204 | ret = configparser.ConfigParser() |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 205 | ret.readfp(data) |
| 206 | |
| 207 | return ret |
| 208 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 209 | def OutputInsns(self, output_file, sect_insns, sect_general, |
| 210 | insns_merge=None): |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 211 | """Generate the output instruction file for sending to the signer. |
| 212 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 213 | The override order is (later has precedence): |
| 214 | [insns] |
| 215 | [insns_merge] (should be named "insns.xxx") |
| 216 | sect_insns |
| 217 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 218 | Note: The format of the instruction file pushimage outputs (and the signer |
| 219 | reads) is not exactly the same as the instruction file pushimage reads. |
| 220 | |
| 221 | Args: |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 222 | output_file: The file to write the new instruction file to. |
| 223 | sect_insns: Items to set/override in the [insns] section. |
| 224 | sect_general: Items to set/override in the [general] section. |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 225 | insns_merge: The alternative insns.xxx section to merge. |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 226 | """ |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 227 | # Create a copy so we can clobber certain fields. |
| 228 | config = self.CopyConfigParser(self.cfg) |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 229 | sect_insns = sect_insns.copy() |
| 230 | |
| 231 | # Merge in the alternative insns section if need be. |
| 232 | if insns_merge is not None: |
| 233 | for k, v in config.items(insns_merge): |
| 234 | sect_insns.setdefault(k, v) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 235 | |
| 236 | # Clear channel entry in instructions file, ensuring we only get |
| 237 | # one channel for the signer to look at. Then provide all the |
| 238 | # other details for this signing request to avoid any ambiguity |
| 239 | # and to avoid relying on encoding data into filenames. |
| 240 | for sect, fields in zip(('insns', 'general'), (sect_insns, sect_general)): |
| 241 | if not config.has_section(sect): |
| 242 | config.add_section(sect) |
Mike Frysinger | 0bdbc10 | 2019-06-13 15:27:29 -0400 | [diff] [blame] | 243 | for k, v in fields.items(): |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 244 | config.set(sect, k, v) |
| 245 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 246 | # Now prune the alternative sections. |
| 247 | for alt in self.GetAltInsnSets(): |
| 248 | config.remove_section(alt) |
| 249 | |
Mike Frysinger | fd54457 | 2019-09-06 16:35:50 -0400 | [diff] [blame] | 250 | output = StringIO() |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 251 | config.write(output) |
| 252 | data = output.getvalue() |
| 253 | osutils.WriteFile(output_file, data) |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 254 | logging.debug('generated insns file for %s:\n%s', self.image_type, data) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 255 | |
| 256 | |
| 257 | def MarkImageToBeSigned(ctx, tbs_base, insns_path, priority): |
| 258 | """Mark an instructions file for signing. |
| 259 | |
| 260 | This will upload a file to the GS bucket flagging an image for signing by |
| 261 | the signers. |
| 262 | |
| 263 | Args: |
| 264 | ctx: A viable gs.GSContext. |
| 265 | tbs_base: The full path to where the tobesigned directory lives. |
| 266 | insns_path: The path (relative to |tbs_base|) of the file to sign. |
| 267 | priority: Set the signing priority (lower == higher prio). |
| 268 | |
| 269 | Returns: |
| 270 | The full path to the remote tobesigned file. |
| 271 | """ |
| 272 | if priority < 0 or priority > 99: |
| 273 | raise ValueError('priority must be [0, 99] inclusive') |
| 274 | |
| 275 | if insns_path.startswith(tbs_base): |
| 276 | insns_path = insns_path[len(tbs_base):].lstrip('/') |
| 277 | |
| 278 | tbs_path = '%s/tobesigned/%02i,%s' % (tbs_base, priority, |
| 279 | insns_path.replace('/', ',')) |
| 280 | |
Mike Frysinger | 6430d13 | 2014-10-27 23:43:30 -0400 | [diff] [blame] | 281 | # The caller will catch gs.GSContextException for us. |
| 282 | ctx.Copy('-', tbs_path, input=cros_build_lib.MachineDetails()) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 283 | |
| 284 | return tbs_path |
| 285 | |
| 286 | |
| 287 | def PushImage(src_path, board, versionrev=None, profile=None, priority=50, |
Mike Frysinger | 7791210 | 2017-08-30 18:35:46 -0400 | [diff] [blame] | 288 | sign_types=None, dry_run=False, mock=False, force_keysets=(), |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 289 | force_channels=None, buildroot=constants.SOURCE_ROOT): |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 290 | """Push the image from the archive bucket to the release bucket. |
| 291 | |
| 292 | Args: |
| 293 | src_path: Where to copy the files from; can be a local path or gs:// URL. |
| 294 | Should be a full path to the artifacts in either case. |
| 295 | board: The board we're uploading artifacts for (e.g. $BOARD). |
| 296 | versionrev: The full Chromium OS version string (e.g. R34-5126.0.0). |
| 297 | profile: The board profile in use (e.g. "asan"). |
| 298 | priority: Set the signing priority (lower == higher prio). |
| 299 | sign_types: If set, a set of types which we'll restrict ourselves to |
| 300 | signing. See the --sign-types option for more details. |
| 301 | dry_run: Show what would be done, but do not upload anything. |
| 302 | mock: Upload to a testing bucket rather than the real one. |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 303 | force_keysets: Set of keysets to use rather than what the inputs say. |
Mike Frysinger | 7791210 | 2017-08-30 18:35:46 -0400 | [diff] [blame] | 304 | force_channels: Set of channels to use rather than what the inputs say. |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 305 | buildroot: Buildroot in which to look for signing instructions. |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 306 | |
| 307 | Returns: |
Don Garrett | 9459c2f | 2014-01-22 18:20:24 -0800 | [diff] [blame] | 308 | A dictionary that maps 'channel' -> ['gs://signer_instruction_uri1', |
| 309 | 'gs://signer_instruction_uri2', |
| 310 | ...] |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 311 | """ |
Mike Frysinger | 4495b03 | 2014-03-05 17:24:03 -0500 | [diff] [blame] | 312 | # Whether we hit an unknown error. If so, we'll throw an error, but only |
| 313 | # at the end (so that we still upload as many files as possible). |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 314 | # It's implemented using a list to deal with variable scopes in nested |
| 315 | # functions below. |
| 316 | unknown_error = [False] |
Mike Frysinger | 4495b03 | 2014-03-05 17:24:03 -0500 | [diff] [blame] | 317 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 318 | if versionrev is None: |
| 319 | # Extract milestone/version from the directory name. |
| 320 | versionrev = os.path.basename(src_path) |
| 321 | |
| 322 | # We only support the latest format here. Older releases can use pushimage |
| 323 | # from the respective branch which deals with legacy cruft. |
| 324 | m = re.match(VERSION_REGEX, versionrev) |
| 325 | if not m: |
| 326 | raise ValueError('version %s does not match %s' % |
| 327 | (versionrev, VERSION_REGEX)) |
| 328 | milestone = m.group(1) |
| 329 | version = m.group(2) |
| 330 | |
| 331 | # Normalize board to always use dashes not underscores. This is mostly a |
| 332 | # historical artifact at this point, but we can't really break it since the |
| 333 | # value is used in URLs. |
| 334 | boardpath = board.replace('_', '-') |
| 335 | if profile is not None: |
| 336 | boardpath += '-%s' % profile.replace('_', '-') |
| 337 | |
| 338 | ctx = gs.GSContext(dry_run=dry_run) |
| 339 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 340 | try: |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 341 | input_insns = InputInsns(board, buildroot=buildroot) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 342 | except MissingBoardInstructions as e: |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 343 | logging.warning('Missing base instruction file: %s', e) |
Ralph Nathan | 446aee9 | 2015-03-23 14:44:56 -0700 | [diff] [blame] | 344 | logging.warning('not uploading anything for signing') |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 345 | return |
Mike Frysinger | 7791210 | 2017-08-30 18:35:46 -0400 | [diff] [blame] | 346 | |
| 347 | if force_channels is None: |
| 348 | channels = input_insns.GetChannels() |
| 349 | else: |
| 350 | # Filter out duplicates. |
| 351 | channels = sorted(set(force_channels)) |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 352 | |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 353 | # We want force_keysets as a set. |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 354 | force_keysets = set(force_keysets) |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 355 | |
| 356 | if mock: |
Ralph Nathan | 0304728 | 2015-03-23 11:09:32 -0700 | [diff] [blame] | 357 | logging.info('Upload mode: mock; signers will not process anything') |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 358 | tbs_base = gs_base = os.path.join(constants.TRASH_BUCKET, 'pushimage-tests', |
| 359 | getpass.getuser()) |
David Riley | f820512 | 2015-09-04 13:46:36 -0700 | [diff] [blame] | 360 | elif set(['%s-%s' % (TEST_KEYSET_PREFIX, x) |
| 361 | for x in TEST_KEYSETS]) & force_keysets: |
Ralph Nathan | 0304728 | 2015-03-23 11:09:32 -0700 | [diff] [blame] | 362 | logging.info('Upload mode: test; signers will process test keys') |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 363 | # We need the tbs_base to be in the place the signer will actually scan. |
| 364 | tbs_base = TEST_SIGN_BUCKET_BASE |
| 365 | gs_base = os.path.join(tbs_base, getpass.getuser()) |
| 366 | else: |
Ralph Nathan | 0304728 | 2015-03-23 11:09:32 -0700 | [diff] [blame] | 367 | logging.info('Upload mode: normal; signers will process the images') |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 368 | tbs_base = gs_base = constants.RELEASE_BUCKET |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 369 | |
| 370 | sect_general = { |
| 371 | 'config_board': board, |
| 372 | 'board': boardpath, |
| 373 | 'version': version, |
| 374 | 'versionrev': versionrev, |
| 375 | 'milestone': milestone, |
| 376 | } |
| 377 | sect_insns = {} |
| 378 | |
| 379 | if dry_run: |
Ralph Nathan | 0304728 | 2015-03-23 11:09:32 -0700 | [diff] [blame] | 380 | logging.info('DRY RUN MODE ACTIVE: NOTHING WILL BE UPLOADED') |
| 381 | logging.info('Signing for channels: %s', ' '.join(channels)) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 382 | |
Don Garrett | 9459c2f | 2014-01-22 18:20:24 -0800 | [diff] [blame] | 383 | instruction_urls = {} |
| 384 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 385 | def _ImageNameBase(image_type=None): |
| 386 | lmid = ('%s-' % image_type) if image_type else '' |
| 387 | return 'ChromeOS-%s%s-%s' % (lmid, versionrev, boardpath) |
| 388 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 389 | # These variables are defined outside the loop so that the nested functions |
| 390 | # below can access them without 'cell-var-from-loop' linter warning. |
Mike Frysinger | 80de501 | 2019-08-01 14:10:53 -0400 | [diff] [blame] | 391 | dst_path = '' |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 392 | files_to_sign = [] |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 393 | for channel in channels: |
Ralph Nathan | 5a582ff | 2015-03-20 18:18:30 -0700 | [diff] [blame] | 394 | logging.debug('\n\n#### CHANNEL: %s ####\n', channel) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 395 | sect_insns['channel'] = channel |
| 396 | sub_path = '%s-channel/%s/%s' % (channel, boardpath, version) |
| 397 | dst_path = '%s/%s' % (gs_base, sub_path) |
Ralph Nathan | 0304728 | 2015-03-23 11:09:32 -0700 | [diff] [blame] | 398 | logging.info('Copying images to %s', dst_path) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 399 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 400 | recovery_basename = _ImageNameBase(constants.IMAGE_TYPE_RECOVERY) |
| 401 | factory_basename = _ImageNameBase(constants.IMAGE_TYPE_FACTORY) |
| 402 | firmware_basename = _ImageNameBase(constants.IMAGE_TYPE_FIRMWARE) |
David Riley | a04d19d | 2015-09-04 16:11:50 -0700 | [diff] [blame] | 403 | nv_lp0_firmware_basename = _ImageNameBase( |
| 404 | constants.IMAGE_TYPE_NV_LP0_FIRMWARE) |
Vincent Palatin | d599c66 | 2015-10-26 09:51:41 -0700 | [diff] [blame] | 405 | acc_usbpd_basename = _ImageNameBase(constants.IMAGE_TYPE_ACCESSORY_USBPD) |
| 406 | acc_rwsig_basename = _ImageNameBase(constants.IMAGE_TYPE_ACCESSORY_RWSIG) |
LaMont Jones | 7d6c98f | 2019-09-27 12:37:33 -0600 | [diff] [blame] | 407 | cr50_firmware_basename = _ImageNameBase(constants.IMAGE_TYPE_CR50_FIRMWARE) |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 408 | test_basename = _ImageNameBase(constants.IMAGE_TYPE_TEST) |
| 409 | base_basename = _ImageNameBase(constants.IMAGE_TYPE_BASE) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 410 | hwqual_tarball = 'chromeos-hwqual-%s-%s.tar.bz2' % (board, versionrev) |
| 411 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 412 | # The following build artifacts, if present, are always copied regardless of |
| 413 | # requested signing types. |
| 414 | files_to_copy_only = ( |
| 415 | # (<src>, <dst>, <suffix>), |
| 416 | ('image.zip', _ImageNameBase(), 'zip'), |
| 417 | (constants.TEST_IMAGE_TAR, test_basename, 'tar.xz'), |
| 418 | ('debug.tgz', 'debug-%s' % boardpath, 'tgz'), |
Xiaochu Liu | 254e0dd | 2019-03-08 16:10:57 -0800 | [diff] [blame] | 419 | (hwqual_tarball, None, None), |
| 420 | ('stateful.tgz', None, None), |
| 421 | ('dlc', None, None), |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 422 | ) |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 423 | |
| 424 | # The following build artifacts, if present, are always copied. |
| 425 | # If |sign_types| is None, all of them are marked for signing, otherwise |
| 426 | # only the image types specified in |sign_types| are marked for signing. |
| 427 | files_to_copy_and_maybe_sign = ( |
| 428 | # (<src>, <dst>, <suffix>, <signing type>), |
| 429 | (constants.RECOVERY_IMAGE_TAR, recovery_basename, 'tar.xz', |
| 430 | constants.IMAGE_TYPE_RECOVERY), |
| 431 | |
| 432 | ('factory_image.zip', factory_basename, 'zip', |
| 433 | constants.IMAGE_TYPE_FACTORY), |
| 434 | |
| 435 | ('firmware_from_source.tar.bz2', firmware_basename, 'tar.bz2', |
| 436 | constants.IMAGE_TYPE_FIRMWARE), |
David Riley | a04d19d | 2015-09-04 16:11:50 -0700 | [diff] [blame] | 437 | |
| 438 | ('firmware_from_source.tar.bz2', nv_lp0_firmware_basename, 'tar.bz2', |
| 439 | constants.IMAGE_TYPE_NV_LP0_FIRMWARE), |
Vincent Palatin | d599c66 | 2015-10-26 09:51:41 -0700 | [diff] [blame] | 440 | |
| 441 | ('firmware_from_source.tar.bz2', acc_usbpd_basename, 'tar.bz2', |
| 442 | constants.IMAGE_TYPE_ACCESSORY_USBPD), |
| 443 | |
| 444 | ('firmware_from_source.tar.bz2', acc_rwsig_basename, 'tar.bz2', |
| 445 | constants.IMAGE_TYPE_ACCESSORY_RWSIG), |
LaMont Jones | 7d6c98f | 2019-09-27 12:37:33 -0600 | [diff] [blame] | 446 | |
| 447 | ('firmware_from_source.tar.bz2', cr50_firmware_basename, 'tar.bz2', |
| 448 | constants.IMAGE_TYPE_CR50_FIRMWARE), |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 449 | ) |
| 450 | |
| 451 | # The following build artifacts are copied and marked for signing, if |
| 452 | # they are present *and* if the image type is specified via |sign_types|. |
| 453 | files_to_maybe_copy_and_sign = ( |
| 454 | # (<src>, <dst>, <suffix>, <signing type>), |
| 455 | (constants.BASE_IMAGE_TAR, base_basename, 'tar.xz', |
| 456 | constants.IMAGE_TYPE_BASE), |
| 457 | ) |
| 458 | |
Xiaochu Liu | 254e0dd | 2019-03-08 16:10:57 -0800 | [diff] [blame] | 459 | def _CopyFileToGS(src, dst=None, suffix=None): |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 460 | """Returns |dst| file name if the copying was successful.""" |
Xiaochu Liu | 254e0dd | 2019-03-08 16:10:57 -0800 | [diff] [blame] | 461 | if dst is None: |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 462 | dst = src |
Xiaochu Liu | 254e0dd | 2019-03-08 16:10:57 -0800 | [diff] [blame] | 463 | elif suffix is not None: |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 464 | dst = '%s.%s' % (dst, suffix) |
| 465 | success = False |
Mike Frysinger | e51a265 | 2014-01-18 02:36:16 -0500 | [diff] [blame] | 466 | try: |
Xiaochu Liu | 254e0dd | 2019-03-08 16:10:57 -0800 | [diff] [blame] | 467 | ctx.Copy(os.path.join(src_path, src), os.path.join(dst_path, dst), |
| 468 | recursive=True) |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 469 | success = True |
Mike Frysinger | e51a265 | 2014-01-18 02:36:16 -0500 | [diff] [blame] | 470 | except gs.GSNoSuchKey: |
Ralph Nathan | 446aee9 | 2015-03-23 14:44:56 -0700 | [diff] [blame] | 471 | logging.warning('Skipping %s as it does not exist', src) |
Mike Frysinger | 4495b03 | 2014-03-05 17:24:03 -0500 | [diff] [blame] | 472 | except gs.GSContextException: |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 473 | unknown_error[0] = True |
Ralph Nathan | 5990042 | 2015-03-24 10:41:17 -0700 | [diff] [blame] | 474 | logging.error('Skipping %s due to unknown GS error', src, exc_info=True) |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 475 | return dst if success else None |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 476 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 477 | for src, dst, suffix in files_to_copy_only: |
| 478 | _CopyFileToGS(src, dst, suffix) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 479 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 480 | # Clear the list of files to sign before adding new artifacts. |
| 481 | files_to_sign = [] |
| 482 | |
| 483 | def _AddToFilesToSign(image_type, dst, suffix): |
| 484 | assert dst.endswith('.' + suffix), ( |
| 485 | 'dst: %s, suffix: %s' % (dst, suffix)) |
| 486 | dst_base = dst[:-(len(suffix) + 1)] |
| 487 | files_to_sign.append([image_type, dst_base, suffix]) |
| 488 | |
| 489 | for src, dst, suffix, image_type in files_to_copy_and_maybe_sign: |
| 490 | dst = _CopyFileToGS(src, dst, suffix) |
| 491 | if dst and (not sign_types or image_type in sign_types): |
| 492 | _AddToFilesToSign(image_type, dst, suffix) |
| 493 | |
| 494 | for src, dst, suffix, image_type in files_to_maybe_copy_and_sign: |
| 495 | if sign_types and image_type in sign_types: |
| 496 | dst = _CopyFileToGS(src, dst, suffix) |
| 497 | if dst: |
| 498 | _AddToFilesToSign(image_type, dst, suffix) |
| 499 | |
| 500 | logging.debug('Files to sign: %s', files_to_sign) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 501 | # Now go through the subset for signing. |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 502 | for image_type, dst_name, suffix in files_to_sign: |
| 503 | try: |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 504 | input_insns = InputInsns(board, image_type=image_type, |
| 505 | buildroot=buildroot) |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 506 | except MissingBoardInstructions as e: |
| 507 | logging.info('Nothing to sign: %s', e) |
| 508 | continue |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 509 | |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 510 | dst_archive = '%s.%s' % (dst_name, suffix) |
| 511 | sect_general['archive'] = dst_archive |
| 512 | sect_general['type'] = image_type |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 513 | |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 514 | # In the default/automatic mode, only flag files for signing if the |
| 515 | # archives were actually uploaded in a previous stage. This additional |
| 516 | # check can be removed in future once |sign_types| becomes a required |
| 517 | # argument. |
| 518 | # TODO: Make |sign_types| a required argument. |
| 519 | gs_artifact_path = os.path.join(dst_path, dst_archive) |
| 520 | exists = False |
| 521 | try: |
| 522 | exists = ctx.Exists(gs_artifact_path) |
| 523 | except gs.GSContextException: |
| 524 | unknown_error[0] = True |
| 525 | logging.error('Unknown error while checking %s', gs_artifact_path, |
| 526 | exc_info=True) |
| 527 | if not exists: |
| 528 | logging.info('%s does not exist. Nothing to sign.', |
| 529 | gs_artifact_path) |
| 530 | continue |
| 531 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 532 | first_image = True |
| 533 | for alt_insn_set in input_insns.GetAltInsnSets(): |
| 534 | # Figure out which keysets have been requested for this type. |
| 535 | # We sort the forced set so tests/runtime behavior is stable. |
| 536 | keysets = sorted(force_keysets) |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 537 | if not keysets: |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 538 | keysets = input_insns.GetKeysets(insns_merge=alt_insn_set) |
| 539 | if not keysets: |
| 540 | logging.warning('Skipping %s image signing due to no keysets', |
| 541 | image_type) |
Mike Frysinger | d84d91e | 2015-11-05 18:02:24 -0500 | [diff] [blame] | 542 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 543 | for keyset in keysets: |
| 544 | sect_insns['keyset'] = keyset |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 545 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 546 | # Generate the insn file for this artifact that the signer will use, |
| 547 | # and flag it for signing. |
Mike Frysinger | 59babdb | 2019-09-06 06:25:50 -0400 | [diff] [blame] | 548 | with cros_build_lib.UnbufferedNamedTemporaryFile( |
| 549 | prefix='pushimage.insns.') as insns_path: |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 550 | input_insns.OutputInsns(insns_path.name, sect_insns, sect_general, |
| 551 | insns_merge=alt_insn_set) |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 552 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 553 | gs_insns_path = '%s/%s' % (dst_path, dst_name) |
| 554 | if not first_image: |
| 555 | gs_insns_path += '-%s' % keyset |
| 556 | first_image = False |
| 557 | gs_insns_path += '.instructions' |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 558 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 559 | try: |
| 560 | ctx.Copy(insns_path.name, gs_insns_path) |
| 561 | except gs.GSContextException: |
| 562 | unknown_error[0] = True |
| 563 | logging.error('Unknown error while uploading insns %s', |
| 564 | gs_insns_path, exc_info=True) |
| 565 | continue |
Mike Frysinger | 4495b03 | 2014-03-05 17:24:03 -0500 | [diff] [blame] | 566 | |
Mike Frysinger | 37ccc2b | 2015-11-11 17:16:51 -0500 | [diff] [blame] | 567 | try: |
| 568 | MarkImageToBeSigned(ctx, tbs_base, gs_insns_path, priority) |
| 569 | except gs.GSContextException: |
| 570 | unknown_error[0] = True |
| 571 | logging.error('Unknown error while marking for signing %s', |
| 572 | gs_insns_path, exc_info=True) |
| 573 | continue |
| 574 | logging.info('Signing %s image with keyset %s at %s', image_type, |
| 575 | keyset, gs_insns_path) |
| 576 | instruction_urls.setdefault(channel, []).append(gs_insns_path) |
Don Garrett | 9459c2f | 2014-01-22 18:20:24 -0800 | [diff] [blame] | 577 | |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 578 | if unknown_error[0]: |
Mike Frysinger | 4495b03 | 2014-03-05 17:24:03 -0500 | [diff] [blame] | 579 | raise PushError('hit some unknown error(s)', instruction_urls) |
| 580 | |
Don Garrett | 9459c2f | 2014-01-22 18:20:24 -0800 | [diff] [blame] | 581 | return instruction_urls |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 582 | |
| 583 | |
Mike Frysinger | 2614419 | 2017-08-30 18:26:46 -0400 | [diff] [blame] | 584 | def GetParser(): |
| 585 | """Creates the argparse parser.""" |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 586 | parser = commandline.ArgumentParser(description=__doc__) |
| 587 | |
| 588 | # The type of image_dir will strip off trailing slashes (makes later |
| 589 | # processing simpler and the display prettier). |
| 590 | parser.add_argument('image_dir', default=None, type='local_or_gs_path', |
| 591 | help='full path of source artifacts to upload') |
| 592 | parser.add_argument('--board', default=None, required=True, |
| 593 | help='board to generate symbols for') |
| 594 | parser.add_argument('--profile', default=None, |
| 595 | help='board profile in use (e.g. "asan")') |
| 596 | parser.add_argument('--version', default=None, |
| 597 | help='version info (normally extracted from image_dir)') |
Mike Frysinger | 7791210 | 2017-08-30 18:35:46 -0400 | [diff] [blame] | 598 | parser.add_argument('--channels', default=None, action='split_extend', |
| 599 | help='override list of channels to process') |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 600 | parser.add_argument('-n', '--dry-run', default=False, action='store_true', |
| 601 | help='show what would be done, but do not upload') |
| 602 | parser.add_argument('-M', '--mock', default=False, action='store_true', |
| 603 | help='upload things to a testing bucket (dev testing)') |
David Riley | f820512 | 2015-09-04 13:46:36 -0700 | [diff] [blame] | 604 | parser.add_argument('--test-sign', default=[], action='append', |
| 605 | choices=TEST_KEYSETS, |
| 606 | help='mung signing behavior to sign w/ test keys') |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 607 | parser.add_argument('--priority', type=int, default=50, |
| 608 | help='set signing priority (lower == higher prio)') |
| 609 | parser.add_argument('--sign-types', default=None, nargs='+', |
Amey Deshpande | a936c62 | 2015-08-12 17:27:54 -0700 | [diff] [blame] | 610 | choices=_SUPPORTED_IMAGE_TYPES, |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 611 | help='only sign specified image types') |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 612 | parser.add_argument('--buildroot', default=constants.SOURCE_ROOT, type='path', |
| 613 | help='Buildroot to use. Defaults to current.') |
Mike Frysinger | 09fe012 | 2014-02-09 02:44:05 -0500 | [diff] [blame] | 614 | parser.add_argument('--yes', action='store_true', default=False, |
| 615 | help='answer yes to all prompts') |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 616 | |
Mike Frysinger | 2614419 | 2017-08-30 18:26:46 -0400 | [diff] [blame] | 617 | return parser |
| 618 | |
| 619 | |
| 620 | def main(argv): |
| 621 | parser = GetParser() |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 622 | opts = parser.parse_args(argv) |
| 623 | opts.Freeze() |
| 624 | |
David Riley | f820512 | 2015-09-04 13:46:36 -0700 | [diff] [blame] | 625 | force_keysets = set(['%s-%s' % (TEST_KEYSET_PREFIX, x) |
| 626 | for x in opts.test_sign]) |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 627 | |
Mike Frysinger | 09fe012 | 2014-02-09 02:44:05 -0500 | [diff] [blame] | 628 | # If we aren't using mock or test or dry run mode, then let's prompt the user |
| 629 | # to make sure they actually want to do this. It's rare that people want to |
| 630 | # run this directly and hit the release bucket. |
| 631 | if not (opts.mock or force_keysets or opts.dry_run) and not opts.yes: |
| 632 | prolog = '\n'.join(textwrap.wrap(textwrap.dedent( |
| 633 | 'Uploading images for signing to the *release* bucket is not something ' |
| 634 | 'you generally should be doing yourself.'), 80)).strip() |
| 635 | if not cros_build_lib.BooleanPrompt( |
| 636 | prompt='Are you sure you want to sign these images', |
| 637 | default=False, prolog=prolog): |
| 638 | cros_build_lib.Die('better safe than sorry') |
| 639 | |
Mike Frysinger | d13faeb | 2013-09-05 16:00:46 -0400 | [diff] [blame] | 640 | PushImage(opts.image_dir, opts.board, versionrev=opts.version, |
| 641 | profile=opts.profile, priority=opts.priority, |
Mike Frysinger | dad40d6 | 2014-02-09 02:18:02 -0500 | [diff] [blame] | 642 | sign_types=opts.sign_types, dry_run=opts.dry_run, mock=opts.mock, |
Don Garrett | 3cf5f9a | 2018-08-14 13:14:47 -0700 | [diff] [blame] | 643 | force_keysets=force_keysets, force_channels=opts.channels, |
| 644 | buildroot=opts.buildroot) |