示例#1
0
def test_run(monkeypatch):
    class Proc:
        def wait(self):
            return 0

        def expect(self, arg):
            assert arg == pexpect.EOF

    commands = [
        ["nice", "/home/lava/bin/PiCtrl.py", "PowerPlug", "0", "off"],
        ["nice", "touch"],
    ]

    def spawn(cmd, args, cwd, encoding, codec_errors, logfile, timeout,
              searchwindowsize):
        command = commands.pop(0)
        assert cmd == command[0]
        assert args == command[1:]
        assert encoding == "utf-8"
        assert codec_errors == "replace"
        assert searchwindowsize == 10
        return Proc()

    monkeypatch.setattr(pexpect, "spawn", spawn)

    action = FlasherAction()
    device = PipelineDevice({
        "actions": {
            "deploy": {
                "methods": {
                    "flasher": {
                        "commands": ["{HARD_RESET_COMMAND}", "touch"]
                    }
                }
            }
        },
        "commands": {
            "hard_reset": "/home/lava/bin/PiCtrl.py PowerPlug 0 off"
        },
    })
    action.job = Job(1234, {}, None)
    action.job.device = device
    action.parameters = {"namespace": "common", "images": {}}
    action.section = Flasher.section

    # self.commands is populated by validate
    action.validate()
    assert action.errors == []  # nosec - unit test

    # Run the action
    action.run(None, 10)
    assert commands == []  # nosec - unit test
示例#2
0
 def test_multi_deploy(self):
     self.assertIsNotNone(self.parsed_data)
     job = Job(4212, self.parsed_data, None)
     job.timeout = Timeout("Job", Timeout.parse({"minutes": 2}))
     pipeline = Pipeline(job=job)
     device = TestMultiDeploy.FakeDevice()
     self.assertIsNotNone(device)
     job.device = device
     job.logger = DummyLogger()
     job.pipeline = pipeline
     counts = {}
     for action_data in self.parsed_data["actions"]:
         for name in action_data:
             counts.setdefault(name, 1)
             parameters = action_data[name]
             test_deploy = TestMultiDeploy.TestDeploy(
                 pipeline, parameters, job)
             self.assertEqual({}, test_deploy.action.data)
             counts[name] += 1
     # check that only one action has the example set
     self.assertEqual(
         ["nowhere"],
         [
             detail["deploy"]["example"]
             for detail in self.parsed_data["actions"]
             if "example" in detail["deploy"]
         ],
     )
     self.assertEqual(
         ["faked", "valid"],
         [
             detail["deploy"]["parameters"]
             for detail in self.parsed_data["actions"]
             if "parameters" in detail["deploy"]
         ],
     )
     self.assertIsInstance(pipeline.actions[0],
                           TestMultiDeploy.TestDeployAction)
     self.assertIsInstance(pipeline.actions[1],
                           TestMultiDeploy.TestDeployAction)
     self.assertIsInstance(pipeline.actions[2],
                           TestMultiDeploy.TestDeployAction)
     job.validate()
     self.assertEqual([], job.pipeline.errors)
     job.run()
     self.assertNotEqual(pipeline.actions[0].data,
                         {"fake-deploy": pipeline.actions[0].parameters})
     self.assertEqual(pipeline.actions[1].data,
                      {"fake-deploy": pipeline.actions[2].parameters})
     # check that values from previous DeployAction run actions have been cleared
     self.assertEqual(pipeline.actions[2].data,
                      {"fake-deploy": pipeline.actions[2].parameters})
