Skip to content

Commit

Permalink
Add container repository content copy commands
Browse files Browse the repository at this point in the history
fixes: pulp#497
  • Loading branch information
gerrod3 committed Apr 14, 2022
1 parent a6cac1c commit 4f6d2f8
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGES/497.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added container repository copy-tag and copy-manifest commands.
19 changes: 19 additions & 0 deletions pulpcore/cli/container/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,25 @@ def modify(
if add_content:
self.call("add", parameters={self.HREF: href}, body={"content_units": add_content})

def copy_tag(self, source_href: str, tags: Optional[List[str]]) -> Any:
body = {"source_repository_version": source_href, "names": tags}
body = self.preprocess_body(body)
return self.call("copy_tags", parameters={self.HREF: self.pulp_href}, body=body)

def copy_manifest(
self,
source_href: str,
digests: Optional[List[str]],
media_types: Optional[List[str]],
) -> Any:
body = {
"source_repository_version": source_href,
"digests": digests,
"media_types": media_types,
}
body = self.preprocess_body(body)
return self.call("copy_manifests", parameters={self.HREF: self.pulp_href}, body=body)


class PulpContainerPushRepositoryContext(PulpContainerBaseRepositoryContext):
HREF = "container_container_push_repository_href"
Expand Down
111 changes: 108 additions & 3 deletions pulpcore/cli/container/repository.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import re
from typing import Any, Dict
from typing import Any, Dict, List, Optional

import click

Expand Down Expand Up @@ -50,13 +50,34 @@

def _tag_callback(ctx: click.Context, param: click.Parameter, value: str) -> str:
if len(value) == 0:
raise click.ClickException("Please pass a non empty tag name.")
raise click.ClickException(_("Please pass a non empty tag name."))
if re.match(VALID_TAG_REGEX, value) is None:
raise click.ClickException("Please pass a valid tag.")
raise click.ClickException(_("Please pass a valid tag."))

return value


source_option = resource_option(
"--source",
default_plugin="container",
default_type="container",
context_table={
"container:container": PulpContainerRepositoryContext,
"container:push": PulpContainerPushRepositoryContext,
},
href_pattern=PulpRepositoryContext.HREF_PATTERN,
help=_(
"Source repository to copy content from in the form `[[<plugin>:]<resource_type>:]<name>' "
"or by href."
),
required=True,
)


version_option = click.option(
"--version", help=_("Version of the source repository to use"), type=int
)

remote_option = resource_option(
"--remote",
default_plugin="container",
Expand Down Expand Up @@ -181,3 +202,87 @@ def add_tag(
@pass_repository_context
def remove_tag(repository_ctx: PulpContainerBaseRepositoryContext, tag: str) -> None:
repository_ctx.untag(tag)


@repository.command(allowed_with_contexts=container_context)
@name_option
@href_option
@source_option
@version_option
@click.option(
"--tag",
"tags",
help=_("Multiple option of tag names to copy, leave blank to copy all"),
multiple=True,
)
@pass_repository_context
def copy_tag(
repository_ctx: PulpContainerRepositoryContext,
source: PulpRepositoryContext,
version: Optional[int],
tags: List[str],
) -> None:
href = source.entity["latest_version_href"]
if version is not None:
latest_version = int(href.split("/")[-2])
if not (0 < int(version) <= latest_version):
raise click.ClickException(
_("Please specify a version that between 0 and the latest version {}").format(
latest_version
)
)
href = f"{source.entity['versions_href']}{version}/"

repository_ctx.copy_tag(source_href=href, tags=tags or None)


@repository.command(allowed_with_contexts=container_context)
@name_option
@href_option
@source_option
@version_option
@click.option(
"--digest",
"digests",
help=_("Multiple option of manifest digests to copy, leave blank to copy all"),
multiple=True,
)
@click.option(
"--media-type",
"media_types",
help=_("Multiple option of media-types to copy, leave blank to copy all types"),
type=click.Choice(
[
"application/vnd.docker.distribution.manifest.v1+json",
"application/vnd.docker.distribution.manifest.v2+json",
"application/vnd.docker.distribution.manifest.list.v2+json",
"application/vnd.oci.image.manifest.v1+json",
"application/vnd.oci.image.index.v1+json",
]
),
multiple=True,
)
@pass_repository_context
def copy_manifest(
repository_ctx: PulpContainerRepositoryContext,
source: PulpRepositoryContext,
version: Optional[int],
digests: List[str],
media_types: List[str],
) -> None:
href = source.entity["latest_version_href"]
if version is not None:
latest_version = int(href.split("/")[-2])
if not (0 < int(version) <= latest_version):
raise click.ClickException(
_("Please specify a version that between 0 and the latest version {}").format(
latest_version
)
)
href = f"{source.entity['versions_href']}{version}/"

repository_ctx.copy_manifest(
source_href=href,
digests=digests or None,
media_types=media_types or None,
)
52 changes: 52 additions & 0 deletions tests/scripts/pulp_container/test_copy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash

# shellcheck source=tests/scripts/config.source
. "$(dirname "$(dirname "$(realpath "$0")")")"/config.source

pulp debug has-plugin --name "container" || exit 3

cleanup() {
pulp container remote destroy --name "cli_test_container_remote" || true
pulp container repository destroy --name "cli_test_source_container_repository" || true
pulp container repository destroy --name "cli_test_dest_container_repository" || true
pulp orphan cleanup || true
}
trap cleanup EXIT

# Prepare
pulp container remote create --name "cli_test_container_remote" --url "$CONTAINER_REMOTE_URL" --upstream-name "$CONTAINER_IMAGE"
source_href="$(pulp container repository create --name "cli_test_source_container_repository" | jq -r .pulp_href)"
pulp container repository create --name "cli_test_dest_container_repository"
pulp container repository sync --name "cli_test_source_container_repository" --remote "cli_test_container_remote"
tag="$(pulp container repository content -t 'tag' list --repository "cli_test_source_container_repository" | jq -r .[0].name)"
digest="$(pulp container repository content -t 'manifest' list --repository "cli_test_source_container_repository" | jq -r '.[] | select(.listed_manifests == []) | .digest' | sed -n '1p')"

# Test copying manifests
expect_succ pulp container repository copy-manifest --name "cli_test_dest_container_repository" --source "cli_test_source_container_repository" --digest "$digest"
expect_succ pulp container repository content -t 'manifest' list --repository "cli_test_dest_container_repository"
test "$(echo "$OUTPUT" | jq -r length)" -eq 1
test "$(echo "$OUTPUT" | jq -r .[0].digest)" = "$digest"

expect_succ pulp container repository copy-manifest --name "cli_test_dest_container_repository" --source "cli_test_source_container_repository" --version "1" --media-type "application/vnd.docker.distribution.manifest.v2+json"
expect_succ pulp container repository content -t 'manifest' list --repository "cli_test_dest_container_repository" --version "2"
copied="$(echo "$OUTPUT" | jq -r length)"
test "$copied" -gt 1

expect_succ pulp container repository copy-manifest --name "cli_test_dest_container_repository" --source "$source_href"
expect_succ pulp container repository content -t 'manifest' list --repository "cli_test_dest_container_repository" --version "3"
test "$(echo "$OUTPUT" | jq -r length)" -gt "$copied"

# Test copying tags
expect_succ pulp container repository copy-tag --name "cli_test_dest_container_repository" --source "cli_test_source_container_repository" --tag "$tag"
expect_succ pulp container repository content -t 'tag' list --repository "cli_test_dest_container_repository" --version "4"
test "$(echo "$OUTPUT" | jq -r length)" -eq 1
test "$(echo "$OUTPUT" | jq -r .[0].name)" = "$tag"

expect_succ pulp container repository copy-tag --name "cli_test_dest_container_repository" --source "$source_href" --version "1"
expect_succ pulp container repository content -t 'tag' list --repository "cli_test_dest_container_repository" --version "5"
test "$(echo "$OUTPUT" | jq -r length)" -gt 1

# Test bad versions
expect_fail pulp container repository copy-tag --name "cli_test_source_container_repository" --source "cli_test_dest_container_repository" --version "0"
expect_fail pulp container repository copy-manifest --name "cli_test_source_container_repository" --source "cli_test_dest_container_repository" --version "6"
test "$ERROUTPUT" = "Error: Please specify a version that between 0 and the latest version 5"

0 comments on commit 4f6d2f8

Please sign in to comment.