Esempio n. 1
0
    def __init__(self, target):
        AmberRepo.__init__(self, target)
        self._with_count = 0

        self._amber_root = tempfile.mkdtemp()
        pm_tool = common.GetHostToolPathFromPlatform('pm')
        subprocess.check_call([pm_tool, 'newrepo', '-repo', self._amber_root])
        logging.info('Creating and serving temporary Amber root: {}.'.format(
            self._amber_root))

        serve_port = common.GetAvailableTcpPort()
        self._pm_serve_task = subprocess.Popen([
            pm_tool, 'serve', '-d',
            os.path.join(self._amber_root, 'repository'), '-l',
            ':%d' % serve_port, '-q'
        ])

        # Block until "pm serve" starts serving HTTP traffic at |serve_port|.
        timeout = time.time() + _PM_SERVE_LIVENESS_TIMEOUT_SECS
        while True:
            try:
                urllib2.urlopen('http://localhost:%d' % serve_port,
                                timeout=1).read()
                break
            except urllib2.URLError:
                logging.info('Waiting until \'pm serve\' is up...')

            if time.time() >= timeout:
                raise Exception('Timed out while waiting for \'pm serve\'.')

            time.sleep(1)

        remote_port = common.ConnectPortForwardingTask(target, serve_port, 0)
        self._RegisterAmberRepository(self._amber_root, remote_port)
Esempio n. 2
0
    def InstallPackage(self, package_path, package_name, package_deps):
        """Installs a package and it's dependencies on the device. If the package is
    already installed then it will be updated to the new version.

    package_path: Path to the .far file to be installed.
    package_name: Package name.
    package_deps: List of .far files with the packages that the main package
                  depends on. These packages are installed or updated as well.
    """
        try:
            tuf_root = tempfile.mkdtemp()
            pm_serve_task = None

            subprocess.check_call([_PM, 'newrepo', '-repo', tuf_root])

            # Serve the |tuf_root| using 'pm serve' and configure the target to pull
            # from it.
            serve_port = common.GetAvailableTcpPort()
            pm_serve_task = subprocess.Popen([
                _PM, 'serve', '-d',
                os.path.join(tuf_root, 'repository'), '-l',
                ':%d' % serve_port, '-q'
            ])

            # Publish all packages to the serving TUF repository under |tuf_root|.
            all_packages = [package_path] + package_deps
            for next_package_path in all_packages:
                _PublishPackage(tuf_root, next_package_path)

            _WaitForPmServeToBeReady(serve_port)

            remote_port = common.ConnectPortForwardingTask(self, serve_port, 0)
            self._RegisterAmberRepository(tuf_root, remote_port)

            # Install all packages.
            for next_package_path in all_packages:
                install_package_name, package_version = \
                    _GetPackageInfo(next_package_path)
                logging.info('Installing %s version %s.' %
                             (install_package_name, package_version))
                return_code = self.RunCommand(
                    [
                        'amberctl', 'get_up', '-n', install_package_name, '-v',
                        package_version
                    ],
                    timeout_secs=_INSTALL_TIMEOUT_SECS)
                if return_code != 0:
                    raise Exception('Error while installing %s.' %
                                    install_package_name)

        finally:
            self._UnregisterAmberRepository()
            if pm_serve_task:
                pm_serve_task.kill()
            shutil.rmtree(tuf_root)
