Skip to content

Commit 6a2a35b

Browse files
authored
Merge pull request #8550 from fstagni/v9_readme
[rel-v9r0] branch bootstrap
2 parents 05ec90d + 679aabe commit 6a2a35b

19 files changed

Lines changed: 296 additions & 132 deletions

File tree

.github/workflows/basic.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,26 @@ jobs:
171171
path: diracx
172172
- uses: prefix-dev/setup-pixi@v0.9.3
173173
with:
174-
run-install: false
174+
cache: false
175175
post-cleanup: false
176+
manifest-path: diracx/pixi.toml
177+
environments: >-
178+
diracx-core
179+
diracx-db
180+
diracx-logic
181+
diracx-tasks
182+
diracx-routers
183+
diracx-client
184+
diracx-api
185+
diracx-cli
176186
- name: Apply workarounds
177187
run: |
178188
cd diracx
179189
# Workaround for https://github.com/prefix-dev/pixi/issues/3762
180190
sed -i.bak 's@editable = true@editable = false@g' pixi.toml
181191
rm pixi.toml.bak
192+
sed -i.bak '/solve-group = "gubbins"/d' pixi.toml
193+
rm pixi.toml.bak
182194
# Add annotations to github actions
183195
pixi add --pypi --feature diracx-core pytest-github-actions-annotate-failures
184196
# Add the current DIRAC clone to the pixi.toml
@@ -189,11 +201,13 @@ jobs:
189201
- uses: prefix-dev/setup-pixi@v0.9.3
190202
with:
191203
cache: false
204+
locked: false
192205
manifest-path: diracx/pixi.toml
193206
environments: >-
194207
diracx-core
195208
diracx-db
196209
diracx-logic
210+
diracx-tasks
197211
diracx-routers
198212
diracx-client
199213
diracx-api

README.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,28 @@ DIRAC provides a complete solution to one or more user community requiring acces
1616

1717
DIRAC has been started by the `LHCb collaboration <https://lhcb.web.cern.ch/lhcb/>`_ who still maintains it. It is now used by several communities (AKA VO=Virtual Organizations) for their distributed computing workflows.
1818

19-
DIRAC is written in python 3.9.
19+
DIRAC is written in python 3.11.
2020

21-
Status rel-v8r0 series (stable, recommended):
21+
Status rel-v9r0 series (stable, recommended):
2222

23-
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/Basic%20tests/badge.svg?branch=rel-v8r0
24-
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22Basic+tests%22+branch%3Arel-v8r0
23+
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/Basic%20tests/badge.svg?branch=rel-v9r0
24+
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22Basic+tests%22+branch%3Arel-v9r0
2525
:alt: Basic Tests Status
2626

27-
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/pilot%20wrapper/badge.svg?branch=rel-v8r0
28-
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22pilot+wrapper%22+branch%3Arel-v8r0
27+
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/pilot%20wrapper/badge.svg?branch=rel-v9r0
28+
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22pilot+wrapper%22+branch%3Arel-v9r0
2929
:alt: Pilot Wrapper Status
3030

31-
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/Integration%20tests/badge.svg?branch=rel-v8r0
32-
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22Integration+tests%22+branch%3Arel-v8r0
31+
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/Integration%20tests/badge.svg?branch=rel-v9r0
32+
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22Integration+tests%22+branch%3Arel-v9r0
3333
:alt: Integration Tests Status
3434

35-
.. image:: https://readthedocs.org/projects/dirac/badge/?version=rel-v8r0
36-
:target: http://dirac.readthedocs.io/en/rel-v8r0/
35+
.. image:: https://readthedocs.org/projects/dirac/badge/?version=rel-v9r0
36+
:target: http://dirac.readthedocs.io/en/rel-v9r0/
3737
:alt: Documentation Status
3838

3939

40-
Status integration branch (devel):
40+
Status integration branch:
4141

4242
.. image:: https://github.com/DIRACGrid/DIRAC/workflows/Basic%20tests/badge.svg?branch=integration
4343
:target: https://github.com/DIRACGrid/DIRAC/actions?query=workflow%3A%22Basic+tests%22+branch%3Aintegration
@@ -124,7 +124,7 @@ Code quality
124124
~~~~~~~~~~~~
125125

