diracx-cli 0.0.1a16__tar.gz → 0.0.1a18__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.0.1a16 → diracx_cli-0.0.1a18}/PKG-INFO +2 -2
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/pyproject.toml +1 -1
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/internal/__init__.py +25 -22
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/internal/legacy.py +14 -13
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/jobs.py +11 -2
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx_cli.egg-info/PKG-INFO +2 -2
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/cs_sync/integration_test.yaml +29 -29
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/cs_sync/test_cssync.py +1 -1
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/test_jobs.py +2 -6
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/README.md +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/setup.cfg +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/__init__.py +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/__main__.py +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/config.py +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/py.typed +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx/cli/utils.py +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx_cli.egg-info/SOURCES.txt +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx_cli.egg-info/dependency_links.txt +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx_cli.egg-info/entry_points.txt +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx_cli.egg-info/requires.txt +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/src/diracx_cli.egg-info/top_level.txt +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/cs_sync/integration_test.cfg +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/cs_sync/integration_test_buggy.cfg +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/cs_sync/integration_test_secret.cfg +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/test_legacy.py +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/test_internal.py +0 -0
- {diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/test_login.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: diracx-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1a18
|
|
4
4
|
Summary: TODO
|
|
5
5
|
License: GPL-3.0-only
|
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -8,7 +8,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Topic :: Scientific/Engineering
|
|
10
10
|
Classifier: Topic :: System :: Distributed Computing
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Requires-Dist: diraccfg
|
|
14
14
|
Requires-Dist: diracx-api
|
|
@@ -4,7 +4,7 @@ from typing import Annotated, Optional
|
|
|
4
4
|
import git
|
|
5
5
|
import typer
|
|
6
6
|
import yaml
|
|
7
|
-
from pydantic import
|
|
7
|
+
from pydantic import TypeAdapter
|
|
8
8
|
|
|
9
9
|
from diracx.core.config import ConfigSource, ConfigSourceUrl
|
|
10
10
|
from diracx.core.config.schema import (
|
|
@@ -25,13 +25,11 @@ app.add_typer(legacy.app, name="legacy")
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
@app.command()
|
|
28
|
-
def generate_cs(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
config_repo = parse_obj_as(ConfigSourceUrl, config_repo)
|
|
34
|
-
if config_repo.scheme != "git+file":
|
|
28
|
+
def generate_cs(config_repo: str):
|
|
29
|
+
"""Generate a minimal DiracX configuration repository."""
|
|
30
|
+
# TODO: The use of TypeAdapter should be moved in to typer itself
|
|
31
|
+
config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
|
|
32
|
+
if config_repo.scheme != "git+file" or config_repo.path is None:
|
|
35
33
|
raise NotImplementedError("Only git+file:// URLs are supported")
|
|
36
34
|
repo_path = Path(config_repo.path)
|
|
37
35
|
if repo_path.exists() and list(repo_path.iterdir()):
|
|
@@ -60,10 +58,11 @@ def add_vo(
|
|
|
60
58
|
idp_url: Annotated[str, typer.Option()],
|
|
61
59
|
idp_client_id: Annotated[str, typer.Option()],
|
|
62
60
|
):
|
|
63
|
-
"""Add a registry entry (vo) to an existing configuration repository"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
config_repo
|
|
61
|
+
"""Add a registry entry (vo) to an existing configuration repository."""
|
|
62
|
+
# TODO: The use of TypeAdapter should be moved in to typer itself
|
|
63
|
+
config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
|
|
64
|
+
if config_repo.scheme != "git+file" or config_repo.path is None:
|
|
65
|
+
raise NotImplementedError("Only git+file:// URLs are supported")
|
|
67
66
|
repo_path = Path(config_repo.path)
|
|
68
67
|
|
|
69
68
|
# A VO should at least contain a default group
|
|
@@ -102,10 +101,11 @@ def add_group(
|
|
|
102
101
|
group: Annotated[str, typer.Option()],
|
|
103
102
|
properties: list[str] = ["NormalUser"],
|
|
104
103
|
):
|
|
105
|
-
"""Add a group to an existing vo in the configuration repository"""
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
config_repo
|
|
104
|
+
"""Add a group to an existing vo in the configuration repository."""
|
|
105
|
+
# TODO: The use of TypeAdapter should be moved in to typer itself
|
|
106
|
+
config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
|
|
107
|
+
if config_repo.scheme != "git+file" or config_repo.path is None:
|
|
108
|
+
raise NotImplementedError("Only git+file:// URLs are supported")
|
|
109
109
|
repo_path = Path(config_repo.path)
|
|
110
110
|
|
|
111
111
|
new_group = GroupConfig(Properties=set(properties), Quota=None, Users=set())
|
|
@@ -137,10 +137,11 @@ def add_user(
|
|
|
137
137
|
sub: Annotated[str, typer.Option()],
|
|
138
138
|
preferred_username: Annotated[str, typer.Option()],
|
|
139
139
|
):
|
|
140
|
-
"""Add a user to an existing vo and group"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
config_repo
|
|
140
|
+
"""Add a user to an existing vo and group."""
|
|
141
|
+
# TODO: The use of TypeAdapter should be moved in to typer itself
|
|
142
|
+
config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
|
|
143
|
+
if config_repo.scheme != "git+file" or config_repo.path is None:
|
|
144
|
+
raise NotImplementedError("Only git+file:// URLs are supported")
|
|
144
145
|
|
|
145
146
|
repo_path = Path(config_repo.path)
|
|
146
147
|
|
|
@@ -180,10 +181,12 @@ def add_user(
|
|
|
180
181
|
|
|
181
182
|
|
|
182
183
|
def update_config_and_commit(repo_path: Path, config: Config, message: str):
|
|
183
|
-
"""Update the yaml file in the repo and commit it"""
|
|
184
|
+
"""Update the yaml file in the repo and commit it."""
|
|
184
185
|
repo = git.Repo(repo_path)
|
|
185
186
|
yaml_path = repo_path / "default.yml"
|
|
186
187
|
typer.echo(f"Writing back configuration to {yaml_path}", err=True)
|
|
187
|
-
yaml_path.write_text(
|
|
188
|
+
yaml_path.write_text(
|
|
189
|
+
yaml.safe_dump(config.model_dump(exclude_unset=True, mode="json"))
|
|
190
|
+
)
|
|
188
191
|
repo.index.add([yaml_path.relative_to(repo_path)])
|
|
189
192
|
repo.index.commit(message)
|
|
@@ -53,7 +53,7 @@ class ConversionConfig(BaseModel):
|
|
|
53
53
|
|
|
54
54
|
@app.command()
|
|
55
55
|
def cs_sync(old_file: Path, new_file: Path):
|
|
56
|
-
"""Load the old CS and convert it to the new YAML format"""
|
|
56
|
+
"""Load the old CS and convert it to the new YAML format."""
|
|
57
57
|
if not os.environ.get("DIRAC_COMPAT_ENABLE_CS_CONVERSION"):
|
|
58
58
|
raise RuntimeError(
|
|
59
59
|
"DIRAC_COMPAT_ENABLE_CS_CONVERSION must be set for the conversion to be possible"
|
|
@@ -79,14 +79,15 @@ def cs_sync(old_file: Path, new_file: Path):
|
|
|
79
79
|
|
|
80
80
|
_apply_fixes(raw)
|
|
81
81
|
|
|
82
|
-
config = Config.
|
|
83
|
-
new_file.write_text(
|
|
82
|
+
config = Config.model_validate(raw)
|
|
83
|
+
new_file.write_text(
|
|
84
|
+
yaml.safe_dump(config.model_dump(exclude_unset=True, mode="json"))
|
|
85
|
+
)
|
|
84
86
|
|
|
85
87
|
|
|
86
88
|
def _apply_fixes(raw):
|
|
87
|
-
"""Modify raw in place to make any layout changes between the old and new structure"""
|
|
88
|
-
|
|
89
|
-
conv_config = ConversionConfig.parse_obj(raw["DiracX"]["CsSync"])
|
|
89
|
+
"""Modify raw in place to make any layout changes between the old and new structure."""
|
|
90
|
+
conv_config = ConversionConfig.model_validate(raw["DiracX"]["CsSync"])
|
|
90
91
|
|
|
91
92
|
raw.pop("DiracX", None)
|
|
92
93
|
# Remove dips specific parts from the CS
|
|
@@ -119,7 +120,7 @@ def _apply_fixes(raw):
|
|
|
119
120
|
|
|
120
121
|
for vo, vo_meta in conv_config.VOs.items():
|
|
121
122
|
raw["Registry"][vo] = {
|
|
122
|
-
"IdP": vo_meta.IdP,
|
|
123
|
+
"IdP": vo_meta.IdP.model_dump(),
|
|
123
124
|
"DefaultGroup": vo_meta.DefaultGroup,
|
|
124
125
|
"Users": {},
|
|
125
126
|
"Groups": {},
|
|
@@ -182,15 +183,15 @@ def generate_helm_values(
|
|
|
182
183
|
),
|
|
183
184
|
output_file: Path = Option(help="Where to dump the yam file"),
|
|
184
185
|
):
|
|
185
|
-
"""Generate an initial values.yaml to run a DiracX installation
|
|
186
|
-
compatible with a DIRAC instance. The file is not complete, and needs
|
|
187
|
-
manual editing"""
|
|
186
|
+
"""Generate an initial values.yaml to run a DiracX installation.
|
|
188
187
|
|
|
188
|
+
The file generated is not complete, and needs manual editing.
|
|
189
|
+
"""
|
|
189
190
|
helm_values = {
|
|
190
191
|
"developer": {"enabled": False},
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
192
|
+
"initCs": {"enabled": True},
|
|
193
|
+
"initSecrets": {"enabled": True},
|
|
194
|
+
"initSql": {"enabled": False, "env": {}},
|
|
194
195
|
"cert-manager": {"enabled": False},
|
|
195
196
|
"cert-manager-issuer": {"enabled": False},
|
|
196
197
|
"minio": {"enabled": False},
|
|
@@ -20,6 +20,12 @@ from .utils import AsyncTyper
|
|
|
20
20
|
app = AsyncTyper()
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
available_operators = (
|
|
24
|
+
f"Scalar operators: {', '.join([op.value for op in ScalarSearchOperator])}. "
|
|
25
|
+
f"Vector operators: {', '.join([op.value for op in VectorSearchOperator])}."
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
23
29
|
def parse_condition(value: str) -> SearchSpec:
|
|
24
30
|
parameter, operator, rest = value.split(" ", 2)
|
|
25
31
|
if operator in set(ScalarSearchOperator):
|
|
@@ -51,15 +57,18 @@ async def search(
|
|
|
51
57
|
"Owner",
|
|
52
58
|
"LastUpdateTime",
|
|
53
59
|
],
|
|
54
|
-
condition: Annotated[
|
|
60
|
+
condition: Annotated[
|
|
61
|
+
list[str], Option(help=f'Example: "JobID eq 1000". {available_operators}')
|
|
62
|
+
] = [],
|
|
55
63
|
all: bool = False,
|
|
56
64
|
page: int = 1,
|
|
57
65
|
per_page: int = 10,
|
|
58
66
|
):
|
|
67
|
+
search_specs = [parse_condition(cond) for cond in condition]
|
|
59
68
|
async with DiracClient() as api:
|
|
60
69
|
jobs, content_range = await api.jobs.search(
|
|
61
70
|
parameters=None if all else parameter,
|
|
62
|
-
search=
|
|
71
|
+
search=search_specs if search_specs else None,
|
|
63
72
|
page=page,
|
|
64
73
|
per_page=per_page,
|
|
65
74
|
cls=lambda _, jobs, headers: (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: diracx-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1a18
|
|
4
4
|
Summary: TODO
|
|
5
5
|
License: GPL-3.0-only
|
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -8,7 +8,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Topic :: Scientific/Engineering
|
|
10
10
|
Classifier: Topic :: System :: Distributed Computing
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Requires-Dist: diraccfg
|
|
14
14
|
Requires-Dist: diracx-api
|
|
@@ -52,20 +52,20 @@ Registry:
|
|
|
52
52
|
DefaultGroup: jenkins_user
|
|
53
53
|
Groups:
|
|
54
54
|
jenkins_fcadmin:
|
|
55
|
-
Properties:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
Users:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
Properties:
|
|
56
|
+
- FileCatalogManagement
|
|
57
|
+
- NormalUser
|
|
58
|
+
Users:
|
|
59
|
+
- 26dbe36e-cf5c-4c52-a834-29a1c904ef74
|
|
60
|
+
- a95ab678-3fa4-41b9-b863-fe62ce8064ce
|
|
61
|
+
- e2cb28ec-1a1e-40ee-a56d-d899b79879ce
|
|
62
62
|
jenkins_user:
|
|
63
|
-
Properties:
|
|
64
|
-
|
|
65
|
-
Users:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
Properties:
|
|
64
|
+
- NormalUser
|
|
65
|
+
Users:
|
|
66
|
+
- 26dbe36e-cf5c-4c52-a834-29a1c904ef74
|
|
67
|
+
- a95ab678-3fa4-41b9-b863-fe62ce8064ce
|
|
68
|
+
- e2cb28ec-1a1e-40ee-a56d-d899b79879ce
|
|
69
69
|
IdP:
|
|
70
70
|
ClientID: 995ed3b9-d5bd-49d3-a7f4-7fc7dbd5a0cd
|
|
71
71
|
URL: https://jenkins.invalid/
|
|
@@ -94,23 +94,23 @@ Registry:
|
|
|
94
94
|
DefaultGroup: dirac_user
|
|
95
95
|
Groups:
|
|
96
96
|
dirac_admin:
|
|
97
|
-
Properties:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
Users:
|
|
106
|
-
|
|
97
|
+
Properties:
|
|
98
|
+
- AlarmsManagement
|
|
99
|
+
- CSAdministrator
|
|
100
|
+
- FullDelegation
|
|
101
|
+
- JobAdministrator
|
|
102
|
+
- Operator
|
|
103
|
+
- ProxyManagement
|
|
104
|
+
- ServiceAdministrator
|
|
105
|
+
Users:
|
|
106
|
+
- 26b14fc9-6d40-4ca5-b014-6234eaf0fb6e
|
|
107
107
|
dirac_user:
|
|
108
|
-
Properties:
|
|
109
|
-
|
|
110
|
-
Users:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
Properties:
|
|
109
|
+
- NormalUser
|
|
110
|
+
Users:
|
|
111
|
+
- 26b14fc9-6d40-4ca5-b014-6234eaf0fb6e
|
|
112
|
+
- d3adc733-6588-4d6f-8581-5986b02d0c87
|
|
113
|
+
- ff2152ff-34f4-4739-b106-3def37e291e3
|
|
114
114
|
IdP:
|
|
115
115
|
ClientID: 072afab5-ed92-46e0-a61d-4ecbc96e0770
|
|
116
116
|
URL: https://vo.invalid/
|
|
@@ -31,7 +31,7 @@ def test_cs_sync(tmp_path, monkeypatch):
|
|
|
31
31
|
actual_output = yaml.safe_load(output_file.read_text())
|
|
32
32
|
expected_output = yaml.safe_load((file_path / "integration_test.yaml").read_text())
|
|
33
33
|
assert actual_output == expected_output
|
|
34
|
-
Config.
|
|
34
|
+
Config.model_validate(actual_output)
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def test_disabled_vos_empty(tmp_path, monkeypatch):
|
|
@@ -8,7 +8,6 @@ import pytest
|
|
|
8
8
|
from pytest import raises
|
|
9
9
|
|
|
10
10
|
from diracx import cli
|
|
11
|
-
from diracx.core.models import ScalarSearchSpec
|
|
12
11
|
from diracx.core.preferences import get_diracx_preferences
|
|
13
12
|
|
|
14
13
|
TEST_JDL = """
|
|
@@ -41,7 +40,6 @@ async def jdl_file():
|
|
|
41
40
|
|
|
42
41
|
async def test_submit(with_cli_login, jdl_file, capfd):
|
|
43
42
|
"""Test submitting a job using a JDL file."""
|
|
44
|
-
|
|
45
43
|
with open(jdl_file, "r") as temp_file:
|
|
46
44
|
await cli.jobs.submit([temp_file])
|
|
47
45
|
|
|
@@ -52,7 +50,6 @@ async def test_submit(with_cli_login, jdl_file, capfd):
|
|
|
52
50
|
|
|
53
51
|
async def test_search(with_cli_login, jdl_file, capfd):
|
|
54
52
|
"""Test searching for jobs."""
|
|
55
|
-
|
|
56
53
|
# Submit 20 jobs
|
|
57
54
|
with open(jdl_file, "r") as temp_file:
|
|
58
55
|
await cli.jobs.submit([temp_file] * 20)
|
|
@@ -82,8 +79,7 @@ async def test_search(with_cli_login, jdl_file, capfd):
|
|
|
82
79
|
assert "JobGroup" in cap.out
|
|
83
80
|
|
|
84
81
|
# Search for a job that doesn't exist
|
|
85
|
-
|
|
86
|
-
await cli.jobs.search(condition=[condition])
|
|
82
|
+
await cli.jobs.search(condition=["Status eq nonexistent"])
|
|
87
83
|
cap = capfd.readouterr()
|
|
88
84
|
assert cap.err == ""
|
|
89
85
|
assert "[]" == cap.out.strip()
|
|
@@ -116,7 +112,7 @@ async def test_search(with_cli_login, jdl_file, capfd):
|
|
|
116
112
|
assert "Showing all jobs" in cap.out
|
|
117
113
|
|
|
118
114
|
# Search for a job that doesn't exist
|
|
119
|
-
await cli.jobs.search(condition=[
|
|
115
|
+
await cli.jobs.search(condition=["Status eq nonexistent"])
|
|
120
116
|
cap = capfd.readouterr()
|
|
121
117
|
assert cap.err == ""
|
|
122
118
|
assert "No jobs found" in cap.out
|
|
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
|
{diracx_cli-0.0.1a16 → diracx_cli-0.0.1a18}/tests/legacy/cs_sync/integration_test_secret.cfg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|