Skip to content

Commit

Permalink
Add commands to manage roles
Browse files Browse the repository at this point in the history
[noissue]
  • Loading branch information
mdellweg committed Oct 6, 2021
1 parent 591d6a6 commit de18611
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 77 deletions.
1 change: 1 addition & 0 deletions CHANGES/382.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added commands to manage roles.
63 changes: 41 additions & 22 deletions pulpcore/cli/common/generic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import gettext
import json
import re
from functools import lru_cache
from typing import (
Any,
Callable,
Expand Down Expand Up @@ -42,6 +43,18 @@


class PulpCommand(click.Command):
def __init__(self, *args: Any, needs_plugins: Optional[List[PluginRequirement]] = None, **kwargs: Any):
self.needs_plugins = needs_plugins
super().__init__(*args, **kwargs)

def invoke(self, ctx: click.Context) -> Any:
if self.needs_plugins:
pulp_ctx = ctx.find_object(PulpContext)
assert pulp_ctx is not None
for plugin_requirement in self.needs_plugins:
pulp_ctx.needs_plugin(plugin_requirement)
return super().invoke(ctx)

def get_short_help_str(self, limit: int = 45) -> str:
return self.short_help or ""

Expand Down Expand Up @@ -129,23 +142,31 @@ def handle_parse_result(
# Option callbacks


def _href_callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[str]:
if value is not None:
entity_ctx = ctx.find_object(PulpEntityContext)
assert entity_ctx is not None
entity_ctx.pulp_href = value
return value
@lru_cache(typed=True)
def lookup_callback(
attribute: str, ContextClass: Type[PulpEntityContext] = PulpEntityContext
) -> Callable[[click.Context, click.Parameter, Optional[str]], Optional[str]]:
def _callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[str]:
if value is not None:
if value == "":
value = "null"
entity_ctx = ctx.find_object(ContextClass)
assert entity_ctx is not None
entity_ctx.entity = {attribute: value}
return value

return _callback


def _name_callback(
def _href_callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[str]:
if value is not None:
entity_ctx = ctx.find_object(PulpEntityContext)
assert entity_ctx is not None
entity_ctx.entity = {"name": value}
entity_ctx.pulp_href = value
return value


Expand All @@ -159,16 +180,6 @@ def _repository_href_callback(
return value


def _repository_callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[str]:
if value is not None:
repository_ctx = ctx.find_object(PulpRepositoryContext)
assert repository_ctx is not None
repository_ctx.entity = {"name": value}
return value


def _version_callback(
ctx: click.Context, param: click.Parameter, value: Optional[int]
) -> Optional[int]:
Expand Down Expand Up @@ -254,6 +265,14 @@ def parse_size_callback(ctx: click.Context, param: click.Parameter, value: str)
return int(float(number) * units[unit])


def null_callback(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[str]:
if value == "":
return "null"
return value


##############################################################################
# Decorator common options

Expand Down Expand Up @@ -387,7 +406,7 @@ def _multi_option_callback(
name_option = pulp_option(
"--name",
help=_("Name of the {entity}"),
callback=_name_callback,
callback=lookup_callback("name"),
expose_value=False,
)

Expand All @@ -401,7 +420,7 @@ def _multi_option_callback(
repository_option = click.option(
"--repository",
help=_("Name of the repository"),
callback=_repository_callback,
callback=lookup_callback("name", PulpRepositoryContext),
expose_value=False,
)

Expand Down
2 changes: 1 addition & 1 deletion pulpcore/cli/common/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def call(
self.debug_callback(1, f"{method} {request.url}")
for key, value in request.headers.items():
self.debug_callback(2, f" {key}: {value}")
if request.body:
if request.body is not None:
self.debug_callback(2, f"{request.body!r}")
if self.safe_calls_only and method.upper() not in SAFE_METHODS:
raise OpenAPIError(_("Call aborted due to safe mode"))
Expand Down
2 changes: 2 additions & 0 deletions pulpcore/cli/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from pulpcore.cli.core.orphan import orphan
from pulpcore.cli.core.orphans import orphans
from pulpcore.cli.core.repository import repository
from pulpcore.cli.core.role import role
from pulpcore.cli.core.show import show
from pulpcore.cli.core.signing_service import signing_service
from pulpcore.cli.core.status import status
Expand All @@ -34,6 +35,7 @@
main.add_command(orphan)
main.add_command(orphans) # This one is deprecated
main.add_command(repository)
main.add_command(role)
main.add_command(show)
main.add_command(signing_service)
main.add_command(status)
Expand Down
54 changes: 54 additions & 0 deletions pulpcore/cli/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,26 @@ class PulpGroupObjectPermissionContext(PulpGroupPermissionContext):
DELETE_ID = "groups_object_permissions_delete"


class PulpGroupRoleContext(PulpEntityContext):
ENTITY = _("group role")
ENTITIES = _("group roles")
HREF = "auth_groups_group_role_href"
LIST_ID = "groups_roles_list"
READ_ID = "groups_roles_read"
CREATE_ID = "groups_roles_create"
DELETE_ID = "groups_roles_delete"
NULLABLES = {"content_object"}
group_ctx: PulpGroupContext

def __init__(self, pulp_ctx: PulpContext, group_ctx: PulpGroupContext) -> None:
super().__init__(pulp_ctx)
self.group_ctx = group_ctx

@property
def scope(self) -> Dict[str, Any]:
return {PulpGroupContext.HREF: self.group_ctx.pulp_href}


class PulpGroupUserContext(PulpEntityContext):
ENTITY = _("group user")
ENTITIES = _("group users")
Expand Down Expand Up @@ -229,6 +249,17 @@ def remove(self, href: str, users: Optional[List[str]], groups: Optional[List[st
return self.pulp_ctx.call(self.REMOVE_ID, parameters={self.HREF: href}, body=body)


class PulpRoleContext(PulpEntityContext):
ENTITY = _("role")
ENTITIES = _("roles")
HREF = "role_href"
LIST_ID = "roles_list"
READ_ID = "roles_read"
CREATE_ID = "roles_create"
UPDATE_ID = "roles_partial_update"
DELETE_ID = "roles_delete"


class PulpSigningServiceContext(PulpEntityContext):
ENTITY = _("signing service")
ENTITIES = _("signing services")
Expand Down Expand Up @@ -296,6 +327,29 @@ class PulpUserContext(PulpEntityContext):
HREF = "auth_user_href"
LIST_ID = "users_list"
READ_ID = "users_read"
CREATE_ID = "users_create"
UPDATE_ID = "users_partial_update"
DELETE_ID = "users_delete"


class PulpUserRoleContext(PulpEntityContext):
ENTITY = _("user role")
ENTITIES = _("user roles")
HREF = "auth_users_user_role_href"
LIST_ID = "users_roles_list"
READ_ID = "users_roles_read"
CREATE_ID = "users_roles_create"
DELETE_ID = "users_roles_delete"
NULLABLES = {"content_object"}
user_ctx: PulpUserContext

def __init__(self, pulp_ctx: PulpContext, user_ctx: PulpUserContext) -> None:
super().__init__(pulp_ctx)
self.user_ctx = user_ctx

@property
def scope(self) -> Dict[str, Any]:
return {PulpUserContext.HREF: self.user_ctx.pulp_href}


class PulpWorkerContext(PulpEntityContext):
Expand Down
108 changes: 75 additions & 33 deletions pulpcore/cli/core/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,28 @@

import click

from pulpcore.cli.common.context import PulpContext, pass_entity_context, pass_pulp_context
from pulpcore.cli.common.context import PulpContext, pass_entity_context, pass_pulp_context, PluginRequirement
from pulpcore.cli.common.generic import (
create_command,
destroy_command,
href_option,
list_command,
lookup_callback,
name_option,
show_command,
null_callback
)
from pulpcore.cli.core.context import (
PulpGroupContext,
PulpGroupModelPermissionContext,
PulpGroupObjectPermissionContext,
PulpGroupPermissionContext,
PulpGroupRoleContext,
PulpGroupUserContext,
PulpUserContext,
)


def _groupname_callback(ctx: click.Context, param: click.Parameter, value: str) -> str:
if value is not None:
entity_ctx = ctx.find_object(PulpGroupContext)
assert entity_ctx is not None
entity_ctx.entity = {"name": value}
return value


def _permission_callback(ctx: click.Context, param: click.Parameter, value: str) -> str:
if value is not None:
entity_ctx = ctx.find_object(PulpGroupPermissionContext)
assert entity_ctx is not None
entity_ctx.entity = {"permission": value}
return value
_ = gettext.gettext


def _object_callback(ctx: click.Context, param: click.Parameter, value: str) -> str:
Expand All @@ -51,9 +40,9 @@ def _object_callback(ctx: click.Context, param: click.Parameter, value: str) ->
return value


groupname_option = click.option("--groupname", callback=_groupname_callback, expose_value=False)

_ = gettext.gettext
group_option = click.option(
"--group", callback=lookup_callback("name", PulpGroupContext), expose_value=False
)


@click.group(help=_("Manage user groups and their granted permissions."))
Expand Down Expand Up @@ -99,13 +88,13 @@ def permission(

permission.add_command(
list_command(
help=_("Show a list of the permissioons granted to a group."), decorators=[groupname_option]
help=_("Show a list of the permissioons granted to a group."), decorators=[group_option]
)
)


@permission.command(name="add", help=_("Grant a permission to the group."))
@groupname_option
@group_option
@click.option("--permission", required=True)
@click.option("--object", "obj", callback=_object_callback)
@pass_entity_context
Expand All @@ -123,9 +112,12 @@ def add_permission(
name="remove",
help=_("Revoke a permission from the group."),
decorators=[
groupname_option,
group_option,
click.option(
"--permission", required=True, callback=_permission_callback, expose_value=False
"--permission",
required=True,
callback=lookup_callback("permission", PulpGroupPermissionContext),
expose_value=False,
),
click.option("--object", callback=_object_callback, expose_value=False),
],
Expand All @@ -141,19 +133,15 @@ def user(ctx: click.Context, pulp_ctx: PulpContext, group_ctx: PulpGroupContext)
ctx.obj = PulpGroupUserContext(pulp_ctx, group_ctx)


user.add_command(list_command(decorators=[groupname_option]))


@user.command(name="add")
@groupname_option
@click.option("--username", required=True)
@pass_entity_context
def add_user(entity_ctx: PulpGroupUserContext, username: str) -> None:
entity_ctx.create(body={"username": username})
user.add_command(list_command(decorators=[group_option]))
user.add_command(
create_command(decorators=[group_option, click.option("--username", required=True)]),
name="add",
)


@user.command(name="remove")
@groupname_option
@group_option
@click.option("--username", required=True)
@pass_entity_context
@pass_pulp_context
Expand All @@ -162,3 +150,57 @@ def remove_user(pulp_ctx: PulpContext, entity_ctx: PulpGroupUserContext, usernam
user_pk = user_href.split("/")[-2]
group_user_href = f"{entity_ctx.group_ctx.pulp_href}users/{user_pk}/"
entity_ctx.delete(group_user_href)


@group.group()
@pass_entity_context
@pass_pulp_context
@click.pass_context
def role(ctx: click.Context, pulp_ctx: PulpContext, group_ctx: PulpGroupContext) -> None:
pulp_ctx.needs_plugin(PluginRequirement("core", min="3.17.dev"))
ctx.obj = PulpGroupRoleContext(pulp_ctx, group_ctx)


role.add_command(
list_command(
decorators=[
group_option,
click.option("--role"),
click.option("--role-in", "role__in"),
click.option("--role-contains", "role__contains"),
click.option("--role-icontains", "role__icontains"),
click.option("--role-startswith", "role__startswith"),
click.option("--content-object", callback=null_callback),
]
)
)
role.add_command(
create_command(
decorators=[
group_option,
click.option("--role", required=True),
click.option("--content-object", required=True),
]
),
name="assign",
)
role.add_command(
destroy_command(
decorators=[
group_option,
click.option(
"--role",
required=True,
callback=lookup_callback("role", PulpGroupRoleContext),
expose_value=False,
),
click.option(
"--content-object",
required=True,
callback=lookup_callback("content_object", PulpGroupRoleContext),
expose_value=False,
),
]
),
name="remove",
)
Loading

0 comments on commit de18611

Please sign in to comment.