Beispiel #1
0
def test_dispatcher_ip_nfs():
    assert (dispatcher_ip(
        {
            "dispatcher_ip": "127.0.0.1",
            "dispatcher_nfs_ip": "192.168.1.2"
        }, "nfs") == "192.168.1.2")
    # Fall back to dispatcher_ip if dispatcher_nfs_ip is missing.
    assert dispatcher_ip({"dispatcher_ip": "127.0.0.1"}, "nfs") == "127.0.0.1"
Beispiel #2
0
def test_dispatcher_ip_http_port():
    assert (dispatcher_ip(
        {
            "dispatcher_ip": "127.0.0.1",
            "dispatcher_http_ip": "192.168.1.2:8080"
        },
        "http",
    ) == "192.168.1.2:8080")
    # Fall back to dispatcher_ip if dispatcher_http_ip is missing.
    assert dispatcher_ip({"dispatcher_ip": "127.0.0.1"}, "http") == "127.0.0.1"
Beispiel #3
0
 def run(self, connection, max_end_time):
     connection = super().run(connection, max_end_time)
     ip_addr = dispatcher_ip(self.job.parameters["dispatcher"])
     substitution_dictionary = {
         "{SERVER_IP}":
         ip_addr,
         "{RAMDISK}":
         self.get_namespace_data(action="compress-ramdisk",
                                 label="file",
                                 key="ramdisk"),
         "{KERNEL}":
         self.get_namespace_data(action="download-action",
                                 label="file",
                                 key="kernel"),
         "{DTB}":
         self.get_namespace_data(action="download-action",
                                 label="file",
                                 key="dtb"),
         "TEST_MENU_NAME":
         "LAVA %s test image" % self.parameters["commands"],
     }
     nfs_address = self.get_namespace_data(action="persistent-nfs-overlay",
                                           label="nfs_address",
                                           key="nfsroot")
     nfs_root = self.get_namespace_data(action="download-action",
                                        label="file",
                                        key="nfsrootfs")
     if nfs_root:
         substitution_dictionary["{NFSROOTFS}"] = self.get_namespace_data(
             action="extract-rootfs", label="file", key="nfsroot")
         substitution_dictionary["{NFS_SERVER_IP}"] = dispatcher_ip(
             self.job.parameters["dispatcher"], "nfs")
     elif nfs_address:
         substitution_dictionary["{NFSROOTFS}"] = nfs_address
         substitution_dictionary[
             "{NFS_SERVER_IP}"] = self.get_namespace_data(
                 action="persistent-nfs-overlay",
                 label="nfs_address",
                 key="serverip")
     for item in self.items:
         if "enter" in item["select"]:
             item["select"]["enter"] = substitute(
                 [item["select"]["enter"]], substitution_dictionary)[0]
         if "items" in item["select"]:
             # items is already a list, so pass without wrapping in []
             item["select"]["items"] = substitute(item["select"]["items"],
                                                  substitution_dictionary)
     return connection
Beispiel #4
0
 def run(self, connection, max_end_time):
     if "deployment_data" not in self.parameters:
         return connection
     if self.parameters["deployment_data"].get("installer_extra_cmd"):
         if self.parameters.get("os") == "debian_installer":
             add_late_command(
                 self.get_namespace_data(action="download-action",
                                         label="preseed",
                                         key="file"),
                 self.parameters["deployment_data"]["installer_extra_cmd"],
             )
         if self.parameters.get("os") == "centos_installer":
             ip_addr = dispatcher_ip(self.job.parameters["dispatcher"])
             overlay = self.get_namespace_data(action="download-action",
                                               label="file",
                                               key="overlay")
             substitutions = {
                 "{OVERLAY_URL}": "tftp://" + ip_addr + "/" + overlay
             }
             post_command = substitute(
                 [
                     self.parameters["deployment_data"]
                     ["installer_extra_cmd"]
                 ],
                 substitutions,
             )
             add_to_kickstart(
                 self.get_namespace_data(action="download-action",
                                         label="preseed",
                                         key="file"),
                 post_command[0],
             )
     return connection
Beispiel #5
0
 def run(self, connection, max_end_time, args=None):
     connection = super(UefiSubstituteCommands, self).run(connection, max_end_time, args)
     ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
     substitution_dictionary = {
         '{SERVER_IP}': ip_addr,
         '{RAMDISK}': self.get_namespace_data(action='compress-ramdisk', label='file', key='ramdisk'),
         '{KERNEL}': self.get_namespace_data(action='download-action', label='file', key='kernel'),
         '{DTB}': self.get_namespace_data(action='download-action', label='file', key='dtb'),
         'TEST_MENU_NAME': "LAVA %s test image" % self.parameters['commands']
     }
     nfs_address = self.get_namespace_data(action='persistent-nfs-overlay', label='nfs_address', key='nfsroot')
     nfs_root = self.get_namespace_data(action='download-action', label='file', key='nfsrootfs')
     if nfs_root:
         substitution_dictionary['{NFSROOTFS}'] = self.get_namespace_data(action='extract-rootfs', label='file', key='nfsroot')
         substitution_dictionary['{NFS_SERVER_IP}'] = ip_addr
     elif nfs_address:
         substitution_dictionary['{NFSROOTFS}'] = nfs_address
         substitution_dictionary['{NFS_SERVER_IP}'] = self.get_namespace_data(
             action='persistent-nfs-overlay', label='nfs_address', key='serverip')
     for item in self.items:
         if 'enter' in item['select']:
             item['select']['enter'] = substitute([item['select']['enter']], substitution_dictionary)[0]
         if 'items' in item['select']:
             # items is already a list, so pass without wrapping in []
             item['select']['items'] = substitute(item['select']['items'], substitution_dictionary)
     return connection
Beispiel #6
0
    def run(self, connection, max_end_time):
        if not self.parameters.get(self.param_key):  # idempotency
            return connection
        connection = super().run(connection, max_end_time)

        if "prefix" in self.parameters[self.param_key]:
            prefix = self.parameters[self.param_key]["prefix"]
            self.logger.warning(
                "Adding '%s' prefix, any other content will not be visible.",
                prefix)

            # Grab the path already defined in super().run() and add the prefix
            root_dir = self.get_namespace_data(action="extract-rootfs",
                                               label="file",
                                               key=self.file_key)
            root_dir = os.path.join(root_dir, prefix)
            # sets the directory into which the overlay is unpacked and which
            # is used in the substitutions into the bootloader command string.
            self.set_namespace_data(action="extract-rootfs",
                                    label="file",
                                    key=self.file_key,
                                    value=root_dir)

        self.job.device["dynamic_data"][
            "NFS_ROOTFS"] = self.get_namespace_data(action="extract-rootfs",
                                                    label="file",
                                                    key=self.file_key)
        self.job.device["dynamic_data"]["NFS_SERVER_IP"] = dispatcher_ip(
            self.job.parameters["dispatcher"])

        return connection
Beispiel #7
0
 def set_port(self, action):
     msg = {"data": {"nbd_server_port": 10809}}
     nbd_port = self.parameters["protocols"]["lava-xnbd"]["port"]
     if nbd_port == "auto":
         self.logger.debug("Get a port from pool")
         nbd_port = get_free_port(self.parameters["dispatcher"])
     self.ports.append(nbd_port)
     msg["data"]["nbd_server_port"] = nbd_port
     action.set_namespace_data(
         "nbd-deploy",
         label="nbd",
         key="nbd_server_port",
         value=nbd_port,
         parameters=action.parameters,
     )
     nbd_ip = dispatcher_ip(self.parameters["dispatcher"])
     action.set_namespace_data(
         "nbd-deploy",
         label="nbd",
         key="nbd_server_ip",
         value=nbd_ip,
         parameters=action.parameters,
     )
     self.logger.debug("Set_port %d", nbd_port)
     return msg["data"]
Beispiel #8
0
    def validate(self):
        super(QemuCommandLine, self).validate()
        boot = self.job.device['actions']['boot']['methods']['qemu']
        qemu_binary = which(boot['parameters']['command'])
        self.sub_command = [qemu_binary]
        self.sub_command.extend(boot['parameters'].get('options', []))
        boot_opts = boot['parameters'].get('boot_options', None)
        if boot_opts:
            self.console = "console=%s" % boot_opts['console']
            self.boot_order = "-boot %s" % boot_opts['boot_order']
        if not qemu_binary or not self.console or not self.boot_order:
            self.errors = "Invalid parameters for %s" % self.name
        # create the preseed.cfg url
        # needs to be an IP address for DI, DNS is not available.
        # PRESEED_URL='http://10.15.0.32/tmp/d-i/jessie/preseed.cfg'
        ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
        self.preseed_url = 'tftp://%s/' % ip_addr

        self.sub_command.append(' -drive format=raw,file={emptyimage} ')
        self.sub_command.append(self.boot_order)
        self.command_line = " -append '%s console=tty0 console=tty1 %s %s %s %s preseed/url=%s{preseed} --- %s '  " % (
            self.parameters['deployment_data']['base'],
            self.parameters['deployment_data']['locale'],
            self.console,
            self.parameters['deployment_data']['keymaps'],
            self.parameters['deployment_data']['netcfg'],
            self.preseed_url,
            self.console)
        self.set_namespace_data(action=self.name, label=self.name, key='prompts', value=self.parameters['deployment_data']['prompts'])
        self.set_namespace_data(action=self.name, label=self.name, key='append', value=self.command_line)
