예제 #1
0
def test_docker_binary_push_image(docker_path: str,
                                  docker: DockerBinary) -> None:
    assert docker.push_image(()) is None

    image_ref = "registry/repo/name:tag"
    push_request = docker.push_image((image_ref, ))
    assert push_request == Process(
        argv=(docker_path, "push", image_ref),
        cache_scope=ProcessCacheScope.PER_SESSION,
        description="",  # The description field is marked `compare=False`
    )
    assert push_request.description == f"Pushing docker image {image_ref}"
예제 #2
0
async def push_docker_images(
    request: PublishDockerImageRequest, docker: DockerBinary, options: DockerOptions
) -> PublishProcesses:
    tags = tuple(
        chain.from_iterable(
            cast(BuiltDockerImage, image).tags
            for pkg in request.packages
            for image in pkg.artifacts
        )
    )

    if request.field_set.skip_push.value:
        return PublishProcesses(
            [
                PublishPackages(
                    names=tags,
                    description=f"(by `{request.field_set.skip_push.alias}` on {request.field_set.address})",
                ),
            ]
        )

    env = await Get(Environment, EnvironmentRequest(options.env_vars))
    processes = zip(tags, docker.push_image(tags, env))
    return PublishProcesses(
        [
            PublishPackages(
                names=(tag,),
                process=InteractiveProcess.from_process(process),
            )
            for tag, process in processes
        ]
    )
예제 #3
0
파일: publish.py 프로젝트: hephex/pants
async def push_docker_images(
    request: PublishDockerImageRequest, docker: DockerBinary, options: DockerOptions
) -> PublishProcesses:
    tags = tuple(
        chain.from_iterable(
            cast(BuiltDockerImage, image).tags
            for pkg in request.packages
            for image in pkg.artifacts
        )
    )

    if request.field_set.skip_push.value:
        return PublishProcesses(
            [
                PublishPackages(
                    names=tags,
                    description=f"(by `{request.field_set.skip_push.alias}` on {request.field_set.address})",
                ),
            ]
        )

    process = docker.push_image(tags)
    return PublishProcesses(
        [
            PublishPackages(
                names=tags,
                process=InteractiveProcess.from_process(process) if process else None,
            ),
        ]
    )
예제 #4
0
async def docker_image_run_request(
    field_set: DockerFieldSet, docker: DockerBinary, options: DockerOptions
) -> RunRequest:
    env, image = await MultiGet(
        Get(Environment, EnvironmentRequest(options.env_vars)),
        Get(BuiltPackage, PackageFieldSet, field_set),
    )
    tag = cast(BuiltDockerImage, image.artifacts[0]).tags[0]
    run = docker.run_image(tag, docker_run_args=options.run_args, env=env)

    return RunRequest(args=run.argv, digest=image.digest, extra_env=run.env)
예제 #5
0
def test_docker_binary_run_image(docker_path: str,
                                 docker: DockerBinary) -> None:
    image_ref = "registry/repo/name:tag"
    port_spec = "127.0.0.1:80:8080/tcp"
    run_request = docker.run_image(image_ref,
                                   docker_run_args=("-p", port_spec),
                                   image_args=("test-input", ))
    assert run_request == Process(
        argv=(docker_path, "run", "-p", port_spec, image_ref, "test-input"),
        cache_scope=ProcessCacheScope.PER_SESSION,
        description="",  # The description field is marked `compare=False`
    )
    assert run_request.description == f"Running docker image {image_ref}"
