X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/90209af8fa35bc99c9821db0c815404d1234ef31..2feec8cbac7ef28a47f3c3a9d071b070ef38cb6e:/sdk/cwl/arvados_cwl/runner.py diff --git a/sdk/cwl/arvados_cwl/runner.py b/sdk/cwl/arvados_cwl/runner.py index 57a672389c..087fed3e16 100644 --- a/sdk/cwl/arvados_cwl/runner.py +++ b/sdk/cwl/arvados_cwl/runner.py @@ -1,3 +1,7 @@ +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + import os import urlparse from functools import partial @@ -14,7 +18,7 @@ from cwltool.draft2tool import CommandLineTool import cwltool.workflow from cwltool.process import get_feature, scandeps, UnsupportedRequirement, normalizeFilesDirs, shortname from cwltool.load_tool import fetch_document -from cwltool.pathmapper import adjustFileObjs, adjustDirObjs +from cwltool.pathmapper import adjustFileObjs, adjustDirObjs, visit_class from cwltool.utils import aslist from cwltool.builder import substitute from cwltool.pack import pack @@ -23,27 +27,36 @@ import arvados.collection import ruamel.yaml as yaml from .arvdocker import arv_docker_get_image -from .pathmapper import ArvPathMapper +from .pathmapper import ArvPathMapper, trim_listing from ._version import __version__ from . import done logger = logging.getLogger('arvados.cwl-runner') -def trim_listing(obj): - """Remove 'listing' field from Directory objects that are keep references. +def trim_anonymous_location(obj): + """Remove 'location' field from File and Directory literals. + + To make internal handling easier, literals are assigned a random id for + 'location'. However, when writing the record back out, this can break + reproducibility. Since it is valid for literals not have a 'location' + field, remove it. - When Directory objects represent Keep references, it redundant and - potentially very expensive to pass fully enumerated Directory objects - between instances of cwl-runner (e.g. a submitting a job, or using the - RunInSingleContainer feature), so delete the 'listing' field when it is - safe to do so. """ - if obj.get("location", "").startswith("keep:") and "listing" in obj: - del obj["listing"] if obj.get("location", "").startswith("_:"): del obj["location"] +def find_defaults(d, op): + if isinstance(d, list): + for i in d: + find_defaults(i, op) + elif isinstance(d, dict): + if "default" in d: + op(d) + else: + for i in d.itervalues(): + find_defaults(i, op) + def upload_dependencies(arvrunner, name, document_loader, workflowobj, uri, loadref_run, include_primary=True): """Upload the dependencies of the workflowobj document to Keep. @@ -99,10 +112,28 @@ def upload_dependencies(arvrunner, name, document_loader, for s in workflowobj["$schemas"]: sc.append({"class": "File", "location": s}) + def capture_default(obj): + remove = [False] + def add_default(f): + if "location" not in f and "path" in f: + f["location"] = f["path"] + del f["path"] + if "location" in f and not arvrunner.fs_access.exists(f["location"]): + # Remove from sc + sc[:] = [x for x in sc if x["location"] != f["location"]] + # Delete "default" from workflowobj + remove[0] = True + visit_class(obj["default"], ("File", "Directory"), add_default) + if remove[0]: + del obj["default"] + + find_defaults(workflowobj, capture_default) + mapper = ArvPathMapper(arvrunner, sc, "", "keep:%s", "keep:%s/%s", - name=name) + name=name, + single_collection=True) def setloc(p): if "location" in p and (not p["location"].startswith("_:")) and (not p["location"].startswith("keep:")): @@ -188,7 +219,7 @@ def upload_job_order(arvrunner, name, tool, job_order): return job_order -def upload_workflow_deps(arvrunner, tool): +def upload_workflow_deps(arvrunner, tool, override_tools): # Ensure that Docker images needed by this workflow are available upload_docker(arvrunner, tool) @@ -205,6 +236,7 @@ def upload_workflow_deps(arvrunner, tool): False, include_primary=False) document_loader.idx[deptool["id"]] = deptool + override_tools[deptool["id"]] = json.dumps(deptool) tool.visit(upload_tool_deps) @@ -248,7 +280,8 @@ class Runner(object): def __init__(self, runner, tool, job_order, enable_reuse, output_name, output_tags, submit_runner_ram=0, - name=None, on_error=None, submit_runner_image=None): + name=None, on_error=None, submit_runner_image=None, + intermediate_output_ttl=0): self.arvrunner = runner self.tool = tool self.job_order = job_order @@ -261,6 +294,7 @@ class Runner(object): self.name = name self.on_error = on_error self.jobs_image = submit_runner_image or "arvados/jobs:"+__version__ + self.intermediate_output_ttl = intermediate_output_ttl if submit_runner_ram: self.submit_runner_ram = submit_runner_ram