Beispiel #9
0
    def test_overlay_noramdisk(self, which_mock):
        parameters = {
            "dispatcher": {},  # fake dispatcher parameter. Normally added by parser
            "device_type": "beaglebone-black",
            "job_name": "uboot-pipeline",
            "job_timeout": "15m",
            "action_timeout": "5m",
            "priority": "medium",
            "actions": {
                "boot": {
                    "namespace": "common",
                    "method": "u-boot",
                    "commands": "ramdisk",
                    "prompts": ["linaro-test", "root@debian:~#"],
                },
                "deploy": {
                    "namespace": "common",
                    "ramdisk": {"url": ""},
                    "kernel": {"url": "zImage", "type": "zimage"},
                    "dtb": {"url": "broken.dtb"},
                },
            },
        }
        data = yaml_safe_load(Factory().create_device("bbb-01.jinja2")[0])
        device = NewDevice(data)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel_addr = "0x83000000"
        ramdisk_addr = "0x83000000"
        dtb_addr = "0x88000000"
        kernel = parameters["actions"]["deploy"]["kernel"]["url"]
        ramdisk = parameters["actions"]["deploy"]["ramdisk"]["url"]
        dtb = parameters["actions"]["deploy"]["dtb"]["url"]

        substitution_dictionary = {
            "{SERVER_IP}": ip_addr,
            # the addresses need to be hexadecimal
            "{KERNEL_ADDR}": kernel_addr,
            "{DTB_ADDR}": dtb_addr,
            "{RAMDISK_ADDR}": ramdisk_addr,
            "{BOOTX}": "%s %s %s %s" % ("bootz", kernel_addr, ramdisk_addr, dtb_addr),
            "{RAMDISK}": ramdisk,
            "{KERNEL}": kernel,
            "{DTB}": dtb,
        }
        params = device["actions"]["boot"]["methods"]
        params["u-boot"]["ramdisk"]["commands"] = substitute(
            params["u-boot"]["ramdisk"]["commands"], substitution_dictionary, drop=True
        )

        commands = params["u-boot"]["ramdisk"]["commands"]
        self.assertIs(type(commands), list)
        self.assertIn("tftp 0x83000000 zImage", commands)
        self.assertNotIn("tftp 0x83000000 {RAMDISK}", commands)
        self.assertNotIn("tftp 0x83000000 ", commands)
        self.assertIn("setenv initrd_size ${filesize}", commands)
        self.assertIn("tftp 0x88000000 broken.dtb", commands)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", commands)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", commands)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", commands)
Beispiel #10
0
 def run(self, connection, max_end_time, args=None):
     if 'deployment_data' not in self.parameters:
         return connection
     if self.parameters["deployment_data"].get('installer_extra_cmd', None):
         if self.parameters.get('os', None) == "debian_installer":
             add_late_command(
                 self.get_namespace_data(action='download-action',
                                         label='preseed',
                                         key='file'),
                 self.parameters["deployment_data"]["installer_extra_cmd"])
         if self.parameters.get('os', None) == "centos_installer":
             ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
             overlay = self.get_namespace_data(action='download-action',
                                               label='file',
                                               key='overlay')
             substitutions = {
                 '{OVERLAY_URL}': 'tftp://' + ip_addr + '/' + overlay
             }
             post_command = substitute([
                 self.parameters["deployment_data"]["installer_extra_cmd"]
             ], substitutions)
             add_to_kickstart(
                 self.get_namespace_data(action='download-action',
                                         label='preseed',
                                         key='file'), post_command[0])
     return connection
Beispiel #11
0
    def run(self, connection, max_end_time):
        connection = super().run(connection, max_end_time)
        if not connection:
            raise LAVABug("Cannot transfer overlay, no connection available.")
        overlay_full_path = self.get_namespace_data(action="compress-overlay",
                                                    label="output",
                                                    key="file")
        if not overlay_full_path:
            raise JobError("No overlay file identified for the transfer.")
        if not overlay_full_path.startswith(DISPATCHER_DOWNLOAD_DIR):
            raise ConfigurationError(
                "overlay should already be in DISPATCHER_DOWNLOAD_DIR")
        overlay_path = overlay_full_path[len(DISPATCHER_DOWNLOAD_DIR) + 1:]
        overlay = os.path.basename(overlay_path)
        connection.sendline("rm %s" % overlay)
        connection.wait()

        cmd = self.parameters["transfer_overlay"]["download_command"]
        ip_addr = dispatcher_ip(self.job.parameters["dispatcher"], "http")
        connection.sendline("%s http://%s/tmp/%s" %
                            (cmd, ip_addr, overlay_path))
        connection.wait()

        unpack = self.parameters["transfer_overlay"]["unpack_command"]
        connection.sendline(unpack + " " + overlay)
        connection.wait()

        return connection
Beispiel #12
0
    def run(self, connection, max_end_time):
        connection = super().run(connection, max_end_time)

        # Create the cmdline file, this is not set by any bootloader command
        ip_addr = dispatcher_ip(self.job.parameters["dispatcher"])
        kernel_path = self.get_namespace_data(
            action="download-action", label="kernel", key="file"
        )
        cmdline_path = os.path.join(os.path.dirname(kernel_path), "cmdline")
        nfs_address = self.get_namespace_data(
            action="persistent-nfs-overlay", label="nfs_address", key="nfsroot"
        )
        nfs_root = self.get_namespace_data(
            action="download-action", label="file", key="nfsrootfs"
        )

        if nfs_root:
            substitutions = {
                "{NFSROOTFS}": self.get_namespace_data(
                    action="extract-rootfs", label="file", key="nfsroot"
                ),
                "{NFS_SERVER_IP}": ip_addr,
            }
        elif nfs_address:
            substitutions = {
                "{NFSROOTFS}": nfs_address,
                "{NFS_SERVER_IP}": self.get_namespace_data(
                    action="persistent-nfs-overlay", label="nfs_address", key="serverip"
                ),
            }
        else:
            substitutions = {}
        cmdline = substitute([self.cmdline], substitutions)[0]

        with open(cmdline_path, "w") as cmdline_file:
            cmdline_file.write(cmdline)

        # Substitute {CMDLINE} with the cmdline file TFTP path
        kernel_tftp = self.get_namespace_data(
            action="download-action", label="file", key="kernel"
        )
        cmdline_tftp = os.path.join(os.path.dirname(kernel_tftp), "cmdline")
        fit_tftp = self.get_namespace_data(
            action="prepare-fit", label="file", key="fit"
        )
        substitutions = {"{CMDLINE}": cmdline_tftp, "{FIT}": fit_tftp}
        commands = self.get_namespace_data(
            action="bootloader-overlay", label=self.method, key="commands"
        )
        commands = substitute(commands, substitutions)
        self.set_namespace_data(
            action="bootloader-overlay",
            label=self.method,
            key="commands",
            value=commands,
        )
        self.logger.info("Parsed boot commands: %s", "; ".join(commands))

        return connection
Beispiel #13
0
    def populate(self, parameters):
        self.tftp_dir = self.mkdtemp(override=tftpd_dir())
        self.internal_pipeline = Pipeline(parent=self,
                                          job=self.job,
                                          parameters=parameters)
        self.set_namespace_data(action=self.name,
                                label='tftp',
                                key='tftp_dir',
                                value=self.tftp_dir,
                                parameters=parameters)

        for key in ['initrd', 'kernel', 'dtb', 'nbdroot']:
            if key in parameters:
                download = DownloaderAction(key, path=self.tftp_dir)
                download.max_retries = 3  # overridden by failure_retry in the parameters, if set.
                self.internal_pipeline.add_action(download)
                if key == 'initrd':
                    self.set_namespace_data(action="tftp-deploy",
                                            label='tftp',
                                            key='ramdisk',
                                            value=True,
                                            parameters=parameters)
                    self.set_namespace_data(action=self.name,
                                            label='nbd',
                                            key='initrd',
                                            value=True,
                                            parameters=parameters)

        # prepare overlay
        self.internal_pipeline.add_action(OverlayAction())
        # setup values for protocol and later steps
        self.set_namespace_data(action=self.name,
                                label='nbd',
                                key='initrd',
                                value=True,
                                parameters=parameters)
        # store in parameters for protocol 'xnbd' to tear-down xnbd-server
        # and store in namespace for boot action
        # ip
        parameters['lava-xnbd'] = {}
        self.nbd_ip = dispatcher_ip(self.job.parameters['dispatcher'])
        parameters['lava-xnbd']['ip'] = self.nbd_ip
        self.set_namespace_data(action=self.name,
                                label='nbd',
                                key='nbd_server_ip',
                                value=self.nbd_ip,
                                parameters=parameters)
        # port
        self.nbd_port = get_free_port(self.job.parameters['dispatcher'])
        parameters['lava-xnbd']['port'] = self.nbd_port
        self.set_namespace_data(action=self.name,
                                label='nbd',
                                key='nbd_server_port',
                                value=self.nbd_port,
                                parameters=parameters)
        # handle XnbdAction next - bring-up xnbd-server
        self.internal_pipeline.add_action(XnbdAction())
Beispiel #14
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            'device_type': 'd02',
            'job_name': 'grub-standard-ramdisk',
            'job_timeout': '15m',
            'action_timeout': '5m',
            'priority': 'medium',
            'actions': {
                'boot': {
                    'method': 'grub',
                    'commands': 'ramdisk',
                    'prompts': ['linaro-test', 'root@debian:~#']
                },
                'deploy': {
                    'ramdisk': 'initrd.gz',
                    'kernel': 'zImage',
                    'dtb': 'broken.dtb'
                }
            }
        }
        (rendered, _) = self.factory.create_device('d02-01.jinja2')
        device = NewDevice(yaml.load(rendered))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters['actions']['boot'])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel = parameters['actions']['deploy']['kernel']
        ramdisk = parameters['actions']['deploy']['ramdisk']
        dtb = parameters['actions']['deploy']['dtb']

        substitution_dictionary = {
            '{SERVER_IP}': ip_addr,
            # the addresses need to be hexadecimal
            '{RAMDISK}': ramdisk,
            '{KERNEL}': kernel,
            '{DTB}': dtb
        }
        params = device['actions']['boot']['methods']
        commands = params['grub']['ramdisk']['commands']
        self.assertIn('net_bootp', commands)
        self.assertIn("linux (tftp,{SERVER_IP})/{KERNEL} console=ttyS0,115200 earlycon=uart8250,mmio32,0x80300000 root=/dev/ram0 ip=dhcp", commands)
        self.assertIn('initrd (tftp,{SERVER_IP})/{RAMDISK}', commands)
        self.assertIn('devicetree (tftp,{SERVER_IP})/{DTB}', commands)

        params['grub']['ramdisk']['commands'] = substitute(params['grub']['ramdisk']['commands'], substitution_dictionary)
        substituted_commands = params['grub']['ramdisk']['commands']
        self.assertIs(type(substituted_commands), list)
        self.assertIn('net_bootp', substituted_commands)
        self.assertNotIn("linux (tftp,{SERVER_IP})/{KERNEL} console=ttyS0,115200 earlycon=uart8250,mmio32,0x80300000 root=/dev/ram0 ip=dhcp", substituted_commands)
        self.assertIn("linux (tftp,%s)/%s console=ttyS0,115200 earlycon=uart8250,mmio32,0x80300000 root=/dev/ram0 ip=dhcp" % (ip_addr, kernel), substituted_commands)
        self.assertNotIn('initrd (tftp,{SERVER_IP})/{RAMDISK}', parsed)
        self.assertNotIn('devicetree (tftp,{SERVER_IP})/{DTB}', parsed)