示例#3
0
def test_file_download_validate(tmpdir):
    # Create the file to use
    (tmpdir / "bla.img").write_text("hello", encoding="utf-8")

    # Working
    action = FileDownloadAction("image", "/path/to/file",
                                urlparse("file://" + str(tmpdir) + "/bla.img"))
    action.section = "deploy"
    action.job = Job(1234, {}, None)
    action.parameters = {
        "image": {
            "url": "file://" + str(tmpdir) + "/bla.img"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == []
    assert action.size == 5

    # Missing file
    action = FileDownloadAction(
        "image", "/path/to/file",
        urlparse("file://" + str(tmpdir) + "/bla2.img"))
    action.section = "deploy"
    action.job = Job(1234, {}, None)
    action.parameters = {
        "image": {
            "url": "file://" + str(tmpdir) + "/bla2.img"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == [
        "Image file '" + str(tmpdir) +
        "/bla2.img' does not exist or is not readable"
    ]
    assert action.size == -1
示例#4
0
def test_append_lava_overlay_update_guestfs(caplog, mocker, tmpdir):
    caplog.set_level(logging.DEBUG)
    params = {"format": "ext4", "overlays": {"lava": True}}

    action = AppendOverlays("rootfs", params)
    action.job = Job(1234, {}, None)
    action.parameters = {
        "rootfs": {
            "url": "http://example.com/rootff.ext4",
            **params
        },
        "namespace": "common",
    }
    action.data = {
        "common": {
            "compress-overlay": {
                "output": {
                    "file": str(tmpdir / "overlay.tar.gz")
                }
            },
            "download-action": {
                "rootfs": {
                    "file": str(tmpdir / "rootfs.ext4"),
                    "compression": "gz",
                    "decompressed": True,
                }
            },
        }
    }

    guestfs = mocker.MagicMock()
    guestfs.add_drive = mocker.MagicMock()
    mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.guestfs.GuestFS",
        guestfs)
    action.update_guestfs()

    guestfs.assert_called_once_with(python_return_dict=True)
    guestfs().launch.assert_called_once_with()
    guestfs().list_devices.assert_called_once_with()
    guestfs().add_drive.assert_called_once_with(str(tmpdir / "rootfs.ext4"))
    guestfs().mount.assert_called_once_with(guestfs().list_devices()[0], "/")
    guestfs().mkdir_p.assert_called_once_with("/")
    guestfs().tar_in.assert_called_once_with(str(tmpdir / "overlay.tar.gz"),
                                             "/",
                                             compress="gzip")
    assert caplog.record_tuples == [
        ("dispatcher", 20, f"Modifying '{tmpdir}/rootfs.ext4'"),
        ("dispatcher", 10, "Overlays:"),
        ("dispatcher", 10, f"- rootfs.lava: '{tmpdir}/overlay.tar.gz' to '/'"),
    ]
示例#5
0
def test_download_handler_validate_simple():
    # "images.key" without extra parameters
    action = DownloadHandler(
        "key", "/path/to/save", urlparse("http://example.com/resource.img")
    )
    action.job = Job(1234, {}, None)
    action.parameters = {
        "images": {"key": {"url": "http://example.com/resource.img"}},
        "namespace": "common",
    }
    action.params = action.parameters["images"]["key"]
    action.validate()
    assert action.data == {
        "common": {
            "download-action": {
                "key": {"file": "/path/to/save/key/resource.img", "compression": None}
            }
        }
    }

    # "key" without extra parameters
    action = DownloadHandler(
        "key", "/path/to/save", urlparse("http://example.com/resource.img")
    )
    action.job = Job(1234, {}, None)
    action.parameters = {
        "key": {"url": "http://example.com/resource.img"},
        "namespace": "common",
    }
    action.params = action.parameters["key"]
    action.validate()
    assert action.data == {
        "common": {
            "download-action": {
                "key": {"file": "/path/to/save/key/resource.img", "compression": None}
            }
        }
    }
示例#6
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)
示例#7
0
def test_wait_for_board_id_is_optional(factory):
    action = DockerTestAction()
    action.job = Job("1234", {}, None)
    rendered, _ = factory.create_device("hi6220-hikey-r2-01.jinja2")
    action.job.device = NewDevice(yaml_load(rendered))
    action.job.timeout = Timeout("blah")
    action.level = 1
    action.populate(
        {
            "namespace": "common",
            "docker": {"image": "foobar", "wait": {"device": False}},
        }
    )
    assert not any(
        [a for a in action.pipeline.actions if a.name == "wait-device-boardid"]
    )

    docker_test_shell = action.pipeline.actions[-2]
    assert not docker_test_shell.wait_for_device
示例#8
0
def test_predownloaded_subdirectory():
    params = {"to": "tmpfs", "rootfs": {"url": "downloads://subdir/rootfs.xz"}}
    job = Job(1234, {}, None)
    destdir = job.mkdtemp("some-other-action")
    action = PreDownloadedAction("rootfs",
                                 urlparse("downloads://subdir/rootfs.xz"),
                                 destdir, params)
    action.job = job

    filename = Path(action.job.tmp_dir) / "downloads/common/subdir/rootfs.xz"
    filename.parent.mkdir(parents=True)
    filename.touch()

    action.data = {}
    action.parameters = {"namespace": "common"}
    action.validate()
    action.run(None, 4242)
    mapped_path = action.get_namespace_data(action="download-action",
                                            label="rootfs",
                                            key="file")
    assert mapped_path == (destdir + "/subdir/rootfs.xz")
    assert Path(mapped_path).exists()
示例#9
0
    def test_overlay_action(self):
        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"]

        overlay.validate()
        assert overlay.method == "ipxe"
        assert overlay.commands == [
            "dhcp net0",
            "set console console=ttyS0,115200n8 lava_mac={LAVA_MAC}",
            "set extraargs  ip=dhcp",
            "kernel tftp://{SERVER_IP}/{KERNEL} ${extraargs} ${console}",
            "initrd tftp://{SERVER_IP}/{RAMDISK}",
            "boot",
        ]
        assert overlay.use_bootscript is False
        assert overlay.lava_mac == "00:90:05:af:00:7d"

        substitution_dictionary = {
            "{SERVER_IP}": ip_addr,
            "{RAMDISK}": ramdisk,
            "{KERNEL}": kernel,
            "{LAVA_MAC}": overlay.lava_mac,
        }
        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:90:05:af:00:7d",
            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)
示例#10
0
def test_copy_to_lxc_without_lxc_should_do_nothing():
    action = CopyToLxcAction()
    action.job = Job(1234, {}, None)
    action.run(None, 4242)  # no crash = success
示例#11
0
def test_append_lava_overlay_update_cpio(caplog, mocker, tmpdir):
    caplog.set_level(logging.DEBUG)
    params = {"format": "cpio.newc", "overlays": {"lava": True}}

    action = AppendOverlays("rootfs", params)
    action.job = Job(1234, {}, None)
    action.parameters = {
        "rootfs": {
            "url": "http://example.com/rootfs.cpio.gz",
            **params
        },
        "namespace": "common",
    }
    action.data = {
        "common": {
            "compress-overlay": {
                "output": {
                    "file": str(tmpdir / "overlay.tar.gz")
                }
            },
            "download-action": {
                "rootfs": {
                    "file": str(tmpdir / "rootfs.cpio.gz"),
                    "compression": "gz",
                    "decompressed": False,
                }
            },
        }
    }
    action.mkdtemp = lambda: str(tmpdir)
    decompress_file = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.decompress_file")
    uncpio = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.uncpio")
    unlink = mocker.patch("os.unlink")
    untar_file = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.untar_file")
    cpio = mocker.patch("lava_dispatcher.actions.deploy.apply_overlay.cpio")
    compress_file = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.compress_file")

    action.update_cpio()

    decompress_file.assert_called_once_with(str(tmpdir / "rootfs.cpio.gz"),
                                            "gz")
    uncpio.assert_called_once_with(decompress_file(), str(tmpdir))
    unlink.assert_called_once_with(decompress_file())
    untar_file.assert_called_once_with(str(tmpdir / "overlay.tar.gz"),
                                       str(tmpdir) + "/")
    cpio.assert_called_once_with(str(tmpdir), decompress_file())
    compress_file.assert_called_once_with(decompress_file(), "gz")

    assert caplog.record_tuples == [
        ("dispatcher", 20, f"Modifying '{tmpdir}/rootfs.cpio.gz'"),
        ("dispatcher", 10, "* decompressing (gz)"),
        ("dispatcher", 10, f"* extracting {decompress_file()}"),
        ("dispatcher", 10, "Overlays:"),
        ("dispatcher", 10,
         f"- rootfs.lava: '{tmpdir}/overlay.tar.gz' to '{tmpdir}/'"),
        ("dispatcher", 10, f"* archiving {decompress_file()}"),
        ("dispatcher", 10, "* compressing (gz)"),
    ]
示例#12
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.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)
        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)