126126
To ensure the code meets DIRAC's coding conventions we recommend installing ``pre-commit`` system wide using your operating system's package manager.
127-
Alteratively, ``pre-commit`` is included in the Python 3 development environment, see the `development guide <https://dirac.readthedocs.io/en/integration/DeveloperGuide/DevelopmentEnvironment/DeveloperInstallation/editingCode.html>`_ for details on how to create one.
127+
Alteratively, ``pre-commit`` is included in the development environment, see the `development guide <https://dirac.readthedocs.io/en/integration/DeveloperGuide/DevelopmentEnvironment/DeveloperInstallation/editingCode.html>`_ for details on how to create one.
128128

129129
Once ``pre-commit`` is installed you can enable it by running:
130130

docs/docs.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ no_inherited_members =
3131
DIRAC.Core.Utilities.Graphs.GraphUtilities,
3232
DIRAC.DataManagementSystem.private.HttpStorageAccessHandler,
3333
DIRAC.FrameworkSystem.private.standardLogging.LogLevels,
34+
DIRAC.Resources.IdProvider.OAuth2IdProvider,
35+
DIRAC.Resources.IdProvider.CheckInIdProvider,
36+
DIRAC.Resources.IdProvider.IAMIdProvider,
3437

3538
# only creating dummy files, because they cannot be safely imported due to sideEffects
3639
create_dummy_files = lfc_dfc_copy, lfc_dfc_db_copy, JobWrapperTemplate, JobWrapperOfflineTemplate

