Example #1
0
    def test_mender_inventory_network_scripts(self, request,
                                              prepared_test_build,
                                              bitbake_image):
        """
        Test the 'inventory-network-scripts' build feature configuration through
        'PACKAGECONFIG' is working as expected.

        This verifies that the 'inventory-network-scripts' option is a part
        build, and also that the inventory scripts are not included when
        removed.


        The test only runs for sdimg, as the build image should not really matter here.
        """

        #
        # Feature enabled
        #
        reset_build_conf(prepared_test_build["build_dir"])
        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [
                'PACKAGECONFIG_append_pn-mender-client = " inventory-network-scripts"'
            ],
        )
        rootfs = latest_build_artifact(request,
                                       prepared_test_build["build_dir"],
                                       "core-image*.ext4")
        assert len(rootfs) > 0, "rootfs not generated"

        output = subprocess.check_output(
            ["debugfs", "-R", "ls /usr/share/mender/inventory", rootfs])
        assert (
            b"mender-inventory-geo" in output
        ), "mender-inventory-network-scripts seems not to be a part of the image, like they should"

        #
        # Feature disabled
        #
        reset_build_conf(prepared_test_build["build_dir"])
        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [
                'PACKAGECONFIG_remove_pn-mender-client = " inventory-network-scripts"'
            ],
        )
        rootfs = latest_build_artifact(request,
                                       prepared_test_build["build_dir"],
                                       "core-image*.ext4")
        assert len(rootfs) > 0, "ext4 not generated"
        output = subprocess.check_output(
            ["debugfs", "-R", "ls /usr/share/mender/inventory", rootfs])
        assert (
            b"mender-inventory-geo" not in output
        ), "mender-inventory-network-scripts unexpectedly a part of the image"
Example #2
0
    def test_artifact_signing_keys(
        self,
        request,
        prepared_test_build,
        bitbake_variables,
        bitbake_path,
        bitbake_image,
    ):
        """Test that MENDER_ARTIFACT_SIGNING_KEY and MENDER_ARTIFACT_VERIFY_KEY
        works correctly."""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [
                'MENDER_ARTIFACT_SIGNING_KEY = "%s"'
                % os.path.join(os.getcwd(), signing_key("RSA").private),
                'MENDER_ARTIFACT_VERIFY_KEY = "%s"'
                % os.path.join(os.getcwd(), signing_key("RSA").public),
            ],
        )

        built_rootfs = latest_build_artifact(
            request, prepared_test_build["build_dir"], "core-image*.ext[234]"
        )
        # Copy out the key we just added from the image and use that to
        # verify instead of the original, just to be sure.
        subprocess.check_call(
            [
                "debugfs",
                "-R",
                "dump -p /etc/mender/artifact-verify-key.pem artifact-verify-key.pem",
                built_rootfs,
            ]
        )
        try:
            built_artifact = latest_build_artifact(
                request, prepared_test_build["build_dir"], "core-image*.mender"
            )
            output = subprocess.check_output(
                [
                    "mender-artifact",
                    "read",
                    "-k",
                    os.path.join(os.getcwd(), "artifact-verify-key.pem"),
                    built_artifact,
                ]
            ).decode()
            assert output.find("Signature: signed and verified correctly") >= 0

        finally:
            os.remove("artifact-verify-key.pem")
Example #3
0
    def test_dataimg_creation(self, request, bitbake_variables,
                              prepared_test_build, bitbake_image):
        """Test that we can build a dataimg successfully."""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_FSTYPES = "dataimg"'],
        )

        built_img = latest_build_artifact(request,
                                          prepared_test_build["build_dir"],
                                          "core-image*.dataimg")

        # Check that it contains the device_type file, as we expect.
        with make_tempdir() as tmpdir:
            menderdir = os.path.join(tmpdir, "mender")
            if ("ARTIFACTIMG_FSTYPE" in bitbake_variables
                    and bitbake_variables["ARTIFACTIMG_FSTYPE"] == "ubifs"):
                subprocess.check_call(
                    ["ubireader_extract_files", "-o", tmpdir, built_img])
            else:
                os.mkdir(menderdir)
                subprocess.check_call([
                    "debugfs",
                    "-R",
                    "dump -p /mender/device_type %s" %
                    os.path.join(menderdir, "device_type"),
                    built_img,
                ])
            with open(os.path.join(menderdir, "device_type")) as fd:
                content = fd.read()
            assert (content == "device_type=%s\n" %
                    bitbake_variables["MENDER_DEVICE_TYPE"])
