Beispiel #1
0
 def _GetBuiltVMImagePath(self):
     """Get path of a locally built VM image."""
     vm_image_path = os.path.join(
         constants.SOURCE_ROOT, 'src/build/images',
         cros_build_lib.GetBoard(self.board, strict=True), 'latest',
         constants.VM_IMAGE_BIN)
     return vm_image_path if os.path.isfile(vm_image_path) else None
Beispiel #2
0
  def Run(self):
    """Run cros debug."""
    commandline.RunInsideChroot(self)
    self.options.Freeze()
    self._ReadOptions()
    with remote_access.ChromiumOSDeviceHandler(
        self.ssh_hostname, port=self.ssh_port, username=self.ssh_username,
        private_key=self.ssh_private_key) as device:
      self.board = cros_build_lib.GetBoard(device_board=device.board,
                                           override_board=self.options.board,
                                           strict=True)
      logging.info('Board is %s', self.board)

      self.gdb_cmd = [
          'gdb_remote', '--ssh',
          '--board', self.board,
          '--remote', self.ssh_hostname,
      ]
      if self.ssh_port:
        self.gdb_cmd.extend(['--ssh_port', str(self.ssh_port)])

      if not (self.pid or self.exe):
        cros_build_lib.Die(
            'Must use --exe or --pid to specify the process to debug.')

      if self.pid:
        if self.list or self.exe:
          cros_build_lib.Die(
              '--list and --exe are disallowed when --pid is used.')
        self._DebugRunningProcess(self.pid)
        return

      if not self.exe.startswith('/'):
        cros_build_lib.Die('--exe must have a full pathname.')
      logging.debug('Executable path is %s', self.exe)
      if not device.IsFileExecutable(self.exe):
        cros_build_lib.Die(
            'File path "%s" does not exist or is not executable on device %s',
            self.exe, self.ssh_hostname)

      pids = device.GetRunningPids(self.exe)
      self._ListProcesses(device, pids)

      if self.list:
        # If '--list' flag is on, do not launch GDB.
        return

      if pids:
        choices = ['Start a new process under GDB']
        choices.extend(pids)
        idx = cros_build_lib.GetChoice(
            'Please select the process pid to debug (select [0] to start a '
            'new process):', choices)
        if idx == 0:
          self._DebugNewProcess()
        else:
          self._DebugRunningProcess(pids[idx - 1])
      else:
        self._DebugNewProcess()
Beispiel #3
0
  def _SetBoard(self):
    """Sets the board.

    Picks the first non-None board from the user-specified board,
    SDK environment variable, cros default board.

    Raises:
      DieSystemExit: If a board cannot be found.
    """
    if self.board:
      return
    sdk_board_env = os.environ.get(cros_chrome_sdk.SDKFetcher.SDK_BOARD_ENV)
    self.board = cros_build_lib.GetBoard(sdk_board_env, strict=True)
