def test_share_layers_docker_image(docker_client, cli, datafiles, tmp_path):
    """
    We have the following dependency graphs:

    (1) multiple-deps.bst
        |-> layer1.bst
        |-> layer2.bst
        |-> layer3.bst

    (2) nested-deps.bst -> layer2-nest.bst -|
        |                                   V
        |------------------------->layer1.bst

    Test that both images share the layer associated with layer1.bst
    """
    test_element1 = "nested-overwrite.bst"
    test_element2 = "multiple-deps.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")
    checkout_dir1 = os.path.join(checkout_dir, "test1")
    checkout_dir2 = os.path.join(checkout_dir, "test2")

    build_and_checkout(test_element1, checkout_dir1, cli, project)
    build_and_checkout(test_element2, checkout_dir2, cli, project)

    tag1 = get_image_tag(load_image(docker_client, checkout_dir1))
    tag2 = get_image_tag(load_image(docker_client, checkout_dir2))

    fs1 = docker_client.images.get(tag1).attrs["RootFS"]["Layers"]
    fs2 = docker_client.images.get(tag2).attrs["RootFS"]["Layers"]

    # one of the layers should be shared
    assert len(set(fs1).intersection(set(fs2))) == 1
def test_custom_tag(docker_client, cli, datafiles, tmp_path):
    test_element = "diamond-deps.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")

    build_and_checkout(test_element, checkout_dir, cli, project)
    tag = get_image_tag(load_image(docker_client, checkout_dir))

    assert tag.split(":")[1] == "this-is-a-tag"
def test_default_tag(docker_client, cli, datafiles, tmp_path):
    test_element = "hello-world-image.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")

    build_and_checkout(test_element, checkout_dir, cli, project)
    tag = get_image_tag(load_image(docker_client, checkout_dir))

    assert tag.split(":")[1] == "latest"
def test_multiple_deps_docker_image(docker_client, cli, datafiles, tmp_path):
    test_element = "multiple-deps.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")

    build_and_checkout(test_element, checkout_dir, cli, project)
    tag = get_image_tag(load_image(docker_client, checkout_dir))

    image_attrs = docker_client.images.get(tag).attrs
    assert len(image_attrs["RootFS"]["Layers"]) == 3
    _test_no_file_duplication(
        _get_layer_files(untar(os.path.join(checkout_dir, "image.tar"))))
def test_multiple_tags(docker_client, cli, datafiles, tmp_path):
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")
    expected_tags = [
        "bst-plugins-container-tests/multiple-tags/name1:tag1",
        "bst-plugins-container-tests/multiple-tags/name1:tag2",
        "bst-plugins-container-tests/multiple-tags/name2:tag1",
        "bst-plugins-container-tests/multiple-tags/name2:tag2",
        "bst-plugins-container-tests/multiple-tags/name3:tag6",
    ]

    build_and_checkout("multiple-tags.bst", checkout_dir, cli, project)
    tags = load_image(docker_client, checkout_dir)[0].tags

    assert sorted(tags) == sorted(expected_tags)
def test_diamond_deps_docker_image(docker_client, cli, datafiles, tmp_path):
    test_element = "diamond-deps.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")

    build_and_checkout(test_element, checkout_dir, cli, project)
    tag = get_image_tag(load_image(docker_client, checkout_dir))
    _check_meta_data(docker_client, tag)

    image_attrs = docker_client.images.get(tag).attrs
    assert len(image_attrs["RootFS"]["Layers"]) == 2

    # assert that there is no file duplication
    layer_files = _get_layer_files(
        untar(os.path.join(checkout_dir, "image.tar")))
    _test_no_file_duplication(layer_files)