Example #4
0
    def test_tenant_token(self, request, prepared_test_build, bitbake_image):
        """Test setting a custom tenant-token"""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [
                'MENDER_TENANT_TOKEN = "%s"' % "authtentoken",
                'IMAGE_FSTYPES += "dataimg"',
            ],
        )

        built_rootfs = latest_build_artifact(request,
                                             prepared_test_build["build_dir"],
                                             "core-image*.dataimg")

        subprocess.check_call([
            "debugfs",
            "-R",
            "dump -p /etc/mender/mender.conf mender.conf",
            built_rootfs,
        ])

        try:
            with open("mender.conf") as fd:
                data = json.load(fd)
            assert data["TenantToken"] == "authtentoken"

        finally:
            os.remove("mender.conf")
Example #5
0
    def test_build_and_run_module(self, request, bitbake_variables,
                                  prepared_test_build, bitbake_image):

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_INSTALL_append = " mender-binary-delta"'],
            [
                'BBLAYERS_append = " %s/../meta-mender-commercial"' %
                bitbake_variables["LAYERDIR_MENDER"]
            ],
        )

        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "core-image*.ext4")
        output = subprocess.check_output(
            ["debugfs", "-R", "ls -p /usr/share/mender/modules/v3",
             image]).decode()

        # Debugfs has output like this:
        #   /3018/100755/0/0/mender-binary-delta/142672/
        #   /3015/100755/0/0/rootfs-image-v2/1606/
        assert "mender-binary-delta" in [
            line.split("/")[5] for line in output.split("\n")
            if line.startswith("/")
        ]
Example #6
0
def ubimg_without_uboot_env(request, latest_ubimg, prepared_test_build,
                            bitbake_image):
    """The ubireader_utils_info tool and friends don't support our UBI volumes
    that contain the U-Boot environment and hence not valid UBIFS structures.
    Therefore, make a new temporary image that doesn't contain U-Boot."""

    # The tests are marked with "only_with_image('ubimg')", but that is checked
    # using a function fixture, and this is a session fixture, which cannot
    # depend on that. So we need this check here to bail out if we don't find a
    # ubimg.
    if not latest_ubimg:
        pytest.skip("No ubimg found")

    reset_build_conf(prepared_test_build["build_dir"])
    build_image(
        prepared_test_build["build_dir"],
        prepared_test_build["bitbake_corebase"],
        bitbake_image,
        ['MENDER_FEATURES_DISABLE_append = " mender-uboot"'],
    )

    ubimg = latest_build_artifact(request, prepared_test_build["build_dir"],
                                  "core-image*.ubimg")
    imgdir = tempfile.mkdtemp()
    tmpimg = os.path.join(imgdir, os.path.basename(ubimg))
    shutil.copyfile(ubimg, tmpimg)

    def remove_ubimg():
        os.unlink(tmpimg)

    request.addfinalizer(remove_ubimg)

    return tmpimg
Example #7
0
    def test_multiple_device_types_compatible(
        self,
        request,
        prepared_test_build,
        bitbake_path,
        bitbake_variables,
        bitbake_image,
    ):
        """Tests that we can include multiple device_types in the artifact."""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['MENDER_DEVICE_TYPES_COMPATIBLE = "machine1 machine2"'],
        )

        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "core-image*.mender")

        output = run_verbose("mender-artifact read %s" % image, capture=True)
        assert b"Compatible devices: '[machine1 machine2]'" in output

        output = subprocess.check_output(
            "tar xOf %s header.tar.gz | tar xOz header-info" % image,
            shell=True).decode()
        data = json.loads(output)
        if version_is_minimum(bitbake_variables, "mender-artifact", "3.0.0"):
            assert data["artifact_depends"]["device_type"] == [
                "machine1", "machine2"
            ]
        else:
            assert data["device_types_compatible"] == ["machine1", "machine2"]
Example #8
0
    def test_module_install(
        self, request, prepared_test_build, bitbake_path, latest_rootfs, bitbake_image
    ):
        # List of expected update modules
        default_update_modules = [
            "deb",
            "directory",
            "docker",
            "rootfs-image-v2",
            "rpm",
            "script",
            "single-file",
        ]

        mender_vars = get_bitbake_variables(request, "mender-client")
        if "modules" in mender_vars["PACKAGECONFIG"].split():
            originally_on = True
        else:
            originally_on = False

        output = subprocess.check_output(
            ["debugfs", "-R", "ls -p /usr/share/mender/modules/v3", latest_rootfs]
        ).decode()
        entries = [
            elem.split("/")[5] for elem in output.split("\n") if elem.startswith("/")
        ]

        if originally_on:
            assert all([e in entries for e in default_update_modules])
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['PACKAGECONFIG_remove = "modules"'],
            )
        else:
            assert not any([e in entries for e in default_update_modules])
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['PACKAGECONFIG_append = " modules"'],
            )

        new_rootfs = latest_build_artifact(
            request, prepared_test_build["build_dir"], "core-image*.ext4"
        )

        output = subprocess.check_output(
            ["debugfs", "-R", "ls -p /usr/share/mender/modules/v3", new_rootfs]
        ).decode()
        entries = [
            elem.split("/")[5] for elem in output.split("\n") if elem.startswith("/")
        ]

        if originally_on:
            assert not any([e in entries for e in default_update_modules])
        else:
            assert all([e in entries for e in default_update_modules])