예제 #6
0
async def push_docker_images(request: PublishDockerImageRequest,
                             docker: DockerBinary,
                             options: DockerOptions) -> PublishProcesses:
    tags = tuple(
        chain.from_iterable(
            cast(BuiltDockerImage, image).tags for pkg in request.packages
            for image in pkg.artifacts))

    if request.field_set.skip_push.value:
        return PublishProcesses([
            PublishPackages(
                names=tags,
                description=
                f"(by `{request.field_set.skip_push.alias}` on {request.field_set.address})",
            ),
        ])

    env = await Get(Environment, EnvironmentRequest(options.env_vars))
    skip_push = defaultdict(set)
    jobs: list[PublishPackages] = []
    refs: list[str] = []
    processes: list[Get] = []

    for tag in tags:
        for registry in options.registries().registries.values():
            if tag.startswith(registry.address) and registry.skip_push:
                skip_push[registry.alias].add(tag)
                break
        else:
            refs.append(tag)
            processes.append(
                Get(InteractiveProcess,
                    InteractiveProcessRequest(docker.push_image(tag, env))))

    interactive_processes = await MultiGet(processes)
    for ref, process in zip(refs, interactive_processes):
        jobs.append(PublishPackages(
            names=(ref, ),
            process=process,
        ))

    if skip_push:
        for name, skip_tags in skip_push.items():
            jobs.append(
                PublishPackages(
                    names=tuple(skip_tags),
                    description=f"(by `skip_push` on registry @{name})",
                ), )

    return PublishProcesses(jobs)
예제 #7
0
def test_docker_binary_build_image(docker_path: str,
                                   docker: DockerBinary) -> None:
    dockerfile = "src/test/repo/Dockerfile"
    digest = Digest(sha256().hexdigest(), 123)
    tags = (
        "test:0.1.0",
        "test:latest",
    )
    build_request = docker.build_image(tags, digest, dockerfile)

    assert build_request == Process(
        argv=(docker_path, "build", "-t", tags[0], "-t", tags[1], "-f",
              dockerfile, "."),
        input_digest=digest,
        cache_scope=ProcessCacheScope.PER_SESSION,
        description="",  # The description field is marked `compare=False`
    )
    assert build_request.description == "Building docker image test:0.1.0 +1 additional tag."
예제 #8
0
def test_docker_binary_build_image(docker_path: str,
                                   docker: DockerBinary) -> None:
    dockerfile = "src/test/repo/Dockerfile"
    digest = Digest(sha256().hexdigest(), 123)
    tags = (
        "test:0.1.0",
        "test:latest",
    )
    env = {"DOCKER_HOST": "tcp://127.0.0.1:1234"}
    build_request = docker.build_image(
        tags=tags,
        digest=digest,
        dockerfile=dockerfile,
        build_args=DockerBuildArgs.from_strings("arg1=2"),
        context_root="build/context",
        env=env,
        extra_args=("--pull", "--squash"),
    )

    assert build_request == Process(
        argv=(
            docker_path,
            "build",
            "--pull",
            "--squash",
            "--tag",
            tags[0],
            "--tag",
            tags[1],
            "--build-arg",
            "arg1=2",
            "--file",
            dockerfile,
            "build/context",
        ),
        env=env,
        input_digest=digest,
        cache_scope=ProcessCacheScope.PER_SESSION,
        description="",  # The description field is marked `compare=False`
    )
    assert build_request.description == "Building docker image test:0.1.0 +1 additional tag."
예제 #9
0
async def build_docker_image(
    field_set: DockerFieldSet,
    options: DockerOptions,
    docker: DockerBinary,
) -> BuiltPackage:
    context = await Get(
        DockerBuildContext,
        DockerBuildContextRequest(
            address=field_set.address,
            build_upstream_images=True,
        ),
    )

    tags = field_set.image_refs(
        default_repository=options.default_repository,
        registries=options.registries(),
        version_context=context.version_context,
    )

    result = await Get(
        ProcessResult,
        Process,
        docker.build_image(
            build_args=context.build_args,
            digest=context.digest,
            dockerfile=context.dockerfile,
            env=context.env,
            tags=tags,
        ),
    )

    logger.debug(f"Docker build output for {tags[0]}:\n"
                 f"{result.stdout.decode()}\n"
                 f"{result.stderr.decode()}")

    return BuiltPackage(
        result.output_digest,
        (BuiltDockerImage.create(tags), ),
    )
