Skip to content

Commit 1a2e563

Browse files
doc: Documenting code, and add a test for PATCH /fields
1 parent 33cfe17 commit 1a2e563

File tree

5 files changed

+73
-26
lines changed

5 files changed

+73
-26
lines changed

diracx-routers/src/diracx/routers/pilots/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async def pilot_login(
5050
dict[str, BaseAccessPolicy], Depends(BaseAccessPolicy.all_used_access_policies)
5151
],
5252
) -> TokenResponse:
53-
"""Endpoint without policy, the pilot uses only its secret."""
53+
"""This endpoint is used by the pilot to exchange a secret for a token."""
5454
try:
5555
access_payload, refresh_payload = await verify_pilot_credentials(
5656
pilot_db=pilot_db,

diracx-routers/src/diracx/routers/pilots/fields.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,7 @@ async def create_pilot_secrets(
5353
pilot_db: PilotAgentsDB,
5454
settings: AuthSettings,
5555
) -> list[PilotSecretsInfo]:
56-
57-
# TODO: Check max for pilot_max
58-
# [SQL: INSERT INTO `PilotSecrets` (`HashedSecret`, `SecretGlobalUseCount`, `SecretGlobalUseCountMax`, `SecretVO`)
59-
# VALUES (%s, %s, %s, %s)]
60-
# [parameters: ('debc69a1f3ada36060b7fea2d1f5bf09339971b089cc2b8037bc3ecba527babf', 0, 1000000000, 'diracAdmin')]
61-
56+
"""Endpoint to create secrets."""
6257
await check_permissions(action=ActionType.CREATE_PILOT_OR_SECRET, vo=vo)
6358

6459
if expiration_minutes and expiration_minutes <= 0:
@@ -141,17 +136,46 @@ async def associate_pilots_with_secrets(
141136
)
142137

143138

139+
EXAMPLE_UPDATE_FIELDS = {
140+
"Update the BenchMark field": {
141+
"summary": "Update BenchMark",
142+
"description": "Update only the BenchMark for one pilot.",
143+
"value": {
144+
"pilot_stamps_to_fields_mapping": [
145+
{"PilotStamp": "the_pilot_stamp", "BenchMark": 1.0}
146+
]
147+
},
148+
},
149+
"Update multiple statuses": {
150+
"summary": "Update multiple pilots",
151+
"description": "Update multiple pilots statuses.",
152+
"value": {
153+
"pilot_stamps_to_fields_mapping": [
154+
{"PilotStamp": "the_first_pilot_stamp", "Status": "Waiting"},
155+
{"PilotStamp": "the_second_pilot_stamp", "Status": "Waiting"},
156+
]
157+
},
158+
},
159+
}
160+
161+
144162
@router.patch("/fields", status_code=HTTPStatus.NO_CONTENT)
145163
async def update_pilot_fields(
146164
pilot_stamps_to_fields_mapping: Annotated[
147165
list[PilotFieldsMapping],
148-
Body(description="(pilot_stamp, pilot_fields) mapping to change.", embed=True),
166+
Body(
167+
description="(pilot_stamp, pilot_fields) mapping to change.",
168+
embed=True,
169+
openapi_examples=EXAMPLE_UPDATE_FIELDS,
170+
),
149171
],
150172
pilot_agents_db: PilotAgentsDB,
151173
check_permissions: CheckPilotManagementPolicyCallable,
152174
):
153-
"""Modify a field of a pilot."""
154-
# TODO: Test this route
175+
"""Modify a field of a pilot.
176+
177+
Note: Only the fields in PilotFieldsMapping are mutable, except for the PilotStamp.
178+
"""
155179
# TODO: Add an example for openapi
156180
pilot_stamps = [mapping.PilotStamp for mapping in pilot_stamps_to_fields_mapping]
157181

@@ -177,6 +201,7 @@ async def associate_pilot_with_jobs(
177201
],
178202
check_permissions: CheckDiracServicesPolicyCallable,
179203
):
204+
"""Endpoint only for DIRAC services, to associate a pilot with a job."""
180205
await check_permissions()
181206

182207
try:

diracx-routers/src/diracx/routers/pilots/management.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from ..utils.users import AuthorizedUserInfo, verify_dirac_access_token
2525
from .access_policies import (
2626
ActionType,
27+
CheckDiracServicesPolicyCallable,
2728
CheckPilotManagementPolicyCallable,
2829
)
2930