Esempio n. 3
0
def RunPackage(output_dir, target, package_path, package_name, package_deps,
               package_args, args):
    """Copies the Fuchsia package at |package_path| to the target,
  executes it with |package_args|, and symbolizes its output.

  output_dir: The path containing the build output files.
  target: The deployment Target object that will run the package.
  package_path: The path to the .far package file.
  package_name: The name of app specified by package metadata.
  package_args: The arguments which will be passed to the Fuchsia process.
  args: Structure of arguments to configure how the package will be run.

  Returns the exit code of the remote package process."""

    system_logger = (_AttachKernelLogReader(target)
                     if args.system_logging else None)
    try:
        if system_logger:
            # Spin up a thread to asynchronously dump the system log to stdout
            # for easier diagnoses of early, pre-execution failures.
            log_output_quit_event = multiprocessing.Event()
            log_output_thread = threading.Thread(
                target=lambda: _DrainStreamToStdout(system_logger.stdout,
                                                    log_output_quit_event))
            log_output_thread.daemon = True
            log_output_thread.start()

        tuf_root = tempfile.mkdtemp()
        pm_serve_task = None

        # Publish all packages to the serving TUF repository under |tuf_root|.
        subprocess.check_call([PM, 'newrepo', '-repo', tuf_root])
        all_packages = [package_path] + package_deps
        for next_package_path in all_packages:
            PublishPackage(tuf_root, next_package_path)

        # Serve the |tuf_root| using 'pm serve' and configure the target to pull
        # from it.
        # TODO(kmarshall): Use -q to suppress pm serve output once blob push
        # is confirmed to be running stably on bots.
        serve_port = common.GetAvailableTcpPort()
        pm_serve_task = subprocess.Popen([
            PM, 'serve', '-d',
            os.path.join(tuf_root, 'repository'), '-l',
            ':%d' % serve_port, '-q'
        ])
        remote_port = common.ConnectPortForwardingTask(target, serve_port, 0)
        _RegisterAmberRepository(target, tuf_root, remote_port)

        # Install all packages.
        for next_package_path in all_packages:
            install_package_name, package_version = GetPackageInfo(
                next_package_path)
            logging.info('Installing %s version %s.' %
                         (install_package_name, package_version))
            return_code = target.RunCommand([
                'amber_ctl', 'get_up', '-n', install_package_name, '-v',
                package_version
            ])
            if return_code != 0:
                raise Exception('Error while installing %s.' %
                                install_package_name)

        if system_logger:
            log_output_quit_event.set()
            log_output_thread.join(timeout=_JOIN_TIMEOUT_SECS)

        if args.install_only:
            logging.info('Installation complete.')
            return

        logging.info('Running application.')
        command = ['run', _GetComponentUri(package_name)] + package_args
        process = target.RunCommandPiped(command,
                                         stdin=open(os.devnull, 'r'),
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.STDOUT)

        if system_logger:
            task_output = _ReadMergedLines(
                [process.stdout, system_logger.stdout])
        else:
            task_output = process.stdout

        if args.symbolizer_config:
            # Decorate the process output stream with the symbolizer.
            output = FilterStream(task_output, package_name,
                                  args.symbolizer_config, output_dir)
        else:
            logging.warn('Symbolization is DISABLED.')
            output = process.stdout

        for next_line in output:
            print next_line.rstrip()

        process.wait()
        if process.returncode == 0:
            logging.info('Process exited normally with status code 0.')
        else:
            # The test runner returns an error status code if *any* tests fail,
            # so we should proceed anyway.
            logging.warning('Process exited with status code %d.' %
                            process.returncode)

    finally:
        if system_logger:
            logging.info('Terminating kernel log reader.')
            log_output_quit_event.set()
            log_output_thread.join()
            system_logger.kill()

        _UnregisterAmberRepository(target)
        if pm_serve_task:
            pm_serve_task.kill()
        shutil.rmtree(tuf_root)

    return process.returncode