Example #9
0
    def test_bootloader_embed(self, request, prepared_test_build,
                              bitbake_image):
        """Test that MENDER_IMAGE_BOOTLOADER_FILE causes the bootloader to be embedded
        correctly in the resulting sdimg."""

        loader_file = "bootloader.bin"
        loader_offset = 4

        new_bb_vars = get_bitbake_variables(
            request,
            "core-image-minimal",
            prepared_test_build=prepared_test_build)

        loader_dir = new_bb_vars["DEPLOY_DIR_IMAGE"]
        loader_path = os.path.join(loader_dir, loader_file)

        run_verbose("mkdir -p %s" % os.path.dirname(loader_path))
        run_verbose("cp /etc/os-release %s" % loader_path)

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [
                'MENDER_IMAGE_BOOTLOADER_FILE = "%s"' % loader_file,
                'MENDER_IMAGE_BOOTLOADER_BOOTSECTOR_OFFSET = "%d"' %
                loader_offset,
            ],
        )

        built_sdimg = latest_build_artifact(request,
                                            prepared_test_build["build_dir"],
                                            "core-image*.sdimg")

        original = os.open(loader_path, os.O_RDONLY)
        embedded = os.open(built_sdimg, os.O_RDONLY)
        os.lseek(embedded, loader_offset * 512, 0)

        block_size = 4096
        while True:
            org_read = os.read(original, block_size)
            org_read_size = len(org_read)
            emb_read = os.read(embedded, org_read_size)

            assert (
                org_read == emb_read
            ), "Embedded bootloader is not identical to the file specified in MENDER_IMAGE_BOOTLOADER_FILE"

            if org_read_size < block_size:
                break

        os.close(original)
        os.close(embedded)
Example #10
0
def versioned_mender_image(request, prepared_test_build, latest_mender_image,
                           bitbake_variables, bitbake_image):
    """Gets the correct version of the artifact, whether it's the one we
    build by default, or one we have to produce ourselves.
    Returns a tuple of version and built image."""

    global LAST_BUILD_VERSION

    version = request.param

    if version == 1:
        pytest.fail()

    if (version >= 2 and not version_is_minimum(
            bitbake_variables, "mender-artifact", "2.0.0")) or (
                version >= 3 and not version_is_minimum(
                    bitbake_variables, "mender-artifact", "3.0.0")):
        pytest.skip("Requires version %d of mender-artifact format." % version)

    if version_is_minimum(bitbake_variables, "mender-artifact", "3.0.0"):
        default_version = 3
    elif version_is_minimum(bitbake_variables, "mender-artifact", "2.0.0"):
        default_version = 2
    else:
        default_version = 2

    if LAST_BUILD_VERSION != version:
        # Run a separate build for this artifact. This doesn't conflict with the
        # above version because the non-default version ends up in a different
        # directory.
        if version != default_version:
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['MENDER_ARTIFACT_EXTRA_ARGS = "-v %d"' % version],
            )
        else:
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
            )

        LAST_BUILD_VERSION = version
    return (
        version,
        latest_build_artifact(request, prepared_test_build["build_dir"],
                              "core-image*.mender"),
    )
Example #11
0
    def test_module_install(self, request, prepared_test_build, bitbake_path,
                            latest_rootfs, bitbake_image):
        mender_vars = get_bitbake_variables(request, "mender-client")
        if "modules" in mender_vars["PACKAGECONFIG"].split():
            originally_on = True
        else:
            originally_on = False

        output = subprocess.check_output(
            ["debugfs", "-R", "ls -p /usr/share/mender",
             latest_rootfs]).decode()
        entries = [
            elem.split("/")[5] for elem in output.split("\n")
            if elem.startswith("/")
        ]

        if originally_on:
            assert "modules" in entries
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['PACKAGECONFIG_remove = "modules"'],
            )
        else:
            assert "modules" not in entries
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['PACKAGECONFIG_append = " modules"'],
            )

        new_rootfs = latest_build_artifact(request,
                                           prepared_test_build["build_dir"],
                                           "core-image*.ext4")

        output = subprocess.check_output(
            ["debugfs", "-R", "ls -p /usr/share/mender", new_rootfs]).decode()
        entries = [
            elem.split("/")[5] for elem in output.split("\n")
            if elem.startswith("/")
        ]

        if originally_on:
            assert "modules" not in entries
        else:
            assert "modules" in entries