示例#13
0
def job(tmpdir):
    job = Job(1234, {}, None)
    return job
示例#14
0
def test_run(monkeypatch):
    class FD:
        def readlines(self):
            return []

    class Proc:
        def __init__(self):
            self.stderr = FD()
            self.stdout = FD()

        def poll(self):
            return 0

        def wait(self):
            return 0

    class Poller:
        def register(self, fd, flag):
            pass

    commands = [
        ["nice", "/home/lava/bin/PiCtrl.py", "PowerPlug", "0", "off"],
        ["nice", "touch"],
    ]

    def Popen(
        cmd, cwd, stdout, stderr, bufsize, universal_newlines
    ):  # nosec - unit test
        assert cmd == commands.pop(0)  # nosec - unit test
        assert stdout == subprocess.PIPE  # nosec - unit test
        assert stderr == subprocess.PIPE  # nosec - unit test
        assert bufsize == 1  # nosec - unit test
        assert universal_newlines  # nosec - unit test
        return Proc()

    monkeypatch.setattr(subprocess, "Popen", Popen)
    monkeypatch.setattr(select, "epoll", lambda: Poller())

    action = FlasherAction()
    device = PipelineDevice(
        {
            "actions": {
                "deploy": {
                    "methods": {
                        "flasher": {"commands": ["{HARD_RESET_COMMAND}", "touch"]}
                    }
                }
            },
            "commands": {"hard_reset": "/home/lava/bin/PiCtrl.py PowerPlug 0 off"},
        }
    )
    action.job = Job(1234, {}, None)
    action.job.device = device
    action.parameters = {"namespace": "common", "images": {}}
    action.section = Flasher.action_type

    # self.commands is populated by validate
    action.validate()
    assert action.errors == []  # nosec - unit test

    # Run the action
    action.run(None, 10)
    assert commands == []  # nosec - unit test