Beispiel #15
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            'device_type': 'd02',
            'job_name': 'grub-standard-ramdisk',
            'job_timeout': '15m',
            'action_timeout': '5m',
            'priority': 'medium',
            'actions': {
                'boot': {
                    'method': 'grub',
                    'commands': 'ramdisk',
                    'prompts': ['linaro-test', 'root@debian:~#']
                },
                'deploy': {
                    'ramdisk': 'initrd.gz',
                    'kernel': 'zImage',
                    'dtb': 'broken.dtb'
                }
            }
        }
        device = NewDevice(os.path.join(os.path.dirname(__file__), '../devices/d02-01.yaml'))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters['actions']['boot'])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel = parameters['actions']['deploy']['kernel']
        ramdisk = parameters['actions']['deploy']['ramdisk']
        dtb = parameters['actions']['deploy']['dtb']

        substitution_dictionary = {
            '{SERVER_IP}': ip_addr,
            # the addresses need to be hexadecimal
            '{RAMDISK}': ramdisk,
            '{KERNEL}': kernel,
            '{DTB}': dtb
        }
        params = device['actions']['boot']['methods']
        commands = params['grub']['ramdisk']['commands']
        self.assertIn('net_bootp', commands)
        self.assertIn("linux (tftp,{SERVER_IP})/{KERNEL} console=ttyS0,115200 earlycon=uart8250,mmio32,0x80300000 root=/dev/ram0 ip=dhcp", commands)
        self.assertIn('initrd (tftp,{SERVER_IP})/{RAMDISK}', commands)
        self.assertIn('devicetree (tftp,{SERVER_IP})/{DTB}', commands)

        params['grub']['ramdisk']['commands'] = substitute(params['grub']['ramdisk']['commands'], substitution_dictionary)
        substituted_commands = params['grub']['ramdisk']['commands']
        self.assertIs(type(substituted_commands), list)
        self.assertIn('net_bootp', substituted_commands)
        self.assertNotIn("linux (tftp,{SERVER_IP})/{KERNEL} console=ttyS0,115200 earlycon=uart8250,mmio32,0x80300000 root=/dev/ram0 ip=dhcp", substituted_commands)
        self.assertIn("linux (tftp,%s)/%s console=ttyS0,115200 earlycon=uart8250,mmio32,0x80300000 root=/dev/ram0 ip=dhcp" % (ip_addr, kernel), substituted_commands)
        self.assertNotIn('initrd (tftp,{SERVER_IP})/{RAMDISK}', parsed)
        self.assertNotIn('devicetree (tftp,{SERVER_IP})/{DTB}', parsed)
Beispiel #16
0
    def target_extract(self, connection, dest):
        """
        Retrieve the decompressed image from the dispatcher by calling the tool specified
        by the test writer, from within the test image of the first deployment, using the
        device to write directly to the secondary media, without needing to cache on the device.
        """
        d_file = self.get_namespace_data(action='download-action', label='rootfs', key='file')
        if not d_file:
            self.logger.debug("Skipping %s - nothing downloaded")
            return connection
        decompressed_image = os.path.basename(d_file)

        decompression_char = ''
        if decompressed_image.endswith('.gz') or decompressed_image.endswith('.tgz'):
            decompression_char = 'z'
        elif decompressed_image.endswith('.bz2'):
            decompression_char = 'j'
        elif decompressed_image.endswith('.tar'):
            decompression_char = ''
        else:
            raise JobError('bad file extension: %s' % tar_url)

        storage_suffix = self.get_namespace_data(action='qemudev-deploy', label='storage', key='suffix')
        if not storage_suffix:
            storage_suffix = ''
        suffix = "%s/%s" % ("tmp", storage_suffix)
        self.logger.debug("suffix :  %s", suffix)

        # As the test writer can use any tool we cannot predict where the
        # download URL will be positioned in the download command.
        # Providing the download URL as a substitution option gets round this
        ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
        download_url = "http://%s/%s/%s" % (
            ip_addr, suffix, decompressed_image
        )

        download_cmd = 'ping 8.8.8.8 -c 4 ;' +\
            'wget --no-check-certificate --no-proxy ' +\
            '--connect-timeout=30 -S --progress=dot -e dotbytes=2M ' +\
            '-O- %s' % (download_url)
        extract_cmd = 'tar --warning=no-timestamp --numeric-owner -C %s -x%sf -' % (dest, decompression_char)

        prompt_string = connection.prompt_str
        connection.prompt_str = 'written to stdout'
        self.logger.debug("Changing prompt to %s", connection.prompt_str)
        connection.sendline("%s | %s" % (download_cmd, extract_cmd))
        self.wait(connection)
        if not self.valid:
            self.logger.error(self.errors)

        connection.prompt_str = prompt_string
        self.logger.debug("Changing prompt to %s", connection.prompt_str)
        self.set_namespace_data(action='shared', label='shared', key='connection', value=connection)
        return connection
Beispiel #17
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            "device_type": "x86",
            "job_name": "ipxe-pipeline",
            "job_timeout": "15m",
            "action_timeout": "5m",
            "priority": "medium",
            "actions": {
                "boot": {
                    "method": "ipxe",
                    "commands": "ramdisk",
                    "prompts": ["linaro-test", "root@debian:~#"],
                },
                "deploy": {
                    "ramdisk": "initrd.gz",
                    "kernel": "zImage"
                },
            },
        }
        (rendered, _) = self.factory.create_device("x86-01.jinja2")
        device = NewDevice(yaml.safe_load(rendered))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters["actions"]["boot"])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        kernel = parameters["actions"]["deploy"]["kernel"]
        ramdisk = parameters["actions"]["deploy"]["ramdisk"]

        substitution_dictionary = {
            "{SERVER_IP}": ip_addr,
            "{RAMDISK}": ramdisk,
            "{KERNEL}": kernel,
            "{LAVA_MAC}": "00:00:00:00:00:00",
        }
        params = device["actions"]["boot"]["methods"]
        params["ipxe"]["ramdisk"]["commands"] = substitute(
            params["ipxe"]["ramdisk"]["commands"], substitution_dictionary)

        commands = params["ipxe"]["ramdisk"]["commands"]
        self.assertIs(type(commands), list)
        self.assertIn("dhcp net0", commands)
        self.assertIn(
            "set console console=ttyS0,115200n8 lava_mac=00:00:00:00:00:00",
            commands)
        self.assertIn("set extraargs  ip=dhcp", commands)
        self.assertNotIn(
            "kernel tftp://{SERVER_IP}/{KERNEL} ${extraargs} ${console}",
            commands)
        self.assertNotIn("initrd tftp://{SERVER_IP}/{RAMDISK}", commands)
        self.assertIn("boot", commands)
Beispiel #18
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            'device_type': 'x86',
            'job_name': 'ipxe-pipeline',
            'job_timeout': '15m',
            'action_timeout': '5m',
            'priority': 'medium',
            'actions': {
                'boot': {
                    'method': 'ipxe',
                    'commands': 'ramdisk',
                    'prompts': ['linaro-test', 'root@debian:~#']
                },
                'deploy': {
                    'ramdisk': 'initrd.gz',
                    'kernel': 'zImage',
                }
            }
        }
        (rendered, _) = self.factory.create_device('x86-01.jinja2')
        device = NewDevice(yaml.safe_load(rendered))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters['actions']['boot'])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        kernel = parameters['actions']['deploy']['kernel']
        ramdisk = parameters['actions']['deploy']['ramdisk']

        substitution_dictionary = {
            '{SERVER_IP}': ip_addr,
            '{RAMDISK}': ramdisk,
            '{KERNEL}': kernel,
            '{LAVA_MAC}': "00:00:00:00:00:00"
        }
        params = device['actions']['boot']['methods']
        params['ipxe']['ramdisk']['commands'] = substitute(
            params['ipxe']['ramdisk']['commands'], substitution_dictionary)

        commands = params['ipxe']['ramdisk']['commands']
        self.assertIs(type(commands), list)
        self.assertIn("dhcp net0", commands)
        self.assertIn(
            "set console console=ttyS0,115200n8 lava_mac=00:00:00:00:00:00",
            commands)
        self.assertIn("set extraargs  ip=dhcp", commands)
        self.assertNotIn(
            "kernel tftp://{SERVER_IP}/{KERNEL} ${extraargs} ${console}",
            commands)
        self.assertNotIn("initrd tftp://{SERVER_IP}/{RAMDISK}", commands)
        self.assertIn("boot", commands)
Beispiel #19
0
    def run(self, connection, max_end_time, args=None):
        connection = super(DepthchargeCommandOverlay, self).run(
            connection, max_end_time, args)

        # Create the cmdline file, this is not set by any bootloader command
        ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
        kernel_path = self.get_namespace_data(
            action='download-action', label='kernel', key='file')
        cmdline_path = os.path.join(os.path.dirname(kernel_path), 'cmdline')
        nfs_address = self.get_namespace_data(
            action='persistent-nfs-overlay', label='nfs_address', key='nfsroot')
        nfs_root = self.get_namespace_data(
            action='download-action', label='file', key='nfsrootfs')

        if nfs_root:
            substitutions = {
                '{NFSROOTFS}': self.get_namespace_data(
                    action='extract-rootfs', label='file', key='nfsroot'),
                '{NFS_SERVER_IP}': ip_addr,
            }
        elif nfs_address:
            substitutions = {
                '{NFSROOTFS}': nfs_address,
                '{NFS_SERVER_IP}': self.get_namespace_data(
                    action='persistent-nfs-overlay', label='nfs_address',
                    key='serverip'),
            }
        else:
            substitutions = {}
        cmdline = substitute([self.cmdline], substitutions)[0]

        with open(cmdline_path, "w") as cmdline_file:
            cmdline_file.write(cmdline)

        # Substitute {CMDLINE} with the cmdline file TFTP path
        kernel_tftp = self.get_namespace_data(
            action='download-action', label='file', key='kernel')
        cmdline_tftp = os.path.join(os.path.dirname(kernel_tftp), 'cmdline')
        fit_tftp = self.get_namespace_data(
            action='prepare-fit', label='file', key='fit')
        substitutions = {
            '{CMDLINE}': cmdline_tftp,
            '{FIT}': fit_tftp,
        }
        commands = self.get_namespace_data(
            action='bootloader-overlay', label=self.method, key='commands')
        commands = substitute(commands, substitutions)
        self.set_namespace_data(
            action='bootloader-overlay', label=self.method, key='commands',
            value=commands)
        self.logger.info("Parsed boot commands: %s", '; '.join(commands))

        return connection