Example #12
0
    def test_image_rootfs_extra_space(self, request, prepared_test_build,
                                      bitbake_variables, bitbake_image):
        """Test that setting IMAGE_ROOTFS_EXTRA_SPACE to arbitrary values does
        not break the build."""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_ROOTFS_EXTRA_SPACE_append = " + 640 - 222 + 900"'],
        )

        built_rootfs = latest_build_artifact(request,
                                             prepared_test_build["build_dir"],
                                             "core-image*.ext4")

        assert (os.stat(built_rootfs).st_size == int(
            bitbake_variables["MENDER_CALC_ROOTFS_SIZE"]) * 1024)
Example #13
0
    def test_build_artifact_depends_and_provides(self, request,
                                                 prepared_test_build,
                                                 bitbake_image, bitbake_path,
                                                 dependsprovides):
        """Test whether a build with enabled Artifact Provides and Depends does
        indeed add the parameters to the built Artifact"""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [param for param in str(dependsprovides).splitlines()],
        )

        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "core-image*.mender")

        output = run_verbose("mender-artifact read %s" % image,
                             capture=True).decode()
        other = TestBuild.BuildDependsProvides.parse(output)

        # MEN-2956: Mender-Artifact now writes rootfs-image-checksum by default.
        # MEN-3482: The new key for the rootfs image checksum is rootfs-image.checksum
        assert (
            "rootfs-image.checksum" in other.provides
            or "rootfs_image_checksum" in other.provides
        ), "Empty rootfs_image_checksum in the built rootfs-image artifact, this should be added by default by `mender-artifact write rootfs-image`"
        # Then remove it, not to mess up the expected test output
        if "rootfs-image.checksum" in other.provides.keys():
            del other.provides["rootfs-image.checksum"]
        if "rootfs_image_checksum" in other.provides.keys():
            del other.provides["rootfs_image_checksum"]

        # MEN-3076: Mender-Artifacts writes software version by default
        # older versions did not, thus we remove the key before asserting the content
        if "rootfs-image.version" in other.provides.keys():
            del other.provides["rootfs-image.version"]

        assert dependsprovides.__dict__ == other.__dict__
Example #14
0
    def test_bootimg_creation(
        self, request, bitbake_variables, prepared_test_build, bitbake_image
    ):
        """Test that we can build a bootimg successfully."""

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_FSTYPES = "bootimg"'],
        )

        built_img = latest_build_artifact(
            request, prepared_test_build["build_dir"], "core-image*.bootimg"
        )

        distro_features = bitbake_variables["MENDER_FEATURES"].split()
        if "mender-grub" in distro_features and "mender-image-uefi" in distro_features:
            output = subprocess.check_output(
                ["mdir", "-i", built_img, "-b", "/EFI/BOOT"]
            ).decode()
            assert "mender_grubenv1" in output.split("/")
Example #15
0
    def test_build_addon(
        self, request, bitbake_variables, prepared_test_build, bitbake_image
    ):
        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_INSTALL_append = " mender-monitor"'],
            [
                'BBLAYERS_append = " %s/../meta-mender-commercial"'
                % bitbake_variables["LAYERDIR_MENDER"]
            ],
        )
        image = latest_build_artifact(
            request, prepared_test_build["build_dir"], "core-image*.ext4"
        )

        for expected_node in (
            "/usr/bin/mender-monitorctl",
            "/usr/bin/mender-monitord",
            "/etc/mender-monitor/monitor.d/log.sh",
            "/etc/mender-monitor/monitor.d/service.sh",
            "/usr/share/mender-monitor/mender-monitorctl",
            "/usr/share/mender-monitor/mender-monitord",
            "/usr/share/mender-monitor/ctl.sh",
            "/usr/share/mender-monitor/daemon.sh",
            "/usr/share/mender-monitor/common/common.sh",
            "/usr/share/mender-monitor/config/config.sh",
            "/usr/share/mender-monitor/lib/monitor-lib.sh",
            "/usr/share/mender-monitor/lib/service-lib.sh",
            "/var/lib/mender-monitor",
        ):
            output = subprocess.check_output(
                ["debugfs", "-R", "stat %s" % expected_node, image]
            ).decode()

            # The nodes are either files or symlinks
            assert "Type: regular" in output or "Type: symlink" in output
    def test_build_mender_gateway(self, request, bitbake_variables,
                                  prepared_test_build, bitbake_image):
        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_INSTALL_append = " mender-gateway"'],
            [
                'BBLAYERS_append = " %s/../meta-mender-commercial"' %
                bitbake_variables["LAYERDIR_MENDER"]
            ],
        )
        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "core-image*.ext4")

        for file in (
                "/usr/bin/mender-gateway",
                "/usr/share/mender/inventory/mender-inventory-mender-gateway",
        ):
            output = subprocess.check_output(
                ["debugfs", "-R", f"stat {file}", image]).decode()
            assert "Type: regular" in output