示例#15
0
文件: parser.py 项目: czfgd/lava
    def parse(self, content, device, job_id, logger, dispatcher_config, env_dut=None):
        data = yaml.safe_load(content)
        job = Job(job_id, data, logger)
        test_counts = {}
        job.device = device
        job.parameters["env_dut"] = env_dut
        # Load the dispatcher config
        job.parameters["dispatcher"] = {}
        if dispatcher_config is not None:
            config = yaml.safe_load(dispatcher_config)
            if isinstance(config, dict):
                job.parameters["dispatcher"] = config

        level_tuple = Protocol.select_all(job.parameters)
        # sort the list of protocol objects by the protocol class level.
        job.protocols = [
            item[0](job.parameters, job_id)
            for item in sorted(level_tuple, key=lambda level_tuple: level_tuple[1])
        ]
        pipeline = Pipeline(job=job)
        self._timeouts(data, job)

        # deploy and boot classes can populate the pipeline differently depending
        # on the test action type they are linked with (via namespacing).
        # This code builds an information dict for each namespace which is then
        # passed as a parameter to each Action class to use.
        test_actions = [action for action in data["actions"] if "test" in action]
        for test_action in test_actions:
            test_parameters = test_action["test"]
            test_type = LavaTest.select(device, test_parameters)
            namespace = test_parameters.get("namespace", "common")
            connection_namespace = test_parameters.get(
                "connection-namespace", namespace
            )
            if namespace in job.test_info:
                job.test_info[namespace].append(
                    {"class": test_type, "parameters": test_parameters}
                )
            else:
                job.test_info.update(
                    {namespace: [{"class": test_type, "parameters": test_parameters}]}
                )
            if namespace != connection_namespace:
                job.test_info.update(
                    {
                        connection_namespace: [
                            {"class": test_type, "parameters": test_parameters}
                        ]
                    }
                )

        # FIXME: also read permissable overrides from device config and set from job data
        # FIXME: ensure that a timeout for deployment 0 does not get set as the timeout for deployment 1 if 1 is default
        for action_data in data["actions"]:
            for name in action_data:
                # Set a default namespace if needed
                namespace = action_data[name].setdefault("namespace", "common")
                test_counts.setdefault(namespace, 1)

                if name == "deploy" or name == "boot" or name == "test":
                    action = parse_action(
                        action_data,
                        name,
                        device,
                        pipeline,
                        job.test_info,
                        test_counts[namespace],
                    )
                    if name == "test" and action.needs_overlay():
                        test_counts[namespace] += 1
                elif name == "repeat":
                    count = action_data[name][
                        "count"
                    ]  # first list entry must be the count dict
                    repeats = action_data[name]["actions"]
                    for c_iter in range(count):
                        for repeating in repeats:  # block of YAML to repeat
                            for (
                                repeat_action
                            ) in repeating:  # name of the action for this block
                                repeating[repeat_action]["repeat-count"] = c_iter
                                namespace = repeating[repeat_action].setdefault(
                                    "namespace", "common"
                                )
                                test_counts.setdefault(namespace, 1)
                                action = parse_action(
                                    repeating,
                                    repeat_action,
                                    device,
                                    pipeline,
                                    job.test_info,
                                    test_counts[namespace],
                                )
                                if repeat_action == "test" and action.needs_overlay():
                                    test_counts[namespace] += 1

                elif name == "command":
                    action = CommandAction()
                    action.parameters = action_data[name]
                    pipeline.add_action(action)

                else:
                    raise JobError("Unknown action name '%s'" % name)

        # there's always going to need to be a finalize_process action
        finalize = FinalizeAction()
        pipeline.add_action(finalize)
        finalize.populate(None)
        job.pipeline = pipeline
        if "compatibility" in data:
            try:
                job_c = int(job.compatibility)
                data_c = int(data["compatibility"])
            except ValueError as exc:
                raise JobError("invalid compatibility value: %s" % exc)
            if job_c < data_c:
                raise JobError(
                    "Dispatcher unable to meet job compatibility requirement. %d > %d"
                    % (job_c, data_c)
                )
        return job