docs/source/DeveloperGuide/CodeTesting/index.rst

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,13 +360,11 @@ To deactivate a service from being used with DiracX, you can add it in `integrat
360360
"WorkloadManagement/JobMonitoring",
361361
]
362362
363-
By setting `TEST_DIRACX=Yes` only, it will take the last version of DiracX by default. If you want to provide your own, you have to build your DiracX project, and provide the `dist` folder path when calling `prepare-client`. This path has to be absolute.
363+
By setting `TEST_DIRACX=Yes` only, it will take the last version of DiracX by default. If you want to test against a local DiracX checkout, provide the source directory path when calling `prepare-environment`. This will build the DiracX container images from source and build wheels for the DIRAC containers.
364364

365365
.. code-block:: bash
366366
367-
./integration-tests.py prepare-client TEST_DIRACX=Yes --diracx-dist-dir my-dist-folder/
368-
369-
It will then mount your dist folder into DIRAC and DiracX (in `/diracx_sources`) to install the right dependencies.
367+
./integration-tests.py prepare-environment TEST_DIRACX=Yes --diracx-src-dir /path/to/diracx/
370368
371369
For MacOS, there are two bugs that can be fixed.
372370

integration_tests.py

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,14 @@ def create(
175175
flags: Optional[list[str]] = typer.Argument(None),
176176
editable: Optional[bool] = None,
177177
extra_module: Optional[list[str]] = None,
178-
diracx_dist_dir: Optional[str] = None,
178+
diracx_src_dir: Optional[str] = None,
179179
release_var: Optional[str] = None,
180180
run_server_tests: bool = True,
181181
run_client_tests: bool = True,
182182
run_pilot_tests: bool = True,
183183
):
184184
"""Start a local instance of the integration tests"""
185-
prepare_environment(flags, editable, extra_module, diracx_dist_dir, release_var)
185+
prepare_environment(flags, editable, extra_module, diracx_src_dir, release_var)
186186
install_server()
187187
install_client()
188188
install_pilot()
@@ -230,7 +230,7 @@ def prepare_environment(
230230
flags: Optional[list[str]] = typer.Argument(None),
231231
editable: Optional[bool] = None,
232232
extra_module: Optional[list[str]] = None,
233-
diracx_dist_dir: Optional[str] = None,
233+
diracx_src_dir: Optional[str] = None,
234234
release_var: Optional[str] = None,
235235
):
236236
"""Prepare the local environment for installing DIRAC."""
@@ -277,7 +277,7 @@ def prepare_environment(
277277
extra_services = list(chain(*[config["extra-services"] for config in module_configs.values()]))
278278

279279
typer.secho("Running docker compose to create containers", fg=c.GREEN)
280-
with _gen_docker_compose(modules, diracx_dist_dir=diracx_dist_dir) as docker_compose_fn:
280+
with _gen_docker_compose(modules, diracx_src_dir=diracx_src_dir) as docker_compose_fn:
281281
subprocess.run(
282282
[*DOCKER_COMPOSE_CMD, "-f", docker_compose_fn, "up", "-d", "dirac-server", "dirac-client", "dirac-pilot"]
283283
+ extra_services,
@@ -374,19 +374,32 @@ def prepare_environment(
374374
typer.secho("Running docker compose to create DiracX containers", fg=c.GREEN)
375375
typer.secho(f"Will leave a folder behind: {docker_compose_fn_final}", fg=c.YELLOW)
376376

377-
with _gen_docker_compose(modules, diracx_dist_dir=diracx_dist_dir) as docker_compose_fn:
377+
with _gen_docker_compose(modules, diracx_src_dir=diracx_src_dir) as docker_compose_fn:
378378
# We cannot use the temporary directory created in the context manager because
379379
# we don't stay in the contect manager (Popen)
380380
# So we need something that outlives it.
381381
shutil.copytree(docker_compose_fn.parent, docker_compose_fn_final, dirs_exist_ok=True)
382+
383+
docker_compose_file = docker_compose_fn_final / "docker-compose.yml"
384+
385+
# Pre-build any images defined with build: directives so that the
386+
# background "up -d" below only needs to start containers (fast).
387+
if diracx_src_dir is not None:
388+
typer.secho("Building DiracX container images from source", fg=c.GREEN)
389+
subprocess.run(
390+
[*DOCKER_COMPOSE_CMD, "-f", docker_compose_file, "build"],
391+
check=True,
392+
env=docker_compose_env,
393+
)
394+
382395
# We use Popen because we don't want to wait for this command to finish.
383396
# It is going to start all the diracx containers, including one which waits
384397
# for the DIRAC installation to be over.
385398
subStdout = open(docker_compose_fn_final / "stdout", "w")
386399
subStderr = open(docker_compose_fn_final / "stderr", "w")
387400

388401
subprocess.Popen(
389-
[*DOCKER_COMPOSE_CMD, "-f", docker_compose_fn_final / "docker-compose.yml", "up", "-d", "diracx"],
402+
[*DOCKER_COMPOSE_CMD, "-f", docker_compose_file, "up", "-d", "diracx"],
390403
env=docker_compose_env,
391404
stdin=None,
392405
stdout=subStdout,
@@ -591,7 +604,7 @@ class TestExit(typer.Exit):
591604

592605

593606
@contextmanager
594-
def _gen_docker_compose(modules, *, diracx_dist_dir=None):
607+
def _gen_docker_compose(modules, *, diracx_src_dir=None):
595608
# Load the docker compose configuration and mount the necessary volumes
596609
input_fn = Path(__file__).parent / "tests/CI/docker-compose.yml"
597610
docker_compose = yaml.safe_load(input_fn.read_text())
@@ -607,23 +620,50 @@ def _gen_docker_compose(modules, *, diracx_dist_dir=None):
607620
docker_compose["services"]["diracx-wait-for-db"]["volumes"].extend(volumes[:])
608621

609622
module_configs = _load_module_configs(modules)
610-
if diracx_dist_dir is not None:
611-
for container_name in [
612-
"dirac-client",
613-
"dirac-pilot",
614-
"dirac-server",
615-
"diracx-init-cs",
616-
"diracx-wait-for-db",
617-
"diracx-init-db",
618-
"diracx",
619-
]:
623+
if diracx_src_dir is not None:
624+
diracx_src_dir = str(Path(diracx_src_dir).absolute())
625+
626+
# Build wheels from the diracx source for the DIRAC containers
627+
diracx_wheel_dir = Path(tempfile.mkdtemp(prefix="diracx-wheels-"))
628+
typer.secho(f"Building diracx wheels in {diracx_wheel_dir}", fg=c.GREEN)
629+
subprocess.run(
630+
[
631+
sys.executable,
632+
"-m",
633+
"pip",
634+
"wheel",
635+
"--no-deps",
636+
f"--wheel-dir={diracx_wheel_dir}",
637+
*[f"{diracx_src_dir}/diracx-{pkg}" for pkg in ["core", "client", "cli"]],
638+
],
639+
check=True,
640+
)
641+
642+
# Mount wheels into DIRAC containers so installDIRACX can find them
643+
for container_name in ["dirac-client", "dirac-pilot", "dirac-server"]:
620644
docker_compose["services"][container_name].setdefault("volumes", []).append(
621-
f"{diracx_dist_dir}:/diracx_sources"
645+
f"{diracx_wheel_dir}:/diracx_sources"
622646
)
623647
docker_compose["services"][container_name].setdefault("environment", []).append(
624648
"DIRACX_CUSTOM_SOURCE_PREFIXES=/diracx_sources"
625649
)
626650

651+
# Build diracx container images from source instead of pulling pre-built ones
652+
diracx_build_services = {
653+
"container-services": ["diracx", "diracx-init-keystore", "diracx-init-db"],
654+
"container-client": ["diracx-init-cs"],
655+
}
656+
for pixi_env, container_names in diracx_build_services.items():
657+
for container_name in container_names:
658+
service = docker_compose["services"][container_name]
659+
del service["image"]
660+
service.pop("pull_policy", None)
661+
service["build"] = {
662+
"context": diracx_src_dir,
663+
"dockerfile": "containers/Dockerfile",
664+
"args": {"PIXI_ENV": pixi_env},
665+
}
666+
627667
# Add any extension services
628668
for module_name, module_configs in module_configs.items():
629669
for service_name, service_config in module_configs["extra-services"].items():

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ install_requires =
3030
certifi
3131
cwltool
3232
diraccfg
33-
DIRACCommon==v9.0.20
33+
DIRACCommon
3434
diracx-client >=v0.0.1
3535
diracx-core >=v0.0.1
3636
diracx-cli >=v0.0.1

src/DIRAC/Core/Utilities/ElasticSearchDB.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ def getDoc(self, index: str, docID: str) -> dict:
265265
"""
266266
sLog.debug(f"Retrieving document {docID} in index {index}")
267267
try:
268-
return S_OK(self.client.get(index, docID)["_source"])
268+
return S_OK(self.client.get(index=index, id=docID)["_source"])
269269
except NotFoundError:
270270
sLog.warn("Could not find the document in index", index)
271271
return S_OK({})
@@ -282,7 +282,7 @@ def getDocs(self, indexFunc, docIDs: list[str], vo: str) -> list[dict]:
282282
sLog.debug(f"Retrieving documents {docIDs}")
283283
docs = [{"_index": indexFunc(docID, vo), "_id": docID} for docID in docIDs]
284284
try:
285-
response = self.client.mget({"docs": docs})
285+
response = self.client.mget(body={"docs": docs})
286286
except RequestError as re:
287287
return S_ERROR(re)
288288
else:
@@ -300,12 +300,12 @@ def updateDoc(self, index: str, docID: str, body) -> dict:
300300
"""
301301
sLog.debug(f"Updating document {docID} in index {index}")
302302
try:
303-
self.client.update(index, docID, body)
303+
self.client.update(index=index, id=docID, body=body)
304304
except ConflictError:
305305
# updates are rather "heavy" operations from ES point of view, needing seqNo to be updated.
306306
# Not ideal, but we just wait and retry.
307307
time.sleep(1)
308-
self.client.update(index, docID, body, params={"retry_on_conflict": 3})
308+
self.client.update(index=index, id=docID, body=body, params={"retry_on_conflict": 3})
309309
except RequestError as re:
310310
return S_ERROR(re)
311311
return S_OK()
@@ -319,7 +319,7 @@ def deleteDoc(self, index: str, docID: str):
319319
"""
320320
sLog.debug(f"Deleting document {docID} in index {index}")
321321
try:
322-
return S_OK(self.client.delete(index, docID))
322+
return S_OK(self.client.delete(index=index, id=docID))
323323
except RequestError as re:
324324
return S_ERROR(re)
325325
except NotFoundError:
@@ -334,7 +334,7 @@ def existsDoc(self, index: str, docID: str) -> bool:
334334
:param docID: document ID
335335
"""
336336
sLog.debug(f"Checking if document {docID} in index {index} exists")
337-
return self.client.exists(index, docID)
337+
return self.client.exists(index=index, id=docID)
338338

339339
@ifConnected
340340
def _Search(self, indexname):
@@ -365,7 +365,7 @@ def getIndexes(self, indexName=None):
365365
indexName = ""
366366
sLog.debug(f"Getting indices alias of {indexName}")
367367
# we only return indexes which belong to a specific prefix for example 'lhcb-production' or 'dirac-production etc.
368-
return list(self.client.indices.get_alias(f"{indexName}*"))
368+
return list(self.client.indices.get_alias(index=f"{indexName}*"))
369369

370370
@ifConnected
371371
def getDocTypes(self, indexName):
@@ -378,7 +378,7 @@ def getDocTypes(self, indexName):
378378
result = []
379379
try:
380380
sLog.debug("Getting mappings for ", indexName)
381-
result = self.client.indices.get_mapping(indexName)
381+
result = self.client.indices.get_mapping(index=indexName)
382382
except Exception as e: # pylint: disable=broad-except
383383
sLog.exception()
384384
return S_ERROR(e)
@@ -409,7 +409,7 @@ def existingIndex(self, indexName):
409409
"""
410410
sLog.debug(f"Checking existance of index {indexName}")
411411
try:
412-
return S_OK(self.client.indices.exists(indexName))
412+
return S_OK(self.client.indices.exists(index=indexName))
413413
except TransportError as e:
414414
sLog.exception()
415415
return S_ERROR(e)
@@ -446,7 +446,7 @@ def deleteIndex(self, indexName):
446446
"""
447447
sLog.info("Deleting index", indexName)
448448
try:
449-
retVal = self.client.indices.delete(indexName)
449+
retVal = self.client.indices.delete(index=indexName)
450450
except NotFoundError:
451451
sLog.warn("Index does not exist", indexName)
452452
return S_OK("Nothing to delete")

src/DIRAC/Core/Utilities/MySQL.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ def __getWithRetry(self, dbName, totalRetries, retriesLeft):
401401

402402
def __ping(self, conn):
403403
try:
404-
conn.ping(True)
404+
conn.ping()
405405
return True
406406
except Exception:
407407
return False

src/DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
""" Client for interacting with Framework/BundleDelivery service
2-
"""
1+
"""Client for interacting with Framework/BundleDelivery service"""
2+
33
import getpass
44
import os
55
import tarfile
@@ -143,9 +143,10 @@ def syncCAs(self):
143143
if "X509_CERT_DIR" in os.environ:
144144
X509_CERT_DIR = os.environ["X509_CERT_DIR"]
145145
del os.environ["X509_CERT_DIR"]
146+
result = self.syncDir("CAs", Locations.getCAsLocation())
146147
if X509_CERT_DIR:
147148
os.environ["X509_CERT_DIR"] = X509_CERT_DIR
148-
return self.syncDir("CAs", Locations.getCAsLocation())
149+
return result
149150

150151
def syncCRLs(self):
151152
"""Synchronize CRLs
@@ -156,9 +157,10 @@ def syncCRLs(self):
156157
if "X509_CERT_DIR" in os.environ:
157158
X509_CERT_DIR = os.environ["X509_CERT_DIR"]
158159
del os.environ["X509_CERT_DIR"]
160+
result = self.syncDir("CRLs", Locations.getCAsLocation())
159161
if X509_CERT_DIR:
160162
os.environ["X509_CERT_DIR"] = X509_CERT_DIR
161-
return self.syncDir("CRLs", Locations.getCAsLocation())
163+
return result
162164

163165
def getCAs(self):
164166
"""This method can be used to create the CAs. If the file can not be created,

0 commit comments

Comments
 (0)