Beispiel #4
0
def Deploy(device, packages, board=None, emerge=True, update=False, deep=False,
           deep_rev=False, clean_binpkg=True, root='/', strip=True,
           emerge_args=None, ssh_private_key=None, ping=True, force=False,
           dry_run=False):
  """Deploys packages to a device.

  Args:
    device: commandline.Device object; None to use the default device.
    packages: List of packages (strings) to deploy to device.
    board: Board to use; None to automatically detect.
    emerge: True to emerge package, False to unmerge.
    update: Check installed version on device.
    deep: Install dependencies also. Implies |update|.
    deep_rev: Install reverse dependencies. Implies |deep|.
    clean_binpkg: Clean outdated binary packages.
    root: Package installation root path.
    strip: Run strip_package to filter out preset paths in the package.
    emerge_args: Extra arguments to pass to emerge.
    ssh_private_key: Path to an SSH private key file; None to use test keys.
    ping: True to ping the device before trying to connect.
    force: Ignore sanity checks and prompts.
    dry_run: Print deployment plan but do not deploy anything.

  Raises:
    ValueError: Invalid parameter or parameter combination.
    DeployError: Unrecoverable failure during deploy.
  """
  if deep_rev:
    deep = True
  if deep:
    update = True

  if not packages:
    raise DeployError('No packages provided, nothing to deploy.')

  if update and not emerge:
    raise ValueError('Cannot update and unmerge.')

  if device:
    hostname, username, port = device.hostname, device.username, device.port
  else:
    hostname, username, port = None, None, None

  lsb_release = None
  sysroot = None
  try:
    with remote_access.ChromiumOSDeviceHandler(
        hostname, port=port, username=username, private_key=ssh_private_key,
        base_dir=_DEVICE_BASE_DIR, ping=ping) as device:
      lsb_release = device.lsb_release

      board = cros_build_lib.GetBoard(device_board=device.board,
                                      override_board=board)
      if not force and board != device.board:
        raise DeployError('Device (%s) is incompatible with board %s. Use '
                          '--force to deploy anyway.' % (device.board, board))

      sysroot = cros_build_lib.GetSysroot(board=board)

      if clean_binpkg:
        logging.notice('Cleaning outdated binary packages from %s', sysroot)
        portage_util.CleanOutdatedBinaryPackages(sysroot)

      if not device.IsDirWritable(root):
        # Only remounts rootfs if the given root is not writable.
        if not device.MountRootfsReadWrite():
          raise DeployError('Cannot remount rootfs as read-write. Exiting.')

      # Obtain list of packages to upgrade/remove.
      pkg_scanner = _InstallPackageScanner(sysroot)
      pkgs, listed, num_updates = pkg_scanner.Run(
          device, root, packages, update, deep, deep_rev)
      if emerge:
        action_str = 'emerge'
      else:
        pkgs.reverse()
        action_str = 'unmerge'

      if not pkgs:
        logging.notice('No packages to %s', action_str)
        return

      logging.notice('These are the packages to %s:', action_str)
      for i, pkg in enumerate(pkgs):
        logging.notice('%s %d) %s', '*' if pkg in listed else ' ', i + 1, pkg)

      if dry_run or not _ConfirmDeploy(num_updates):
        return

      # Select function (emerge or unmerge) and bind args.
      if emerge:
        func = functools.partial(_EmergePackages, pkgs, device, strip,
                                 sysroot, root, emerge_args)
      else:
        func = functools.partial(_UnmergePackages, pkgs, device, root)

      # Call the function with the progress bar or with normal output.
      if command.UseProgressBar():
        op = BrilloDeployOperation(len(pkgs), emerge)
        op.Run(func, log_level=logging.DEBUG)
      else:
        func()

      logging.warning('Please restart any updated services on the device, '
                      'or just reboot it.')
  except Exception:
    if lsb_release:
      lsb_entries = sorted(lsb_release.items())
      logging.info('Following are the LSB version details of the device:\n%s',
                   '\n'.join('%s=%s' % (k, v) for k, v in lsb_entries))
    raise
Beispiel #5
0
    def GetPayloadDir(self, device):
        """Get directory of payload for update.

    This method is used to obtain the directory of payload for cros-flash. The
    given path 'self.image' is passed in when initializing RemoteDeviceUpdater.

    If self.image is a directory, we directly use the provided update payload(s)
    in this directory.

    If self.image is an image, let devserver access it and generate payloads.

    If not in the above cases, let devserver first obtain the image path. Then
    devserver will access the image and generate payloads.

    Args:
      device: A ChromiumOSDevice object.

    Returns:
      A string payload_dir, that represents the payload directory.
    """
        payload_dir = self.tempdir

        if os.path.isdir(self.image):
            # The given path is a directory.
            payload_dir = self.image
            logging.info('Using provided payloads in %s', payload_dir)
        elif os.path.isfile(self.image):
            # The given path is an image.
            logging.info('Using image %s', self.image)
            ds_wrapper.GetUpdatePayloadsFromLocalPath(
                self.image,
                payload_dir,
                src_image_to_delta=self.src_image_to_delta,
                static_dir=DEVSERVER_STATIC_DIR)
        else:
            self.board = cros_build_lib.GetBoard(device_board=device.board,
                                                 override_board=self.board,
                                                 force=self.yes)
            if not self.board:
                raise FlashError('No board identified')

            if not self.force and self.board != device.board:
                # If a board was specified, it must be compatible with the device.
                raise FlashError('Device (%s) is incompatible with board %s' %
                                 (device.board, self.board))

            logging.info('Board is %s', self.board)

            # Translate the xbuddy path to get the exact image to use.
            translated_path, resolved_path = ds_wrapper.GetImagePathWithXbuddy(
                self.image,
                self.board,
                static_dir=DEVSERVER_STATIC_DIR,
                lookup_only=True)
            logging.info('Using image %s', translated_path)
            # Convert the translated path to be used in the update request.
            image_path = ds_wrapper.ConvertTranslatedPath(
                resolved_path, translated_path)

            # Launch a local devserver to generate/serve update payloads.
            ds_wrapper.GetUpdatePayloads(
                image_path,
                payload_dir,
                board=self.board,
                src_image_to_delta=self.src_image_to_delta,
                static_dir=DEVSERVER_STATIC_DIR)

        return payload_dir