示例#16
0
文件: parser.py 项目: yuhua-eric/lava
    def parse(self, content, device, job_id, logger, dispatcher_config,
              env_dut=None):
        self.loader = yaml.SafeLoader(content)
        self.loader.compose_node = self.compose_node
        self.loader.construct_mapping = self.construct_mapping
        data = self.loader.get_single_data()
        job = Job(job_id, data, logger)
        test_counts = {}
        job.device = device
        job.parameters['env_dut'] = env_dut
        # Load the dispatcher config
        job.parameters['dispatcher'] = {}
        if dispatcher_config is not None:
            config = yaml.safe_load(dispatcher_config)
            if isinstance(config, dict):
                job.parameters['dispatcher'] = config

        level_tuple = Protocol.select_all(job.parameters)
        # sort the list of protocol objects by the protocol class level.
        job.protocols = [item[0](job.parameters, job_id) for item in sorted(level_tuple, key=lambda level_tuple: level_tuple[1])]
        pipeline = Pipeline(job=job)
        self._timeouts(data, job)

        # deploy and boot classes can populate the pipeline differently depending
        # on the test action type they are linked with (via namespacing).
        # This code builds an information dict for each namespace which is then
        # passed as a parameter to each Action class to use.
        test_info = {}
        test_actions = ([action for action in data['actions'] if 'test' in action])
        for test_action in test_actions:
            test_parameters = test_action['test']
            test_type = LavaTest.select(device, test_parameters)
            namespace = test_parameters.get('namespace', 'common')
            connection_namespace = test_parameters.get('connection-namespace', namespace)
            if namespace in test_info:
                test_info[namespace].append({'class': test_type, 'parameters': test_parameters})
            else:
                test_info.update({namespace: [{'class': test_type, 'parameters': test_parameters}]})
            if namespace != connection_namespace:
                test_info.update({connection_namespace: [{'class': test_type, 'parameters': test_parameters}]})

        # FIXME: also read permissable overrides from device config and set from job data
        # FIXME: ensure that a timeout for deployment 0 does not get set as the timeout for deployment 1 if 1 is default
        for action_data in data['actions']:
            action_data.pop('yaml_line', None)
            for name in action_data:
                # Set a default namespace if needed
                namespace = action_data[name].setdefault('namespace', 'common')
                test_counts.setdefault(namespace, 1)

                if name == 'deploy' or name == 'boot' or name == 'test':
                    parse_action(action_data, name, device, pipeline,
                                 test_info, test_counts[namespace])
                    if name == 'test':
                        test_counts[namespace] += 1
                elif name == 'repeat':
                    count = action_data[name]['count']  # first list entry must be the count dict
                    repeats = action_data[name]['actions']
                    for c_iter in range(count):
                        for repeating in repeats:  # block of YAML to repeat
                            for repeat_action in repeating:  # name of the action for this block
                                if repeat_action == 'yaml_line':
                                    continue
                                repeating[repeat_action]['repeat-count'] = c_iter
                                namespace = repeating[repeat_action].setdefault('namespace', 'common')
                                test_counts.setdefault(namespace, 1)
                                parse_action(repeating, repeat_action, device,
                                             pipeline, test_info, test_counts[namespace])
                                if repeat_action == 'test':
                                    test_counts[namespace] += 1

                elif name == 'command':
                    action = CommandAction()
                    action.parameters = action_data[name]
                    pipeline.add_action(action)

                else:
                    raise JobError("Unknown action name '%s'" % name)

        # there's always going to need to be a finalize_process action
        finalize = FinalizeAction()
        pipeline.add_action(finalize)
        finalize.populate(None)
        job.pipeline = pipeline
        if 'compatibility' in data:
            try:
                job_c = int(job.compatibility)
                data_c = int(data['compatibility'])
            except ValueError as exc:
                raise JobError('invalid compatibility value: %s' % exc)
            if job_c < data_c:
                raise JobError('Dispatcher unable to meet job compatibility requirement. %d > %d' % (job_c, data_c))
        return job
示例#17
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_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)
        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)