def test_single_build_dep_docker_image(cli, docker_client, datafiles,
                                       tmp_path):
    test_element = "hello-world-image.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")
    hello_exec = os.path.join(project, "files", "hello-world-image-fs",
                              "hello")

    # need to reset permission as copying files into `DATA_DIR` changes permissions
    os.chmod(hello_exec, READ_WRITE_USER_PERMISSION)

    build_and_checkout(test_element, checkout_dir, cli, project)
    tag = get_image_tag(load_image(docker_client, checkout_dir))

    # compare output of docker run
    output = docker_client.containers.run(tag).decode("utf-8")
    with open(os.path.join(project, "files",
                           "hello-world_output.txt")) as expected_output:
        assert output == expected_output.read()

    _check_meta_data(docker_client, tag)
def test_correct_checksum_docker_image(cli, datafiles, tmp_path):
    test_element = "multiple-deps.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")

    build_and_checkout(test_element, checkout_dir, cli, project)
    extract_path = untar(os.path.join(checkout_dir, "image.tar"))

    # check config file is correctly named
    config_json = [
        file for file in os.listdir(extract_path)
        if file.endswith(".json") and file != "manifest.json"
    ][0]
    assert config_json == "{}.json".format(
        hash_digest(os.path.join(extract_path, config_json)))

    # check each directory is correctly named
    for layer in os.listdir(extract_path):
        if os.path.isdir(layer):
            assert os.path.basename(layer) == hash_digest(
                os.path.join(layer, "layer.tar"))
def test_nested_overwrite_docker_image(docker_client, cli, datafiles,
                                       tmp_path):
    # pylint: disable=too-many-locals

    test_element = "nested-overwrite.bst"
    project = str(datafiles)
    checkout_dir = os.path.join(str(tmp_path), "checkout")
    container_fs_export_dir = os.path.join(str(tmp_path), "fs_extract")
    exported_tar = os.path.join(container_fs_export_dir, "image.tar")
    os.makedirs(container_fs_export_dir)

    build_and_checkout(test_element, checkout_dir, cli, project)
    tag = get_image_tag(load_image(docker_client, checkout_dir))

    image_attrs = docker_client.images.get(tag).attrs
    assert len(image_attrs["RootFS"]["Layers"]) == 2

    # assert that file is indeed overwritten
    extract_path = untar(os.path.join(checkout_dir, "image.tar"))
    assert (_get_number_of_file_duplications(
        _get_layer_files(extract_path)) == 2)

    # check overwritten file is content is as expected
    container = docker_client.containers.create(tag, command="/bin/sh")
    with open(exported_tar, "wb+") as tar_handle:
        for chunk in container.export():
            tar_handle.write(chunk)
    with tarfile.open(exported_tar) as tar_handle:
        tar_handle.extractall(path=container_fs_export_dir)

    try:
        with open(os.path.join(container_fs_export_dir, "layer1",
                               "hello.txt")) as produced_file:
            with open(
                    os.path.join(project, "files", "layers", "layer2",
                                 "hello.txt")) as actual_file:
                assert produced_file.read() == actual_file.read()
    except FileNotFoundError:
        assert False