Beispiel #20
0
    def run(self, connection, max_end_time):
        connection = super().run(connection, max_end_time)

        # Create the cmdline file, this is not set by any bootloader command
        ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
        kernel_path = self.get_namespace_data(
            action='download-action', label='kernel', key='file')
        cmdline_path = os.path.join(os.path.dirname(kernel_path), 'cmdline')
        nfs_address = self.get_namespace_data(
            action='persistent-nfs-overlay', label='nfs_address', key='nfsroot')
        nfs_root = self.get_namespace_data(
            action='download-action', label='file', key='nfsrootfs')

        if nfs_root:
            substitutions = {
                '{NFSROOTFS}': self.get_namespace_data(
                    action='extract-rootfs', label='file', key='nfsroot'),
                '{NFS_SERVER_IP}': ip_addr,
            }
        elif nfs_address:
            substitutions = {
                '{NFSROOTFS}': nfs_address,
                '{NFS_SERVER_IP}': self.get_namespace_data(
                    action='persistent-nfs-overlay', label='nfs_address',
                    key='serverip'),
            }
        else:
            substitutions = {}
        cmdline = substitute([self.cmdline], substitutions)[0]

        with open(cmdline_path, "w") as cmdline_file:
            cmdline_file.write(cmdline)

        # Substitute {CMDLINE} with the cmdline file TFTP path
        kernel_tftp = self.get_namespace_data(
            action='download-action', label='file', key='kernel')
        cmdline_tftp = os.path.join(os.path.dirname(kernel_tftp), 'cmdline')
        fit_tftp = self.get_namespace_data(
            action='prepare-fit', label='file', key='fit')
        substitutions = {
            '{CMDLINE}': cmdline_tftp,
            '{FIT}': fit_tftp,
        }
        commands = self.get_namespace_data(
            action='bootloader-overlay', label=self.method, key='commands')
        commands = substitute(commands, substitutions)
        self.set_namespace_data(
            action='bootloader-overlay', label=self.method, key='commands',
            value=commands)
        self.logger.info("Parsed boot commands: %s", '; '.join(commands))

        return connection
Beispiel #21
0
 def run(self, connection, max_end_time, args=None):
     connection = super(UefiSubstituteCommands,
                        self).run(connection, max_end_time, args)
     ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
     substitution_dictionary = {
         '{SERVER_IP}':
         ip_addr,
         '{RAMDISK}':
         self.get_namespace_data(action='compress-ramdisk',
                                 label='file',
                                 key='ramdisk'),
         '{KERNEL}':
         self.get_namespace_data(action='download-action',
                                 label='file',
                                 key='kernel'),
         '{DTB}':
         self.get_namespace_data(action='download-action',
                                 label='file',
                                 key='dtb'),
         'TEST_MENU_NAME':
         "LAVA %s test image" % self.parameters['commands']
     }
     nfs_address = self.get_namespace_data(action='persistent-nfs-overlay',
                                           label='nfs_address',
                                           key='nfsroot')
     nfs_root = self.get_namespace_data(action='download-action',
                                        label='file',
                                        key='nfsrootfs')
     if nfs_root:
         substitution_dictionary['{NFSROOTFS}'] = self.get_namespace_data(
             action='extract-rootfs', label='file', key='nfsroot')
         substitution_dictionary['{NFS_SERVER_IP}'] = ip_addr
     elif nfs_address:
         substitution_dictionary['{NFSROOTFS}'] = nfs_address
         substitution_dictionary[
             '{NFS_SERVER_IP}'] = self.get_namespace_data(
                 action='persistent-nfs-overlay',
                 label='nfs_address',
                 key='serverip')
     for item in self.items:
         if 'enter' in item['select']:
             item['select']['enter'] = substitute(
                 [item['select']['enter']], substitution_dictionary)[0]
         if 'items' in item['select']:
             # items is already a list, so pass without wrapping in []
             item['select']['items'] = substitute(item['select']['items'],
                                                  substitution_dictionary)
     return connection
Beispiel #22
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            'device_type': 'x86',
            'job_name': 'ipxe-pipeline',
            'job_timeout': '15m',
            'action_timeout': '5m',
            'priority': 'medium',
            'actions': {
                'boot': {
                    'method': 'ipxe',
                    'commands': 'ramdisk',
                    'prompts': ['linaro-test', 'root@debian:~#']
                },
                'deploy': {
                    'ramdisk': 'initrd.gz',
                    'kernel': 'zImage',
                }
            }
        }
        device = NewDevice(os.path.join(os.path.dirname(__file__), '../devices/x86-01.yaml'))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters['actions']['boot'])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        kernel = parameters['actions']['deploy']['kernel']
        ramdisk = parameters['actions']['deploy']['ramdisk']

        substitution_dictionary = {
            '{SERVER_IP}': ip_addr,
            '{RAMDISK}': ramdisk,
            '{KERNEL}': kernel,
            '{LAVA_MAC}': "00:00:00:00:00:00"
        }
        params = device['actions']['boot']['methods']
        params['ipxe']['ramdisk']['commands'] = substitute(params['ipxe']['ramdisk']['commands'], substitution_dictionary)

        commands = params['ipxe']['ramdisk']['commands']
        self.assertIs(type(commands), list)
        self.assertIn("dhcp net0", commands)
        self.assertIn("set console console=ttyS0,115200n8 lava_mac=00:00:00:00:00:00", commands)
        self.assertIn("set extraargs init=/sbin/init ip=dhcp", commands)
        self.assertNotIn("kernel tftp://{SERVER_IP}/{KERNEL} ${extraargs} ${console}", commands)
        self.assertNotIn("initrd tftp://{SERVER_IP}/{RAMDISK}", commands)
        self.assertIn("boot", commands)
Beispiel #23
0
 def run(self, connection, max_end_time, args=None):
     if 'deployment_data' not in self.parameters:
         return connection
     if self.parameters["deployment_data"].get('installer_extra_cmd', None):
         if self.parameters.get('os', None) == "debian_installer":
             add_late_command(self.get_namespace_data(action='download-action', label='preseed', key='file'),
                              self.parameters["deployment_data"]["installer_extra_cmd"])
         if self.parameters.get('os', None) == "centos_installer":
             ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
             overlay = self.get_namespace_data(
                 action='download-action', label='file', key='overlay')
             substitutions = {
                 '{OVERLAY_URL}': 'tftp://' + ip_addr + '/' + overlay
             }
             post_command = substitute([self.parameters["deployment_data"]["installer_extra_cmd"]], substitutions)
             add_to_kickstart(self.get_namespace_data(action='download-action', label='preseed', key='file'), post_command[0])
     return connection
Beispiel #24
0
    def validate(self):
        super().validate()
        self.scripts_to_copy = sorted(
            glob.glob(os.path.join(self.lava_test_dir, "lava-*")))

        lava_test_results_dir = self.get_constant("lava_test_results_dir",
                                                  "posix")
        lava_test_results_dir = lava_test_results_dir % self.job.job_id
        self.set_namespace_data(
            action="test",
            label="results",
            key="lava_test_results_dir",
            value=lava_test_results_dir,
        )
        lava_test_sh_cmd = self.get_constant("lava_test_sh_cmd", "posix")
        self.set_namespace_data(
            action="test",
            label="shared",
            key="lava_test_sh_cmd",
            value=lava_test_sh_cmd,
        )

        # Add distro support scripts - only if deployment_data is set
        distro = self.parameters.get("deployment_data", {}).get("distro")
        if distro:
            distro_support_dir = "%s/distro/%s" % (self.lava_test_dir, distro)
            self.scripts_to_copy += sorted(
                glob.glob(os.path.join(distro_support_dir, "lava-*")))

        if not self.scripts_to_copy:
            self.logger.debug("Skipping lava_test_shell support scripts.")
        if "parameters" in self.job.device:
            if "interfaces" in self.job.device["parameters"]:
                if "target" in self.job.device["parameters"]["interfaces"]:
                    self.target_mac = self.job.device["parameters"][
                        "interfaces"]["target"].get("mac", "")
                    self.target_ip = self.job.device["parameters"][
                        "interfaces"]["target"].get("ip", "")
        for device in self.job.device.get("static_info", []):
            if "probe_channel" in device and "probe_ip" in device:
                self.probe_channel = device["probe_channel"]
                self.probe_ip = device["probe_ip"]
                break

        self.dispatcher_ip = dispatcher_ip(self.job.parameters["dispatcher"])
Beispiel #25
0
 def run(self, connection, max_end_time, args=None):
     connection = super(OverlayUnpack, self).run(connection, max_end_time, args)
     if not connection:
         raise LAVABug("Cannot transfer overlay, no connection available.")
     ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
     overlay_full_path = self.get_namespace_data(action='compress-overlay', label='output', key='file')
     if not overlay_full_path:
         raise JobError("No overlay file identified for the transfer.")
     if not overlay_full_path.startswith(DISPATCHER_DOWNLOAD_DIR):
         raise ConfigurationError("overlay should already be in DISPATCHER_DOWNLOAD_DIR")
     overlay_path = overlay_full_path[len(DISPATCHER_DOWNLOAD_DIR) + 1:]
     overlay = os.path.basename(overlay_path)
     dwnld = self.parameters['transfer_overlay']['download_command']
     dwnld += " http://%s/tmp/%s" % (ip_addr, overlay_path)
     unpack = self.parameters['transfer_overlay']['unpack_command']
     unpack += ' ' + overlay
     connection.sendline("rm %s; %s && %s" % (overlay, dwnld, unpack))
     return connection
Beispiel #26
0
 def run(self, connection, max_end_time, args=None):
     connection = super(OverlayUnpack, self).run(connection, max_end_time, args)
     if not connection:
         raise LAVABug("Cannot transfer overlay, no connection available.")
     ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
     overlay_full_path = self.get_namespace_data(action='compress-overlay', label='output', key='file')
     if not overlay_full_path:
         raise JobError("No overlay file identified for the transfer.")
     if not overlay_full_path.startswith(DISPATCHER_DOWNLOAD_DIR):
         raise ConfigurationError("overlay should already be in DISPATCHER_DOWNLOAD_DIR")
     overlay_path = overlay_full_path[len(DISPATCHER_DOWNLOAD_DIR) + 1:]
     overlay = os.path.basename(overlay_path)
     dwnld = self.parameters['transfer_overlay']['download_command']
     dwnld += " http://%s/tmp/%s" % (ip_addr, overlay_path)
     unpack = self.parameters['transfer_overlay']['unpack_command']
     unpack += ' ' + overlay
     connection.sendline("rm %s; %s && %s" % (overlay, dwnld, unpack))
     return connection