@@ -95,7 +96,10 @@ async def delete_pilots(
9596
pilot_agents_db: PilotAgentsDB,
9697
check_permissions: CheckPilotManagementPolicyCallable,
9798
):
98-
"""Endpoint to delete a pilot."""
99+
"""Endpoint to delete a pilot.
100+
101+
If at least one pilot is not found, it WILL rollback.
102+
"""
99103
await check_permissions(
100104
action=ActionType.CHANGE_PILOT_FIELD,
101105
pilot_stamps=pilot_stamps,
@@ -125,7 +129,7 @@ async def clear_pilots(
125129
)
126130
),
127131
],
128-
check_permissions: CheckPilotManagementPolicyCallable,
132+
check_permissions: CheckDiracServicesPolicyCallable,
129133
delete_only_aborted: Annotated[
130134
bool,
131135
Query(
@@ -137,13 +141,8 @@ async def clear_pilots(
137141
),
138142
] = True,
139143
):
140-
"""Delete all pilots that lived more than age_in_days."""
141-
# TODO: Be stricter here and only allow admins?
142-
# TODO: Add test (how to test? Millisec?)
143-
await check_permissions(
144-
action=ActionType.CREATE_PILOT_OR_SECRET,
145-
pilot_db=pilot_agents_db,
146-
)
144+
"""Endpoint for DIRAC to delete all pilots that lived more than age_in_days."""
145+
await check_permissions()
147146

148147
if age_in_days < 0:
149148
raise HTTPException(

diracx-routers/src/diracx/routers/pilots/query.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
"value": {"search": [{"parameter": "PilotID", "operator": "eq", "value": "5"}]},
3030
},
3131
"Get ordered pilot statuses": {
32-
"summary": "Get ordered job statuses",
33-
"description": "Get only job statuses for specific jobs, ordered by status",
32+
"summary": "Get ordered pilot statuses",
33+
"description": "Get only pilot statuses for specific pilots, ordered by status",
3434
"value": {
3535
"parameters": ["PilotID", "Status"],
3636
"search": [
@@ -115,7 +115,7 @@ async def search(
115115
] = None,
116116
) -> list[dict[str, Any]]:
117117
"""Retrieve information about pilots."""
118-
# TODO: Test this route
118+
# Inspired by /api/jobs/query
119119
await check_permissions(action=ActionType.READ_PILOT_FIELDS)
120120

121121
total, pilots = await get_pilot_info_bl(

diracx-routers/tests/pilots/test_pilot_creation.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,12 @@ async def test_create_pilot_and_delete_it(normal_test_client):
297297

298298

299299
async def test_create_pilot_and_modify_it(normal_test_client):
300-
pilot_stamp = "stamps_1"
300+
pilot_stamps = ["stamps_1", "stamp_2"]
301301

302302
# -------------- Insert --------------
303-
body = {"vo": MAIN_VO, "pilot_stamps": [pilot_stamp]}
303+
body = {"vo": MAIN_VO, "pilot_stamps": pilot_stamps}
304304

305-
# Create a pilot
305+
# Create pilots
306306
r = normal_test_client.post(
307307
"/api/pilots/",
308308
json=body,
@@ -311,10 +311,11 @@ async def test_create_pilot_and_modify_it(normal_test_client):
311311
assert r.status_code == 200, r.json()
312312

313313
# -------------- Modify --------------
314+
# We modify only the first pilot
314315
body = {
315316
"pilot_stamps_to_fields_mapping": [
316317
PilotFieldsMapping(
317-
PilotStamp=pilot_stamp,
318+
PilotStamp=pilot_stamps[0],
318319
BenchMark=1.0,
319320
StatusReason="NewReason",
320321
AccountingSent=True,
@@ -326,3 +327,25 @@ async def test_create_pilot_and_modify_it(normal_test_client):
326327
r = normal_test_client.patch("/api/pilots/fields", json=body)
327328

328329
assert r.status_code == 204
330+
331+
body = {
332+
"parameters": [],
333+
"search": [],
334+
"sort": [],
335+
"distinct": True,
336+
}
337+
338+
r = normal_test_client.post("/api/pilots/search", json=body)
339+
assert r.status_code == 200, r.json()
340+
pilot1 = r.json()[0]
341+
pilot2 = r.json()[1]
342+
343+
assert pilot1["BenchMark"] == 1.0
344+
assert pilot1["StatusReason"] == "NewReason"
345+
assert pilot1["AccountingSent"]
346+
assert pilot1["Status"] == "Waiting"
347+
348+
assert pilot2["BenchMark"] != pilot1["BenchMark"]
349+
assert pilot2["StatusReason"] != pilot1["StatusReason"]
350+
assert pilot2["AccountingSent"] != pilot1["AccountingSent"]
351+
assert pilot2["Status"] != pilot1["Status"]

0 commit comments

Comments
 (0)