Beispiel #6
0
    def VerifyAndFinishInitialization(self, device):
        """Verify files/processes exist and flags are correct."""
        if not self.board:
            if self.remote:
                self.board = cros_build_lib.GetBoard(device_board=device.board,
                                                     override_board=self.board)
            else:
                raise GdbCannotDetectBoardError(
                    'Cannot determine which board to use. '
                    'Please specify the with --board flag.')

        self.sysroot = cros_build_lib.GetSysroot(board=self.board)
        self.prompt = '(%s-gdb) ' % self.board
        self.inf_cmd = self.RemoveSysrootPrefix(self.inf_cmd)
        self.cross_gdb = self.GetCrossGdb()

        if self.remote:

            # If given remote process name, find pid & inf_cmd on remote device.
            if self.remote_process_name or self.pid:
                self._FindRemoteProcess(device)

            # Verify that sysroot is valid (exists).
            if not os.path.isdir(self.sysroot):
                raise GdbMissingSysrootError('Sysroot does not exist: %s' %
                                             self.sysroot)

        self.device = device
        sysroot_inf_cmd = ''
        if self.inf_cmd:
            sysroot_inf_cmd = os.path.join(self.sysroot,
                                           self.inf_cmd.lstrip('/'))

        # Verify that inf_cmd, if given, exists.
        if sysroot_inf_cmd and not os.path.exists(sysroot_inf_cmd):
            raise GdbMissingInferiorError('Cannot find file %s (in sysroot).' %
                                          sysroot_inf_cmd)

        # Check to see if inf_cmd is stripped, and if so, check to see if debug file
        # exists.  If not, tell user and give them the option of quitting & getting
        # the debug info.
        if sysroot_inf_cmd:
            stripped_info = cros_build_lib.RunCommand(
                ['file', sysroot_inf_cmd], capture_output=True).output
            if not ' not stripped' in stripped_info:
                debug_file = os.path.join(self.sysroot, 'usr/lib/debug',
                                          self.inf_cmd.lstrip('/'))
                debug_file += '.debug'
                if not os.path.exists(debug_file):
                    equery = 'equery-%s' % self.board
                    package = cros_build_lib.RunCommand(
                        [equery, '-q', 'b', self.inf_cmd],
                        capture_output=True).output
                    logging.info(
                        self._MISSING_DEBUG_INFO_MSG % {
                            'board': self.board,
                            'inf_cmd': self.inf_cmd,
                            'package': package,
                            'debug_file': debug_file
                        })
                    answer = cros_build_lib.BooleanPrompt()
                    if not answer:
                        raise GdbEarlyExitError(
                            'Exiting early, at user request.')

        # Set up qemu, if appropriate.
        qemu_arch = qemu.Qemu.DetectArch(self._GDB, self.sysroot)
        if qemu_arch is None:
            self.framework = 'ldso'
        else:
            self.framework = 'qemu'
            self.qemu = qemu.Qemu(self.sysroot, arch=qemu_arch)

        if self.remote:
            # Verify cgdb flag info.
            if self.cgdb:
                if osutils.Which('cgdb') is None:
                    raise GdbMissingDebuggerError(
                        'Cannot find cgdb.  Please install '
                        'cgdb first.')
