Skip to content

Commit 43cfccc

Browse files
feat: Migrating pilot functionalities from DIRAC, and add DiracX pilot auth
Squashed commits: [33cfe17] test: Changing from sleep to freezegun #537 [3e5d677] refactor: Refactorized the exceptions [d84f6fe] doc: Documenting the database [1c0db02] test: Better testing: Tested search engine [cd1caf4] refactor: Refactoring from the auth router to the pilot router [9cc99f1] feat: Adding indexes to the database [de0b580] refactor: Moved the pilot_to_secret_mapping into the pilotagents table itself [14396f6] refactoring: Lots of refactoring of the code [56daac5] refactor: Moving db parts to the logic, and some fixes [79a11cf] fix: Fixed dependency and client [8c45582] test: Tested interval deletion for the db. [dd07bca] feat: We can clear pilots that lived more than n days [7e93153] feat: We can search for pilots [9da8033] feat: DIRAC can associate a pilot with a job [77a59b0] feat: We can modify pilot fields (statuses, benchmarks, ...) [ca0e727] fix: Added pilot management [521164f] fix: Fixed text [8e6e881] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci [adadb68] fix: Semantic [15d9fe6] feat: We can add a number of use max for the secret in pilot registration [4549203] fix: Fixed cli [a9ece0a] feat: Adding a command to add a pilot to the CS, and some fixes [42e4f0b] fix: Changed secret expiration from 600 to 3600s [1dcb4b8] fix: Regenerated client [02a5e31] feat: A user can create secrets, and associate them to a pilot [8072227] feat: Ability to add only secrets, and lots of refactoring in the tests [10205d6] feat: Autodeletion of secrets after full use or expiration. [3f013df] feat: Restricting a secret for a certain VO [c2181aa] fix: Chunky client [d374ec6] feat: Changing the pilot login db, and moved from references to stamps [aa67bda] fix: Regenerating client [135235f] feat: Using pilot user, model for pilot creds, and documentation [0e0a117] feat: Added last_time_used for a pilot secret, and a max value [62977ee] fix: Few fixes with refactoring, and tests (+4 squashed commits) Squashed commits: [5169ee2] refactor: Moved login for pilots into token file [12da5c0] fix: Fixed according the the new commits from main branch [a8e06d8] fix: Fixed client [93b83b4] fix: Fixed the tests and autorest [a78c028] feat: A user can register pilots and get their credentials [1e9f907] fix: Removing the pilot login cli [3f7c632] feat: Adding duration to secrets [8aff5d9] fix: Regenerating client, type ignore for the cli Squashed commits: [06a969b] fix: Type ignore for mypy... [28e1ee1] fix: Generated code broke everything [339ab4f] fix: Fixed cli and pilot endpoints [31af99e] fix: Regenerated client [a171d01] feat: Added pilot login to the cli [54951a6] fix: Correcting client generation with the error patch Squashed commits: [65db1ae] fix: Regenerating clients with autorest [5a4f370] feat: Better handling of refresh tokens for pilots [6da7bb4] fix: Generating client with autorest [2c4d2fb] feat: Adding pilot registrations
1 parent 8fd7d1c commit 43cfccc

File tree

51 files changed

+10325
-245
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+10325
-245
lines changed

diracx-cli/src/diracx/cli/internal/config.py

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def generate_cs(config_repo: str):
5959
update_config_and_commit(
6060
repo_path=repo_path, config=config, message="Initial commit"
6161
)
62-
typer.echo(f"Successfully created repo in {config_repo}", err=True)
62+
typer.echo(f"Successfully created repo in {config_repo}")
6363

6464