Example #17
0
    def do_install_mender_binary_delta(
        self,
        request,
        prepared_test_build,
        bitbake_variables,
        bitbake_image,
        connection,
        http_server,
        board_type,
        use_s3,
        s3_address,
    ):
        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['IMAGE_INSTALL_append = " mender-binary-delta"'],
            [
                'BBLAYERS_append = " %s/../meta-mender-commercial"' %
                bitbake_variables["LAYERDIR_MENDER"]
            ],
        )

        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "core-image*.mender")

        Helpers.install_update(image, connection, http_server, board_type,
                               use_s3, s3_address)

        reboot(connection)

        run_after_connect("true", connection)
        connection.run("mender -commit")

        return image
Example #18
0
    def test_equal_checksum_ubimg_and_artifact(self, request,
                                               prepared_test_build,
                                               bitbake_image):

        # See ubimg_without_uboot_env() for why this is needed. We need to do it
        # explicitly here because we need both the artifact and the ubimg.

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            ['MENDER_FEATURES_DISABLE_append = " mender-uboot"'],
        )

        bufsize = 1048576  # 1MiB
        with tempfile.NamedTemporaryFile() as tmp_artifact:
            latest_mender_image = latest_build_artifact(
                request, prepared_test_build["build_dir"], "*.mender")
            subprocess.check_call(
                "tar xOf %s data/0000.tar.gz | tar xzO > %s" %
                (latest_mender_image, tmp_artifact.name),
                shell=True,
            )
            size = os.stat(tmp_artifact.name).st_size
            hash = hashlib.md5()
            while True:
                buf = tmp_artifact.read(bufsize)
                if len(buf) == 0:
                    break
                hash.update(buf)
            artifact_hash = hash.hexdigest()
            artifact_info = subprocess.check_output(
                ["ubireader_display_info", tmp_artifact.name])
            artifact_ls = subprocess.check_output(
                ["ls", "-l", tmp_artifact.name])

        tmpdir = tempfile.mkdtemp()
        try:
            ubifsdir = extract_ubimg_images(
                latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "*.ubimg"),
                tmpdir,
            )
            rootfsa = os.path.join(ubifsdir, [
                img for img in os.listdir(ubifsdir) if "rootfsa" in img
            ][0])
            bytes_read = 0
            hash = hashlib.md5()
            with open(rootfsa, "rb") as fd:
                while bytes_read < size:
                    buf = fd.read(min(size - bytes_read, bufsize))
                    if len(buf) == 0:
                        break
                    bytes_read += len(buf)
                    hash.update(buf)
                image_hash = hash.hexdigest()
            image_info = subprocess.check_output(
                ["ubireader_display_info", rootfsa])
            image_ls = subprocess.check_output(["ls", "-l", rootfsa])
        finally:
            shutil.rmtree(tmpdir)

        assert artifact_info == image_info
        assert artifact_hash == image_hash, "Artifact:\n%s\nImage:\n%s" % (
            artifact_ls,
            image_ls,
        )
Example #19
0
    def test_perform_update(
        self,
        request,
        setup_board,
        prepared_test_build,
        bitbake_variables,
        bitbake_image,
        connection,
        http_server,
        board_type,
        use_s3,
        s3_address,
    ):
        """Perform a delta update.

        """

        if ("read-only-rootfs"
                not in bitbake_variables["IMAGE_FEATURES"].strip().split()):
            pytest.skip("Only works when using read-only-rootfs IMAGE_FEATURE")

        if distutils.spawn.find_executable(
                "mender-binary-delta-generator") is None:
            pytest.fail("mender-binary-delta-generator not found in PATH")

        built_artifact = self.do_install_mender_binary_delta(
            request,
            prepared_test_build,
            bitbake_variables,
            bitbake_image,
            connection,
            http_server,
            board_type,
            use_s3,
            s3_address,
        )

        with make_tempdir() as tmpdir:
            # Copy previous build
            artifact_from = os.path.join(tmpdir, "artifact_from.mender")
            shutil.copyfile(built_artifact, artifact_from)

            # Create new image installing some extra software
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['IMAGE_INSTALL_append = " nano"'],
            )
            built_artifact = latest_build_artifact(
                request, prepared_test_build["build_dir"],
                "core-image*.mender")
            artifact_to = os.path.join(tmpdir, "artifact_to.mender")
            shutil.copyfile(built_artifact, artifact_to)

            # Create delta Artifact using mender-binary-delta-generator
            artifact_delta = os.path.join(tmpdir, "artifact_delta.mender")
            subprocess.check_call(
                f"mender-binary-delta-generator -n v2.0-deltafrom-v1.0 {artifact_from} {artifact_to} -o {artifact_delta}",
                shell=True,
            )

            # Verbose provides/depends of the different Artifacts and the client (when supported)
            connection.run("mender show-provides", warn=True)
            subprocess.check_call(
                "mender-artifact read %s" % artifact_from,
                shell=True,
            )
            subprocess.check_call(
                "mender-artifact read %s" % artifact_to,
                shell=True,
            )
            subprocess.check_call(
                "mender-artifact read %s" % artifact_delta,
                shell=True,
            )

            # Install Artifact, verify partitions and commit
            (active,
             passive) = determine_active_passive_part(bitbake_variables,
                                                      connection)
            Helpers.install_update(artifact_delta, connection, http_server,
                                   board_type, use_s3, s3_address)
            reboot(connection)
            run_after_connect("true", connection)
            (new_active, new_passive) = determine_active_passive_part(
                bitbake_variables, connection)
            assert new_active == passive
            assert new_passive == active
            connection.run("mender -commit")
