Skip to content

Commit

Permalink
Add container repository content management commands
Browse files Browse the repository at this point in the history
fixes: pulp#422
  • Loading branch information
gerrod3 committed Mar 22, 2022
1 parent e567714 commit 79028cf
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGES/422.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added container repository content management commands.
26 changes: 13 additions & 13 deletions pulpcore/cli/common/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,8 +986,6 @@ def repository_content_command(**kwargs: Any) -> click.Group:
"""A factory that creates a repository content command group."""

content_contexts = kwargs.pop("contexts", {})
names = list(content_contexts.keys()) + ["all"]
content_contexts.update({"all": PulpContentContext})

def version_callback(
ctx: click.Context, param: click.Parameter, value: Optional[int]
Expand All @@ -1002,29 +1000,30 @@ def version_callback(
)
return repo_ver_ctx

@click.command("list")
@click.option("-t", "--type", "type", type=click.Choice(names), default=names[0])
@pulp_command("list")
@click.option("--all-types", is_flag=True)
@limit_option
@offset_option
@repository_option
@click.option("--version", type=int, callback=version_callback)
@pass_pulp_context
@click.pass_context
def content_list(
ctx: click.Context,
pulp_ctx: PulpContext,
version: PulpRepositoryVersionContext,
offset: Optional[int],
limit: Optional[int],
type: Optional[str],
all_types: Optional[bool],
**params: Any,
) -> None:
parameters = {k: v for k, v in params.items() if v is not None}
parameters.update({"repository_version": version.pulp_href})
result = content_contexts[type](pulp_ctx).list(
limit=limit, offset=offset, parameters=parameters
)
ctx_obj = PulpContentContext(pulp_ctx) if all_types else ctx.obj
result = ctx_obj.list(limit=limit, offset=offset, parameters=parameters)
pulp_ctx.output_result(result)

@click.command("add")
@pulp_command("add")
@repository_option
@click.option("--base-version", type=int, callback=version_callback)
@pass_content_context
Expand All @@ -1039,7 +1038,7 @@ def content_add(
base_version=base_version.pulp_href,
)

@click.command("remove")
@pulp_command("remove")
@click.option("--all", is_flag=True, help=_("Remove all content from repository version"))
@repository_option
@click.option("--base-version", type=int, callback=version_callback)
Expand All @@ -1055,7 +1054,7 @@ def content_remove(
repo_ctx.pulp_href, remove_content=remove_content, base_version=base_version.pulp_href
)

@click.command("modify")
@pulp_command("modify")
@repository_option
@click.option("--base-version", type=int, callback=version_callback)
def content_modify(
Expand All @@ -1077,11 +1076,12 @@ def content_modify(
if not kwargs.get("name"):
kwargs["name"] = "content"

@click.group(**kwargs)
@pulp_group(**kwargs)
@pass_pulp_context
@click.pass_context
@type_option(choices=content_contexts)
def content_group(ctx: click.Context, pulp_ctx: PulpContext) -> None:
ctx.obj = PulpContentContext(pulp_ctx)
pass

for command, options in command_decorators.items():
if options is not None:
Expand Down
45 changes: 44 additions & 1 deletion pulpcore/cli/container/context.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any
from typing import Any, List, Optional

from pulpcore.cli.common.context import (
EntityDefinition,
Expand Down Expand Up @@ -106,6 +106,49 @@ class PulpContainerRepositoryContext(PulpContainerBaseRepositoryContext):
"tag": [PluginRequirement("container", "2.3.0")],
}

def preprocess_body(self, body: EntityDefinition) -> EntityDefinition:
body = super().preprocess_body(body)
if "version" in body and "source_repository" in body:
body[
"source_repository_version"
] = f"{body.pop('source_repository')}versions/{body.pop('version')}/"
return body

def modify(
self,
href: str,
add_content: Optional[List[str]] = None,
remove_content: Optional[List[str]] = None,
base_version: Optional[str] = None,
) -> Any:
if remove_content:
self.call(
"remove", parameters={self.HREF: href}, body={"content_units": remove_content}
)
if add_content:
self.call("add", parameters={self.HREF: href}, body={"content_units": add_content})

def copy_tag(self, source_href: str, version: Optional[str], tags: Optional[List[str]]) -> Any:
body = {"source_repository": source_href, "names": tags, "version": version}
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,
version: Optional[str],
digests: Optional[List[str]],
media_types: Optional[List[str]],
) -> Any:
body = {
"source_repository": source_href,
"version": version,
"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
145 changes: 139 additions & 6 deletions pulpcore/cli/container/repository.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import re
from typing import Any, Dict
from typing import Any, Dict, List, Optional

import click

from pulpcore.cli.common.context import (
EntityDefinition,
EntityFieldDefinition,
PulpContext,
PulpEntityContext,
PulpRemoteContext,
PulpRepositoryContext,
Expand All @@ -19,6 +21,7 @@
list_command,
name_option,
pulp_group,
repository_content_command,
repository_href_option,
repository_option,
resource_option,
Expand All @@ -29,11 +32,15 @@
version_command,
)
from pulpcore.cli.common.i18n import get_translation
from pulpcore.cli.container.content import show_options
from pulpcore.cli.container.context import (
PulpContainerBaseRepositoryContext,
PulpContainerBlobContext,
PulpContainerManifestContext,
PulpContainerPushRepositoryContext,
PulpContainerRemoteContext,
PulpContainerRepositoryContext,
PulpContainerTagContext,
)
from pulpcore.cli.core.generic import task_command

Expand All @@ -44,22 +51,62 @@

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


def _source_callback(ctx: click.Context, param: click.Parameter, value: str) -> PulpEntityContext:
pulp_ctx = ctx.find_object(PulpContext)
assert pulp_ctx is not None
if len(value) == 0:
raise click.ClickException(_("Please pass in a non empty source repository."))

version: Optional[str] = None
pulp_href: Optional[str] = None
entity: Optional[EntityDefinition] = None
if value.startswith("/"):
pattern = rf"^{pulp_ctx.api_path}{PulpContainerRepositoryContext.HREF_PATTERN}"
if re.match(pattern, value) is None:
raise click.ClickException(
_("'{value}' is not a valid href for {option_name}.").format(
value=value, option_name=param.name
)
)
pulp_href = value
if "versions" in value:
pulp_href = value.partition("versions")[0]
version = value.split("/")[-2]
else:
split_value = value.split(":", maxsplit=1)
if len(split_value) == 2:
version = split_value[1]
entity = {"name": split_value[0]}

repo_ctx = PulpContainerRepositoryContext(pulp_ctx, pulp_href=pulp_href, entity=entity)
if version:
# Check that the version makes sense
latest_version = int(repo_ctx.entity["latest_version_href"].split("/")[-2])
if not (0 < int(version) <= latest_version):
raise click.ClickException(
_(
"Please specify a version that is less then the latest version {} and greater"
" than 0"
).format(latest_version)
)
repo_ctx.meta["version"] = version
return repo_ctx


remote_option = resource_option(
"--remote",
default_plugin="container",
default_type="container",
context_table={"container:container": PulpContainerRemoteContext},
href_pattern=PulpRemoteContext.HREF_PATTERN,
help=_(
"Remote used for synching in the form '[[<plugin>:]<resource_type>:]<name>' or by href."
),
help=_("Remote used for syncing in the form '[[<plugin>:]<resource_type>:]<name>' or by href."),
)


Expand All @@ -83,6 +130,11 @@ def repository() -> None:
retained_versions_option,
]
create_options = update_options + [click.option("--name", required=True)]
contexts = {
"tag": PulpContainerTagContext,
"manifest": PulpContainerManifestContext,
"blob": PulpContainerBlobContext,
}
container_context = (PulpContainerRepositoryContext,)

repository.add_command(list_command(decorators=[label_select_option]))
Expand All @@ -101,6 +153,14 @@ def repository() -> None:
repository.add_command(task_command(decorators=nested_lookup_options))
repository.add_command(version_command(decorators=nested_lookup_options))
repository.add_command(label_command(decorators=nested_lookup_options))
repository.add_command(
repository_content_command(
contexts=contexts,
add_decorators=show_options,
remove_decorators=show_options,
allowed_with_contexts=container_context,
)
)


@repository.command(allowed_with_contexts=container_context)
Expand Down Expand Up @@ -163,3 +223,76 @@ 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
@click.option(
"--source",
help=_("Source repository to copy tags from. Specify in format of href or <name>[:<version>]"),
required=True,
callback=_source_callback,
)
@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: PulpContainerRepositoryContext,
tags: List[str],
) -> None:
version = source.meta.get("version") # Set in the source_callback
repository_ctx.copy_tag(source_href=source.pulp_href, version=version, tags=tags or None)


@repository.command(allowed_with_contexts=container_context)
@name_option
@href_option
@click.option(
"--source",
help=_(
"Source repository to copy manifests from. Specify in format of href or <name>[:<version>]"
),
required=True,
callback=_source_callback,
)
@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: PulpContainerRepositoryContext,
digests: List[str],
media_types: List[str],
) -> None:
version = source.meta.get("version") # Set in the source_callback
repository_ctx.copy_manifest(
source_href=source.pulp_href,
version=version,
digests=digests or None,
media_types=media_types or None,
)
6 changes: 3 additions & 3 deletions tests/scripts/pulp_ansible/test_content.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ expect_succ pulp ansible repository create --name "cli_test_ansible_repository"
expect_succ pulp ansible repository content add --repository "cli_test_ansible_repository" --name "posix" --namespace "ansible" --version "1.3.0"
expect_succ pulp ansible repository content list --repository "cli_test_ansible_repository" --version 1
test "$(echo "$OUTPUT" | jq -r length)" -eq "1"
expect_succ pulp ansible repository content add --repository "cli_test_ansible_repository" --type "role" --name "kubernetes-modules" --namespace "ansible" --version "0.0.1"
expect_succ pulp ansible repository content list --repository "cli_test_ansible_repository" --version 2 --type "role"
expect_succ pulp ansible repository content --type "role" add --repository "cli_test_ansible_repository" --name "kubernetes-modules" --namespace "ansible" --version "0.0.1"
expect_succ pulp ansible repository content --type "role" list --repository "cli_test_ansible_repository" --version 2
test "$(echo "$OUTPUT" | jq -r length)" -eq "1"