Beispiel #27
0
    def run(self, connection, max_end_time):
        location = self.get_namespace_data(action="test",
                                           label="shared",
                                           key="location")
        docker_image = self.get_namespace_data(action="deploy-docker",
                                               label="image",
                                               key="name")

        # Build the command line
        # The docker image is safe to be included in the command line
        cmd = "docker" + self.remote + " run --rm --interactive --tty --hostname lava"
        cmd += " --name %s" % self.container
        if self.test_needs_overlay(self.parameters):
            overlay = self.get_namespace_data(action="test",
                                              label="results",
                                              key="lava_test_results_dir")
            if not self.remote:
                cmd += " --volume %s:%s" % (
                    os.path.join(location, overlay.strip("/")),
                    overlay,
                )
            else:
                cmd += (
                    ' --mount type=volume,volume-driver=local,dst=%s,volume-opt=type=nfs,volume-opt=device=:%s,"volume-opt=o=addr=%s"'
                    % (
                        overlay,
                        os.path.join(location, overlay.strip("/")),
                        dispatcher_ip(self.job.parameters["dispatcher"]),
                    ))
        cmd += self.extra_options
        cmd += " %s %s" % (docker_image, self.parameters["command"])

        self.logger.debug("Boot command: %s", cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)
        self.cleanup_required = True

        shell_connection = ShellSession(self.job, shell)
        shell_connection = super().run(shell_connection, max_end_time)

        self.set_namespace_data(action="shared",
                                label="shared",
                                key="connection",
                                value=shell_connection)
        return shell_connection
Beispiel #28
0
    def validate(self):
        super().validate()
        self.command = self.parameters.get("command", "/sbin/kexec")
        self.load_command = self.command[:]  # local copy for idempotency

        if self.parameters.get("deploy", False):
            initrd_path = self.get_namespace_data(action="download-action",
                                                  label="initrd",
                                                  key="file")
            ip_addr = dispatcher_ip(self.job.parameters["dispatcher"], "http")

            self.append_deploy_cmd("kernel", ip_addr)
            self.append_deploy_cmd("initrd", ip_addr)
            self.append_deploy_cmd("dtb", ip_addr)
            self.logger.debug("deploy commands:")
            for cmd in self.deploy_commands:
                self.logger.info("- %s", cmd)

        # If on_panic is set, crash the kernel instead of calling "kexec -e"
        if self.parameters.get("on_panic", False):
            self.command = "echo c > /proc/sysrq-trigger"
        else:
            self.command += " -e"

        # If on_panic is set, use --load-panic instead of --load
        if "kernel" in self.parameters:
            if self.parameters.get("on_panic", False):
                self.load_command += " --load-panic %s" % self.parameters[
                    "kernel"]
            else:
                self.load_command += " --load %s" % self.parameters["kernel"]

        if "dtb" in self.parameters:
            self.load_command += " --dtb %s" % self.parameters["dtb"]
        if "initrd" in self.parameters:
            self.load_command += " --initrd %s" % self.parameters["initrd"]
        if "options" in self.parameters:
            for option in self.parameters["options"]:
                self.load_command += " %s" % option
        if self.load_command == "/sbin/kexec":
            self.errors = "Default kexec handler needs at least a kernel to pass to the --load command"
Beispiel #29
0
    def validate(self):
        super().validate()
        boot = self.job.device["actions"]["boot"]["methods"]["qemu"]
        qemu_binary = which(boot["parameters"]["command"])
        self.sub_command = [qemu_binary]
        self.sub_command.extend(boot["parameters"].get("options", []))
        boot_opts = boot["parameters"].get("boot_options")
        if boot_opts:
            self.console = "console=%s" % boot_opts["console"]
            self.boot_order = "-boot %s" % boot_opts["boot_order"]
        if not qemu_binary or not self.console or not self.boot_order:
            self.errors = "Invalid parameters for %s" % self.name
        # create the preseed.cfg url
        # needs to be an IP address for DI, DNS is not available.
        # PRESEED_URL='http://10.15.0.32/tmp/d-i/jessie/preseed.cfg'
        ip_addr = dispatcher_ip(self.job.parameters["dispatcher"], "tftp")
        self.preseed_url = "tftp://%s/" % ip_addr

        self.sub_command.append(" -drive format=raw,file={emptyimage} ")
        self.sub_command.append(self.boot_order)
        self.command_line = (
            " -append '%s console=tty0 console=tty1 %s %s %s %s preseed/url=%s{preseed} --- %s '  "
            % (
                self.parameters["deployment_data"]["base"],
                self.parameters["deployment_data"]["locale"],
                self.console,
                self.parameters["deployment_data"]["keymaps"],
                self.parameters["deployment_data"]["netcfg"],
                self.preseed_url,
                self.console,
            ))
        self.set_namespace_data(
            action=self.name,
            label=self.name,
            key="prompts",
            value=self.parameters["deployment_data"]["prompts"],
        )
        self.set_namespace_data(action=self.name,
                                label=self.name,
                                key="append",
                                value=self.command_line)
Beispiel #30
0
 def set_port(self, action):
     msg = {'data': {'nbd_server_port': 10809}}
     nbd_port = self.parameters['protocols']['lava-xnbd']['port']
     if nbd_port == 'auto':
         self.logger.debug("Get a port from pool")
         nbd_port = get_free_port(self.parameters['dispatcher'])
     self.ports.append(nbd_port)
     msg['data']['nbd_server_port'] = nbd_port
     action.set_namespace_data('nbd-deploy',
                               label='nbd',
                               key='nbd_server_port',
                               value=nbd_port,
                               parameters=action.parameters)
     nbd_ip = dispatcher_ip(self.parameters['dispatcher'])
     action.set_namespace_data('nbd-deploy',
                               label='nbd',
                               key='nbd_server_ip',
                               value=nbd_ip,
                               parameters=action.parameters)
     self.logger.debug("Set_port %d", nbd_port)
     return msg['data']
Beispiel #31
0
    def get_manipulated_command(self, cmd):
        if self.driver.is_container and self.driver.docker_options:
            ip_addr = dispatcher_ip(self.job.parameters["dispatcher"])
            root_location = self.get_namespace_data(action="uuu-deploy",
                                                    label="uuu-images",
                                                    key="root_location")
            cmd = [
                "mkdir",
                "-p",
                root_location,
                "&&",
                "mount",
                "-t",
                "nfs",
                "-o",
                "nolock",
                ip_addr + ":" + root_location,
                root_location,
                "&&",
            ] + cmd
            cmd = ["bash", "-c", " ".join(cmd)]

        return cmd
Beispiel #32
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            "device_type": "beaglebone-black",
            "job_name": "uboot-pipeline",
            "job_timeout": "15m",
            "action_timeout": "5m",
            "priority": "medium",
            "actions": {
                "boot": {
                    "method": "u-boot",
                    "commands": "ramdisk",
                    "type": "bootz",
                    "prompts": ["linaro-test", "root@debian:~#"],
                },
                "deploy": {
                    "ramdisk": "initrd.gz",
                    "kernel": "zImage",
                    "dtb": "broken.dtb",
                },
            },
        }
        device = NewDevice(
            os.path.join(os.path.dirname(__file__), "devices/bbb-01.yaml"))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters["actions"]["boot"])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel_addr = job.device["parameters"][
            overlay.parameters["type"]]["ramdisk"]
        ramdisk_addr = job.device["parameters"][
            overlay.parameters["type"]]["ramdisk"]
        dtb_addr = job.device["parameters"][overlay.parameters["type"]]["dtb"]
        kernel = parameters["actions"]["deploy"]["kernel"]
        ramdisk = parameters["actions"]["deploy"]["ramdisk"]
        dtb = parameters["actions"]["deploy"]["dtb"]

        substitution_dictionary = {
            "{SERVER_IP}":
            ip_addr,
            # the addresses need to be hexadecimal
            "{KERNEL_ADDR}":
            kernel_addr,
            "{DTB_ADDR}":
            dtb_addr,
            "{RAMDISK_ADDR}":
            ramdisk_addr,
            "{BOOTX}":
            "%s %s %s %s" %
            (overlay.parameters["type"], kernel_addr, ramdisk_addr, dtb_addr),
            "{RAMDISK}":
            ramdisk,
            "{KERNEL}":
            kernel,
            "{DTB}":
            dtb,
        }
        params = device["actions"]["boot"]["methods"]
        params["u-boot"]["ramdisk"]["commands"] = substitute(
            params["u-boot"]["ramdisk"]["commands"], substitution_dictionary)

        commands = params["u-boot"]["ramdisk"]["commands"]
        self.assertIs(type(commands), list)
        self.assertIn("setenv loadkernel 'tftp ${kernel_addr_r} zImage'",
                      commands)
        self.assertIn(
            "setenv loadinitrd 'tftp ${initrd_addr_r} initrd.gz; setenv initrd_size ${filesize}'",
            commands,
        )
        self.assertIn("setenv loadfdt 'tftp ${fdt_addr_r} broken.dtb'",
                      commands)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", commands)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", commands)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", commands)

        for line in params["u-boot"]["ramdisk"]["commands"]:
            line = line.replace("{SERVER_IP}", ip_addr)
            # the addresses need to be hexadecimal
            line = line.replace("{KERNEL_ADDR}", kernel_addr)
            line = line.replace("{DTB_ADDR}", dtb_addr)
            line = line.replace("{RAMDISK_ADDR}", ramdisk_addr)
            line = line.replace(
                "{BOOTX}",
                "%s %s %s %s" % (overlay.parameters["type"], kernel_addr,
                                 ramdisk_addr, dtb_addr),
            )
            line = line.replace("{RAMDISK}", ramdisk)
            line = line.replace("{KERNEL}", kernel)
            line = line.replace("{DTB}", dtb)
            parsed.append(line)
        self.assertIn("setenv loadkernel 'tftp ${kernel_addr_r} zImage'",
                      parsed)
        self.assertIn(
            "setenv loadinitrd 'tftp ${initrd_addr_r} initrd.gz; setenv initrd_size ${filesize}'",
            parsed,
        )
        self.assertIn("setenv loadfdt 'tftp ${fdt_addr_r} broken.dtb'", parsed)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", parsed)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", parsed)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", parsed)