Example #20
0
    def test_state_scripts(
        self,
        request,
        prepared_test_build,
        bitbake_variables,
        bitbake_path,
        latest_rootfs,
        latest_mender_image,
        bitbake_image,
    ):
        """Test that state scripts that are specified in the build are included
        correctly."""

        # First verify that the base build does *not* contain any state scripts.
        # Check rootfs.
        output = subprocess.check_output(
            ["debugfs", "-R", "ls -p /etc/mender", latest_rootfs]).decode()
        for line in output.split("\n"):
            if len(line) == 0:
                continue

            entry = line.split("/")
            if entry[5] == "scripts":
                # The scripts directory exists. That is fine in itself, but it
                # should not contain any script files ("version" is allowed).
                output = subprocess.check_output([
                    "debugfs", "-R", "ls -p /etc/mender/scripts", latest_rootfs
                ]).decode()
                for line in output.split("\n"):
                    if len(line) == 0:
                        continue

                    entry = line.split("/")
                    assert (
                        entry[5] == "." or entry[5] == ".."
                        or entry[5] == "version"
                    ), "There should be no script file in /etc/mender/scripts"
                break

        # Check artifact.
        output = subprocess.check_output("tar xOf %s header.tar.gz| tar tz" %
                                         latest_mender_image,
                                         shell=True).decode()
        for line in output.strip().split("\n"):
            if line == "scripts":
                output = subprocess.check_output(
                    "tar xOf %s header.tar.gz| tar tz scripts" %
                    latest_mender_image,
                    shell=True,
                ).decode()
                assert len(output.strip()) == 0, (
                    "Unexpected scripts in base image: %s" % output)

        try:
            # Alright, now build a new image containing scripts.
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['IMAGE_INSTALL_append = " example-state-scripts"'],
            )

            found_rootfs_scripts = {
                "version": False,
                "Idle_Enter_00": False,
                "Sync_Enter_10": False,
                "Sync_Leave_90": False,
            }
            found_artifact_scripts = {
                "ArtifactInstall_Enter_00": False,
                "ArtifactInstall_Leave_99": False,
                "ArtifactReboot_Leave_50": False,
                "ArtifactCommit_Enter_50": False,
                "ArtifactCommit_Leave_50": False,
            }

            # Check new rootfs.
            built_rootfs = latest_build_artifact(
                request, prepared_test_build["build_dir"],
                "core-image*.ext[234]")
            output = subprocess.check_output(
                ["debugfs", "-R", "ls -p /etc/mender/scripts",
                 built_rootfs]).decode()
            for line in output.split("\n"):
                if len(line) == 0:
                    continue

                entry = line.split("/")

                if entry[5] == "." or entry[5] == "..":
                    continue

                assert found_rootfs_scripts.get(
                    entry[5]) is not None, ("Unexpected script in rootfs %s" %
                                            entry[5])
                found_rootfs_scripts[entry[5]] = True

            for script in found_rootfs_scripts:
                assert found_rootfs_scripts[script], (
                    "%s not found in rootfs script list" % script)

            # Check new artifact.
            built_mender_image = latest_build_artifact(
                request, prepared_test_build["build_dir"],
                "core-image*.mender")
            output = subprocess.check_output(
                "tar xOf %s header.tar.gz| tar tz scripts" %
                built_mender_image,
                shell=True,
            ).decode()
            for line in output.strip().split("\n"):
                script = os.path.basename(line)
                assert found_artifact_scripts.get(script) is not None, (
                    "Unexpected script in image: %s" % script)
                found_artifact_scripts[script] = True

            for script in found_artifact_scripts:
                assert found_artifact_scripts[script], (
                    "%s not found in artifact script list" % script)

        finally:
            # Clean up the state scripts directory. Ideally this wouldn't be
            # necessary, but unfortunately bitbake does not clean up deployment
            # files from recipes that are not included in the current build, so
            # we have to do it manually.
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                target="-c clean example-state-scripts",
            )