6565
@app.command()
@@ -93,13 +93,14 @@ def add_vo(
9393
raise typer.Exit(1)
9494

9595
config.Registry[vo] = new_registry
96+
config.Operations[vo] = OperationsConfig(Pilot={})
9697

9798
update_config_and_commit(
9899
repo_path=repo_path,
99100
config=config,
100101
message=f"Added vo {vo} registry (default group {default_group} and idp {idp_url})",
101102
)
102-
typer.echo(f"Successfully added vo to {config_repo}", err=True)
103+
typer.echo(f"Successfully added vo to {config_repo}")
103104

104105

105106
@app.command()
@@ -130,7 +131,7 @@ def add_group(
130131
update_config_and_commit(
131132
repo_path=repo_path, config=config, message=f"Added group {group} in {vo}"
132133
)
133-
typer.echo(f"Successfully added group to {config_repo}", err=True)
134+
typer.echo(f"Successfully added group to {config_repo}")
134135

135136

136137
@app.command()
@@ -177,7 +178,103 @@ def add_user(
177178
config=config,
178179
message=f"Added user {sub} ({preferred_username}) to vo {vo} and groups {groups}",
179180
)
180-
typer.echo(f"Successfully added user to {config_repo}", err=True)
181+
typer.echo(f"Successfully added user to {config_repo}")
182+
183+
184+
@app.command()
185+
def set_user_as_pilot_user(
186+
config_repo: str,
187+
*,
188+
vo: Annotated[str, typer.Option()],
189+
pilot_group: Annotated[str, typer.Option()],
190+
sub: Annotated[str, typer.Option()],
191+
pilot_preferred_username: Annotated[str, typer.Option()],
192+
):
193+
"""Set a user as a pilot.
194+
195+
*Warning*: This requires an existing VO, and also a group and a pilot dedicated to the pilot.
196+
"""
197+
config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
198+
if config_repo.scheme != "git+file" or config_repo.path is None:
199+
raise NotImplementedError("Only git+file:// URLs are supported")
200+
201+
repo_path = Path(config_repo.path)
202+
203+
config = ConfigSource.create_from_url(backend_url=repo_path).read_config()
204+
205+
# The VO has to exist
206+
if vo not in config.Registry:
207+
typer.secho(
208+
f"ERROR: Virtual Organization {vo} does not exist", err=True, fg="red"
209+
)
210+
raise typer.Exit(1)
211+
212+
# The sub has to exist
213+
if sub not in config.Registry[vo].Users:
214+
typer.secho(
215+
f"ERROR: User {sub} does not exist. You have to create it first before setting it as a pilot user",
216+
err=True,
217+
fg="red",
218+
)
219+
raise typer.Exit(1)
220+
221+
# The preferred_username has to match the sub
222+
if not config.Registry[vo].Users[sub].PreferedUsername == pilot_preferred_username:
223+
typer.secho(
224+
f"ERROR: User {sub} does not match pilot_preferred_username {pilot_preferred_username}",
225+
err=True,
226+
fg="red",
227+
)
228+
raise typer.Exit(1)
229+
230+
# The pilot group has to exist
231+
groups = config.Registry[vo].Groups
232+
if pilot_group not in groups:
233+
typer.secho(
234+
(
235+
f"ERROR: Group {pilot_group} does not exist."
236+
"You have to create it first before setting it as a pilot group"
237+
),
238+
err=True,
239+
fg="red",
240+
)
241+
raise typer.Exit(1)
242+
243+
# The sub has to be in the pilot group
244+
group_users = groups[pilot_group].Users
245+
if sub not in group_users:
246+
typer.secho(
247+
(
248+
f"ERROR: User {sub} is not set into the pilot group."
249+
"You have to add it before setting this group as a pilot group"
250+
),
251+
err=True,
252+
fg="red",
253+
)
254+
raise typer.Exit(1)
255+
256+
# Now we know that our pilot is in the pilot_group
257+
# We need to define the Operations
258+
# Normally, if we have a group, vo, ..., we do have Operations[vo]
259+
260+
# If the current pilot_group is different, just change it
261+
# No error is raised. We could change the "official" pilot group
262+
pilot = config.Operations[vo].Pilot
263+
264+
if pilot is None:
265+
typer.secho("Pilot operation must not be None", err=True, fg="red")
266+
raise typer.Exit(1)
267+
268+
pilot["GenericPilotGroup"] = pilot_group
269+
pilot["GenericPilotUser"] = pilot_preferred_username
270+
271+
update_config_and_commit(
272+
repo_path=repo_path,
273+
config=config,
274+
message=f"Setting user {sub} ({pilot_preferred_username}) as {vo}'s pilot user in group {pilot_group}",
275+
)
276+
typer.secho(f"Successfully set user as pilot to {config_repo}", fg="green")
277+
typer.secho(f"New config :\n{config}", fg="green")
181278

182279

183280
def update_config_and_commit(repo_path: Path, config: Config, message: str):

diracx-cli/tests/test_internal.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,64 @@ def test_add_user(cs_repo, vo, user_group):
222222
assert sub in config.Registry[vo].Users
223223
for group in user_group or [TEST_USER_GROUP]:
224224
assert config.Registry[vo].Groups[group].Users == {sub}
225+
226+
227+
def test_add_pilot_user(cs_repo):
228+
229+
sub = "lhcb:rvandeme"
230+
231+
pilot_group = "pilot_group"
232+
pilot_user = "pilot_user"
233+
234+
config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()
235+
236+
# Add a second group to it
237+
result = runner.invoke(
238+
app,
239+
[
240+
"internal",
241+
"add-group",
242+
cs_repo,
243+
f"--vo={TEST_VO}",
244+
f"--group={pilot_group}",
245+
"--properties",
246+
"GenericPilot",
247+
],
248+
)
249+
assert result.exit_code == 0, result.output
250+
251+
# Add a user to it
252+
result = runner.invoke(
253+
app,
254+
[
255+
"internal",
256+
"add-user",
257+
cs_repo,
258+
f"--vo={TEST_VO}",
259+
f"--sub={sub}",
260+
f"--preferred-username={pilot_user}",
261+
f"--group={pilot_group}",
262+
],
263+
)
264+
assert result.exit_code == 0, result.output
265+
266+
# Set this user as a pilot
267+
result = runner.invoke(
268+
app,
269+
[
270+
"internal",
271+
"set-user-as-pilot-user",
272+
cs_repo,
273+
f"--vo={TEST_VO}",
274+
f"--sub={sub}",
275+
f"--pilot-preferred-username={pilot_user}",
276+
f"--pilot-group={pilot_group}",
277+
],
278+
)
279+
assert result.exit_code == 0, result.output
280+
281+
config = ConfigSource.create_from_url(backend_url=cs_repo).read_config()
282+
283+
# User pilot exists, same for pilot group
284+
assert config.Operations[TEST_VO].Pilot["GenericPilotUser"] == pilot_user
285+
assert config.Operations[TEST_VO].Pilot["GenericPilotGroup"] == pilot_group

diracx-client/src/diracx/client/_generated/_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
AuthOperations,
2020
ConfigOperations,
2121
JobsOperations,
22+
PilotsOperations,
2223
WellKnownOperations,
2324
)
2425

@@ -34,6 +35,8 @@ class Dirac: # pylint: disable=client-accepts-api-version-keyword
3435
:vartype config: _generated.operations.ConfigOperations
3536
:ivar jobs: JobsOperations operations
3637
:vartype jobs: _generated.operations.JobsOperations
38+
:ivar pilots: PilotsOperations operations
39+
:vartype pilots: _generated.operations.PilotsOperations
3740
:keyword endpoint: Service URL. Required. Default value is "".
3841
:paramtype endpoint: str
3942
"""
@@ -86,6 +89,9 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential
8689
self.jobs = JobsOperations(
8790
self._client, self._config, self._serialize, self._deserialize
8891
)
92+
self.pilots = PilotsOperations(
93+
self._client, self._config, self._serialize, self._deserialize
94+
)
8995

9096
def send_request(
9197
self, request: HttpRequest, *, stream: bool = False, **kwargs: Any

diracx-client/src/diracx/client/_generated/aio/_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
AuthOperations,
2020
ConfigOperations,
2121
JobsOperations,
22+
PilotsOperations,
2223
WellKnownOperations,
2324
)
2425

@@ -34,6 +35,8 @@ class Dirac: # pylint: disable=client-accepts-api-version-keyword
3435
:vartype config: _generated.aio.operations.ConfigOperations
3536
:ivar jobs: JobsOperations operations
3637
:vartype jobs: _generated.aio.operations.JobsOperations
38+
:ivar pilots: PilotsOperations operations
39+
:vartype pilots: _generated.aio.operations.PilotsOperations
3740
:keyword endpoint: Service URL. Required. Default value is "".
3841
:paramtype endpoint: str
3942
"""
@@ -86,6 +89,9 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential
8689
self.jobs = JobsOperations(
8790
self._client, self._config, self._serialize, self._deserialize
8891
)
92+
self.pilots = PilotsOperations(
93+
self._client, self._config, self._serialize, self._deserialize
94+
)
8995

9096
def send_request(
9197
self, request: HttpRequest, *, stream: bool = False, **kwargs: Any

diracx-client/src/diracx/client/_generated/aio/operations/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ._operations import AuthOperations # type: ignore
1515
from ._operations import ConfigOperations # type: ignore
1616
from ._operations import JobsOperations # type: ignore
17+
from ._operations import PilotsOperations # type: ignore
1718

1819
from ._patch import __all__ as _patch_all
1920
from ._patch import *
@@ -24,6 +25,7 @@
2425
"AuthOperations",
2526
"ConfigOperations",
2627
"JobsOperations",
28+
"PilotsOperations",
2729
]
2830
__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore
2931
_patch_sdk()

0 commit comments

Comments
 (0)