Esempio n. 4
0
  def Start(self):
    qemu_path = os.path.join(GetQemuRootForPlatform(), 'bin',
                             'qemu-system-' + self._GetTargetSdkLegacyArch())
    kernel_args = boot_data.GetKernelArgs(self._output_dir)

    # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
    # noisy ANSI spew from the user's terminal emulator.
    kernel_args.append('TERM=dumb')

    # Enable logging to the serial port. This is a temporary fix to investigate
    # the root cause for https://crbug.com/869753 .
    kernel_args.append('kernel.serial=legacy')

    qemu_command = [qemu_path,
        '-m', str(self._ram_size_mb),
        '-nographic',
        '-kernel', EnsurePathExists(
            boot_data.GetTargetFile('qemu-kernel.kernel',
                                    self._GetTargetSdkArch(),
                                    boot_data.TARGET_TYPE_QEMU)),
        '-initrd', EnsurePathExists(
            boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch(),
                                   boot_data.TARGET_TYPE_QEMU)),
        '-smp', str(self._cpu_cores),

        # Attach the blobstore and data volumes. Use snapshot mode to discard
        # any changes.
        '-snapshot',
        '-drive', 'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
                    EnsurePathExists(
                        os.path.join(self._output_dir, 'fvm.blk.qcow2')),
        '-device', 'virtio-blk-pci,drive=blobstore',

        # Use stdio for the guest OS only; don't attach the QEMU interactive
        # monitor.
        '-serial', 'stdio',
        '-monitor', 'none',

        '-append', ' '.join(kernel_args)
      ]

    # Configure the machine to emulate, based on the target architecture.
    if self._target_cpu == 'arm64':
      qemu_command.extend([
          '-machine','virt',
      ])
      netdev_type = 'virtio-net-pci'
    else:
      qemu_command.extend([
          '-machine', 'q35',
      ])
      netdev_type = 'e1000'

    # Configure the CPU to emulate.
    # On Linux, we can enable lightweight virtualization (KVM) if the host and
    # guest architectures are the same.
    enable_kvm = self._require_kvm or (sys.platform.startswith('linux') and (
        (self._target_cpu == 'arm64' and platform.machine() == 'aarch64') or
        (self._target_cpu == 'x64' and platform.machine() == 'x86_64')) and
      os.access('/dev/kvm', os.R_OK | os.W_OK))
    if enable_kvm:
      qemu_command.extend(['-enable-kvm', '-cpu', 'host,migratable=no'])
    else:
      logging.warning('Unable to launch QEMU with KVM acceleration.')
      if self._target_cpu == 'arm64':
        qemu_command.extend(['-cpu', 'cortex-a53'])
      else:
        qemu_command.extend(['-cpu', 'Haswell,+smap,-check,-fsgsbase'])

    # Configure virtual network. It is used in the tests to connect to
    # testserver running on the host.
    netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
            (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)

    self._host_ssh_port = common.GetAvailableTcpPort()
    netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
    qemu_command.extend([
      '-netdev', netdev_config,
      '-device', '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
    ])

    # We pass a separate stdin stream to qemu. Sharing stdin across processes
    # leads to flakiness due to the OS prematurely killing the stream and the
    # Python script panicking and aborting.
    # The precise root cause is still nebulous, but this fix works.
    # See crbug.com/741194.
    logging.debug('Launching QEMU.')
    logging.debug(' '.join(qemu_command))

    # Zircon sends debug logs to serial port (see kernel.serial=legacy flag
    # above). Serial port is redirected to a file through QEMU stdout.
    # Unless a |_system_log_file| is explicitly set, we output the kernel serial
    # log to a temporary file, and print that out if we are unable to connect to
    # the QEMU guest, to make it easier to diagnose connectivity issues.
    temporary_system_log_file = None
    if self._system_log_file:
      stdout = self._system_log_file
      stderr = subprocess.STDOUT
    else:
      temporary_system_log_file = tempfile.NamedTemporaryFile('w')
      stdout = temporary_system_log_file
      stderr = sys.stderr

    self._qemu_process = subprocess.Popen(qemu_command, stdin=open(os.devnull),
                                          stdout=stdout, stderr=stderr)
    try:
      self._WaitUntilReady();
    except target.FuchsiaTargetException:
      if temporary_system_log_file:
        logging.info("Kernel logs:\n" +
                     open(temporary_system_log_file.name, 'r').read())
      raise