Beispiel #33
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            'device_type': 'beaglebone-black',
            'job_name': 'uboot-pipeline',
            'job_timeout': '15m',
            'action_timeout': '5m',
            'priority': 'medium',
            'actions': {
                'boot': {
                    'method': 'u-boot',
                    'commands': 'ramdisk',
                    'type': 'bootz',
                    'prompts': ['linaro-test', 'root@debian:~#']
                },
                'deploy': {
                    'ramdisk': 'initrd.gz',
                    'kernel': 'zImage',
                    'dtb': 'broken.dtb'
                }
            }
        }
        device = NewDevice(
            os.path.join(os.path.dirname(__file__), '../devices/bbb-01.yaml'))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters['actions']['boot'])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel_addr = job.device['parameters'][
            overlay.parameters['type']]['ramdisk']
        ramdisk_addr = job.device['parameters'][
            overlay.parameters['type']]['ramdisk']
        dtb_addr = job.device['parameters'][overlay.parameters['type']]['dtb']
        kernel = parameters['actions']['deploy']['kernel']
        ramdisk = parameters['actions']['deploy']['ramdisk']
        dtb = parameters['actions']['deploy']['dtb']

        substitution_dictionary = {
            '{SERVER_IP}':
            ip_addr,
            # the addresses need to be hexadecimal
            '{KERNEL_ADDR}':
            kernel_addr,
            '{DTB_ADDR}':
            dtb_addr,
            '{RAMDISK_ADDR}':
            ramdisk_addr,
            '{BOOTX}':
            "%s %s %s %s" %
            (overlay.parameters['type'], kernel_addr, ramdisk_addr, dtb_addr),
            '{RAMDISK}':
            ramdisk,
            '{KERNEL}':
            kernel,
            '{DTB}':
            dtb
        }
        params = device['actions']['boot']['methods']
        params['u-boot']['ramdisk']['commands'] = substitute(
            params['u-boot']['ramdisk']['commands'], substitution_dictionary)

        commands = params['u-boot']['ramdisk']['commands']
        self.assertIs(type(commands), list)
        self.assertIn("setenv loadkernel 'tftp ${kernel_addr_r} zImage'",
                      commands)
        self.assertIn(
            "setenv loadinitrd 'tftp ${initrd_addr_r} initrd.gz; setenv initrd_size ${filesize}'",
            commands)
        self.assertIn("setenv loadfdt 'tftp ${fdt_addr_r} broken.dtb'",
                      commands)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", commands)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", commands)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", commands)

        for line in params['u-boot']['ramdisk']['commands']:
            line = line.replace('{SERVER_IP}', ip_addr)
            # the addresses need to be hexadecimal
            line = line.replace('{KERNEL_ADDR}', kernel_addr)
            line = line.replace('{DTB_ADDR}', dtb_addr)
            line = line.replace('{RAMDISK_ADDR}', ramdisk_addr)
            line = line.replace(
                '{BOOTX}',
                "%s %s %s %s" % (overlay.parameters['type'], kernel_addr,
                                 ramdisk_addr, dtb_addr))
            line = line.replace('{RAMDISK}', ramdisk)
            line = line.replace('{KERNEL}', kernel)
            line = line.replace('{DTB}', dtb)
            parsed.append(line)
        self.assertIn("setenv loadkernel 'tftp ${kernel_addr_r} zImage'",
                      parsed)
        self.assertIn(
            "setenv loadinitrd 'tftp ${initrd_addr_r} initrd.gz; setenv initrd_size ${filesize}'",
            parsed)
        self.assertIn("setenv loadfdt 'tftp ${fdt_addr_r} broken.dtb'", parsed)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", parsed)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", parsed)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", parsed)
Beispiel #34
0
    def run(self, connection, max_end_time, args=None):
        """
        Read data from the download action and replace in context
        Use common data for all values passed into the substitutions so that
        multiple actions can use the same code.
        """
        # Multiple deployments would overwrite the value if parsed in the validate step.
        # FIXME: implement isolation for repeated steps.
        connection = super(BootloaderCommandOverlay, self).run(connection, max_end_time, args)
        ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])

        self.ram_disk = self.get_namespace_data(action='compress-ramdisk', label='file', key='ramdisk')
        # most jobs substitute RAMDISK, so also use this for the initrd
        if self.get_namespace_data(action='nbd-deploy', label='nbd', key='initrd'):
            self.ram_disk = self.get_namespace_data(action='download-action', label='file', key='initrd')

        substitutions = {
            '{SERVER_IP}': ip_addr,
            '{PRESEED_CONFIG}': self.get_namespace_data(action='download-action', label='file', key='preseed'),
            '{PRESEED_LOCAL}': self.get_namespace_data(action='compress-ramdisk', label='file', key='preseed_local'),
            '{DTB}': self.get_namespace_data(action='download-action', label='file', key='dtb'),
            '{RAMDISK}': self.ram_disk,
            '{INITRD}': self.ram_disk,
            '{KERNEL}': self.get_namespace_data(action='download-action', label='file', key='kernel'),
            '{LAVA_MAC}': self.lava_mac
        }
        self.bootcommand = self.get_namespace_data(action='uboot-prepare-kernel', label='bootcommand', key='bootcommand')
        if not self.bootcommand:
            if 'type' in self.parameters:
                self.logger.warning("Using type from the boot action as the boot-command. "
                                    "Declaring a kernel type in the deploy is preferred.")
                self.bootcommand = self.parameters['type']
        prepared_kernel = self.get_namespace_data(action='prepare-kernel', label='file', key='kernel')
        if prepared_kernel:
            self.logger.info("Using kernel file from prepare-kernel: %s", prepared_kernel)
            substitutions['{KERNEL}'] = prepared_kernel
        if self.bootcommand:
            self.logger.debug("%s", self.job.device['parameters'])
            kernel_addr = self.job.device['parameters'][self.bootcommand]['kernel']
            dtb_addr = self.job.device['parameters'][self.bootcommand]['dtb']
            ramdisk_addr = self.job.device['parameters'][self.bootcommand]['ramdisk']

            if not self.get_namespace_data(action='tftp-deploy', label='tftp', key='ramdisk') \
                    and not self.get_namespace_data(action='download-action', label='file', key='ramdisk') \
                    and not self.get_namespace_data(action='download-action', label='file', key='initrd'):
                ramdisk_addr = '-'
            add_header = self.job.device['actions']['deploy']['parameters'].get('add_header', None)
            if self.method == 'u-boot' and not add_header == "u-boot":
                self.logger.debug("No u-boot header, not passing ramdisk to bootX cmd")
                ramdisk_addr = '-'

            if self.get_namespace_data(action='download-action', label='file', key='initrd'):
                # no u-boot header, thus no embedded size, so we have to add it to the
                # boot cmd with colon after the ramdisk
                substitutions['{BOOTX}'] = "%s %s %s:%s %s" % (
                    self.bootcommand, kernel_addr, ramdisk_addr, '${initrd_size}', dtb_addr)
            else:
                substitutions['{BOOTX}'] = "%s %s %s %s" % (
                    self.bootcommand, kernel_addr, ramdisk_addr, dtb_addr)

            substitutions['{KERNEL_ADDR}'] = kernel_addr
            substitutions['{DTB_ADDR}'] = dtb_addr
            substitutions['{RAMDISK_ADDR}'] = ramdisk_addr
            self.results = {
                'kernel_addr': kernel_addr,
                'dtb_addr': dtb_addr,
                'ramdisk_addr': ramdisk_addr
            }

        nfs_address = self.get_namespace_data(action='persistent-nfs-overlay', label='nfs_address', key='nfsroot')
        nfs_root = self.get_namespace_data(action='download-action', label='file', key='nfsrootfs')
        if nfs_root:
            substitutions['{NFSROOTFS}'] = self.get_namespace_data(action='extract-rootfs', label='file', key='nfsroot')
            substitutions['{NFS_SERVER_IP}'] = ip_addr
        elif nfs_address:
            substitutions['{NFSROOTFS}'] = nfs_address
            substitutions['{NFS_SERVER_IP}'] = self.get_namespace_data(
                action='persistent-nfs-overlay', label='nfs_address', key='serverip')

        nbd_root = self.get_namespace_data(action='download-action', label='file', key='nbdroot')
        if nbd_root:
            substitutions['{NBDSERVERIP}'] = str(self.get_namespace_data(action='nbd-deploy', label='nbd', key='nbd_server_ip'))
            substitutions['{NBDSERVERPORT}'] = str(self.get_namespace_data(action='nbd-deploy', label='nbd', key='nbd_server_port'))

        substitutions['{ROOT}'] = self.get_namespace_data(action='bootloader-from-media', label='uuid', key='root')  # UUID label, not a file
        substitutions['{ROOT_PART}'] = self.get_namespace_data(action='bootloader-from-media', label='uuid', key='boot_part')
        if self.use_bootscript:
            script = "/script.ipxe"
            bootscript = self.get_namespace_data(action='tftp-deploy', label='tftp', key='tftp_dir') + script
            bootscripturi = "tftp://%s/%s" % (ip_addr, os.path.dirname(substitutions['{KERNEL}']) + script)
            write_bootscript(substitute(self.commands, substitutions), bootscript)
            bootscript_commands = ['dhcp net0', "chain %s" % bootscripturi]
            self.set_namespace_data(action=self.name, label=self.method, key='commands', value=bootscript_commands)
            self.logger.info("Parsed boot commands: %s", '; '.join(bootscript_commands))
            return connection
        subs = substitute(self.commands, substitutions)
        self.set_namespace_data(action='bootloader-overlay', label=self.method, key='commands', value=subs)
        self.logger.info("Parsed boot commands: %s", '; '.join(subs))
        return connection