示例#18
0
def test_append_lava_overlay_update_tar(caplog, mocker, tmpdir):
    caplog.set_level(logging.DEBUG)
    params = {
        "format": "tar",
        "overlays": {
            "modules": {
                "url": "http://example.com/modules.tar.xz",
                "compression": "xz",
                "format": "tar",
                "path": "/",
            }
        },
    }

    action = AppendOverlays("nfsrootfs", params)
    action.job = Job(1234, {}, None)
    action.parameters = {
        "nfsrootfs": {"url": "http://example.com/rootfs.tar.gz", **params},
        "namespace": "common",
    }
    action.data = {
        "common": {
            "download-action": {
                "nfsrootfs": {
                    "file": str(tmpdir / "rootfs.tar.gz"),
                    "compression": "gz",
                    "decompressed": False,
                },
                "nfsrootfs.modules": {"file": str(tmpdir / "modules.tar")},
            },
        }
    }
    action.mkdtemp = lambda: str(tmpdir)
    decompress_file = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.decompress_file"
    )
    untar_file = mocker.patch("lava_dispatcher.actions.deploy.apply_overlay.untar_file")
    unlink = mocker.patch("os.unlink")
    create_tarfile = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.create_tarfile"
    )
    compress_file = mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.compress_file"
    )

    action.update_tar()

    decompress_file.assert_called_once_with(str(tmpdir / "rootfs.tar.gz"), "gz")
    assert untar_file.mock_calls == [
        mocker.call(decompress_file(), str(tmpdir)),
        mocker.call(str(tmpdir / "modules.tar"), str(tmpdir) + "/"),
    ]
    unlink.assert_called_once_with(decompress_file())

    create_tarfile.assert_called_once_with(str(tmpdir), decompress_file())
    compress_file.assert_called_once_with(decompress_file(), "gz")

    assert caplog.record_tuples == [
        ("dispatcher", 20, f"Modifying '{tmpdir}/rootfs.tar.gz'"),
        ("dispatcher", 10, "* decompressing (gz)"),
        ("dispatcher", 10, f"* extracting {decompress_file()}"),
        ("dispatcher", 10, "Overlays:"),
        (
            "dispatcher",
            10,
            f"- nfsrootfs.modules: untar '{tmpdir}/modules.tar' to '{tmpdir}/'",
        ),
        ("dispatcher", 10, f"* archiving {decompress_file()}"),
        ("dispatcher", 10, "* compressing (gz)"),
    ]
示例#19
0
def test_append_overlays_update_guestfs_sparse(caplog, mocker, tmpdir):
    caplog.set_level(logging.DEBUG)
    params = {
        "format": "ext4",
        "sparse": True,
        "overlays": {
            "modules": {
                "url": "http://example.com/modules.tar.xz",
                "compression": "xz",
                "format": "tar",
                "path": "/lib",
            }
        },
    }

    action = AppendOverlays("rootfs", params)
    action.job = Job(1234, {}, None)
    action.parameters = {
        "rootfs": {"url": "http://example.com/rootff.ext4", **params},
        "namespace": "common",
    }
    action.data = {
        "common": {
            "download-action": {
                "rootfs": {
                    "file": str(tmpdir / "rootfs.ext4"),
                    "compression": "gz",
                    "decompressed": True,
                },
                "rootfs.modules": {"file": str(tmpdir / "modules.tar")},
            }
        }
    }
    action.run_cmd = mocker.MagicMock()
    replace = mocker.patch("lava_dispatcher.actions.deploy.apply_overlay.os.replace")

    guestfs = mocker.MagicMock()
    guestfs.add_drive = mocker.MagicMock()
    mocker.patch(
        "lava_dispatcher.actions.deploy.apply_overlay.guestfs.GuestFS", guestfs
    )
    action.update_guestfs()

    guestfs.assert_called_once_with(python_return_dict=True)
    guestfs().launch.assert_called_once_with()
    guestfs().list_devices.assert_called_once_with()
    guestfs().add_drive.assert_called_once_with(str(tmpdir / "rootfs.ext4"))
    guestfs().mount.assert_called_once_with(guestfs().list_devices()[0], "/")
    guestfs().mkdir_p.assert_called_once_with("/lib")
    guestfs().tar_in.assert_called_once_with(
        str(tmpdir / "modules.tar"), "/lib", compress=None
    )
    action.run_cmd.assert_called_once_with(
        ["/usr/bin/img2simg", f"{tmpdir}/rootfs.ext4", f"{tmpdir}/rootfs.ext4.sparse"],
        error_msg=f"img2simg failed for {tmpdir}/rootfs.ext4",
    )
    replace.assert_called_once_with(
        f"{tmpdir}/rootfs.ext4.sparse", f"{tmpdir}/rootfs.ext4"
    )

    assert caplog.record_tuples == [
        ("dispatcher", 20, f"Modifying '{tmpdir}/rootfs.ext4'"),
        ("dispatcher", 10, "Overlays:"),
        ("dispatcher", 10, f"- rootfs.modules: '{tmpdir}/modules.tar' to '/lib'"),
        ("dispatcher", 10, f"Calling img2simg on '{tmpdir}/rootfs.ext4'"),
    ]