def Deploy(device,
           packages,
           board=None,
           emerge=True,
           update=False,
           deep=False,
           deep_rev=False,
           clean_binpkg=True,
           root='/',
           strip=True,
           emerge_args=None,
           ssh_private_key=None,
           ping=True,
           force=False,
           dry_run=False):
    """Deploys packages to a device.

  Args:
    device: commandline.Device object; None to use the default device.
    packages: List of packages (strings) to deploy to device.
    board: Board to use; None to automatically detect.
    emerge: True to emerge package, False to unmerge.
    update: Check installed version on device.
    deep: Install dependencies also. Implies |update|.
    deep_rev: Install reverse dependencies. Implies |deep|.
    clean_binpkg: Clean outdated binary packages.
    root: Package installation root path.
    strip: Run strip_package to filter out preset paths in the package.
    emerge_args: Extra arguments to pass to emerge.
    ssh_private_key: Path to an SSH private key file; None to use test keys.
    ping: True to ping the device before trying to connect.
    force: Ignore sanity checks and prompts.
    dry_run: Print deployment plan but do not deploy anything.

  Raises:
    ValueError: Invalid parameter or parameter combination.
    DeployError: Unrecoverable failure during deploy.
  """
    if deep_rev:
        deep = True
    if deep:
        update = True

    if not packages:
        raise DeployError('No packages provided, nothing to deploy.')

    if update and not emerge:
        raise ValueError('Cannot update and unmerge.')

    if device:
        hostname, username, port = device.hostname, device.username, device.port
    else:
        hostname, username, port = None, None, None

    lsb_release = None
    sysroot = None
    try:
        # Somewhat confusing to clobber, but here we are.
        # pylint: disable=redefined-argument-from-local
        with remote_access.ChromiumOSDeviceHandler(hostname,
                                                   port=port,
                                                   username=username,
                                                   private_key=ssh_private_key,
                                                   base_dir=_DEVICE_BASE_DIR,
                                                   ping=ping) as device:
            lsb_release = device.lsb_release

            board = cros_build_lib.GetBoard(device_board=device.board,
                                            override_board=board)
            if not force and board != device.board:
                raise DeployError(
                    'Device (%s) is incompatible with board %s. Use '
                    '--force to deploy anyway.' % (device.board, board))

            sysroot = cros_build_lib.GetSysroot(board=board)

            if clean_binpkg:
                logging.notice('Cleaning outdated binary packages from %s',
                               sysroot)
                portage_util.CleanOutdatedBinaryPackages(sysroot)

            # Remount rootfs as writable if necessary.
            if not device.MountRootfsReadWrite():
                raise DeployError(
                    'Cannot remount rootfs as read-write. Exiting.')

            # Obtain list of packages to upgrade/remove.
            pkg_scanner = _InstallPackageScanner(sysroot)
            pkgs, listed, num_updates, pkgs_attrs = pkg_scanner.Run(
                device, root, packages, update, deep, deep_rev)
            if emerge:
                action_str = 'emerge'
            else:
                pkgs.reverse()
                action_str = 'unmerge'

            if not pkgs:
                logging.notice('No packages to %s', action_str)
                return

            # Warn when the user seems to forget `cros workon start`.
            worked_on_cps = workon_helper.WorkonHelper(sysroot).ListAtoms()
            for package in listed:
                cp = package_info.SplitCPV(package).cp
                if cp not in worked_on_cps:
                    logging.warning(
                        'Are you intentionally deploying unmodified packages, or did '
                        'you forget to run `cros workon --board=$BOARD start %s`?',
                        cp)

            logging.notice('These are the packages to %s:', action_str)
            for i, pkg in enumerate(pkgs):
                logging.notice('%s %d) %s', '*' if pkg in listed else ' ',
                               i + 1, pkg)

            if dry_run or not _ConfirmDeploy(num_updates):
                return

            # Select function (emerge or unmerge) and bind args.
            if emerge:
                func = functools.partial(_EmergePackages, pkgs, device, strip,
                                         sysroot, root, board, emerge_args)
            else:
                func = functools.partial(_UnmergePackages, pkgs, device, root,
                                         pkgs_attrs)

            # Call the function with the progress bar or with normal output.
            if command.UseProgressBar():
                op = BrilloDeployOperation(len(pkgs), emerge)
                op.Run(func, log_level=logging.DEBUG)
            else:
                func()

            if device.IsSELinuxAvailable():
                if sum(x.count('selinux-policy') for x in pkgs):
                    logging.warning(
                        'Deploying SELinux policy will not take effect until reboot. '
                        'SELinux policy is loaded by init. Also, changing the security '
                        'contexts (labels) of a file will require building a new image '
                        'and flashing the image onto the device.')

            logging.warning(
                'Please restart any updated services on the device, '
                'or just reboot it.')
    except Exception:
        if lsb_release:
            lsb_entries = sorted(lsb_release.items())
            logging.info(
                'Following are the LSB version details of the device:\n%s',
                '\n'.join('%s=%s' % (k, v) for k, v in lsb_entries))
        raise
    def GetPayloadDir(self, device):
        """Get directory of payload for update.

    This method is used to obtain the directory of payload for cros-flash. The
    given path 'self.image' is passed in when initializing RemoteDeviceUpdater.

    If self.image is a directory, we directly use the provided update payload(s)
    in this directory.

    If self.image is an image, we will generate payloads for it and put them in
    our temporary directory. The reason is that people may modify a local image
    or override it (on the same path) with a different image, so in order to be
    safe each time we need to generate the payloads and not cache them.

    If non of the above cases, we use the xbuddy to first obtain the image path
    (and possibly download it). Then we will generate the payloads in the same
    directory the image is located. The reason is that this is what devserver
    used to do. The path to the image generated by the devserver (or xbuddy) is
    unique and normally nobody override its image with a different one. That is
    why I think it is safe to put the payloads next to the image. This is a poor
    man's version of caching but it makes cros flash faster for users who flash
    the same image multiple times (without doing any change to the image).

    Args:
      device: A ChromiumOSDevice object.

    Returns:
      A string payload_dir, that represents the payload directory.
    """
        if os.path.isdir(self.image):
            # The given path is a directory.
            logging.info('Using provided payloads in %s', self.image)
            return self.image

        image_path = None
        if os.path.isfile(self.image):
            # The given path is an image.
            image_path = self.image
            payload_dir = self.tempdir
        else:
            # Assuming it is an xbuddy path.
            self.board = cros_build_lib.GetBoard(device_board=device.board
                                                 or GetDefaultBoard(),
                                                 override_board=self.board,
                                                 force=self.yes,
                                                 strict=True)
            if not self.force and self.board != device.board:
                # If a board was specified, it must be compatible with the device.
                raise FlashError('Device (%s) is incompatible with board %s' %
                                 (device.board, self.board))
            logging.info('Board is %s', self.board)

            # TODO(crbug.com/872441): Once devserver code has been moved to chromite,
            # use xbuddy library directly instead of the devserver_wrapper.
            # Fetch the full payload and properties, and stateful files. If this
            # fails, fallback to downloading the image.
            try:
                translated_path, _ = ds_wrapper.GetImagePathWithXbuddy(
                    os.path.join(self.image, artifact_info.FULL_PAYLOAD),
                    self.board,
                    self.version,
                    silent=True)
                payload_dir = os.path.dirname(
                    ds_wrapper.TranslatedPathToLocalPath(translated_path))
                ds_wrapper.GetImagePathWithXbuddy(os.path.join(
                    self.image, artifact_info.STATEFUL_PAYLOAD),
                                                  self.board,
                                                  self.version,
                                                  silent=True)
                fetch_image = False
            except (ds_wrapper.ImagePathError,
                    ds_wrapper.ArtifactDownloadError):
                logging.info(
                    'Could not find full_payload or stateful for "%s"',
                    self.image)
                fetch_image = True

            # We didn't find the full_payload, attempt to download the image.
            if fetch_image:
                translated_path, _ = ds_wrapper.GetImagePathWithXbuddy(
                    self.image, self.board, self.version)
                image_path = ds_wrapper.TranslatedPathToLocalPath(
                    translated_path)
                payload_dir = os.path.join(os.path.dirname(image_path),
                                           'payloads')
                logging.notice('Using image path %s and payload directory %s',
                               image_path, payload_dir)

        # Generate rootfs and stateful update payloads if they do not exist.
        payload_path = os.path.join(payload_dir,
                                    auto_updater_transfer.ROOTFS_FILENAME)
        if not os.path.exists(payload_path):
            paygen_payload_lib.GenerateUpdatePayload(
                image_path, payload_path, src_image=self.src_image_to_delta)
        if not os.path.exists(
                os.path.join(payload_dir,
                             auto_updater_transfer.STATEFUL_FILENAME)):
            paygen_stateful_payload_lib.GenerateStatefulPayload(
                image_path, payload_dir)
        return payload_dir