Skip to content

Commit

Permalink
feat: internals add_vo and add_group
Browse files Browse the repository at this point in the history
  • Loading branch information
aldbr committed Nov 27, 2023
1 parent 3b4761c commit 3c9dddf
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 24 deletions.
108 changes: 84 additions & 24 deletions src/diracx/cli/internal/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
from typing import List

import git
import typer
Expand Down Expand Up @@ -26,11 +27,6 @@
@app.command()
def generate_cs(
config_repo: str,
*,
vo: str = "testvo",
user_group: str = "user",
idp_url: str = "https://idp.invalid",
idp_client_id: str = "idp-client-id",
):
"""Generate a minimal DiracX configuration repository"""
# TODO: The use of parse_obj_as should be moved in to typer itself
Expand All @@ -42,29 +38,86 @@ def generate_cs(
typer.echo(f"ERROR: Directory {repo_path} already exists", err=True)
raise typer.Exit(1)

registry = RegistryConfig(
IdP=IdpConfig(URL=idp_url, ClientID=idp_client_id),
DefaultGroup=user_group,
Users={},
Groups={
user_group: GroupConfig(Properties={"NormalUser"}, Quota=None, Users=set())
},
)
config = Config(
Registry={vo: registry},
Registry={},
DIRAC=DIRACConfig(),
Operations={"Defaults": OperationsConfig()},
)

repo = git.Repo.init(repo_path, initial_branch="master")
yaml_path = repo_path / "default.yml"
typer.echo(f"Writing configuration to {yaml_path}", err=True)
yaml_path.write_text(yaml.safe_dump(config.dict(exclude_unset=True)))
repo.index.add([yaml_path.relative_to(repo_path)])
repo.index.commit("Initial commit")
update_config_and_commit(
repo_path=repo_path, config=config, message="Initial commit"
)
typer.echo(f"Successfully created repo in {config_repo}", err=True)


@app.command()
def add_vo(
config_repo: str,
*,
vo: str = "testvo",
default_group: str = "user",
idp_url: str = "https://idp.invalid",
idp_client_id: str = "idp-client-id",
):
"""Add a registry entry (vo) to an existing configuration repository"""

# TODO: The use of parse_obj_as should be moved in to typer itself
config_repo = parse_obj_as(ConfigSourceUrl, config_repo)
repo_path = Path(config_repo.path)

new_registry = RegistryConfig(
IdP=IdpConfig(URL=idp_url, ClientID=idp_client_id),
DefaultGroup=default_group,
Users={},
Groups={},
)

config = ConfigSource.create_from_url(backend_url=repo_path).read_config()

if vo in config.Registry:
typer.echo(f"ERROR: VO {vo} already exists", err=True)
raise typer.Exit(1)

config.Registry[vo] = new_registry

update_config_and_commit(
repo_path=repo_path,
config=config,
message=f"Added vo {vo} registry (default group {default_group} and idp {idp_url})",
)
typer.echo(f"Successfully added vo to {config_repo}", err=True)


@app.command()
def add_group(
config_repo: str,
*,
vo: str = "testvo",
group: str = "user",
properties: List[str] = ["NormalUser"],
):
"""Add a group to an existing vo in the configuration repository"""

# TODO: The use of parse_obj_as should be moved in to typer itself
config_repo = parse_obj_as(ConfigSourceUrl, config_repo)
repo_path = Path(config_repo.path)

new_group = GroupConfig(Properties=set(properties), Quota=None, Users=set())

config = ConfigSource.create_from_url(backend_url=repo_path).read_config()

if group in config.Registry[vo].Groups.keys():
typer.echo(f"ERROR: Group {group} already exists in {vo}", err=True)
raise typer.Exit(1)

config.Registry[vo].Groups[group] = new_group

update_config_and_commit(
repo_path=repo_path, config=config, message=f"Added group {group} in {vo}"
)
typer.echo(f"Successfully added group to {config_repo}", err=True)


@app.command()
def add_user(
config_repo: str,
Expand Down Expand Up @@ -93,12 +146,19 @@ def add_user(

config.Registry[vo].Groups[user_group].Users.add(sub)

update_config_and_commit(
repo_path=repo_path,
config=config,
message=f"Added user {sub} ({preferred_username}) to vo {vo} and user_group {user_group}",
)
typer.echo(f"Successfully added user to {config_repo}", err=True)


def update_config_and_commit(repo_path: Path, config: Config, message: str):
"""Update the yaml file in the repo and commit it"""
repo = git.Repo.init(repo_path)
yaml_path = repo_path / "default.yml"
typer.echo(f"Writing back configuration to {yaml_path}", err=True)
yaml_path.write_text(yaml.safe_dump(config.dict(exclude_unset=True)))
repo.index.add([yaml_path.relative_to(repo_path)])
repo.index.commit(
f"Added user {sub} ({preferred_username}) to vo {vo} and user_group {user_group}"
)
typer.echo(f"Successfully added user to {config_repo}", err=True)
repo.index.commit(message)
112 changes: 112 additions & 0 deletions tests/cli/test_internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,114 @@ def test_generate_cs(tmp_path, protocol):
assert result.exit_code != 0


def test_add_vo(tmp_path):
cs_repo = f"git+file://{tmp_path}"

# Create the CS
runner.invoke(app, ["internal", "generate-cs", cs_repo])

# Add a VO to it
vo1 = "testvo"
result = runner.invoke(app, ["internal", "add-vo", cs_repo, "--vo", vo1])
assert result.exit_code == 0, result.output

config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()

assert vo1 in config.Registry
assert config.Registry[vo1].DefaultGroup == "user"
assert config.Registry[vo1].IdP.URL == "https://idp.invalid"

# Add a second VO to it
vo2 = "lhcb"
result = runner.invoke(
app,
[
"internal",
"add-vo",
cs_repo,
"--vo",
vo2,
"--default-group",
"admin",
"--idp-url",
"https://idp.example.com",
],
)

config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()
assert result.exit_code == 0, result.output

assert vo2 in config.Registry
assert config.Registry[vo2].DefaultGroup == "admin"
assert config.Registry[vo2].IdP.URL == "https://idp.example.com"

# Try to insert a VO that already exists
result = runner.invoke(app, ["internal", "add-vo", cs_repo, "--vo", vo1])
assert result.exit_code != 0, result.output


def test_add_group(tmp_path):
cs_repo = f"git+file://{tmp_path}"
vo = "testvo"
group1 = "testgroup"
group2 = "cta"

# Create the CS
runner.invoke(app, ["internal", "generate-cs", cs_repo])
runner.invoke(app, ["internal", "add-vo", cs_repo, "--vo", vo])

# Add a group to it
result = runner.invoke(
app, ["internal", "add-group", cs_repo, "--vo", vo, "--group", group1]
)
assert result.exit_code == 0, result.output

config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()

assert group1 in config.Registry[vo].Groups
assert config.Registry[vo].Groups[group1].JobShare == 1000
assert config.Registry[vo].Groups[group1].Properties == {"NormalUser"}
assert config.Registry[vo].Groups[group1].Users == set()

# Add a second group to it
result = runner.invoke(
app,
[
"internal",
"add-group",
cs_repo,
"--vo",
vo,
"--group",
group2,
"--properties",
"NormalUser",
"--properties",
"AdminUser",
],
)
config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()
assert result.exit_code == 0, result.output

assert group2 in config.Registry[vo].Groups
assert config.Registry[vo].Groups[group2].JobShare == 1000
assert config.Registry[vo].Groups[group2].Properties == {"AdminUser", "NormalUser"}
assert config.Registry[vo].Groups[group2].Users == set()

# Try to insert a group that already exists
result = runner.invoke(
app, ["internal", "add-group", cs_repo, "--vo", vo, "--group", group1]
)
assert result.exit_code != 0, result.output

# Try to insert a group with a non-existing VO
result = runner.invoke(
app,
["internal", "add-group", cs_repo, "--vo", "nonexistingvo", "--group", group1],
)
assert result.exit_code != 0, result.output


@pytest.mark.parametrize("vo", ["nonexistingvo", "testvo"])
@pytest.mark.parametrize("user_group", ["nonexisting_group", "user"])
def test_add_user(tmp_path, vo, user_group):
Expand All @@ -35,6 +143,10 @@ def test_add_user(tmp_path, vo, user_group):

# Create the CS
runner.invoke(app, ["internal", "generate-cs", cs_repo])
runner.invoke(app, ["internal", "add-vo", cs_repo, "--vo", "testvo"])
runner.invoke(
app, ["internal", "add-group", cs_repo, "--vo", "testvo", "--group", "user"]
)

config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()

Expand Down

0 comments on commit 3c9dddf

Please sign in to comment.