diracx-cli 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/PKG-INFO +1 -1
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/__init__.py +2 -3
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/auth.py +1 -1
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/config.py +1 -1
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/internal/__init__.py +2 -2
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/internal/config.py +28 -25
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/internal/legacy.py +20 -19
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/jobs.py +2 -2
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/utils.py +1 -1
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/cs_sync/test_cssync.py +1 -1
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/test_internal.py +21 -21
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/test_login.py +1 -1
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/.gitignore +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/LICENSE +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/README.md +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/pyproject.toml +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/__main__.py +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/src/diracx/cli/py.typed +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/__init__.py +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/cs_sync/__init__.py +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/cs_sync/integration_test.cfg +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/cs_sync/integration_test.yaml +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/cs_sync/integration_test_buggy.cfg +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/cs_sync/integration_test_secret.cfg +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/legacy/test_legacy.py +0 -0
- {diracx_cli-0.1.0 → diracx_cli-0.2.0}/tests/test_jobs.py +0 -0
|
@@ -8,9 +8,10 @@ import typer
|
|
|
8
8
|
import yaml
|
|
9
9
|
from pydantic import TypeAdapter
|
|
10
10
|
|
|
11
|
-
from diracx.core.config import
|
|
12
|
-
from diracx.core.config.schema import (
|
|
11
|
+
from diracx.core.config import (
|
|
13
12
|
Config,
|
|
13
|
+
ConfigSource,
|
|
14
|
+
ConfigSourceUrl,
|
|
14
15
|
DIRACConfig,
|
|
15
16
|
GroupConfig,
|
|
16
17
|
IdpConfig,
|
|
@@ -50,9 +51,9 @@ def generate_cs(config_repo: str):
|
|
|
50
51
|
raise typer.Exit(1)
|
|
51
52
|
|
|
52
53
|
config = Config(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
registry={},
|
|
55
|
+
dirac=DIRACConfig(),
|
|
56
|
+
operations={"Defaults": OperationsConfig()},
|
|
56
57
|
)
|
|
57
58
|
|
|
58
59
|
git.Repo.init(repo_path, initial_branch="master")
|
|
@@ -78,21 +79,21 @@ def add_vo(
|
|
|
78
79
|
|
|
79
80
|
# A VO should at least contain a default group
|
|
80
81
|
new_registry = RegistryConfig(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
idp=IdpConfig(url=idp_url, client_id=idp_client_id),
|
|
83
|
+
default_group=default_group,
|
|
84
|
+
users={},
|
|
85
|
+
groups={
|
|
85
86
|
default_group: GroupConfig(
|
|
86
|
-
|
|
87
|
+
properties={"NormalUser"}, quota=None, users=set()
|
|
87
88
|
)
|
|
88
89
|
},
|
|
89
90
|
)
|
|
90
91
|
|
|
91
|
-
if vo in config.
|
|
92
|
+
if vo in config.registry:
|
|
92
93
|
typer.echo(f"ERROR: VO {vo} already exists", err=True)
|
|
93
94
|
raise typer.Exit(1)
|
|
94
95
|
|
|
95
|
-
config.
|
|
96
|
+
config.registry[vo] = new_registry
|
|
96
97
|
|
|
97
98
|
update_config_and_commit(
|
|
98
99
|
repo_path=repo_path,
|
|
@@ -115,17 +116,17 @@ def add_group(
|
|
|
115
116
|
repo_path = get_repo_path(config_repo)
|
|
116
117
|
config = get_config_from_repo_path(repo_path)
|
|
117
118
|
|
|
118
|
-
new_group = GroupConfig(
|
|
119
|
+
new_group = GroupConfig(properties=set(properties), quota=None, users=set())
|
|
119
120
|
|
|
120
|
-
if vo not in config.
|
|
121
|
+
if vo not in config.registry:
|
|
121
122
|
typer.echo(f"ERROR: Virtual Organization {vo} does not exist", err=True)
|
|
122
123
|
raise typer.Exit(1)
|
|
123
124
|
|
|
124
|
-
if group in config.
|
|
125
|
+
if group in config.registry[vo].groups.keys():
|
|
125
126
|
typer.echo(f"ERROR: Group {group} already exists in {vo}", err=True)
|
|
126
127
|
raise typer.Exit(1)
|
|
127
128
|
|
|
128
|
-
config.
|
|
129
|
+
config.registry[vo].groups[group] = new_group
|
|
129
130
|
|
|
130
131
|
update_config_and_commit(
|
|
131
132
|
repo_path=repo_path, config=config, message=f"Added group {group} in {vo}"
|
|
@@ -147,30 +148,30 @@ def add_user(
|
|
|
147
148
|
repo_path = get_repo_path(config_repo)
|
|
148
149
|
config = get_config_from_repo_path(repo_path)
|
|
149
150
|
|
|
150
|
-
new_user = UserConfig(
|
|
151
|
+
new_user = UserConfig(prefered_username=preferred_username)
|
|
151
152
|
|
|
152
|
-
if vo not in config.
|
|
153
|
+
if vo not in config.registry:
|
|
153
154
|
typer.echo(f"ERROR: Virtual Organization {vo} does not exist", err=True)
|
|
154
155
|
raise typer.Exit(1)
|
|
155
156
|
|
|
156
|
-
if sub in config.
|
|
157
|
+
if sub in config.registry[vo].users:
|
|
157
158
|
typer.echo(f"ERROR: User {sub} already exists", err=True)
|
|
158
159
|
raise typer.Exit(1)
|
|
159
160
|
|
|
160
|
-
config.
|
|
161
|
+
config.registry[vo].users[sub] = new_user
|
|
161
162
|
|
|
162
163
|
if not groups:
|
|
163
|
-
groups = [config.
|
|
164
|
+
groups = [config.registry[vo].default_group]
|
|
164
165
|
|
|
165
166
|
for group in set(groups):
|
|
166
|
-
if group not in config.
|
|
167
|
+
if group not in config.registry[vo].groups:
|
|
167
168
|
typer.echo(f"ERROR: Group {group} does not exist in {vo}", err=True)
|
|
168
169
|
raise typer.Exit(1)
|
|
169
|
-
if sub in config.
|
|
170
|
+
if sub in config.registry[vo].groups[group].users:
|
|
170
171
|
typer.echo(f"ERROR: User {sub} already exists in group {group}", err=True)
|
|
171
172
|
raise typer.Exit(1)
|
|
172
173
|
|
|
173
|
-
config.
|
|
174
|
+
config.registry[vo].groups[group].users.add(sub)
|
|
174
175
|
|
|
175
176
|
update_config_and_commit(
|
|
176
177
|
repo_path=repo_path,
|
|
@@ -186,7 +187,9 @@ def update_config_and_commit(repo_path: Path, config: Config, message: str):
|
|
|
186
187
|
yaml_path = repo_path / "default.yml"
|
|
187
188
|
typer.echo(f"Writing back configuration to {yaml_path}", err=True)
|
|
188
189
|
yaml_path.write_text(
|
|
189
|
-
yaml.safe_dump(
|
|
190
|
+
yaml.safe_dump(
|
|
191
|
+
config.model_dump(exclude_unset=True, mode="json", by_alias=True)
|
|
192
|
+
)
|
|
190
193
|
)
|
|
191
194
|
repo.index.add([yaml_path.relative_to(repo_path)])
|
|
192
195
|
repo.index.commit(message)
|
|
@@ -16,11 +16,10 @@ import yaml
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
from diraccfg.cfg import CFGAsDict
|
|
18
18
|
|
|
19
|
-
from pydantic import BaseModel
|
|
19
|
+
from pydantic import BaseModel, Field
|
|
20
20
|
from typer import Option
|
|
21
21
|
|
|
22
|
-
from diracx.core.config import Config
|
|
23
|
-
from diracx.core.config.schema import Field, SupportInfo
|
|
22
|
+
from diracx.core.config import Config, SupportInfo
|
|
24
23
|
from diracx.core.extensions import DiracEntryPoint, select_from_extension
|
|
25
24
|
|
|
26
25
|
from ..utils import AsyncTyper
|
|
@@ -35,19 +34,19 @@ LEGACY_EXCHANGE_PATTERN = rf"diracx:legacy:({BASE_64_URL_SAFE_PATTERN})"
|
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
class IdPConfig(BaseModel):
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
url: str = Field(alias="URL")
|
|
38
|
+
client_id: str = Field(alias="ClientID")
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
class VOConfig(BaseModel):
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
default_group: str = Field(alias="DefaultGroup")
|
|
43
|
+
idp: IdPConfig = Field(alias="IdP")
|
|
44
|
+
user_subjects: dict[str, str] = Field(alias="UserSubjects")
|
|
45
|
+
support: SupportInfo = Field(default_factory=SupportInfo, alias="Support")
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
class ConversionConfig(BaseModel):
|
|
50
|
-
|
|
49
|
+
vos: dict[str, VOConfig] = Field(alias="VOs")
|
|
51
50
|
|
|
52
51
|
|
|
53
52
|
@app.command()
|
|
@@ -82,7 +81,9 @@ def cs_sync(old_file: Path, new_file: Path):
|
|
|
82
81
|
)[0].load()
|
|
83
82
|
config = config_class.model_validate(raw)
|
|
84
83
|
new_file.write_text(
|
|
85
|
-
yaml.safe_dump(
|
|
84
|
+
yaml.safe_dump(
|
|
85
|
+
config.model_dump(by_alias=True, exclude_unset=True, mode="json")
|
|
86
|
+
)
|
|
86
87
|
)
|
|
87
88
|
|
|
88
89
|
|
|
@@ -113,20 +114,20 @@ def _apply_fixes(raw):
|
|
|
113
114
|
|
|
114
115
|
# Check that we have the config for all the VOs
|
|
115
116
|
vos = set(raw["Registry"].get("VO", []))
|
|
116
|
-
if non_configured_vos := vos - set(conv_config.
|
|
117
|
+
if non_configured_vos := vos - set(conv_config.vos):
|
|
117
118
|
print(f"{non_configured_vos} don't have a migration config, ignoring")
|
|
118
119
|
|
|
119
120
|
# Modify the registry to be fully multi-VO
|
|
120
121
|
original_registry = raw.pop("Registry")
|
|
121
122
|
raw["Registry"] = {}
|
|
122
123
|
|
|
123
|
-
for vo, vo_meta in conv_config.
|
|
124
|
+
for vo, vo_meta in conv_config.vos.items():
|
|
124
125
|
raw["Registry"][vo] = {
|
|
125
|
-
"IdP": vo_meta.
|
|
126
|
-
"DefaultGroup": vo_meta.
|
|
126
|
+
"IdP": vo_meta.idp.model_dump(by_alias=True),
|
|
127
|
+
"DefaultGroup": vo_meta.default_group,
|
|
127
128
|
"Users": {},
|
|
128
129
|
"Groups": {},
|
|
129
|
-
"Support": vo_meta.
|
|
130
|
+
"Support": vo_meta.support,
|
|
130
131
|
}
|
|
131
132
|
if "DefaultStorageQuota" in original_registry:
|
|
132
133
|
raw["Registry"][vo]["DefaultStorageQuota"] = original_registry[
|
|
@@ -155,14 +156,14 @@ def _apply_fixes(raw):
|
|
|
155
156
|
nicknames = {u.strip() for u in info["Users"].split(",") if u.strip()}
|
|
156
157
|
vo_users |= nicknames
|
|
157
158
|
raw["Registry"][vo]["Groups"][name]["Users"] = [
|
|
158
|
-
vo_meta.
|
|
159
|
+
vo_meta.user_subjects[n]
|
|
159
160
|
for n in nicknames
|
|
160
|
-
if n in vo_meta.
|
|
161
|
+
if n in vo_meta.user_subjects
|
|
161
162
|
]
|
|
162
163
|
# Find the users that belong to this VO
|
|
163
164
|
for name, info in original_registry["Users"].items():
|
|
164
165
|
if name in vo_users:
|
|
165
|
-
if subject := vo_meta.
|
|
166
|
+
if subject := vo_meta.user_subjects.get(name):
|
|
166
167
|
raw["Registry"][vo]["Users"][subject] = info | {
|
|
167
168
|
"PreferedUsername": name
|
|
168
169
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# from __future__ import annotations
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__all__ =
|
|
5
|
+
__all__ = ["app"]
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import re
|
|
@@ -13,7 +13,7 @@ from rich.table import Table
|
|
|
13
13
|
from typer import FileText, Option
|
|
14
14
|
|
|
15
15
|
from diracx.client.aio import AsyncDiracClient
|
|
16
|
-
from diracx.core.models
|
|
16
|
+
from diracx.core.models import (
|
|
17
17
|
ScalarSearchOperator,
|
|
18
18
|
SearchSpec,
|
|
19
19
|
VectorSearchOperator,
|
|
@@ -74,10 +74,10 @@ def test_generate_cs(tmp_path, protocol):
|
|
|
74
74
|
def test_add_vo(cs_repo):
|
|
75
75
|
config = ConfigSource.create_from_url(backend_url=cs_repo).read()
|
|
76
76
|
|
|
77
|
-
assert TEST_VO in config.
|
|
78
|
-
assert config.
|
|
79
|
-
assert config.
|
|
80
|
-
assert config.
|
|
77
|
+
assert TEST_VO in config.registry
|
|
78
|
+
assert config.registry[TEST_VO].default_group == "user"
|
|
79
|
+
assert config.registry[TEST_VO].idp.url == "https://idp.invalid"
|
|
80
|
+
assert config.registry[TEST_VO].idp.client_id == "idp-client-id"
|
|
81
81
|
|
|
82
82
|
# Add a second VO to it
|
|
83
83
|
vo2 = "lhcb"
|
|
@@ -98,10 +98,10 @@ def test_add_vo(cs_repo):
|
|
|
98
98
|
config = ConfigSource.create_from_url(backend_url=cs_repo).read()
|
|
99
99
|
assert result.exit_code == 0, result.output
|
|
100
100
|
|
|
101
|
-
assert vo2 in config.
|
|
102
|
-
assert config.
|
|
103
|
-
assert config.
|
|
104
|
-
assert config.
|
|
101
|
+
assert vo2 in config.registry
|
|
102
|
+
assert config.registry[vo2].default_group == "admin"
|
|
103
|
+
assert config.registry[vo2].idp.url == "https://idp.example.invalid"
|
|
104
|
+
assert config.registry[vo2].idp.client_id == "idp-client-id2"
|
|
105
105
|
|
|
106
106
|
# Try to insert a VO that already exists
|
|
107
107
|
result = runner.invoke(
|
|
@@ -123,10 +123,10 @@ def test_add_group(cs_repo):
|
|
|
123
123
|
|
|
124
124
|
config = ConfigSource.create_from_url(backend_url=cs_repo).read()
|
|
125
125
|
|
|
126
|
-
assert TEST_USER_GROUP in config.
|
|
127
|
-
assert config.
|
|
128
|
-
assert config.
|
|
129
|
-
assert config.
|
|
126
|
+
assert TEST_USER_GROUP in config.registry[TEST_VO].groups
|
|
127
|
+
assert config.registry[TEST_VO].groups[TEST_USER_GROUP].job_share == 1000
|
|
128
|
+
assert config.registry[TEST_VO].groups[TEST_USER_GROUP].properties == {"NormalUser"}
|
|
129
|
+
assert config.registry[TEST_VO].groups[TEST_USER_GROUP].users == set()
|
|
130
130
|
|
|
131
131
|
# Add a second group to it
|
|
132
132
|
result = runner.invoke(
|
|
@@ -146,13 +146,13 @@ def test_add_group(cs_repo):
|
|
|
146
146
|
config = ConfigSource.create_from_url(backend_url=cs_repo).read()
|
|
147
147
|
assert result.exit_code == 0, result.output
|
|
148
148
|
|
|
149
|
-
assert new_group in config.
|
|
150
|
-
assert config.
|
|
151
|
-
assert config.
|
|
149
|
+
assert new_group in config.registry[TEST_VO].groups
|
|
150
|
+
assert config.registry[TEST_VO].groups[new_group].job_share == 1000
|
|
151
|
+
assert config.registry[TEST_VO].groups[new_group].properties == {
|
|
152
152
|
"AdminUser",
|
|
153
153
|
"NormalUser",
|
|
154
154
|
}
|
|
155
|
-
assert config.
|
|
155
|
+
assert config.registry[TEST_VO].groups[new_group].users == set()
|
|
156
156
|
|
|
157
157
|
# Try to insert a group that already exists
|
|
158
158
|
result = runner.invoke(
|
|
@@ -193,8 +193,8 @@ def test_add_user(cs_repo, vo, user_group):
|
|
|
193
193
|
config = ConfigSource.create_from_url(backend_url=cs_repo).read()
|
|
194
194
|
|
|
195
195
|
# Check the user isn't in it
|
|
196
|
-
if vo in config.
|
|
197
|
-
assert sub not in config.
|
|
196
|
+
if vo in config.registry:
|
|
197
|
+
assert sub not in config.registry[vo].users
|
|
198
198
|
|
|
199
199
|
# Add a user to it
|
|
200
200
|
result = runner.invoke(
|
|
@@ -218,7 +218,7 @@ def test_add_user(cs_repo, vo, user_group):
|
|
|
218
218
|
|
|
219
219
|
config = ConfigSource.create_from_url(backend_url=cs_repo).read()
|
|
220
220
|
# check the user is defined
|
|
221
|
-
assert vo in config.
|
|
222
|
-
assert sub in config.
|
|
221
|
+
assert vo in config.registry
|
|
222
|
+
assert sub in config.registry[vo].users
|
|
223
223
|
for group in user_group or [TEST_USER_GROUP]:
|
|
224
|
-
assert config.
|
|
224
|
+
assert config.registry[vo].groups[group].users == {sub}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|