Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions reana_workflow_engine_cwl/cwl_reana.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
from reana_commons.api_client import JobControllerAPIClient as rjc_api_client
from reana_commons.config import REANA_WORKFLOW_UMASK

from reana_commons.k8s.secrets import resolve_secret_names


from reana_workflow_engine_cwl.config import LOGGING_MODULE, MOUNT_CVMFS
from reana_workflow_engine_cwl.pipeline import Pipeline
from reana_workflow_engine_cwl.poll import PollThread
Expand All @@ -51,6 +54,7 @@ def __init__(self, **kwargs):
self.service = kwargs.get(
"rjc_api_client", rjc_api_client("reana-job-controller")
)
self.workflow_resources = kwargs.get("workflow_resources") or {}
if kwargs.get("basedir") is not None:
self.basedir = kwargs.get("basedir")
else:
Expand Down Expand Up @@ -310,6 +314,9 @@ def shouldquote(x):
c4p_cpu_cores = self._get_hint("c4p_cpu_cores")
c4p_memory_limit = self._get_hint("c4p_memory_limit")
c4p_additional_requirements = self._get_hint("c4p_additional_requirements")
secret_names = resolve_secret_names(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Cross-component note for PR546-07: align CWL runtime hint resolution with sidecar discovery

The corresponding commons review found that packed-CWL sidecar discovery and ReanaPipelineJob._get_hint() resolve inherited REANA hints differently. Commons currently models step → tool and omits the Workflow node, while the runtime job scans cwltool's inherited workflow → step → tool list from the beginning. A workflow-only secret_names hint therefore scopes the job but leaves the sidecar at None (all secrets), and a step cannot narrow a conflicting workflow-level value.

The runtime resolver in this PR is one half of that contract. Its forward scan also governs compute_backend, kerberos, voms_proxy, rucio, kubernetes_uid, and the other REANA-specific fields, so changing precedence requires coordinated coverage beyond secret_names.

Suggested fix — coordinate this PR with the shared resolver proposed in PR546-07 so runtime job construction and packed-workflow discovery use the same explicitly defined workflow/step/tool precedence. Add packed-CWL regressions for workflow-only and conflicting workflow/step/tool hints, including a shared tool invoked from steps with different local values.

self._get_hint("secret_names"), getattr(self, "workflow_resources", {})
)
create_body = {
"image": container,
"cmd": wrapped_cmd,
Expand All @@ -323,6 +330,7 @@ def shouldquote(x):
"unpacked_img": unpacked_img,
"voms_proxy": voms_proxy,
"rucio": rucio,
"secret_names": secret_names,
"htcondor_max_runtime": htcondor_max_runtime,
"htcondor_accounting_group": htcondor_accounting_group,
"htcondor_request_cpus": htcondor_request_cpus,
Expand Down Expand Up @@ -362,6 +370,7 @@ def _get_hint(self, hint_name):
def run(self, runtimeContext): # noqa: C901
"""Run a job."""
self._setup(runtimeContext)
self.workflow_resources = runtimeContext.pipeline.workflow_resources

env = self.environment
if not os.path.exists(self.tmpdir):
Expand Down
5 changes: 4 additions & 1 deletion reana_workflow_engine_cwl/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def main(
rjc_api_client,
workflow_uuid,
workflow_spec,
workflow_resources,
workflow_inputs,
operational_options,
working_dir,
Expand Down Expand Up @@ -127,7 +128,9 @@ def main(
if parsed_args.debug:
log.setLevel(logging.DEBUG)

pipeline = ReanaPipeline(rjc_api_client=rjc_api_client)
pipeline = ReanaPipeline(
rjc_api_client=rjc_api_client, workflow_resources=workflow_resources
)
log.info("starting the run..")
db_log_writer = SQLiteHandler(workflow_uuid, publisher)

Expand Down
2 changes: 2 additions & 0 deletions reana_workflow_engine_cwl/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def run_cwl_workflow_engine_adapter(
workflow_uuid=None,
workflow_workspace=None,
workflow_json=None,
workflow_resources=None,
workflow_parameters=None,
operational_options={},
**kwargs,
Expand All @@ -43,6 +44,7 @@ def run_cwl_workflow_engine_adapter(
rjc_api_client,
workflow_uuid,
workflow_json,
workflow_resources,
workflow_parameters,
operational_options,
workflow_workspace,
Expand Down
45 changes: 44 additions & 1 deletion tests/test_cwl_reana.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""REANA CWL job tests."""
"""REANA Workflow Engine CWL tests."""

import subprocess
from types import SimpleNamespace

import pytest
import shellescape

from reana_workflow_engine_cwl.cwl_reana import ReanaPipelineJob
Expand Down Expand Up @@ -68,3 +69,45 @@ def test_initial_workdir_cleanup_preserves_inplace_update_symlinks(tmp_path):
assert staged_input.read_text() == "generated output"
assert staged_writable_input.is_symlink()
assert staged_writable_input.read_text() == "writable input"


@pytest.mark.parametrize(
"step_secret_names,workflow_secret_names,expected_secret_names",
[
(None, None, None),
(None, ["global"], ["global"]),
([], ["global"], []),
(["local"], ["global"], ["local"]),
],
)
def test_create_task_msg_secret_names_resolution(
step_secret_names, workflow_secret_names, expected_secret_names
):
"""Step hints should override or inherit workflow-global secret_names."""
job = ReanaPipelineJob.__new__(ReanaPipelineJob)
job.name = "fit"
job.environment = {"HOME": "/tmp/outdir"}
job.volumes = []
job.command_line = ["echo", "hello"]
job.stdin = None
job.stdout = None
job.stderr = None
job.outdir = "/tmp/outdir"
job.builder = SimpleNamespace(outdir="/tmp/outdir", bindings=[])
job.workflow_resources = (
{"secret_names": workflow_secret_names}
if workflow_secret_names is not None
else {}
)
job.hints = []
if step_secret_names is not None:
job.hints.append({"secret_names": step_secret_names})
job.get_requirement = lambda name: (
({"dockerPull": "docker.io/library/busybox"}, None)
if name == "DockerRequirement"
else (None, None)
)

create_body = job.create_task_msg("/tmp/workspace", "workflow-uuid")

assert create_body["secret_names"] == expected_secret_names
Loading