Example #21
0
    def test_boot_partition_population(self, request, prepared_test_build,
                                       bitbake_path, bitbake_image):
        # Notice in particular a mix of tabs, newlines and spaces. All there to
        # check that whitespace it treated correctly.

        build_image(
            prepared_test_build["build_dir"],
            prepared_test_build["bitbake_corebase"],
            bitbake_image,
            [
                """
IMAGE_INSTALL_append = " test-boot-files"

IMAGE_BOOT_FILES_append = " deployed-test1 deployed-test-dir2/deployed-test2 \
    deployed-test3;renamed-deployed-test3 \
 deployed-test-dir4/deployed-test4;renamed-deployed-test4	deployed-test5;renamed-deployed-test-dir5/renamed-deployed-test5 \
deployed-test-dir6/deployed-test6;renamed-deployed-test-dir6/renamed-deployed-test6 \
deployed-test-dir7/* \
deployed-test-dir8/*;./ \
deployed-test-dir9/*;renamed-deployed-test-dir9/ \
"
"""
            ],
        )

        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"],
                                      "core-image*.*img")
        extract_partition(image, 1)
        try:
            listing = (run_verbose("mdir -i img1.fs -b -/",
                                   capture=True).decode().split())
            expected = [
                "::/deployed-test1",
                "::/deployed-test2",
                "::/renamed-deployed-test3",
                "::/renamed-deployed-test4",
                "::/renamed-deployed-test-dir5/renamed-deployed-test5",
                "::/renamed-deployed-test-dir6/renamed-deployed-test6",
                "::/deployed-test7",
                "::/deployed-test8",
                "::/renamed-deployed-test-dir9/deployed-test9",
            ]
            assert all([item in listing for item in expected])

            # Conflicting file with the same content should pass.
            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                ['IMAGE_BOOT_FILES_append = " conflict-test1"'],
            )

            # Conflicting file with different content should fail.
            try:
                build_image(
                    prepared_test_build["build_dir"],
                    prepared_test_build["bitbake_corebase"],
                    bitbake_image,
                    ['IMAGE_BOOT_FILES_append = " conflict-test2"'],
                )
                pytest.fail(
                    "Bitbake succeeded, but should have failed with a file conflict"
                )
            except subprocess.CalledProcessError:
                pass
        finally:
            os.remove("img1.fs")