示例#20
0
def job():
    return Job(42, {}, None)
示例#21
0
文件: test_uboot.py 项目: atline/lava
    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)
示例#22
0
def test_http_download_validate(mocker):
    class DummyResponseNOK:
        status_code = 404

        def close(self):
            pass

    class DummyResponseOK:
        status_code = requests.codes.OK
        headers = {"content-length": "4212"}

        def close(self):
            pass

    def dummyhead(url, allow_redirects, headers):
        assert allow_redirects is True
        assert headers == {"Accept-Encoding": ""}
        if url == "https://example.com/kernel":
            return DummyResponseOK()
        elif url == "https://example.com/dtb":
            return DummyResponseNOK()
        assert 0

    def dummyget(url, allow_redirects, stream, headers):
        assert allow_redirects is True
        assert stream is True
        assert headers == {"Accept-Encoding": ""}
        assert url == "https://example.com/dtb"
        return DummyResponseOK()

    mocker.patch("requests.head", dummyhead)
    mocker.patch("requests.get", dummyget)

    # HEAD is working
    action = HttpDownloadAction("image", "/path/to/file",
                                urlparse("https://example.com/kernel"))
    action.section = "deploy"
    action.job = Job(1234, {"dispatcher": {}}, None)
    action.parameters = {
        "image": {
            "url": "https://example.com/kernel"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == []
    assert action.size == 4212

    # Only GET works
    action = HttpDownloadAction("image", "/path/to/file",
                                urlparse("https://example.com/dtb"))
    action.section = "deploy"
    action.job = Job(1234, {"dispatcher": {}}, None)
    action.parameters = {
        "image": {
            "url": "https://example.com/dtb"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == []
    assert action.size == 4212

    # 404
    def response404(*args, **kwargs):
        print(args)
        print(str(kwargs))
        return DummyResponseNOK()

    mocker.patch("requests.head", response404)
    mocker.patch("requests.get", response404)

    action = HttpDownloadAction("image", "/path/to/file",
                                urlparse("https://example.com/kernel"))
    action.section = "deploy"
    action.job = Job(1234, {"dispatcher": {}}, None)
    action.parameters = {
        "image": {
            "url": "https://example.com/kernel"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == [
        "Resource unavailable at 'https://example.com/kernel' (404)"
    ]

    # Raising exceptions
    def raisinghead(url, allow_redirects, headers):
        raise requests.Timeout()

    mocker.patch("requests.head", raisinghead)
    action = HttpDownloadAction("image", "/path/to/file",
                                urlparse("https://example.com/kernel"))
    action.section = "deploy"
    action.job = Job(1234, {"dispatcher": {}}, None)
    action.parameters = {
        "image": {
            "url": "https://example.com/kernel"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == ["'https://example.com/kernel' timed out"]

    def raisinghead2(url, allow_redirects, headers):
        raise requests.RequestException("an error occured")

    mocker.patch("requests.head", raisinghead2)
    action = HttpDownloadAction("image", "/path/to/file",
                                urlparse("https://example.com/kernel"))
    action.section = "deploy"
    action.job = Job(1234, {"dispatcher": {}}, None)
    action.parameters = {
        "image": {
            "url": "https://example.com/kernel"
        },
        "namespace": "common",
    }
    action.params = action.parameters["image"]
    action.validate()
    assert action.errors == [
        "Unable to get 'https://example.com/kernel': an error occured"
    ]
示例#23
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)
示例#24
0
def test_http_download_run(tmpdir):
    def reader():
        yield b"hello"
        yield b"world"

    action = HttpDownloadAction("dtb", str(tmpdir),
                                urlparse("https://example.com/dtb"))
    action.job = Job(1234, {"dispatcher": {}}, None)
    action.url = urlparse("https://example.com/dtb")
    action.parameters = {
        "to": "download",
        "images": {
            "dtb": {
                "url":
                "https://example.com/dtb",
                "md5sum":
                "fc5e038d38a57032085441e7fe7010b0",
                "sha256sum":
                "936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af",
                "sha512sum":
                "1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60",
            }
        },
        "namespace": "common",
    }
    action.params = action.parameters["images"]["dtb"]
    action.reader = reader
    action.fname = str(tmpdir / "dtb/dtb")
    action.run(None, 4212)
    data = ""
    with open(str(tmpdir / "dtb/dtb")) as f_in:
        data = f_in.read()
    assert data == "helloworld"
    assert dict(action.results) == {
        "success": {
            "sha512":
            "1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60"
        },
        "label":
        "dtb",
        "size":
        10,
        "md5sum":
        "fc5e038d38a57032085441e7fe7010b0",
        "sha256sum":
        "936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af",
        "sha512sum":
        "1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60",
    }
    assert action.data == {
        "common": {
            "download-action": {
                "dtb": {
                    "decompressed":
                    False,
                    "file":
                    "%s/dtb/dtb" % str(tmpdir),
                    "md5":
                    "fc5e038d38a57032085441e7fe7010b0",
                    "sha256":
                    "936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af",
                    "sha512":
                    "1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60",
                },
                "file": {
                    "dtb": "%s/dtb/dtb" % str(tmpdir)
                },
            }
        }
    }
示例#25
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)
示例#26
0
def test_http_download_run_compressed(tmpdir):
    def reader():
        yield b"\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00"
        yield b"\x00t/\xe5\xa3\x01\x00\x0bhello world\n\x00\xa1\xf2\xff\xc4j"
        yield b"\x7f\xbf\xcf\x00\x01$\x0c\xa6\x18\xd8\xd8\x1f\xb6\xf3}\x01"
        yield b"\x00\x00\x00\x00\x04YZ"

    action = HttpDownloadAction("rootfs", str(tmpdir),
                                urlparse("https://example.com/rootfs.xz"))
    action.job = Job(1234, {}, None)
    action.url = urlparse("https://example.com/rootfs.xz")
    action.parameters = {
        "to": "download",
        "rootfs": {
            "url":
            "https://example.com/rootfs.xz",
            "compression":
            "xz",
            "md5sum":
            "0107d527acf9b8de628b7b4d103c89d1",
            "sha256sum":
            "3275a39be7b717d548b66f3c8f23d940603a63b0f13d84a596d979a7f66feb2c",
            "sha512sum":
            "d0850c3e0c45bdf74995907a04f69806a070d79a4f0b2dd82d6b96adafdbfd85ce6c1daaff916ff089bdf9b04eba7805041c49afecdbeabca69fef802e60de35",
        },
        "namespace": "common",
    }
    action.params = action.parameters["rootfs"]
    action.reader = reader
    action.size = 68
    action.fname = str(tmpdir / "rootfs/rootfs")
    action.run(None, 4212)
    data = ""
    with open(str(tmpdir / "rootfs/rootfs")) as f_in:
        data = f_in.read()
    assert data == "hello world\n"
    assert dict(action.results) == {
        "success": {
            "sha512":
            "d0850c3e0c45bdf74995907a04f69806a070d79a4f0b2dd82d6b96adafdbfd85ce6c1daaff916ff089bdf9b04eba7805041c49afecdbeabca69fef802e60de35"
        },
        "label":
        "rootfs",
        "size":
        68,
        "md5sum":
        "0107d527acf9b8de628b7b4d103c89d1",
        "sha256sum":
        "3275a39be7b717d548b66f3c8f23d940603a63b0f13d84a596d979a7f66feb2c",
        "sha512sum":
        "d0850c3e0c45bdf74995907a04f69806a070d79a4f0b2dd82d6b96adafdbfd85ce6c1daaff916ff089bdf9b04eba7805041c49afecdbeabca69fef802e60de35",
    }

    assert action.data == {
        "common": {
            "download-action": {
                "rootfs": {
                    "decompressed":
                    True,
                    "file":
                    "%s/rootfs/rootfs" % str(tmpdir),
                    "md5":
                    "0107d527acf9b8de628b7b4d103c89d1",
                    "sha256":
                    "3275a39be7b717d548b66f3c8f23d940603a63b0f13d84a596d979a7f66feb2c",
                    "sha512":
                    "d0850c3e0c45bdf74995907a04f69806a070d79a4f0b2dd82d6b96adafdbfd85ce6c1daaff916ff089bdf9b04eba7805041c49afecdbeabca69fef802e60de35",
                },
                "file": {
                    "rootfs": "%s/rootfs/rootfs" % str(tmpdir)
                },
            }
        }
    }