def _ProvisionDevice(self): """Pave a device with a generic image of Fuchsia.""" bootserver_path = GetHostToolPathFromPlatform('bootserver') bootserver_command = [ bootserver_path, '-1', '--fvm', EnsurePathExists( boot_data.GetTargetFile('storage-sparse.blk', self._GetTargetSdkArch(), boot_data.TARGET_TYPE_GENERIC)), EnsurePathExists( boot_data.GetBootImage(self._out_dir, self._GetTargetSdkArch(), boot_data.TARGET_TYPE_GENERIC)) ] if self._node_name: bootserver_command += ['-n', self._node_name] bootserver_command += ['--'] bootserver_command += boot_data.GetKernelArgs() logging.debug(' '.join(bootserver_command)) _, stdout = SubprocessCallWithTimeout(bootserver_command, silent=False, timeout_secs=300) self._ParseNodename(stdout) # Update the target's hash to match the current tree's. self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
def __ProvisionDevice(self): """Netboots a device with Fuchsia. If |_node_name| is set, then only a device with a matching node name is used. The device is up and reachable via SSH when the function is successfully completes.""" bootserver_path = os.path.join(SDK_ROOT, 'tools', 'bootserver') bootserver_command = [ bootserver_path, '-1', '--fvm', EnsurePathExists( boot_data.GetTargetFile(self._GetTargetSdkArch(), 'fvm.sparse.blk')), EnsurePathExists( boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch())) ] if self._node_name: bootserver_command += ['-n', self._node_name] bootserver_command += ['--'] bootserver_command += boot_data.GetKernelArgs(self._output_dir) logging.debug(' '.join(bootserver_command)) stdout = subprocess.check_output(bootserver_command, stderr=subprocess.STDOUT) # Parse the nodename from bootserver stdout. m = re.search(r'.*Proceeding with nodename (?P<nodename>.*)$', stdout, re.MULTILINE) if not m: raise Exception('Couldn\'t parse nodename from bootserver output.') self._node_name = m.groupdict()['nodename'] logging.info('Booted device "%s".' % self._node_name) # Start loglistener to save system logs. if self._system_log_file: loglistener_path = os.path.join(SDK_ROOT, 'tools', 'loglistener') self._loglistener = subprocess.Popen( [loglistener_path, self._node_name], stdout=self._system_log_file, stderr=subprocess.STDOUT, stdin=open(os.devnull)) # Repeatdly query mDNS until we find the device, or we hit the timeout of # DISCOVERY_TIMEOUT_SECS. logging.info('Waiting for device to join network.') for _ in xrange(_BOOT_DISCOVERY_ATTEMPTS): if self.__Discover(): break if not self._host: raise Exception('Device %s couldn\'t be discovered via mDNS.' % self._node_name) self._WaitUntilReady() # Update the target's hash to match the current tree's. self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
def __ProvisionDevice(self, node_name): logging.info('Netbooting Fuchsia. ' + 'Please ensure that your device is in bootloader mode.') bootserver_path = os.path.join(SDK_ROOT, 'tools', 'bootserver') bootserver_command = [ bootserver_path, '-1', '--fvm', EnsurePathExists( boot_data.GetTargetFile(self._GetTargetSdkArch(), 'fvm.sparse.blk')), EnsurePathExists( boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch())) ] if self._GetTargetSdkArch() == 'x64': bootserver_command += [ '--efi', EnsurePathExists( boot_data.GetTargetFile(self._GetTargetSdkArch(), 'local.esp.blk')) ] bootserver_command += ['--'] bootserver_command += boot_data.GetKernelArgs(self._output_dir) logging.debug(' '.join(bootserver_command)) subprocess.check_call(bootserver_command) # Start loglistener to save system logs. if self._system_log_file: loglistener_path = os.path.join(SDK_ROOT, 'tools', 'loglistener') self._loglistener = subprocess.Popen([loglistener_path, node_name], stdout=self._system_log_file, stderr=subprocess.STDOUT, stdin=open(os.devnull)) logging.debug('Waiting for device to join network.') for retry in xrange(CONNECT_RETRY_COUNT): self._host = self.__Discover(node_name) if self._host: break time.sleep(CONNECT_RETRY_WAIT_SECS) if not self._host: raise Exception('Couldn\'t connect to device.') logging.debug('host=%s, port=%d' % (self._host, self._port)) self._WaitUntilReady() # Update the target's hash to match the current tree's. self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
def _ProvisionDevice(self): """Pave a device with a generic image of Fuchsia.""" bootserver_path = GetHostToolPathFromPlatform('bootserver') bootserver_command = [ bootserver_path, '-1', '--fvm', EnsurePathExists( boot_data.GetTargetFile('storage-sparse.blk', self._GetTargetSdkArch(), boot_data.TARGET_TYPE_GENERIC)), EnsurePathExists( boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch(), boot_data.TARGET_TYPE_GENERIC)) ] if self._node_name: bootserver_command += ['-n', self._node_name] bootserver_command += ['--'] bootserver_command += boot_data.GetKernelArgs(self._output_dir) logging.debug(' '.join(bootserver_command)) _, stdout = SubprocessCallWithTimeout(bootserver_command, silent=False, timeout_secs=300) self._ParseNodename(stdout) # Start loglistener to save system logs. if self._system_log_file: self._StartLoglistener() # Repeatdly query mDNS until we find the device, or we hit # BOOT_DISCOVERY_ATTEMPTS logging.info('Waiting for device to join network.') for _ in xrange(device_target.BOOT_DISCOVERY_ATTEMPTS): if self.__Discover(): break if not self._host: raise Exception("Device %s couldn't be discovered via mDNS." % self._node_name) self._WaitUntilReady() # Update the target's hash to match the current tree's. self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
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
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