예제 #10
0
async def build_docker_image(
    field_set: DockerFieldSet,
    options: DockerOptions,
    global_options: GlobalOptions,
    docker: DockerBinary,
    process_cleanup: ProcessCleanupOption,
) -> BuiltPackage:
    context, wrapped_target = await MultiGet(
        Get(
            DockerBuildContext,
            DockerBuildContextRequest(
                address=field_set.address,
                build_upstream_images=True,
            ),
        ),
        Get(WrappedTarget, Address, field_set.address),
    )

    tags = field_set.image_refs(
        default_repository=options.default_repository,
        registries=options.registries(),
        interpolation_context=context.interpolation_context,
    )

    context_root = field_set.get_context_root(options.default_context_root)
    process = docker.build_image(
        build_args=context.build_args,
        digest=context.digest,
        dockerfile=context.dockerfile,
        context_root=context_root,
        env=context.build_env.environment,
        tags=tags,
        extra_args=tuple(
            get_build_options(
                context=context,
                field_set=field_set,
                global_target_stage_option=options.build_target_stage,
                target=wrapped_target.target,
            )),
    )
    result = await Get(FallibleProcessResult, Process, process)

    if result.exit_code != 0:
        maybe_msg = format_docker_build_context_help_message(
            address=field_set.address,
            context_root=context_root,
            context=context,
            colors=global_options.colors,
        )
        if maybe_msg:
            logger.warning(maybe_msg)

        raise ProcessExecutionFailure(
            result.exit_code,
            result.stdout,
            result.stderr,
            process.description,
            process_cleanup=process_cleanup.val,
        )

    image_id = parse_image_id_from_docker_build_output(result.stdout,
                                                       result.stderr)
    docker_build_output_msg = "\n".join((
        f"Docker build output for {tags[0]}:",
        "stdout:",
        result.stdout.decode(),
        "stderr:",
        result.stderr.decode(),
    ))

    if options.build_verbose:
        logger.info(docker_build_output_msg)
    else:
        logger.debug(docker_build_output_msg)

    return BuiltPackage(
        result.output_digest,
        (BuiltDockerImage.create(image_id, tags), ),
    )
예제 #11
0
def assert_build(
    rule_runner: RuleRunner,
    address: Address,
    *extra_log_lines: str,
    options: dict | None = None,
    process_assertions: Callable[[Process], None] | None = None,
) -> None:
    tgt = rule_runner.get_target(address)

    def build_context_mock(request: DockerBuildContextRequest) -> DockerBuildContext:
        return DockerBuildContext.create(
            digest=EMPTY_DIGEST,
            dockerfile_info=DockerfileInfo(source="docker/test/Dockerfile"),
            build_args=rule_runner.request(DockerBuildArgs, [DockerBuildArgsRequest(tgt)]),
            env=rule_runner.request(DockerBuildEnvironment, [DockerBuildEnvironmentRequest(tgt)]),
        )

    def run_process_mock(process: Process) -> ProcessResult:
        if process_assertions:
            process_assertions(process)

        return ProcessResult(
            stdout=b"stdout",
            stdout_digest=EMPTY_FILE_DIGEST,
            stderr=b"stderr",
            stderr_digest=EMPTY_FILE_DIGEST,
            output_digest=EMPTY_DIGEST,
            platform=Platform.current,
            metadata=ProcessResultMetadata(0, "ran_locally", 0),
        )

    if options:
        opts = options or {}
        opts.setdefault("registries", {})
        opts.setdefault("default_repository", "{directory}/{name}")
        opts.setdefault("build_args", [])
        opts.setdefault("env_vars", [])

        docker_options = create_subsystem(
            DockerOptions,
            **opts,
        )
    else:
        docker_options = rule_runner.request(DockerOptions, [])

    result = run_rule_with_mocks(
        build_docker_image,
        rule_args=[
            DockerFieldSet.create(tgt),
            docker_options,
            DockerBinary("/dummy/docker"),
        ],
        mock_gets=[
            MockGet(
                output_type=DockerBuildContext,
                input_type=DockerBuildContextRequest,
                mock=build_context_mock,
            ),
            MockGet(
                output_type=ProcessResult,
                input_type=Process,
                mock=run_process_mock,
            ),
        ],
    )

    assert result.digest == EMPTY_DIGEST
    assert len(result.artifacts) == 1
    assert result.artifacts[0].relpath is None

    for log_line in extra_log_lines:
        assert log_line in result.artifacts[0].extra_log_lines
