Skip to content

Commit 6a43f16

Browse files
committed
fix(cwl_reana): preserve inplace update symlinks (reanahub#322)
Restrict initial-workdir cleanup to ordinary staged files and directories. Keep writable symlinks intact for in-place updates because CWL uses their write-through behaviour to modify the original workspace input.
1 parent 95a837a commit 6a43f16

2 files changed

Lines changed: 17 additions & 9 deletions

File tree

reana_workflow_engine_cwl/cwl_reana.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,9 @@ def _initial_workdir_symlink_cleanup_command(self):
171171
host_outdir = os.path.abspath(self.outdir)
172172
cleanup_command = ""
173173
for _, volume in generatemapper.items():
174-
is_linked_type = volume.type in ("File", "Directory") or (
175-
self.inplace_update
176-
and volume.type in ("WritableFile", "WritableDirectory")
177-
)
178174
if (
179175
not volume.staged
180-
or not is_linked_type
176+
or volume.type not in ("File", "Directory")
181177
or volume.resolved.startswith("_:")
182178
or not volume.target.startswith(target_prefix)
183179
):

tests/test_cwl_reana.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@
1616
from reana_workflow_engine_cwl.cwl_reana import ReanaPipelineJob
1717

1818

19-
def test_initial_workdir_input_is_not_overwritten_during_copy(tmp_path):
20-
"""Unlink a staged input before copying an output with the same name."""
19+
def test_initial_workdir_cleanup_preserves_inplace_update_symlinks(tmp_path):
20+
"""Unlink staged inputs while preserving intentional writable symlinks."""
2121
uploaded_input = tmp_path / "workspace" / "gendata.C"
2222
uploaded_input.parent.mkdir()
2323
uploaded_input.write_text("uploaded input")
24+
writable_input = uploaded_input.parent / "writable.txt"
25+
writable_input.write_text("writable input")
2426

2527
outdir = tmp_path / "cwl" / "outdir"
2628
outdir.mkdir(parents=True)
2729
staged_input = outdir / uploaded_input.name
2830
staged_input.symlink_to(uploaded_input)
31+
staged_writable_input = outdir / writable_input.name
32+
staged_writable_input.symlink_to(writable_input)
2933

3034
container_outdir = "/var/lib/cwl/job"
3135
job = object.__new__(ReanaPipelineJob)
@@ -36,9 +40,15 @@ def test_initial_workdir_input_is_not_overwritten_during_copy(tmp_path):
3640
type="File",
3741
resolved=str(uploaded_input),
3842
target=f"{container_outdir}/{uploaded_input.name}",
39-
)
43+
),
44+
"writable_input": SimpleNamespace(
45+
staged=True,
46+
type="WritableFile",
47+
resolved=str(writable_input),
48+
target=f"{container_outdir}/{writable_input.name}",
49+
),
4050
}
41-
job.inplace_update = False
51+
job.inplace_update = True
4252
job.outdir = str(outdir)
4353

4454
generated_output = tmp_path / "job-output"
@@ -56,3 +66,5 @@ def test_initial_workdir_input_is_not_overwritten_during_copy(tmp_path):
5666
assert uploaded_input.read_text() == "uploaded input"
5767
assert not staged_input.is_symlink()
5868
assert staged_input.read_text() == "generated output"
69+
assert staged_writable_input.is_symlink()
70+
assert staged_writable_input.read_text() == "writable input"

0 commit comments

Comments
 (0)