Skip to content

Commit

Permalink
Add repository content commands for ansible
Browse files Browse the repository at this point in the history
fixes: #363
  • Loading branch information
gerrod3 authored and mdellweg committed Oct 16, 2021
1 parent f7c522d commit 1ae7e30
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGES/363.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added content management commands for Ansible repositories
17 changes: 12 additions & 5 deletions pulpcore/cli/ansible/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import click

from pulpcore.cli.ansible.context import PulpAnsibleCollectionVersionContext, PulpAnsibleRoleContext
from pulpcore.cli.common.context import PulpContext, pass_entity_context, pass_pulp_context
from pulpcore.cli.common.context import (
PulpContext,
PulpEntityContext,
pass_entity_context,
pass_pulp_context,
)
from pulpcore.cli.common.generic import (
GroupOption,
chunk_size_option,
Expand All @@ -20,7 +25,9 @@

def _content_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
if value:
ctx.obj.entity = value # The context should be already set based on the type option
entity_ctx = ctx.find_object(PulpEntityContext)
assert entity_ctx is not None
entity_ctx.entity = value
return value


Expand Down Expand Up @@ -48,7 +55,7 @@ def content(ctx: click.Context, pulp_ctx: PulpContext, content_type: str) -> Non
pulp_option("--namespace", help=_("Namespace of {entity}")),
pulp_option("--version", help=_("Version of {entity}")),
pulp_option(
"--only-highest",
"--latest",
"is_highest",
is_flag=True,
default=None,
Expand All @@ -59,7 +66,7 @@ def content(ctx: click.Context, pulp_ctx: PulpContext, content_type: str) -> Non
pulp_option(
"--tags",
help=_(
"Comma separated list of tags that must all match (only works for collection-versions)"
"Comma separated list of tags that must all match (only works for collection versions)"
),
),
]
Expand Down Expand Up @@ -132,7 +139,7 @@ def upload(
result = content_ctx.create(body=body)
pulp_ctx.output_result(result)
else:
# Collection upload uses name, namespace, and version for extra validation
# Collection upload uses name, namespace, and version for server side validation
body = {"expected_name": name, "expected_namespace": namespace, "expected_version": version}
result = content_ctx.upload(file=file, body=body)
pulp_ctx.output_result(result)
4 changes: 2 additions & 2 deletions pulpcore/cli/ansible/context.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import gettext
from typing import IO, Any
from typing import IO, Any, ClassVar

from pulpcore.cli.common.context import (
EntityDefinition,
Expand All @@ -22,7 +22,7 @@ class PulpAnsibleCollectionVersionContext(PulpContentContext):
LIST_ID = "content_ansible_collection_versions_list"
READ_ID = "content_ansible_collection_versions_read"
CREATE_ID = "content_ansible_collection_versions_create"
UPLOAD_ID = "upload_collection"
UPLOAD_ID: ClassVar[str] = "upload_collection"

def upload(self, file: IO[bytes], body: Any) -> Any:
body = self.preprocess_body(body)
Expand Down
112 changes: 109 additions & 3 deletions pulpcore/cli/ansible/repository.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import gettext
from typing import Any

import click
import schema as s

from pulpcore.cli.ansible.context import (
PulpAnsibleCollectionRemoteContext,
PulpAnsibleCollectionVersionContext,
PulpAnsibleRepositoryContext,
PulpAnsibleRoleContext,
PulpAnsibleRoleRemoteContext,
)
from pulpcore.cli.common.context import (
Expand All @@ -17,13 +21,16 @@
pass_repository_context,
)
from pulpcore.cli.common.generic import (
GroupOption,
create_command,
create_content_json_callback,
destroy_command,
href_option,
label_command,
label_select_option,
list_command,
name_option,
repository_content_command,
resource_option,
retained_versions_option,
show_command,
Expand All @@ -49,6 +56,30 @@
)


CONTENT_LIST_SCHEMA = s.Schema(
[{"name": s.And(str, len), "namespace": s.And(str, len), "version": s.And(str, len)}]
)


def _content_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
if value:
ctx.obj.entity = value # The context is set by the type parameter on the content commands
return value


def _content_type_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
# This needs to run eagerly
pulp_ctx = ctx.find_object(PulpContext)
assert pulp_ctx is not None
if value == "collection-version":
ctx.obj = PulpAnsibleCollectionVersionContext(pulp_ctx)
elif value == "role":
ctx.obj = PulpAnsibleRoleContext(pulp_ctx)
else:
raise NotImplementedError()
return value


@click.group()
@click.option(
"-t",
Expand Down Expand Up @@ -78,6 +109,73 @@ def repository(ctx: click.Context, pulp_ctx: PulpContext, repo_type: str) -> Non
remote_option,
retained_versions_option,
]
content_options = [
click.option(
"--name",
help=_("Name of {entity}"),
group=["namespace", "version"],
expose_value=False,
cls=GroupOption,
callback=_content_callback,
),
click.option(
"--namespace",
help=_("Namespace of {entity}"),
group=["name", "version"],
expose_value=False,
cls=GroupOption,
),
click.option(
"--version",
help=_("Version of {entity}"),
group=["namespace", "name"],
expose_value=False,
cls=GroupOption,
),
click.option(
"-t",
"--type",
"type",
type=click.Choice(["collection-version", "role"]),
default="collection-version",
expose_value=False,
callback=_content_type_callback,
is_eager=True,
),
href_option,
]
content_json_callback = create_content_json_callback(schema=CONTENT_LIST_SCHEMA)
modify_options = [
click.option(
"--add-content",
callback=content_json_callback,
help=_(
"""JSON string with a list of objects to add to the repository.
Each object must contain the following keys: "name", "namespace", "version".
The argument prefixed with the '@' can be the path to a JSON file with a list of objects."""
),
),
click.option(
"--remove-content",
callback=content_json_callback,
help=_(
"""JSON string with a list of objects to remove from the repository.
Each object must contain the following keys: "name", "namespace", "version".
The argument prefixed with the '@' can be the path to a JSON file with a list of objects."""
),
),
click.option(
"-t",
"--type",
"type",
type=click.Choice(["collection-version", "role"]),
default="collection-version",
expose_value=False,
callback=_content_type_callback,
is_eager=True,
),
]


repository.add_command(show_command(decorators=lookup_options))
repository.add_command(list_command(decorators=[label_select_option]))
Expand All @@ -86,6 +184,17 @@ def repository(ctx: click.Context, pulp_ctx: PulpContext, repo_type: str) -> Non
repository.add_command(create_command(decorators=create_options))
repository.add_command(update_command(decorators=lookup_options + update_options))
repository.add_command(label_command())
repository.add_command(
repository_content_command(
contexts={
"collection-version": PulpAnsibleCollectionVersionContext,
"role": PulpAnsibleRoleContext,
},
add_decorators=content_options,
remove_decorators=content_options,
modify_decorators=modify_options,
)
)


@repository.command()
Expand Down Expand Up @@ -119,6 +228,3 @@ def sync(
href=repository_href,
body=body,
)


# TODO Finish 'add' and 'remove' commands when role and collection contexts are implemented
20 changes: 13 additions & 7 deletions pulpcore/cli/common/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,18 @@ def handle_parse_result(
) -> Any:
assert self.name is not None
all_options = self.group + [self.name]
if all(x in opts for x in all_options):
self.prompt = None
else:
options_present = [x for x in all_options if x in opts]
num_options = len(options_present)
if num_options != len(all_options) and (num_options != 0 or self.required):
raise click.UsageError(
_("Illegal usage, please specify all options in the group: {option_list}").format(
option_list=", ".join(all_options)
)
)
self.prompt = None
value = opts.get(self.name)
if self.callback is not None:
value = self.callback(ctx, self, {o: opts[o] for o in all_options})
if self.callback is not None and num_options != 0:
value = self.callback(ctx, self, {o: opts[o] for o in options_present})
if self.expose_value:
ctx.params[self.name] = value
return value, args
Expand Down Expand Up @@ -217,11 +218,12 @@ def load_json_callback(


def create_content_json_callback(
content_ctx: Type[PulpContentContext], schema: s.Schema = None
context_class: Optional[Type[PulpContentContext]] = None, schema: s.Schema = None
) -> Any:
def _callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[List[PulpContentContext]]:
ctx_class = context_class
new_value = load_json_callback(ctx, param, value)
if new_value is not None:
if schema is not None:
Expand All @@ -235,7 +237,11 @@ def _callback(
)
pulp_ctx = ctx.find_object(PulpContext)
assert pulp_ctx is not None
return [content_ctx(pulp_ctx, entity=unit) for unit in new_value]
if ctx_class is None:
context = ctx.find_object(PulpContentContext)
assert context is not None
ctx_class = type(context)
return [ctx_class(pulp_ctx, entity=unit) for unit in new_value]
return new_value

return _callback
Expand Down
21 changes: 21 additions & 0 deletions tests/scripts/pulp_ansible/test_content.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
pulp debug has-plugin --name "ansible" || exit 3

cleanup() {
pulp ansible repository destroy --name "cli_test_ansible_repository" || true
pulp orphans delete || true
}
trap cleanup EXIT
Expand Down Expand Up @@ -33,3 +34,23 @@ expect_succ pulp ansible content --type "role" list --name "kubernetes-modules"
test "$(echo "$OUTPUT" | jq -r length)" -eq "1"
content2_href="$(echo "$OUTPUT" | jq -r .[0].pulp_href)"
expect_succ pulp ansible content --type "role" show --href "$content2_href"

# New content commands
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"
test "$(echo "$OUTPUT" | jq -r length)" -eq "1"

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

expect_succ pulp ansible repository content remove --repository "cli_test_ansible_repository" --href "$content_href"
expect_succ pulp ansible repository content remove --repository "cli_test_ansible_repository" --href "$content2_href"
expect_succ pulp ansible repository content list --repository "cli_test_ansible_repository"
test "$(echo "$OUTPUT" | jq -r length)" -eq "0"

0 comments on commit 1ae7e30

Please sign in to comment.