blob: d3a97380660d1e210b5338fb9adaa90ad5e258f7 [file] [log] [blame]
David Pursellf1d16a62015-03-25 13:31:04 -07001# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Install/copy the image to the device."""
6
7from __future__ import print_function
8
David Pursellf1d16a62015-03-25 13:31:04 -07009import os
Ralph Nathan9b997232015-05-15 13:13:12 -070010import re
David Pursellf1d16a62015-03-25 13:31:04 -070011import shutil
12import tempfile
David Pursellf1d16a62015-03-25 13:31:04 -070013
Aviv Keshetb7519e12016-10-04 00:50:00 -070014from chromite.lib import constants
xixuane851dfb2016-05-02 18:02:37 -070015from chromite.lib import auto_updater
David Pursellf1d16a62015-03-25 13:31:04 -070016from chromite.lib import commandline
17from chromite.lib import cros_build_lib
18from chromite.lib import cros_logging as logging
19from chromite.lib import dev_server_wrapper as ds_wrapper
Ralph Nathan872ea4d2015-05-05 18:04:56 -070020from chromite.lib import operation
David Pursellf1d16a62015-03-25 13:31:04 -070021from chromite.lib import osutils
Gilad Arnold1c8eda52015-05-04 22:32:38 -070022from chromite.lib import path_util
David Pursellf1d16a62015-03-25 13:31:04 -070023from chromite.lib import remote_access
24
25
Don Garrett97d7dc22015-01-20 14:07:56 -080026DEVSERVER_STATIC_DIR = path_util.FromChrootPath(
David Pursellf1d16a62015-03-25 13:31:04 -070027 os.path.join(constants.CHROOT_SOURCE_ROOT, 'devserver', 'static'))
28
29
Ralph Nathan9b997232015-05-15 13:13:12 -070030class UsbImagerOperation(operation.ProgressBarOperation):
31 """Progress bar for flashing image to operation."""
32
33 def __init__(self, image):
34 super(UsbImagerOperation, self).__init__()
35 self._size = os.path.getsize(image)
36 self._transferred = 0.
37 self._bytes = re.compile(r'(\d+) bytes')
38
39 def _GetDDPid(self):
40 """Get the Pid of dd."""
41 try:
42 pids = cros_build_lib.RunCommand(['pgrep', 'dd'], capture_output=True,
43 print_cmd=False).output
44 for pid in pids.splitlines():
45 if osutils.IsChildProcess(int(pid), name='dd'):
46 return int(pid)
47 return -1
48 except cros_build_lib.RunCommandError:
49 # If dd isn't still running, then we assume that it is finished.
50 return -1
51
52 def _PingDD(self, dd_pid):
53 """Send USR1 signal to dd to get status update."""
54 try:
55 cmd = ['kill', '-USR1', str(dd_pid)]
56 cros_build_lib.SudoRunCommand(cmd, print_cmd=False)
57 except cros_build_lib.RunCommandError:
58 # Here we assume that dd finished in the background.
59 return
60
61 def ParseOutput(self, output=None):
62 """Parse the output of dd to update progress bar."""
63 dd_pid = self._GetDDPid()
64 if dd_pid == -1:
65 return
66
67 self._PingDD(dd_pid)
68
69 if output is None:
70 stdout = self._stdout.read()
71 stderr = self._stderr.read()
72 output = stdout + stderr
73
74 match = self._bytes.search(output)
75 if match:
76 self._transferred = match.groups()[0]
77
78 self.ProgressBar(float(self._transferred) / self._size)
79
80
Mike Frysinger32759e42016-12-21 18:40:16 -050081def _IsFilePathGPTDiskImage(file_path, require_pmbr=False):
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070082 """Determines if a file is a valid GPT disk.
83
84 Args:
85 file_path: Path to the file to test.
Mike Frysinger32759e42016-12-21 18:40:16 -050086 require_pmbr: Whether to require a PMBR in LBA0.
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070087 """
88 if os.path.isfile(file_path):
Mike Frysinger32759e42016-12-21 18:40:16 -050089 with open(file_path) as image_file:
90 if require_pmbr:
91 # Seek to the end of LBA0 and look for the PMBR boot signature.
92 image_file.seek(0x1fe)
93 if image_file.read(2) != '\x55\xaa':
94 return False
95 # Current file position is start of LBA1 now.
96 else:
97 # Seek to LBA1 where the GPT starts.
98 image_file.seek(0x200)
99
100 # See if there's a GPT here.
101 if image_file.read(8) == 'EFI PART':
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700102 return True
Mike Frysinger32759e42016-12-21 18:40:16 -0500103
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700104 return False
105
106
107def _ChooseImageFromDirectory(dir_path):
108 """Lists all image files in |dir_path| and ask user to select one.
109
110 Args:
111 dir_path: Path to the directory.
112 """
113 images = sorted([x for x in os.listdir(dir_path) if
114 _IsFilePathGPTDiskImage(os.path.join(dir_path, x))])
115 idx = 0
116 if len(images) == 0:
117 raise ValueError('No image found in %s.' % dir_path)
118 elif len(images) > 1:
119 idx = cros_build_lib.GetChoice(
120 'Multiple images found in %s. Please select one to continue:' % (
121 (dir_path,)),
122 images)
123
124 return os.path.join(dir_path, images[idx])
125
126
David Pursellf1d16a62015-03-25 13:31:04 -0700127class FlashError(Exception):
128 """Thrown when there is an unrecoverable error during flash."""
129
130
131class USBImager(object):
132 """Copy image to the target removable device."""
133
Gilad Arnoldd0461442015-07-07 11:52:46 -0700134 def __init__(self, device, board, image, debug=False, install=False,
135 yes=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700136 """Initalizes USBImager."""
137 self.device = device
138 self.board = board if board else cros_build_lib.GetDefaultBoard()
139 self.image = image
David Pursellf1d16a62015-03-25 13:31:04 -0700140 self.debug = debug
141 self.debug_level = logging.DEBUG if debug else logging.INFO
142 self.install = install
143 self.yes = yes
144
145 def DeviceNameToPath(self, device_name):
146 return '/dev/%s' % device_name
147
148 def GetRemovableDeviceDescription(self, device):
149 """Returns a informational description of the removable |device|.
150
151 Args:
152 device: the device name (e.g. sdc).
153
154 Returns:
155 A string describing |device| (e.g. Patriot Memory 7918 MB).
156 """
157 desc = [
158 osutils.GetDeviceInfo(device, keyword='manufacturer'),
159 osutils.GetDeviceInfo(device, keyword='product'),
160 osutils.GetDeviceSize(self.DeviceNameToPath(device)),
161 '(%s)' % self.DeviceNameToPath(device),
162 ]
163 return ' '.join([x for x in desc if x])
164
165 def ListAllRemovableDevices(self):
166 """Returns a list of removable devices.
167
168 Returns:
169 A list of device names (e.g. ['sdb', 'sdc']).
170 """
171 devices = osutils.ListBlockDevices()
172 removable_devices = []
173 for d in devices:
174 if d.TYPE == 'disk' and d.RM == '1':
175 removable_devices.append(d.NAME)
176
177 return removable_devices
178
179 def ChooseRemovableDevice(self, devices):
180 """Lists all removable devices and asks user to select/confirm.
181
182 Args:
183 devices: a list of device names (e.g. ['sda', 'sdb']).
184
185 Returns:
186 The device name chosen by the user.
187 """
188 idx = cros_build_lib.GetChoice(
189 'Removable device(s) found. Please select/confirm to continue:',
190 [self.GetRemovableDeviceDescription(x) for x in devices])
191
192 return devices[idx]
193
194 def InstallImageToDevice(self, image, device):
195 """Installs |image| to the removable |device|.
196
197 Args:
198 image: Path to the image to copy.
199 device: Device to copy to.
200 """
201 cmd = [
202 'chromeos-install',
203 '--yes',
204 '--skip_src_removable',
205 '--skip_dst_removable',
206 '--payload_image=%s' % image,
207 '--dst=%s' % device,
208 '--skip_postinstall',
209 ]
Shuqian Zhao33242472017-08-02 18:28:44 -0700210 cros_build_lib.SudoRunCommand(cmd,
211 print_cmd=True,
212 debug_level=logging.NOTICE,
213 combine_stdout_stderr=True,
214 log_output=True)
David Pursellf1d16a62015-03-25 13:31:04 -0700215
216 def CopyImageToDevice(self, image, device):
217 """Copies |image| to the removable |device|.
218
219 Args:
220 image: Path to the image to copy.
221 device: Device to copy to.
222 """
Ralph Nathan9b997232015-05-15 13:13:12 -0700223 cmd = ['dd', 'if=%s' % image, 'of=%s' % device, 'bs=4M', 'iflag=fullblock',
224 'oflag=sync']
225 if logging.getLogger().getEffectiveLevel() <= logging.NOTICE:
226 op = UsbImagerOperation(image)
227 op.Run(cros_build_lib.SudoRunCommand, cmd, debug_level=logging.NOTICE,
228 update_period=0.5)
229 else:
230 cros_build_lib.SudoRunCommand(
231 cmd, debug_level=logging.NOTICE,
232 print_cmd=logging.getLogger().getEffectiveLevel() < logging.NOTICE)
David Pursellf1d16a62015-03-25 13:31:04 -0700233
David Pursellf1d16a62015-03-25 13:31:04 -0700234 cros_build_lib.SudoRunCommand(['sync'], debug_level=self.debug_level)
235
David Pursellf1d16a62015-03-25 13:31:04 -0700236 def _GetImagePath(self):
237 """Returns the image path to use."""
238 image_path = translated_path = None
239 if os.path.isfile(self.image):
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700240 if not self.yes and not _IsFilePathGPTDiskImage(self.image):
David Pursellf1d16a62015-03-25 13:31:04 -0700241 # TODO(wnwen): Open the tarball and if there is just one file in it,
242 # use that instead. Existing code in upload_symbols.py.
243 if cros_build_lib.BooleanPrompt(
244 prolog='The given image file is not a valid disk image. Perhaps '
245 'you forgot to untar it.',
246 prompt='Terminate the current flash process?'):
247 raise FlashError('Update terminated by user.')
248 image_path = self.image
249 elif os.path.isdir(self.image):
250 # Ask user which image (*.bin) in the folder to use.
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700251 image_path = _ChooseImageFromDirectory(self.image)
David Pursellf1d16a62015-03-25 13:31:04 -0700252 else:
253 # Translate the xbuddy path to get the exact image to use.
Gilad Arnolde62ec902015-04-24 14:41:02 -0700254 translated_path, _ = ds_wrapper.GetImagePathWithXbuddy(
Don Garrett97d7dc22015-01-20 14:07:56 -0800255 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700256 image_path = ds_wrapper.TranslatedPathToLocalPath(
Don Garrett97d7dc22015-01-20 14:07:56 -0800257 translated_path, DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700258
259 logging.info('Using image %s', translated_path or image_path)
260 return image_path
261
262 def Run(self):
263 """Image the removable device."""
264 devices = self.ListAllRemovableDevices()
265
266 if self.device:
267 # If user specified a device path, check if it exists.
268 if not os.path.exists(self.device):
269 raise FlashError('Device path %s does not exist.' % self.device)
270
271 # Then check if it is removable.
272 if self.device not in [self.DeviceNameToPath(x) for x in devices]:
273 msg = '%s is not a removable device.' % self.device
274 if not (self.yes or cros_build_lib.BooleanPrompt(
275 default=False, prolog=msg)):
276 raise FlashError('You can specify usb:// to choose from a list of '
277 'removable devices.')
278 target = None
279 if self.device:
280 # Get device name from path (e.g. sdc in /dev/sdc).
281 target = self.device.rsplit(os.path.sep, 1)[-1]
282 elif devices:
283 # Ask user to choose from the list.
284 target = self.ChooseRemovableDevice(devices)
285 else:
286 raise FlashError('No removable devices detected.')
287
288 image_path = self._GetImagePath()
289 try:
290 device = self.DeviceNameToPath(target)
291 if self.install:
292 self.InstallImageToDevice(image_path, device)
293 else:
294 self.CopyImageToDevice(image_path, device)
295 except cros_build_lib.RunCommandError:
296 logging.error('Failed copying image to device %s',
297 self.DeviceNameToPath(target))
298
299
300class FileImager(USBImager):
301 """Copy image to the target path."""
302
303 def Run(self):
304 """Copy the image to the path specified by self.device."""
Mao Huangc4777e82016-03-14 20:20:08 +0800305 if not os.path.isdir(os.path.dirname(self.device)):
306 raise FlashError('Parent of path %s is not a directory.' % self.device)
David Pursellf1d16a62015-03-25 13:31:04 -0700307
308 image_path = self._GetImagePath()
309 if os.path.isdir(self.device):
310 logging.info('Copying to %s',
311 os.path.join(self.device, os.path.basename(image_path)))
312 else:
313 logging.info('Copying to %s', self.device)
314 try:
315 shutil.copy(image_path, self.device)
316 except IOError:
317 logging.error('Failed to copy image %s to %s', image_path, self.device)
318
319
320class RemoteDeviceUpdater(object):
321 """Performs update on a remote device."""
322 DEVSERVER_FILENAME = 'devserver.py'
323 STATEFUL_UPDATE_BIN = '/usr/bin/stateful_update'
324 UPDATE_ENGINE_BIN = 'update_engine_client'
David Pursellf1d16a62015-03-25 13:31:04 -0700325 # Root working directory on the device. This directory is in the
326 # stateful partition and thus has enough space to store the payloads.
327 DEVICE_BASE_DIR = '/mnt/stateful_partition/cros-flash'
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700328 UPDATE_CHECK_INTERVAL_PROGRESSBAR = 0.5
329 UPDATE_CHECK_INTERVAL_NORMAL = 10
David Pursellf1d16a62015-03-25 13:31:04 -0700330
331 def __init__(self, ssh_hostname, ssh_port, image, stateful_update=True,
332 rootfs_update=True, clobber_stateful=False, reboot=True,
Gilad Arnoldd0461442015-07-07 11:52:46 -0700333 board=None, src_image_to_delta=None, wipe=True, debug=False,
Daniel Erat30fd2072016-08-29 10:08:56 -0600334 yes=False, force=False, ssh_private_key=None, ping=True,
Gilad Arnold821547c2015-07-07 08:57:48 -0700335 disable_verification=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700336 """Initializes RemoteDeviceUpdater"""
337 if not stateful_update and not rootfs_update:
338 raise ValueError('No update operation to perform; either stateful or'
339 ' rootfs partitions must be updated.')
340 self.tempdir = tempfile.mkdtemp(prefix='cros-flash')
341 self.ssh_hostname = ssh_hostname
342 self.ssh_port = ssh_port
343 self.image = image
344 self.board = board
David Pursellf1d16a62015-03-25 13:31:04 -0700345 self.src_image_to_delta = src_image_to_delta
346 self.do_stateful_update = stateful_update
347 self.do_rootfs_update = rootfs_update
348 self.disable_verification = disable_verification
349 self.clobber_stateful = clobber_stateful
350 self.reboot = reboot
351 self.debug = debug
Daniel Erat30fd2072016-08-29 10:08:56 -0600352 self.ssh_private_key = ssh_private_key
David Pursellf1d16a62015-03-25 13:31:04 -0700353 self.ping = ping
354 # Do not wipe if debug is set.
355 self.wipe = wipe and not debug
356 self.yes = yes
357 self.force = force
David Pursellf1d16a62015-03-25 13:31:04 -0700358
David Pursellf1d16a62015-03-25 13:31:04 -0700359 def Cleanup(self):
360 """Cleans up the temporary directory."""
361 if self.wipe:
362 logging.info('Cleaning up temporary working directory...')
363 osutils.RmDir(self.tempdir)
364 else:
365 logging.info('You can find the log files and/or payloads in %s',
366 self.tempdir)
367
xixuane851dfb2016-05-02 18:02:37 -0700368 def GetPayloadDir(self, device):
369 """Get directory of payload for update.
David Pursellf1d16a62015-03-25 13:31:04 -0700370
xixuane851dfb2016-05-02 18:02:37 -0700371 This method is used to obtain the directory of payload for cros-flash. The
372 given path 'self.image' is passed in when initializing RemoteDeviceUpdater.
David Pursellf1d16a62015-03-25 13:31:04 -0700373
xixuane851dfb2016-05-02 18:02:37 -0700374 If self.image is a directory, we directly use the provided update payload(s)
375 in this directory.
376
377 If self.image is an image, let devserver access it and generate payloads.
378
379 If not in the above cases, let devserver first obtain the image path. Then
380 devserver will access the image and generate payloads.
David Pursellf1d16a62015-03-25 13:31:04 -0700381
382 Args:
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400383 device: A ChromiumOSDevice object.
David Pursellf1d16a62015-03-25 13:31:04 -0700384
385 Returns:
xixuane851dfb2016-05-02 18:02:37 -0700386 A string payload_dir, that represents the payload directory.
David Pursellf1d16a62015-03-25 13:31:04 -0700387 """
xixuane851dfb2016-05-02 18:02:37 -0700388 payload_dir = self.tempdir
David Pursellf1d16a62015-03-25 13:31:04 -0700389
xixuane851dfb2016-05-02 18:02:37 -0700390 if os.path.isdir(self.image):
391 # The given path is a directory.
392 payload_dir = self.image
393 logging.info('Using provided payloads in %s', payload_dir)
394 elif os.path.isfile(self.image):
395 # The given path is an image.
396 logging.info('Using image %s', self.image)
Steven Bennetts4304c7e2017-09-05 12:30:30 -0600397 try:
398 ds_wrapper.GetUpdatePayloadsFromLocalPath(
399 self.image, payload_dir,
400 src_image_to_delta=self.src_image_to_delta,
401 static_dir=DEVSERVER_STATIC_DIR)
402 except:
403 logging.error('Unable to get payloads from local path: %s', payload_dir)
404 raise
405
xixuane851dfb2016-05-02 18:02:37 -0700406 else:
407 self.board = cros_build_lib.GetBoard(device_board=device.board,
408 override_board=self.board,
409 force=self.yes)
410 if not self.board:
411 raise FlashError('No board identified')
David Pursellf1d16a62015-03-25 13:31:04 -0700412
xixuane851dfb2016-05-02 18:02:37 -0700413 if not self.force and self.board != device.board:
414 # If a board was specified, it must be compatible with the device.
Brian Norrisfab3fb22016-06-02 14:59:20 -0700415 raise FlashError('Device (%s) is incompatible with board %s' %
416 (device.board, self.board))
xixuane851dfb2016-05-02 18:02:37 -0700417
418 logging.info('Board is %s', self.board)
419
420 # Translate the xbuddy path to get the exact image to use.
421 translated_path, resolved_path = ds_wrapper.GetImagePathWithXbuddy(
422 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR,
423 lookup_only=True)
Vadim Bendebury3c993462017-08-22 15:42:16 -0700424 logging.notice('Using image %s', translated_path)
xixuane851dfb2016-05-02 18:02:37 -0700425 # Convert the translated path to be used in the update request.
426 image_path = ds_wrapper.ConvertTranslatedPath(resolved_path,
427 translated_path)
428
429 # Launch a local devserver to generate/serve update payloads.
430 ds_wrapper.GetUpdatePayloads(
431 image_path, payload_dir, board=self.board,
432 src_image_to_delta=self.src_image_to_delta,
433 static_dir=DEVSERVER_STATIC_DIR)
434
435 return payload_dir
David Pursellf1d16a62015-03-25 13:31:04 -0700436
437 def Run(self):
xixuane851dfb2016-05-02 18:02:37 -0700438 """Perform remote device update.
439
440 The update process includes:
441 1. initialize a device instance for the given remote device.
442 2. achieve payload_dir which contains the required payloads for updating.
443 3. initialize an auto-updater instance to do RunUpdate().
444 4. After auto-update, all temp files and dir will be cleaned up.
445 """
David Pursellf1d16a62015-03-25 13:31:04 -0700446 try:
David Pursellf1d16a62015-03-25 13:31:04 -0700447 with remote_access.ChromiumOSDeviceHandler(
Daniel Erat30fd2072016-08-29 10:08:56 -0600448 self.ssh_hostname, port=self.ssh_port, base_dir=self.DEVICE_BASE_DIR,
449 private_key=self.ssh_private_key, ping=self.ping) as device:
David Pursellf1d16a62015-03-25 13:31:04 -0700450
Steven Bennetts4304c7e2017-09-05 12:30:30 -0600451 try:
452 # Get payload directory
453 payload_dir = self.GetPayloadDir(device)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700454
Steven Bennetts4304c7e2017-09-05 12:30:30 -0600455 # Do auto-update
456 chromeos_AU = auto_updater.ChromiumOSFlashUpdater(
457 device, payload_dir, self.tempdir,
458 do_rootfs_update=self.do_rootfs_update,
459 do_stateful_update=self.do_stateful_update,
460 reboot=self.reboot,
461 disable_verification=self.disable_verification,
462 clobber_stateful=self.clobber_stateful,
463 yes=self.yes)
464 chromeos_AU.CheckPayloads()
465 chromeos_AU.RunUpdate()
David Pursellf1d16a62015-03-25 13:31:04 -0700466
Steven Bennetts4304c7e2017-09-05 12:30:30 -0600467 except Exception:
468 logging.error('Device update failed.')
469 lsb_entries = sorted(device.lsb_release.items())
470 logging.info(
471 'Following are the LSB version details of the device:\n%s',
472 '\n'.join('%s=%s' % (k, v) for k, v in lsb_entries))
473 raise
474
475 logging.notice('Update performed successfully.')
476
477 except remote_access.RemoteAccessException:
478 logging.error('Remote device failed to initialize.')
David Pursellf1d16a62015-03-25 13:31:04 -0700479 raise
Steven Bennetts4304c7e2017-09-05 12:30:30 -0600480
David Pursellf1d16a62015-03-25 13:31:04 -0700481 finally:
482 self.Cleanup()
483
Gilad Arnoldbfcfaff2015-07-07 10:08:02 -0700484def Flash(device, image, board=None, install=False, src_image_to_delta=None,
485 rootfs_update=True, stateful_update=True, clobber_stateful=False,
Daniel Erat30fd2072016-08-29 10:08:56 -0600486 reboot=True, wipe=True, ssh_private_key=None, ping=True,
487 disable_rootfs_verification=False, clear_cache=False, yes=False,
488 force=False, debug=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700489 """Flashes a device, USB drive, or file with an image.
490
491 This provides functionality common to `cros flash` and `brillo flash`
492 so that they can parse the commandline separately but still use the
493 same underlying functionality.
494
495 Args:
David Pursell2e773382015-04-03 14:30:47 -0700496 device: commandline.Device object; None to use the default device.
David Pursellf1d16a62015-03-25 13:31:04 -0700497 image: Path (string) to the update image. Can be a local or xbuddy path;
498 non-existant local paths are converted to xbuddy.
David Pursellf1d16a62015-03-25 13:31:04 -0700499 board: Board to use; None to automatically detect.
David Pursellf1d16a62015-03-25 13:31:04 -0700500 install: Install to USB using base disk layout; USB |device| scheme only.
501 src_image_to_delta: Local path to an image to be used as the base to
502 generate delta payloads; SSH |device| scheme only.
503 rootfs_update: Update rootfs partition; SSH |device| scheme only.
504 stateful_update: Update stateful partition; SSH |device| scheme only.
505 clobber_stateful: Clobber stateful partition; SSH |device| scheme only.
506 reboot: Reboot device after update; SSH |device| scheme only.
507 wipe: Wipe temporary working directory; SSH |device| scheme only.
Daniel Erat30fd2072016-08-29 10:08:56 -0600508 ssh_private_key: Path to an SSH private key file; None to use test keys.
David Pursellf1d16a62015-03-25 13:31:04 -0700509 ping: Ping the device before attempting update; SSH |device| scheme only.
510 disable_rootfs_verification: Remove rootfs verification after update; SSH
511 |device| scheme only.
512 clear_cache: Clear the devserver static directory.
513 yes: Assume "yes" for any prompt.
514 force: Ignore sanity checks and prompts. Overrides |yes| if True.
515 debug: Print additional debugging messages.
516
517 Raises:
518 FlashError: An unrecoverable error occured.
519 ValueError: Invalid parameter combination.
520 """
521 if force:
522 yes = True
523
524 if clear_cache:
525 logging.info('Clearing the cache...')
Don Garrett97d7dc22015-01-20 14:07:56 -0800526 ds_wrapper.DevServerWrapper.WipeStaticDirectory(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700527
528 try:
Don Garrett97d7dc22015-01-20 14:07:56 -0800529 osutils.SafeMakedirsNonRoot(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700530 except OSError:
Don Garrett97d7dc22015-01-20 14:07:56 -0800531 logging.error('Failed to create %s', DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700532
533 if install:
David Pursell2e773382015-04-03 14:30:47 -0700534 if not device or device.scheme != commandline.DEVICE_SCHEME_USB:
David Pursellf1d16a62015-03-25 13:31:04 -0700535 raise ValueError(
536 '--install can only be used when writing to a USB device')
537 if not cros_build_lib.IsInsideChroot():
538 raise ValueError('--install can only be used inside the chroot')
539
David Pursell2e773382015-04-03 14:30:47 -0700540 if not device or device.scheme == commandline.DEVICE_SCHEME_SSH:
541 if device:
542 hostname, port = device.hostname, device.port
543 else:
544 hostname, port = None, None
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700545 logging.notice('Preparing to update the remote device %s', hostname)
David Pursellf1d16a62015-03-25 13:31:04 -0700546 updater = RemoteDeviceUpdater(
David Pursell2e773382015-04-03 14:30:47 -0700547 hostname,
548 port,
David Pursellf1d16a62015-03-25 13:31:04 -0700549 image,
550 board=board,
David Pursellf1d16a62015-03-25 13:31:04 -0700551 src_image_to_delta=src_image_to_delta,
552 rootfs_update=rootfs_update,
553 stateful_update=stateful_update,
554 clobber_stateful=clobber_stateful,
555 reboot=reboot,
556 wipe=wipe,
557 debug=debug,
558 yes=yes,
559 force=force,
Daniel Erat30fd2072016-08-29 10:08:56 -0600560 ssh_private_key=ssh_private_key,
David Pursellf1d16a62015-03-25 13:31:04 -0700561 ping=ping,
Gilad Arnold821547c2015-07-07 08:57:48 -0700562 disable_verification=disable_rootfs_verification)
David Pursellf1d16a62015-03-25 13:31:04 -0700563 updater.Run()
564 elif device.scheme == commandline.DEVICE_SCHEME_USB:
565 path = osutils.ExpandPath(device.path) if device.path else ''
566 logging.info('Preparing to image the removable device %s', path)
567 imager = USBImager(path,
568 board,
569 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700570 debug=debug,
571 install=install,
572 yes=yes)
573 imager.Run()
574 elif device.scheme == commandline.DEVICE_SCHEME_FILE:
575 logging.info('Preparing to copy image to %s', device.path)
576 imager = FileImager(device.path,
577 board,
578 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700579 debug=debug,
580 yes=yes)
581 imager.Run()