if pulp debug has-plugin --name "core" --min-version "3.11.0"
then
expect_succ pulp ansible repository content list --repository "cli_test_ansible_repository" --version 2 --type "all"
expect_succ pulp ansible repository content list --repository "cli_test_ansible_repository" --version 2 --all-types
test "$(echo "$OUTPUT" | jq -r length)" -eq "2"
fi

Expand Down
14 changes: 14 additions & 0 deletions tests/scripts/pulp_container/test_content.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,17 @@ tag_digest="$(echo "$OUTPUT" | jq -r .digest)"

expect_succ pulp container content -t tag show --name "$tag_name" --digest "$tag_digest"
test "$(echo "$OUTPUT" | jq -r .pulp_href)" = "$tag_href"

# Test repository content commands
expect_succ pulp container repository content list --repository "cli_test_container_repository" --all-types
expect_succ pulp container repository content --type "tag" list --repository "cli_test_container_repository"
expect_succ pulp container repository content --type "manifest" list --repository "cli_test_container_repository"
expect_succ pulp container repository content --type "blob" list --repository "cli_test_container_repository"

expect_succ pulp container repository content --type "blob" remove --repository "cli_test_container_repository" --digest "$blob_digest"
expect_succ pulp container repository content --type "manifest" remove --repository "cli_test_container_repository" --digest "$manifest_digest"
expect_succ pulp container repository content --type "tag" remove --repository "cli_test_container_repository" --name "$tag_name" --digest "$tag_digest"

expect_succ pulp container repository content add --repository "cli_test_container_repository" --href "$blob_href"
expect_succ pulp container repository content add --repository "cli_test_container_repository" --href "$manifest_href"
expect_succ pulp container repository content add --repository "cli_test_container_repository" --href "$tag_href"
Loading

0 comments on commit 79028cf

Please sign in to comment.