Example #22
0
    def test_extra_parts(self, request, latest_part_image, prepared_test_build,
                         bitbake_image):
        sdimg = latest_part_image.endswith(".sdimg")
        uefiimg = latest_part_image.endswith(".uefiimg")
        gptimg = latest_part_image.endswith(".gptimg")
        biosimg = latest_part_image.endswith(".biosimg")

        with make_tempdir() as tmpdir1, make_tempdir(
        ) as tmpdir2, make_tempdir() as tmpdir3, make_tempdir() as tmpdir4:
            with open(os.path.join(tmpdir1, "tmpfile1"), "w") as fd:
                fd.write("Test content1\n")
            with open(os.path.join(tmpdir2, "tmpfile2"), "w") as fd:
                fd.write("Test content2\n")
            with open(os.path.join(tmpdir3, "tmpfile3"), "w") as fd:
                fd.write("Test content3\n")
            with open(os.path.join(tmpdir4, "tmpfile4"), "w") as fd:
                fd.write("Test content4\n")

            build_image(
                prepared_test_build["build_dir"],
                prepared_test_build["bitbake_corebase"],
                bitbake_image,
                [
                    'MENDER_EXTRA_PARTS = "test1 test2 test3 test4"',
                    'MENDER_EXTRA_PARTS[test1] = "--fixed-size 100M --label=test1 --fstype=ext4 --source rootfs --rootfs-dir %s"'
                    % tmpdir1,
                    'MENDER_EXTRA_PARTS[test2] = "--fixed-size 50M --fstype=ext4 --source rootfs --rootfs-dir %s --label=test2"'
                    % tmpdir2,
                    'MENDER_EXTRA_PARTS[test3] = "--fixed-size 50M --fstype=ext4 --source rootfs --rootfs-dir %s --label=test3"'
                    % tmpdir3,
                    'MENDER_EXTRA_PARTS[test4] = "--fixed-size 50M --fstype=ext4 --source rootfs --rootfs-dir %s --label=test4"'
                    % tmpdir4,
                    'MENDER_EXTRA_PARTS_FSTAB[test1] = "auto nouser"',
                    'MENDER_EXTRA_PARTS_FSTAB[test2] = "ext4 default,ro"',
                    'MENDER_EXTRA_PARTS_FSTAB[test3] = "ext4 default,ro 1"',
                    'MENDER_EXTRA_PARTS_FSTAB[test4] = "ext4 default,ro 1 0"',
                ],
            )

        image = latest_build_artifact(request,
                                      prepared_test_build["build_dir"], "*img")

        # Take extended partition into account for MBR partition tables.
        if uefiimg or gptimg:
            # Example
            # 1           16384           49151   16.0 MiB    0700  Microsoft basic data
            # 2           49152          507903   224.0 MiB   8300  Linux filesystem
            # 3          507904          966655   224.0 MiB   8300  Linux filesystem
            # 4          983040         1245183   128.0 MiB   8300  Linux filesystem
            # 5         1261568         1466367   100.0 MiB   8300  Linux filesystem
            # 6         1474560         1679359   100.0 MiB   8300  Linux filesystem
            output = subprocess.check_output(["sgdisk", "-p", image]).decode()
            test1_re = r"^\s*5\s+([0-9]+)\s+([0-9]+)\s+100.0\s+MiB\s+8300\s+"
            test2_re = r"^\s*6\s+([0-9]+)\s+([0-9]+)\s+50.0\s+MiB\s+8300\s+"
            test3_re = r"^\s*7\s+([0-9]+)\s+([0-9]+)\s+50.0\s+MiB\s+8300\s+"
            test4_re = r"^\s*8\s+([0-9]+)\s+([0-9]+)\s+50.0\s+MiB\s+8300\s+"
            extra_start = 5
        else:
            # Example:
            # ...sdimg1 *      16384   49151   32768   16M  c W95 FAT32 (LBA)
            # ...sdimg2        49152  507903  458752  224M 83 Linux
            # ...sdimg3       507904  966655  458752  224M 83 Linux
            # ...sdimg4       983039 1576959  593921  290M  f W95 Ext'd (LBA)
            # ...sdimg5       983040 1245183  262144  128M 83 Linux
            # ...sdimg6      1261568 1466367  204800  100M 83 Linux
            # ...sdimg7      1474560 1576959  102400   50M 83 Linux
            output = subprocess.check_output(["fdisk", "-l", image]).decode()
            test1_re = r"img6(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+100M\s+83\s+"
            test2_re = r"img7(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+50M\s+83\s+"
            test3_re = r"img8(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+50M\s+83\s+"
            test4_re = r"img9(?:\s|\*)+([0-9]+)\s+([0-9]+)\s+[0-9]+\s+50M\s+83\s+"
            extra_start = 6

        match1 = re.search(test1_re, output, flags=re.MULTILINE)
        match2 = re.search(test2_re, output, flags=re.MULTILINE)
        match3 = re.search(test3_re, output, flags=re.MULTILINE)
        match4 = re.search(test4_re, output, flags=re.MULTILINE)
        assert match1 is not None
        assert match2 is not None
        assert match3 is not None
        assert match4 is not None

        ext4 = latest_build_artifact(request, prepared_test_build["build_dir"],
                                     "*.ext4")
        fstab = subprocess.check_output(
            ["debugfs", "-R", "cat /etc/fstab", ext4]).decode()

        # Example:
        # /dev/mmcblk0p5       /mnt/test1           auto       nouser                0  2
        # /dev/mmcblk0p6       /mnt/test2           auto       default,ro            0  2
        # /dev/mmcblk0p7       /mnt/test3           auto       default,ro            1  2
        # /dev/mmcblk0p8       /mnt/test4           auto       default,ro            1  0

        test1_re = (
            r"^/dev/[a-z0-9]+%d\s+/mnt/test1\s+auto\s+nouser\s+0\s+2\s*$" %
            extra_start)
        test2_re = r"^/dev/[a-z0-9]+%d\s+/mnt/test2\s+ext4\s+default,ro\s+0\s+2\s*$" % (
            extra_start + 1)
        test3_re = r"^/dev/[a-z0-9]+%d\s+/mnt/test3\s+ext4\s+default,ro\s+1\s+2\s*$" % (
            extra_start + 2)
        test4_re = r"^/dev/[a-z0-9]+%d\s+/mnt/test4\s+ext4\s+default,ro\s+1\s+0\s*$" % (
            extra_start + 3)
        assert re.search(test1_re, fstab, flags=re.MULTILINE) is not None
        assert re.search(test2_re, fstab, flags=re.MULTILINE) is not None
        assert re.search(test3_re, fstab, flags=re.MULTILINE) is not None
        assert re.search(test4_re, fstab, flags=re.MULTILINE) is not None