Beispiel #35
0
    def run(self, connection, max_end_time, args=None):  # pylint: disable=too-many-locals
        """
        Retrieve the decompressed image from the dispatcher by calling the tool specified
        by the test writer, from within the test image of the first deployment, using the
        device to write directly to the secondary media, without needing to cache on the device.
        """
        connection = super(DDAction, self).run(connection, max_end_time, args)
        d_file = self.get_namespace_data(action='download-action', label='image', key='file')
        if not d_file:
            self.logger.debug("Skipping %s - nothing downloaded")
            return connection
        decompressed_image = os.path.basename(d_file)
        try:
            device_path = os.path.realpath(
                "/dev/disk/by-id/%s" %
                self.boot_params[self.parameters['device']]['uuid'])
        except OSError:
            raise JobError("Unable to find disk by id %s" %
                           self.boot_params[self.parameters['device']]['uuid'])
        storage_suffix = self.get_namespace_data(action='storage-deploy', label='storage', key='suffix')
        if not storage_suffix:
            storage_suffix = ''
        suffix = "%s/%s" % ("tmp", storage_suffix)

        # As the test writer can use any tool we cannot predict where the
        # download URL will be positioned in the download command.
        # Providing the download URL as a substitution option gets round this
        ip_addr = dispatcher_ip(self.job.parameters['dispatcher'])
        download_url = "http://%s/%s/%s" % (
            ip_addr, suffix, decompressed_image
        )
        substitutions = {
            '{DOWNLOAD_URL}': download_url,
            '{DEVICE}': device_path
        }

        download_cmd = None
        download_params = self.parameters.get('download')
        if download_params:
            download_options = substitute([download_params['options']], substitutions)[0]
            download_cmd = ' '.join([download_params['tool'], download_options])

        writer_params = self.parameters.get('writer')
        if writer_params:
            tool_options = substitute([writer_params['options']], substitutions)[0]
            tool_cmd = [writer_params['tool'], tool_options]
        else:
            tool_cmd = ["dd of='{}' bs=4M".format(device_path)]  # busybox dd does not support other flags
        if self.tool_flags:
            tool_cmd.append(self.tool_flags)
        cmd = ' '.join(tool_cmd)

        cmd_line = ' '.join([download_cmd, '|', cmd]) if download_cmd else cmd

        # set prompt to either `download' or `writer' prompt to ensure that the
        # secondary deployment has started
        prompt_string = connection.prompt_str
        prompt_param = download_params or writer_params
        connection.prompt_str = prompt_param['prompt']
        self.logger.debug("Changing prompt to %s", connection.prompt_str)

        connection.sendline(cmd_line)
        self.wait(connection)
        if not self.valid:
            self.logger.error(self.errors)

        # change prompt string to list of dd outputs
        connection.prompt_str = self.tool_prompts
        self.logger.debug("Changing prompt to %s", connection.prompt_str)
        self.wait(connection)

        # set prompt back once secondary deployment is complete
        connection.prompt_str = prompt_string
        self.logger.debug("Changing prompt to %s", connection.prompt_str)
        self.set_namespace_data(action='shared', label='shared', key='connection', value=connection)
        return connection
Beispiel #36
0
    def validate(self):
        super(CallQemuAction, self).validate()

        # 'arch' must be defined in job definition context.
        try:
            if self.job.parameters['context']['arch'] not in \
               self.job.device['available_architectures']:
                self.errors = "Non existing architecture specified in context arch parameter. Please check the device configuration for available options."
                return
        except KeyError:
            self.errors = "Arch parameter must be set in the context section. Please check the device configuration for available architectures."
            return
        if self.job.parameters['context']['arch'] in ['amd64', 'x86_64']:
            self.logger.info("qemu-system-x86, installed at version: %s",
                             debian_package_version(pkg='qemu-system-x86', split=False))
        if self.job.parameters['context']['arch'] in ['arm64', 'arm', 'armhf', 'aarch64']:
            self.logger.info("qemu-system-arm, installed at version: %s",
                             debian_package_version(pkg='qemu-system-arm', split=False))

        if self.parameters['method'] in ['qemu', 'qemu-nfs']:
            if 'prompts' not in self.parameters:
                if self.test_has_shell(self.parameters):
                    self.errors = "Unable to identify boot prompts from job definition."
        self.methods = self.job.device['actions']['boot']['methods']
        method = self.parameters['method']
        boot = self.methods['qemu'] if 'qemu' in self.methods else self.methods['qemu-nfs']
        try:
            if 'parameters' not in boot or 'command' not in boot['parameters']:
                self.errors = "Invalid device configuration - missing parameters"
            elif not boot['parameters']['command']:
                self.errors = "No QEMU binary command found - missing context."
            qemu_binary = which(boot['parameters']['command'])
            self.sub_command = [qemu_binary]
            self.sub_command.extend(boot['parameters'].get('options', []))
            self.sub_command.extend(
                ['%s' % item for item in boot['parameters'].get('extra', [])])
        except AttributeError as exc:
            self.errors = "Unable to parse device options: %s %s" % (
                exc, self.job.device['actions']['boot']['methods'][method])
        except (KeyError, TypeError):
            self.errors = "Invalid parameters for %s" % self.name
        namespace = self.parameters['namespace']
        for label in self.data[namespace]['download-action'].keys():
            if label in ['offset', 'available_loops', 'uefi', 'nfsrootfs']:
                continue
            image_arg = self.get_namespace_data(action='download-action', label=label, key='image_arg')
            action_arg = self.get_namespace_data(action='download-action', label=label, key='file')
            if not image_arg or not action_arg:
                self.errors = "Missing image_arg for %s. " % label
                continue
            self.substitutions["{%s}" % label] = action_arg
            self.commands.append(image_arg)
        self.substitutions["{NFS_SERVER_IP}"] = dispatcher_ip(self.job.parameters['dispatcher'])
        self.sub_command.extend(substitute(self.commands, self.substitutions))
        if not self.sub_command:
            self.errors = "No QEMU command to execute"
        uefi_dir = self.get_namespace_data(action='deployimages', label='image', key='uefi_dir')
        if uefi_dir:
            self.sub_command.extend(['-L', uefi_dir, '-monitor', 'none'])

        # Check for enable-kvm command line option in device configuration.
        if method not in self.job.device['actions']['boot']['methods']:
            self.errors = "Unknown boot method '%s'" % method
            return

        options = self.job.device['actions']['boot']['methods'][method]['parameters']['options']
        if "-enable-kvm" in options:
            # Check if the worker has kvm enabled.
            if not os.path.exists(SYS_CLASS_KVM):
                self.errors = "Device configuration contains -enable-kvm option but kvm module is not enabled."
Beispiel #37
0
    def test_overlay_action(self):  # pylint: disable=too-many-locals
        parameters = {
            'device_type': 'beaglebone-black',
            'job_name': 'uboot-pipeline',
            'job_timeout': '15m',
            'action_timeout': '5m',
            'priority': 'medium',
            'actions': {
                'boot': {
                    'method': 'u-boot',
                    'commands': 'ramdisk',
                    'type': 'bootz',
                    'prompts': ['linaro-test', 'root@debian:~#']
                },
                'deploy': {
                    'ramdisk': 'initrd.gz',
                    'kernel': 'zImage',
                    'dtb': 'broken.dtb'
                }
            }
        }
        device = NewDevice(os.path.join(os.path.dirname(__file__), '../devices/bbb-01.yaml'))
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters['actions']['boot'])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        pipeline.add_action(overlay)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel_addr = job.device['parameters'][overlay.parameters['type']]['ramdisk']
        ramdisk_addr = job.device['parameters'][overlay.parameters['type']]['ramdisk']
        dtb_addr = job.device['parameters'][overlay.parameters['type']]['dtb']
        kernel = parameters['actions']['deploy']['kernel']
        ramdisk = parameters['actions']['deploy']['ramdisk']
        dtb = parameters['actions']['deploy']['dtb']

        substitution_dictionary = {
            '{SERVER_IP}': ip_addr,
            # the addresses need to be hexadecimal
            '{KERNEL_ADDR}': kernel_addr,
            '{DTB_ADDR}': dtb_addr,
            '{RAMDISK_ADDR}': ramdisk_addr,
            '{BOOTX}': "%s %s %s %s" % (
                overlay.parameters['type'], kernel_addr, ramdisk_addr, dtb_addr),
            '{RAMDISK}': ramdisk,
            '{KERNEL}': kernel,
            '{DTB}': dtb
        }
        params = device['actions']['boot']['methods']
        params['u-boot']['ramdisk']['commands'] = substitute(params['u-boot']['ramdisk']['commands'], substitution_dictionary)

        commands = params['u-boot']['ramdisk']['commands']
        self.assertIs(type(commands), list)
        self.assertIn("setenv loadkernel 'tftp ${kernel_addr_r} zImage'", commands)
        self.assertIn("setenv loadinitrd 'tftp ${initrd_addr_r} initrd.gz; setenv initrd_size ${filesize}'", commands)
        self.assertIn("setenv loadfdt 'tftp ${fdt_addr_r} broken.dtb'", commands)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", commands)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", commands)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", commands)

        for line in params['u-boot']['ramdisk']['commands']:
            line = line.replace('{SERVER_IP}', ip_addr)
            # the addresses need to be hexadecimal
            line = line.replace('{KERNEL_ADDR}', kernel_addr)
            line = line.replace('{DTB_ADDR}', dtb_addr)
            line = line.replace('{RAMDISK_ADDR}', ramdisk_addr)
            line = line.replace('{BOOTX}', "%s %s %s %s" % (
                overlay.parameters['type'], kernel_addr, ramdisk_addr, dtb_addr))
            line = line.replace('{RAMDISK}', ramdisk)
            line = line.replace('{KERNEL}', kernel)
            line = line.replace('{DTB}', dtb)
            parsed.append(line)
        self.assertIn("setenv loadkernel 'tftp ${kernel_addr_r} zImage'", parsed)
        self.assertIn("setenv loadinitrd 'tftp ${initrd_addr_r} initrd.gz; setenv initrd_size ${filesize}'", parsed)
        self.assertIn("setenv loadfdt 'tftp ${fdt_addr_r} broken.dtb'", parsed)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", parsed)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", parsed)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", parsed)