Beispiel #10
0
def test_filesystem_equality(cli, datafiles, docker_client, docker_registry,
                             tmp_path):
    # pylint: disable=too-many-locals
    """
    Check that creating a docker_image from a base filesystem, and reimporting
    this image as a docker_source results in the same filesystem.
    """

    project = str(datafiles)
    file_system = os.path.join("files", "layers")
    yaml = YAML()
    yaml.default_flow_style = False
    client_to_registry = "{}:5000".format(get_docker_host(docker_client))

    # create example-tar.bst
    local_fs = "local-fs.bst"
    local_fs_element = {
        "kind": "import",
        "sources": [{
            "kind": "local",
            "path": "./{}".format(file_system)
        }],
    }
    create_element(yaml, local_fs, local_fs_element, project)

    image_name = "example-image"

    # create example-image.bst
    example_image = "example-image.bst"

    example_image_element = {
        "kind": "docker_image",
        "config": {
            "image-names": [
                "{}:latest".format(image_name),
                "bst-plugins-container-tests/{}:latest".format(image_name),
            ]
        },
        "build-depends": [local_fs],
    }
    create_element(yaml, example_image, example_image_element, project)

    # checkout and push image
    image_checkout_dir = os.path.join(str(tmp_path), "image_checkout")
    build_and_checkout(example_image, image_checkout_dir, cli, project)
    load_image(docker_client, image_checkout_dir)
    push_image(docker_client, docker_registry, image_name)

    # create docker source element
    docker_source = "example-image-source.bst"

    docker_source_element = {
        "kind":
        "import",
        "sources": [{
            "kind": "docker",
            "registry-url": "http://{}".format(client_to_registry),
            "image": image_name,
            "track": "latest",
        }],
    }
    create_element(yaml, docker_source, docker_source_element, project)

    # source track Docker-sourced import element
    result = cli.run(project=project, args=["source", "track", docker_source])
    result.assert_success()

    # build Docker-sourced import element
    tar_checkout_dir = os.path.join(str(tmp_path), "tar_checkout")
    build_and_checkout(docker_source, tar_checkout_dir, cli, project)

    # assert files systems are equal
    layers_dir = os.path.join(project, "files", "layers")
    assert os.listdir(tar_checkout_dir) == os.listdir(layers_dir)
    # assert file systems have the same contents
    _compare_directory_files(layers_dir, tar_checkout_dir)
Beispiel #11
0
def test_image_equality(cli, datafiles, tmp_path):
    # pylint: disable=too-many-locals
    """
    Check that the filesystem of a rebuilt image built from an imported third-party image,
    results in the filesystem of the third-party image.
    """
    project = str(datafiles)
    yaml = YAML()
    yaml.default_flow_style = False

    # build and checkout hello-world image
    hello_world_source = "hello-world-image-source.bst"
    hello_world_source_element = {
        "kind":
        "import",
        "sources": [{
            "kind": "docker",
            "image": "library/hello-world",
            "track": "latest",
        }],
    }
    create_element(yaml, hello_world_source, hello_world_source_element,
                   project)

    hello_world_checkout_rel_dir = os.path.join("files", "hello-world")
    hello_world_checkout_dir = os.path.join(project,
                                            hello_world_checkout_rel_dir)
    result = cli.run(project=project,
                     args=["source", "track", hello_world_source])
    result.assert_success()
    build_and_checkout(hello_world_source, hello_world_checkout_dir, cli,
                       project)

    # build image from extracted fs
    # create elements
    import_hello_world = "import-hello-world.bst"
    import_hello_world_element = {
        "kind":
        "import",
        "sources": [{
            "kind": "local",
            "path": "./{}".format(hello_world_checkout_rel_dir),
        }],
    }
    create_element(yaml, import_hello_world, import_hello_world_element,
                   project)

    hello_world_rebuild = "hello-world-image-rebuild.bst"
    hello_world_rebuild_element = {
        "kind": "docker_image",
        "config": {
            "image-names":
            ["bst-plugins-container-tests/hello-world-rebuild:latest"]
        },
        "build-depends": [import_hello_world],
    }
    create_element(yaml, hello_world_rebuild, hello_world_rebuild_element,
                   project)

    # build image
    rebuilt_image_checkout_dir = os.path.join(str(tmp_path),
                                              "rebuilt_image_checkout_dir")
    build_and_checkout(hello_world_rebuild, rebuilt_image_checkout_dir, cli,
                       project)

    # get layer filesystem
    untar_dir = untar(os.path.join(rebuilt_image_checkout_dir, "image.tar"))
    layer_dir = [
        os.path.join(untar_dir, layer_dir)
        for layer_dir in os.listdir(untar_dir)
        if os.path.isdir(os.path.join(untar_dir, layer_dir))
    ][0]
    layer_untar_dir = untar(os.path.join(layer_dir, "layer.tar"))

    # assert file systems are equal and have the same contents
    _compare_directory_files(layer_untar_dir, hello_world_checkout_dir)