Esempio n. 5
0
  def _BuildCommand(self):
    boot_data.ProvisionSSH()
    self._host_ssh_port = common.GetAvailableTcpPort()
    kernel_image = common.EnsurePathExists(
        boot_data.GetTargetFile('qemu-kernel.kernel', self._image_arch,
                                self._image_type))
    zbi_image = common.EnsurePathExists(
        boot_data.GetTargetFile('zircon-a.zbi', self._image_arch,
                                self._image_type))
    fvm_image = common.EnsurePathExists(
        boot_data.GetTargetFile('storage-full.blk', self._image_arch,
                                self._image_type))
    aemu_path = common.EnsurePathExists(
        os.path.join(common.GetEmuRootForPlatform(self.EMULATOR_NAME),
                     'emulator'))

    emu_command = [
        self._FVDL_PATH,
        '--sdk',
        'start',
        '--nointeractive',

        # Host port mapping for user-networking mode.
        '--port-map',
        'hostfwd=tcp::{}-:22'.format(self._host_ssh_port),

        # no-interactive requires a --vdl-output flag to shutdown the emulator.
        '--vdl-output',
        self._vdl_output_file.name,
        '-c',
        ' '.join(boot_data.GetKernelArgs()),

        # Use existing images instead of downloading new ones.
        '--kernel-image',
        kernel_image,
        '--zbi-image',
        zbi_image,
        '--fvm-image',
        fvm_image,
        '--image-architecture',
        self._target_cpu,

        # Use an existing emulator checked out by Chromium.
        '--aemu-path',
        aemu_path,

        # Use this flag and temp file to define ram size.
        '--device-proto',
        self._device_proto_file.name,
        '--cpu-count',
        str(self._cpu_cores)
    ]
    self._ConfigureEmulatorLog(emu_command)

    if not self._require_kvm:
      emu_command.append('--noacceleration')
    if not self._enable_graphics:
      emu_command.append('--headless')
    if self._hardware_gpu:
      emu_command.append('--host-gpu')
    if self._with_network:
      emu_command.append('-N')

    return emu_command
Esempio n. 6
0
    def _BuildQemuConfig(self):
        boot_data.AssertBootImagesExist(self._GetTargetSdkArch(), 'qemu')

        emu_command = [
            '-kernel',
            EnsurePathExists(
                boot_data.GetTargetFile('qemu-kernel.kernel',
                                        self._GetTargetSdkArch(),
                                        boot_data.TARGET_TYPE_QEMU)),
            '-initrd',
            EnsurePathExists(
                boot_data.GetBootImage(self._output_dir,
                                       self._GetTargetSdkArch(),
                                       boot_data.TARGET_TYPE_QEMU)),
            '-m',
            str(self._ram_size_mb),
            '-smp',
            str(self._cpu_cores),

            # Attach the blobstore and data volumes. Use snapshot mode to discard
            # any changes.
            '-snapshot',
            '-drive',
            'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
            _EnsureBlobstoreQcowAndReturnPath(self._output_dir,
                                              self._GetTargetSdkArch(),
                                              self._qemu_img_retries),
            '-device',
            'virtio-blk-pci,drive=blobstore',

            # Use stdio for the guest OS only; don't attach the QEMU interactive
            # monitor.
            '-serial',
            'stdio',
            '-monitor',
            'none',
        ]

        # Configure the machine to emulate, based on the target architecture.
        if self._target_cpu == 'arm64':
            emu_command.extend([
                '-machine',
                'virt,gic_version=3',
            ])
            netdev_type = 'virtio-net-pci'
        else:
            emu_command.extend([
                '-machine',
                'q35',
            ])
            netdev_type = 'e1000'

        # Configure virtual network. It is used in the tests to connect to
        # testserver running on the host.
        netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
                (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)

        self._host_ssh_port = common.GetAvailableTcpPort()
        netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
        emu_command.extend([
            '-netdev',
            netdev_config,
            '-device',
            '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
        ])

        # Configure the CPU to emulate.
        # On Linux, we can enable lightweight virtualization (KVM) if the host and
        # guest architectures are the same.
        if self._IsKvmEnabled():
            kvm_command = ['-enable-kvm', '-cpu']
            if self._target_cpu == 'arm64':
                kvm_command.append('host')
            else:
                kvm_command.append('host,migratable=no')
        else:
            logging.warning('Unable to launch %s with KVM acceleration.' %
                            (self._emu_type) + 'The guest VM will be slow.')
            if self._target_cpu == 'arm64':
                kvm_command = ['-cpu', 'cortex-a53']
            else:
                kvm_command = ['-cpu', 'Haswell,+smap,-check,-fsgsbase']

        emu_command.extend(kvm_command)

        kernel_args = boot_data.GetKernelArgs(self._output_dir)

        # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
        # noisy ANSI spew from the user's terminal emulator.
        kernel_args.append('TERM=dumb')

        # Construct kernel cmd line
        kernel_args.append('kernel.serial=legacy')

        # Don't 'reboot' the emulator if the kernel crashes
        kernel_args.append('kernel.halt-on-panic=true')

        emu_command.extend(['-append', ' '.join(kernel_args)])

        return emu_command