Beispiel #38
0
    def test_overlay_action(self, which_mock):
        parameters = {
            "dispatcher":
            {},  # fake dispatcher parameter. Normally added by parser
            "device_type": "beaglebone-black",
            "job_name": "uboot-pipeline",
            "job_timeout": "15m",
            "action_timeout": "5m",
            "priority": "medium",
            "actions": {
                "boot": {
                    "namespace": "common",
                    "method": "u-boot",
                    "commands": "ramdisk",
                    "prompts": ["linaro-test", "root@debian:~#"],
                },
                "deploy": {
                    "namespace": "common",
                    "ramdisk": {
                        "url": "initrd.gz",
                        "compression": "gz"
                    },
                    "kernel": {
                        "url": "zImage",
                        "type": "zimage"
                    },
                    "dtb": {
                        "url": "broken.dtb"
                    },
                },
            },
        }
        data = yaml_safe_load(Factory().create_device("bbb-01.jinja2")[0])
        device = NewDevice(data)
        job = Job(4212, parameters, None)
        job.device = device
        pipeline = Pipeline(job=job, parameters=parameters["actions"]["boot"])
        job.pipeline = pipeline
        overlay = BootloaderCommandOverlay()
        connection = MagicMock()
        connection.timeout = MagicMock()
        pipeline.add_action(overlay)
        overlay.set_namespace_data(
            action="uboot-prepare-kernel",
            label="bootcommand",
            key="bootcommand",
            value="bootz",
        )
        overlay.validate()
        overlay.run(connection, 100)
        ip_addr = dispatcher_ip(None)
        parsed = []
        kernel_addr = job.device["parameters"][overlay.bootcommand]["ramdisk"]
        ramdisk_addr = job.device["parameters"][overlay.bootcommand]["ramdisk"]
        dtb_addr = job.device["parameters"][overlay.bootcommand]["dtb"]
        kernel = parameters["actions"]["deploy"]["kernel"]["url"]
        ramdisk = parameters["actions"]["deploy"]["ramdisk"]["url"]
        dtb = parameters["actions"]["deploy"]["dtb"]["url"]

        substitution_dictionary = {
            "{SERVER_IP}":
            ip_addr,
            # the addresses need to be hexadecimal
            "{KERNEL_ADDR}":
            kernel_addr,
            "{DTB_ADDR}":
            dtb_addr,
            "{RAMDISK_ADDR}":
            ramdisk_addr,
            "{BOOTX}":
            "%s %s %s %s" %
            (overlay.bootcommand, kernel_addr, ramdisk_addr, dtb_addr),
            "{RAMDISK}":
            ramdisk,
            "{KERNEL}":
            kernel,
            "{DTB}":
            dtb,
        }
        params = device["actions"]["boot"]["methods"]
        params["u-boot"]["ramdisk"]["commands"] = substitute(
            params["u-boot"]["ramdisk"]["commands"], substitution_dictionary)

        commands = params["u-boot"]["ramdisk"]["commands"]
        self.assertIs(type(commands), list)
        self.assertIn("tftp 0x83000000 zImage", commands)
        self.assertIn("tftp 0x83000000 initrd.gz", commands)
        self.assertIn("setenv initrd_size ${filesize}", commands)
        self.assertIn("tftp 0x88000000 broken.dtb", commands)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", commands)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", commands)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", commands)

        for line in params["u-boot"]["ramdisk"]["commands"]:
            line = line.replace("{SERVER_IP}", ip_addr)
            # the addresses need to be hexadecimal
            line = line.replace("{KERNEL_ADDR}", kernel_addr)
            line = line.replace("{DTB_ADDR}", dtb_addr)
            line = line.replace("{RAMDISK_ADDR}", ramdisk_addr)
            line = line.replace(
                "{BOOTX}",
                "%s %s %s %s" %
                (overlay.bootcommand, kernel_addr, ramdisk_addr, dtb_addr),
            )
            line = line.replace("{RAMDISK}", ramdisk)
            line = line.replace("{KERNEL}", kernel)
            line = line.replace("{DTB}", dtb)
            parsed.append(line)
        self.assertNotIn("setenv kernel_addr_r '{KERNEL_ADDR}'", parsed)
        self.assertNotIn("setenv initrd_addr_r '{RAMDISK_ADDR}'", parsed)
        self.assertNotIn("setenv fdt_addr_r '{DTB_ADDR}'", parsed)
Beispiel #39
0
    def run(self, connection, max_end_time):
        """
        Retrieve the decompressed image from the dispatcher by calling the tool specified
        by the test writer, from within the test image of the first deployment, using the
        device to write directly to the secondary media, without needing to cache on the device.
        """
        connection = super().run(connection, max_end_time)
        d_file = self.get_namespace_data(action="download-action",
                                         label="image",
                                         key="file")
        if not d_file:
            self.logger.debug("Skipping %s - nothing downloaded")
            return connection
        decompressed_image = os.path.basename(d_file)
        try:
            device_path = os.path.realpath(
                "/dev/disk/by-id/%s" %
                self.boot_params[self.parameters["device"]]["uuid"])
        except OSError:
            raise JobError("Unable to find disk by id %s" %
                           self.boot_params[self.parameters["device"]]["uuid"])

        # As the test writer can use any tool we cannot predict where the
        # download URL will be positioned in the download command.
        # Providing the download URL as a substitution option gets round this
        ip_addr = dispatcher_ip(self.job.parameters["dispatcher"], "http")
        path = d_file[len(DISPATCHER_DOWNLOAD_DIR) + 1:]
        download_url = "http://%s/tmp/%s" % (ip_addr, path)
        substitutions = {
            "{DOWNLOAD_URL}": download_url,
            "{DEVICE}": device_path
        }

        download_cmd = None
        download_params = self.parameters.get("download")
        if download_params:
            download_options = substitute([download_params["options"]],
                                          substitutions)[0]
            download_cmd = " ".join(
                [download_params["tool"], download_options])

        writer_params = self.parameters.get("writer")
        if writer_params:
            tool_options = substitute([writer_params["options"]],
                                      substitutions)[0]
            tool_cmd = [writer_params["tool"], tool_options]
        else:
            tool_cmd = ["dd of='{}' bs=4M".format(device_path)
                        ]  # busybox dd does not support other flags
        if self.tool_flags:
            tool_cmd.append(self.tool_flags)
        cmd = " ".join(tool_cmd)

        cmd_line = " ".join([download_cmd, "|", cmd]) if download_cmd else cmd

        # set prompt to either `download' or `writer' prompt to ensure that the
        # secondary deployment has started
        prompt_string = connection.prompt_str
        prompt_param = download_params or writer_params
        connection.prompt_str = prompt_param["prompt"]
        self.logger.debug("Changing prompt to %s", connection.prompt_str)

        connection.sendline(cmd_line)
        self.wait(connection)
        if not self.valid:
            self.logger.error(self.errors)

        # change prompt string to list of dd outputs
        connection.prompt_str = self.tool_prompts
        self.logger.debug("Changing prompt to %s", connection.prompt_str)
        self.wait(connection)

        # set prompt back once secondary deployment is complete
        connection.prompt_str = prompt_string
        self.logger.debug("Changing prompt to %s", connection.prompt_str)
        self.set_namespace_data(action="shared",
                                label="shared",
                                key="connection",
                                value=connection)
        return connection
Beispiel #40
0
    def validate(self):
        super().validate()

        # 'arch' must be defined in job definition context.
        architecture = self.job.parameters["context"]["arch"]
        if "available_architectures" not in self.job.device:
            self.errors = "Device lacks list of available architectures."
        try:
            if architecture not in self.job.device["available_architectures"]:
                self.errors = "Non existing architecture specified in context arch parameter. Please check the device configuration for available options."
                return
        except KeyError:
            self.errors = "Arch parameter must be set in the context section. Please check the device configuration for available architectures."
            return
        if architecture in ["amd64", "x86_64"]:
            ver_str = debian_package_version(pkg="qemu-system-x86",
                                             split=False)
            arch_str = debian_package_arch(pkg="qemu-system-x86")
            self.qemu_data = {
                "qemu_version": ver_str,
                "host_arch": arch_str,
                "job_arch": architecture,
            }
            self.logger.info(
                "qemu-system-x86, installed at version: %s, host architecture: %s",
                ver_str,
                arch_str,
            )
        if architecture in ["arm64", "arm", "armhf", "aarch64"]:
            ver_str = debian_package_version(pkg="qemu-system-arm",
                                             split=False)
            arch_str = debian_package_arch(pkg="qemu-system-arm")
            self.qemu_data = {
                "qemu_version": ver_str,
                "host_arch": arch_str,
                "job_arch": architecture,
            }
            self.logger.info(
                "qemu-system-arm, installed at version: %s, host architecture: %s",
                ver_str,
                arch_str,
            )

        if self.parameters["method"] in ["qemu", "qemu-nfs"]:
            if "prompts" not in self.parameters:
                if self.test_has_shell(self.parameters):
                    self.errors = "Unable to identify boot prompts from job definition."
        self.methods = self.job.device["actions"]["boot"]["methods"]
        method = self.parameters["method"]
        boot = (self.methods["qemu"]
                if "qemu" in self.methods else self.methods["qemu-nfs"])
        try:
            if "parameters" not in boot or "command" not in boot["parameters"]:
                self.errors = "Invalid device configuration - missing parameters"
            elif not boot["parameters"]["command"]:
                self.errors = "No QEMU binary command found - missing context."
            qemu_binary = which(boot["parameters"]["command"])
            self.sub_command = [qemu_binary]
            self.sub_command.extend(boot["parameters"].get("options", []))
            self.sub_command.extend(
                ["%s" % item for item in boot["parameters"].get("extra", [])])
        except AttributeError as exc:
            self.errors = "Unable to parse device options: %s %s" % (
                exc,
                self.job.device["actions"]["boot"]["methods"][method],
            )
        except (KeyError, TypeError):
            self.errors = "Invalid parameters for %s" % self.name

        for label in self.get_namespace_keys("download-action"):
            if label in ["offset", "available_loops", "uefi", "nfsrootfs"]:
                continue
            image_arg = self.get_namespace_data(action="download-action",
                                                label=label,
                                                key="image_arg")
            action_arg = self.get_namespace_data(action="download-action",
                                                 label=label,
                                                 key="file")
            if not image_arg or not action_arg:
                self.errors = "Missing image_arg for %s. " % label
                continue
            self.substitutions["{%s}" % label] = action_arg
            self.commands.append(image_arg)
        self.substitutions["{NFS_SERVER_IP}"] = dispatcher_ip(
            self.job.parameters["dispatcher"])
        self.sub_command.extend(substitute(self.commands, self.substitutions))
        if not self.sub_command:
            self.errors = "No QEMU command to execute"
        uefi_dir = self.get_namespace_data(action="deployimages",
                                           label="image",
                                           key="uefi_dir")
        if uefi_dir:
            self.sub_command.extend(["-L", uefi_dir, "-monitor", "none"])

        # Check for enable-kvm command line option in device configuration.
        if method not in self.job.device["actions"]["boot"]["methods"]:
            self.errors = "Unknown boot method '%s'" % method
            return

        options = self.job.device["actions"]["boot"]["methods"][method][
            "parameters"]["options"]
        if "-enable-kvm" in options:
            # Check if the worker has kvm enabled.
            if not os.path.exists(SYS_CLASS_KVM):
                self.errors = "Device configuration contains -enable-kvm option but kvm module is not enabled."