Example #1
0
def stage_deps(target, args):
    """Pull image dependencies into the `img` store.

    Arguments:
        target (taskboot.target.Target): Target
        args (argparse.Namespace): CLI arguments

    Returns:
        None
    """
    create_cert(CA_KEY, CA_CRT, ca=True)
    create_cert(SRV_KEY, SRV_CRT, ca_key=CA_KEY, ca_cert=CA_CRT)
    img_tool = Img(cache=args.cache)

    # retrieve image archives from dependency tasks to /images
    image_path = Path(mkdtemp(prefix="image-deps-"))
    try:
        config = Configuration(Namespace(secret=None, config=None))
        queue = taskcluster.Queue(config.get_taskcluster_options())

        # load images into the img image store via Docker registry
        with Registry():
            for task_id, artifact_name in load_artifacts(
                    args.task_id, queue, "public/**.tar.zst"):
                img = download_artifact(queue, task_id, artifact_name,
                                        image_path)
                image_name = Path(artifact_name).stem
                check_call([
                    "skopeo",
                    "copy",
                    f"docker-archive:{img}",
                    f"docker://localhost/mozillasecurity/{image_name}:latest",
                ])
                img.unlink()
                img_tool.run(
                    ["pull", f"localhost/mozillasecurity/{image_name}:latest"])
                img_tool.run([
                    "tag",
                    f"localhost/mozillasecurity/{image_name}:latest",
                    f"{args.registry}/mozillasecurity/{image_name}:latest",
                ])
                img_tool.run([
                    "tag",
                    f"localhost/mozillasecurity/{image_name}:latest",
                    (f"{args.registry}/mozillasecurity/"
                     f"{image_name}:{args.git_revision}"),
                ])
    finally:
        rmtree(image_path)

    # workaround https://github.com/genuinetools/img/issues/206
    patch_dockerfile(target.check_path(args.dockerfile),
                     img_tool.list_images())
Example #2
0
def build_image(target, args):
    """
    Build a docker image and allow save/push
    """
    if args.build_tool == "img":
        build_tool = Img(cache=args.cache)
    elif args.build_tool == "docker":
        build_tool = Docker()
    else:
        raise ValueError("Unsupported build tool: {}".format(args.build_tool))

    # Load config from file/secret
    config = Configuration(args)

    # Check the dockerfile is available in target
    dockerfile = target.check_path(args.dockerfile)

    # Check the output is writable
    output = None
    if args.write:
        output = os.path.realpath(args.write)
        assert output.lower().endswith(
            ".tar"), "Destination path must ends in .tar"
        assert os.access(os.path.dirname(output),
                         os.W_OK | os.W_OK), "Destination is not writable"

    # Build the tags
    base_image = args.image or "taskboot-{}".format(uuid.uuid4())
    tags = gen_docker_images(base_image, args.tag, args.registry)

    if args.push:
        assert config.has_docker_auth(), "Missing Docker authentication"
        registry = config.docker["registry"]

        if registry != args.registry:
            msg = "The credentials are the ones for %r not %r"
            logger.warning(msg, registry, args.registry)

        # Login on docker
        build_tool.login(registry, config.docker["username"],
                         config.docker["password"])

    # Build the image
    build_tool.build(target.dir, dockerfile, tags, args.build_arg)

    # Write the produced image
    if output:
        build_tool.save(tags, output)

    # Push the produced image
    if args.push:
        for tag in tags:
            build_tool.push(tag)
Example #3
0
def build_compose(target, args):
    """
    Read a compose file and build each image described as buildable
    """
    assert args.build_retries > 0, "Build retries must be a positive integer"
    build_tool = Img(cache=args.cache)

    # Check the dockerfile is available in target
    composefile = target.check_path(args.composefile)

    # Check compose file has version >= 3.0
    compose = yaml.load(open(composefile))
    version = compose.get("version")
    assert version is not None, "Missing version in {}".format(composefile)
    assert compose["version"].startswith(
        "3."), "Only docker compose version 3 is supported"

    # Check output folder
    output = None
    if args.write:
        output = os.path.realpath(args.write)
        os.makedirs(output, exist_ok=True)
        logger.info("Will write images in {}".format(output))

    # Load services
    services = compose.get("services")
    assert isinstance(services, dict), "Missing services"

    # All paths are relative to the dockerfile folder
    root = os.path.dirname(composefile)

    for name, service in services.items():
        build = service.get("build")
        if build is None:
            logger.info(
                "Skipping service {}, no build declaration".format(name))
            continue

        if args.service and name not in args.service:
            msg = "Skipping service {}, building only {}".format(
                name, args.service)
            logger.info(msg)
            continue

        # Build the image
        logger.info("Building image for service {}".format(name))
        context = os.path.realpath(
            os.path.join(root, build.get("context", ".")))
        dockerfile = os.path.realpath(
            os.path.join(context, build.get("dockerfile", "Dockerfile")))

        # We need to replace the FROM statements by their local versions
        # to avoid using the remote repository first
        patch_dockerfile(dockerfile, build_tool.list_images())

        docker_image = service.get("image", name)
        tags = gen_docker_images(docker_image, args.tag, args.registry)

        retry(
            lambda: build_tool.build(context, dockerfile, tags, args.build_arg
                                     ),
            wait_between_retries=1,
            retries=args.build_retries,
        )

        # Write the produced image
        if output:
            build_tool.save(tags, os.path.join(output, "{}.tar".format(name)))

    logger.info("Compose file fully processed.")