common-workflow-language / common-workflow-language/cwltool

stagedir not configurable, sometimes uses system tempory directory vs requested tmpdir

Open
#1,087 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
376
Forks
255
Avg merge
2d 7h
Merged PRs (30d)
12

Description

Not all temporary work directories/files are created under the directory specified via `cwltool --tmpdir-prefix`. There appears to be an issue in properly setting `stagedir`.

This may be related to issue #129, where it was noted that _`--leave-tmpdir`` doesn't work_, perhaps because staged files don't always end up in that specified temporary directory.

## Expected Behavior
I don't know the expected behavior: it is not completely clear if the stage directory is supposed to be independent of the `tmpdir-prefix`, or if the stage directory should be relative to that temporary directory. However, *the current behavior is inconsistent*, sometimes using the operating system temporary directory, sometimes being relative to the explicit temporary directory. Whatever is chosen, the behavior should be made consistent.

## Actual Behavior
If a Docker image is being used, then staged files are created in the directory specified by `tmpdir-prefix`.
If a Docker image is not being used, then staged files are created in the operating system's temporary directory, ignoring any specified `tmpdir_prefix`.

## Workflow Code
Any workflow involving staged inputs, invoked with `--no-container` and `--tmpdir-prefix`:
```
cwltool --timestamps --no-container --tmpdir-prefix ./tmpdir/ --leave-tmpdir --tmp-outdir-prefix ./tmp-outdir/ --copy-outputs --outdir ./outdir [...]
```

## Full Traceback
Log outputs show filepaths which don't match the specified `tmpdir-prefix`. For example, note files in a `/tmp` directory despite specifying ./tmpdir as the `tmpdir-prefix`.
```
[2019-02-10 16:02:14] [job pgapx_yaml_ctl] /t/tmp-outdir/50hocnr6$ pgapx_yaml_ctl \
-ifmt \
JSON \
-input \
/tmp/tmp_oujvz_q/stge4efe441-6597-4153-a8a9-3586bea62c0c/submol.json \
-input-fasta \
/tmp/tmp_oujvz_q/stgc2dc26da-de43-4f0f-b998-727418174c1c/ASM2732v1.annotation.nucleotide.1.fasta \
-ofmt \
JSON \
-output-entries \
input_entries.asn \
-output-ltp \
genome.ltp.txt \
-output-seq-submit \
input_seq_submit.sqn \
-taxon-db \
/tmp/tmp_oujvz_q/stgde198228-473f-4fb5-9b2f-8e928a010a2f/taxonomy.sqlite3
```

## Your Environment
* cwltool version: 1.0.20190228155703

## Additionl Diagnostics - Code Inspection
A code inspection of `cwltool` suggests there is a bug, either failure to set `stagedir` with suitable defaults, or failure to expose the path as a configurable command line option.

This code hints that stagedir should exist within tmpdir_prefix:
```
class CommandLineTool(Process):
[...]
if dockerReq is not None and runtimeContext.use_container:
out_dir, out_prefix = os.path.split(
runtimeContext.tmp_outdir_prefix)
j.outdir = runtimeContext.outdir or \
tempfile.mkdtemp(prefix=out_prefix, dir=out_dir)
tmpdir_dir, tmpdir_prefix = os.path.split(
runtimeContext.tmpdir_prefix)
j.tmpdir = runtimeContext.tmpdir or \
tempfile.mkdtemp(prefix=tmpdir_prefix, dir=tmpdir_dir)
j.stagedir = tempfile.mkdtemp(prefix=tmpdir_prefix, dir=tmpdir_dir)
else:
j.outdir = builder.outdir
j.tmpdir = builder.tmpdir
j.stagedir = builder.stagedir
[...]
```

When cwltool uses Docker, the `stagedir` is relative to the `tmpdir_prefix`, but when it is _not itself using Docker_, the `else` part applies, and *the paths are taken verbatim* from the builder runtime context, which is configured here:

```
def main([...]): # type: (...) -> int
[...]
for dirprefix in ("tmpdir_prefix", "tmp_outdir_prefix", "cachedir"):
if getattr(runtimeContext, dirprefix) and getattr(runtimeContext, dirprefix) != DEFAULT_TMP_PREFIX:
sl = "/" if getattr(runtimeContext, dirprefix).endswith("/") or dirprefix == "cachedir" \
else ""
setattr(runtimeContext, dirprefix,
os.path.abspath(getattr(runtimeContext, dirprefix)) + sl)
if not os.path.exists(os.path.dirname(getattr(runtimeContext, dirprefix))):
try:
os.makedirs(os.path.dirname(getattr(runtimeContext, dirprefix)))
except Exception as e:
_logger.error("Failed to create directory: %s", e)
return 1

if args.cachedir:
if args.move_outputs == "move":
runtimeContext.move_outputs = "copy"
runtimeContext.tmp_outdir_prefix = args.cachedir
[...]
```

Note how the main() function *only sets 3 paths into the runtime context*, omitting `stagedir`, a potential 4th path to be exposed on the command line.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.