예제 #12
0
def docker(docker_path: str) -> DockerBinary:
    return DockerBinary(docker_path)
예제 #13
0
def assert_build(
        rule_runner: RuleRunner,
        address: Address,
        *extra_log_lines: str,
        options: dict | None = None,
        process_assertions: Callable[[Process], None] | None = None,
        exit_code: int = 0,
        copy_sources: tuple[str, ...] = (),
        build_context_snapshot: Snapshot = EMPTY_SNAPSHOT,
        version_tags: tuple[str, ...] = (),
) -> None:
    tgt = rule_runner.get_target(address)

    def build_context_mock(
            request: DockerBuildContextRequest) -> DockerBuildContext:
        return DockerBuildContext.create(
            snapshot=build_context_snapshot,
            dockerfile_info=DockerfileInfo(
                request.address,
                digest=EMPTY_DIGEST,
                source=os.path.join(address.spec_path, "Dockerfile"),
                copy_source_paths=copy_sources,
                version_tags=version_tags,
            ),
            build_args=rule_runner.request(DockerBuildArgs,
                                           [DockerBuildArgsRequest(tgt)]),
            build_env=rule_runner.request(
                DockerBuildEnvironment, [DockerBuildEnvironmentRequest(tgt)]),
        )

    def run_process_mock(process: Process) -> FallibleProcessResult:
        if process_assertions:
            process_assertions(process)

        return FallibleProcessResult(
            exit_code=exit_code,
            stdout=b"stdout",
            stdout_digest=EMPTY_FILE_DIGEST,
            stderr=b"stderr",
            stderr_digest=EMPTY_FILE_DIGEST,
            output_digest=EMPTY_DIGEST,
            platform=Platform.current,
            metadata=ProcessResultMetadata(0, "ran_locally", 0),
        )

    if options:
        opts = options or {}
        opts.setdefault("registries", {})
        opts.setdefault("default_repository", "{name}")
        opts.setdefault("default_context_root", "")
        opts.setdefault("build_args", [])
        opts.setdefault("build_target_stage", None)
        opts.setdefault("build_verbose", False)
        opts.setdefault("env_vars", [])

        docker_options = create_subsystem(
            DockerOptions,
            **opts,
        )
    else:
        docker_options = rule_runner.request(DockerOptions, [])

    global_options = rule_runner.request(GlobalOptions, [])

    result = run_rule_with_mocks(
        build_docker_image,
        rule_args=[
            DockerFieldSet.create(tgt),
            docker_options,
            global_options,
            DockerBinary("/dummy/docker"),
            ProcessCleanupOption(True),
        ],
        mock_gets=[
            MockGet(
                output_type=DockerBuildContext,
                input_type=DockerBuildContextRequest,
                mock=build_context_mock,
            ),
            MockGet(
                output_type=WrappedTarget,
                input_type=WrappedTargetRequest,
                mock=lambda _: WrappedTarget(tgt),
            ),
            MockGet(
                output_type=FallibleProcessResult,
                input_type=Process,
                mock=run_process_mock,
            ),
        ],
    )

    assert result.digest == EMPTY_DIGEST
    assert len(result.artifacts) == 1
    assert result.artifacts[0].relpath is None

    for log_line in extra_log_lines:
        assert log_line in result.artifacts[0].extra_log_lines