Skip to content

Commit 24cb362

Browse files
committed
feat(dask): create VOMS proxy sidecars for Dask workflows (#633)
We detect if VOMS_proxy is necessary for Dask cluster by checking top level voms_proxy statement under resources field in reana.yaml. Some amendments were needed in order to fetch the secrets from secrets store instead of environment variables since workflow controller does not have access to runtime environment variables just like job controller. Closes reanahub/reana#872
1 parent 0f90c8a commit 24cb362

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-8
lines changed

reana_workflow_controller/dask.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def __init__(
6060
num_of_workers,
6161
single_worker_memory,
6262
kerberos=False,
63+
voms_proxy=False,
6364
):
6465
"""Instantiate Dask resource manager.
6566
@@ -95,6 +96,7 @@ def __init__(
9596
self.kubernetes_uid = WORKFLOW_RUNTIME_USER_UID
9697

9798
self.kerberos = kerberos
99+
self.voms_proxy = voms_proxy
98100

99101
if DASK_AUTOSCALER_ENABLED:
100102
self.autoscaler_name = get_dask_component_name(workflow_id, "autoscaler")
@@ -216,11 +218,10 @@ def _prepare_cluster(self):
216218
)
217219

218220
rucio = False
219-
voms_proxy = False
220221

221222
if self.kerberos:
222223
self._add_krb5_containers()
223-
if voms_proxy:
224+
if self.voms_proxy:
224225
self._add_voms_proxy_init_container()
225226
if rucio:
226227
self._add_rucio_init_container()
@@ -343,6 +344,28 @@ def _add_krb5_containers(self):
343344
f"trap 'touch {KRB5_STATUS_FILE_LOCATION}' EXIT; " + existing_args[0]
344345
]
345346

347+
def _get_voms_proxy_secrets(self, secrets_store):
348+
"""Get VOMS proxy secrets from secrets store.
349+
350+
Args:
351+
secrets_store: User secrets store instance
352+
353+
Returns:
354+
dict: Dictionary containing VOMS proxy secrets with empty string defaults
355+
"""
356+
secret_keys = ["VONAME", "VOMSPROXY_FILE", "VOMSPROXY_PASS"]
357+
secrets = {}
358+
359+
for key in secret_keys:
360+
secret = secrets_store.get_secret(key)
361+
secrets[key.lower()] = secret.value_str if secret else ""
362+
363+
return {
364+
"vo": secrets["voname"],
365+
"file": secrets["vomsproxy_file"],
366+
"pass": secrets["vomsproxy_pass"],
367+
}
368+
346369
def _add_voms_proxy_init_container(self):
347370
"""Add sidecar container for Dask workers."""
348371
ticket_cache_volume = {"name": "voms-proxy-cache", "emptyDir": {}}
@@ -358,8 +381,10 @@ def _add_voms_proxy_init_container(self):
358381
current_app.config["VOMSPROXY_CERT_CACHE_FILENAME"],
359382
)
360383

361-
voms_proxy_vo = os.environ.get("VONAME", "")
362-
voms_proxy_user_file = os.environ.get("VOMSPROXY_FILE", "")
384+
voms_proxy_secrets = self._get_voms_proxy_secrets(self.secrets_store)
385+
voms_proxy_vo = voms_proxy_secrets["vo"]
386+
voms_proxy_user_file = voms_proxy_secrets["file"]
387+
voms_proxy_pass = voms_proxy_secrets["pass"]
363388

364389
if voms_proxy_user_file:
365390
# multi-user deployment mode, where we rely on VOMS proxy file supplied by the user
@@ -399,23 +424,24 @@ def _add_voms_proxy_init_container(self):
399424
echo "[ERROR] File usercert.pem does not exist in user secrets."; \
400425
exit; \
401426
fi; \
402-
if [ -z "$VOMSPROXY_PASS" ]; then \
427+
if [ -z {voms_proxy_pass} ]; then \
403428
echo "[ERROR] Environment variable VOMSPROXY_PASS is not set in user secrets."; \
404429
exit; \
405430
fi; \
406-
if [ -z "$VONAME" ]; then \
431+
if [ -z {voms_proxy_vo} ]; then \
407432
echo "[ERROR] Environment variable VONAME is not set in user secrets."; \
408433
exit; \
409434
fi; \
410435
cp /etc/reana/secrets/userkey.pem /tmp/userkey.pem; \
411436
chmod 400 /tmp/userkey.pem; \
412-
echo $VOMSPROXY_PASS | base64 -d | voms-proxy-init \
437+
echo {voms_proxy_pass} | base64 -d | voms-proxy-init \
413438
--voms {voms_proxy_vo} --key /tmp/userkey.pem \
414439
--cert $(readlink -f /etc/reana/secrets/usercert.pem) \
415440
--pwstdin --out {voms_proxy_file_path}; \
416441
chown {kubernetes_uid} {voms_proxy_file_path}'.format(
417442
voms_proxy_vo=voms_proxy_vo.lower(),
418443
voms_proxy_file_path=voms_proxy_file_path,
444+
voms_proxy_pass=voms_proxy_pass,
419445
kubernetes_uid=self.kubernetes_uid,
420446
),
421447
],

reana_workflow_controller/workflow_run_manager.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,14 @@ def requires_kerberos(self) -> bool:
353353
.get("kerberos", False)
354354
)
355355

356+
def requires_voms_proxy(self) -> bool:
357+
"""Check whether Voms_proxy is necessary to run the workflow engine."""
358+
return (
359+
self.workflow.reana_specification["workflow"]
360+
.get("resources", {})
361+
.get("voms_proxy", False)
362+
)
363+
356364

357365
class KubernetesWorkflowRunManager(WorkflowRunManager):
358366
"""Implementation of WorkflowRunManager for Kubernetes."""
@@ -400,6 +408,7 @@ def start_batch_workflow_run(
400408
REANA_DASK_CLUSTER_DEFAULT_SINGLE_WORKER_MEMORY,
401409
),
402410
kerberos=self.requires_kerberos(),
411+
voms_proxy=self.requires_voms_proxy(),
403412
).create_dask_resources()
404413

405414
current_k8s_batchv1_api_client.create_namespaced_job(

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"marshmallow>2.13.0,<3.0.0", # same upper pin as reana-server
5252
"opensearch-py>=2.7.0,<2.8.0",
5353
"packaging>=18.0",
54-
"reana-commons[kubernetes]>=0.95.0a7,<0.96.0",
54+
"reana-commons[kubernetes]>=0.95.0a8,<0.96.0",
5555
"reana-db>=0.95.0a5,<0.96.0",
5656
"requests>=2.25.0",
5757
"sqlalchemy-utils>=0.31.0",

0 commit comments

Comments
 (0)