Skip to content

Commit 4985d1a

Browse files
authored
Merge pull request #17 from common-workflow-language/arv
support http references
2 parents bd8aa2f + 7241608 commit 4985d1a

File tree

11 files changed

+160
-50
lines changed

11 files changed

+160
-50
lines changed

Dockerfile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
FROM debian:9
2+
3+
# Install passenger
4+
5+
RUN apt-get update && \
6+
apt-get install -y dirmngr gnupg && \
7+
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7 && \
8+
apt-get install -y apt-transport-https ca-certificates && \
9+
sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger stretch main > /etc/apt/sources.list.d/passenger.list'
10+
11+
RUN apt-get update && \
12+
apt-get install -y --no-install-recommends passenger python-setuptools build-essential python-dev python-pip git && \
13+
pip install pip==9.0.3
14+
15+
RUN apt-get install -y --no-install-recommends libcurl4-openssl-dev libssl1.0-dev
16+
17+
RUN apt-key adv --keyserver hkp://pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D || \
18+
apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
19+
20+
RUN mkdir -p /etc/apt/sources.list.d && \
21+
echo deb https://apt.dockerproject.org/repo debian-stretch main > /etc/apt/sources.list.d/docker.list && \
22+
apt-get update && \
23+
apt-get -yq --no-install-recommends install docker-engine=17.05.0~ce-0~debian-stretch && \
24+
apt-get clean
25+
26+
ARG version
27+
ARG arvversion
28+
29+
COPY dist/wes-service-${version}.tar.gz /root
30+
COPY dist/arvados-cwl-runner-${arvversion}.tar.gz /root
31+
32+
RUN cd /root && tar xzf arvados-cwl-runner-${arvversion}.tar.gz && \
33+
cd arvados-cwl-runner-${arvversion} && \
34+
pip install .
35+
36+
RUN cd /root && tar xzf wes-service-${version}.tar.gz && \
37+
cd wes-service-${version} && \
38+
pip install .[arvados]
39+
40+
COPY passenger_wsgi.py /var/www/wes-server/passenger_wsgi.py
41+
42+
EXPOSE 443
43+
44+
WORKDIR /var/www/wes-server/
45+
RUN chown www-data:www-data -R /var/www && adduser www-data docker
46+
47+
CMD ["passenger", "start", "--environment=production", "--user=www-data", "--port=443", "--ssl", \
48+
"--ssl-certificate=/etc/ssl/certs/ssl-cert-wes.pem", \
49+
"--ssl-certificate-key=/etc/ssl/private/ssl-cert-wes.key"]

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include README.pypi.rst
2+
include wes_service/openapi/workflow_execution_service.swagger.yaml

passenger_wsgi.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import wes_service
2+
3+
application = wes_service.setup()

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
long_description = readmeFile.read()
1616

1717
setup(name='wes-service',
18-
version='2.2',
18+
version='2.3',
1919
description='GA4GH Workflow Execution Service reference implementation',
2020
long_description=long_description,
2121
author='GA4GH Containers and Workflows task team',
@@ -30,7 +30,8 @@
3030
'connexion',
3131
'bravado',
3232
'ruamel.yaml >= 0.12.4, < 0.15',
33-
'cwl-runner'
33+
'cwlref-runner',
34+
'schema-salad'
3435
],
3536
entry_points={
3637
'console_scripts': [ "wes-server=wes_service:main",
@@ -41,5 +42,5 @@
4142
"arvados-cwl-runner"
4243
]
4344
},
44-
zip_safe=True
45+
zip_safe=False
4546
)

testdata/md5sum.cwl.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
{
22
"input_file": {
33
"class": "File",
4-
"path": "../../testdata/md5sum.input"
5-
},
6-
"output_file": {
7-
"class": "File",
8-
"path": "/tmp/md5sum.txt"
4+
"path": "md5sum.input"
95
}
10-
}
6+
}

wes-docker.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
set -e
3+
python setup.py sdist
4+
docker build --build-arg version=2.3 -t commonworkflowlanguage/workflow-service .
5+
docker run -ti \
6+
-v$PWD/config.yml:/var/www/wes-server/config.yml \
7+
-v/etc/ssl/certs/ssl-cert-snakeoil.pem:/etc/ssl/certs/ssl-cert-wes.pem \
8+
-v/etc/ssl/private/ssl-cert-snakeoil.key:/etc/ssl/private/ssl-cert-wes.key \
9+
-v/var/run/docker.sock:/var/run/docker.sock \
10+
commonworkflowlanguage/workflow-service

wes_client/__init__.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from wes_service.util import visit
1414
import urllib
1515
import ruamel.yaml as yaml
16-
16+
import schema_salad.ref_resolver
1717

1818
def main(argv=sys.argv[1:]):
1919
parser = argparse.ArgumentParser(description='Workflow Execution Service')
@@ -31,6 +31,7 @@ def main(argv=sys.argv[1:]):
3131
exgroup.add_argument("--get", type=str, default=None)
3232
exgroup.add_argument("--log", type=str, default=None)
3333
exgroup.add_argument("--list", action="store_true", default=False)
34+
exgroup.add_argument("--info", action="store_true", default=False)
3435
exgroup.add_argument("--version", action="store_true", default=False)
3536

3637
exgroup = parser.add_mutually_exclusive_group()
@@ -75,17 +76,36 @@ def main(argv=sys.argv[1:]):
7576
json.dump(response.result(), sys.stdout, indent=4)
7677
return 0
7778

78-
with open(args.job_order) as f:
79-
input = yaml.safe_load(f)
80-
basedir = os.path.dirname(args.job_order)
79+
if args.info:
80+
response = client.WorkflowExecutionService.GetServiceInfo()
81+
json.dump(response.result(), sys.stdout, indent=4)
82+
return 0
83+
84+
loader = schema_salad.ref_resolver.Loader({
85+
"location": {"@type": "@id"},
86+
"path": {"@type": "@id"}
87+
})
88+
input, _ = loader.resolve_ref(args.job_order)
89+
90+
basedir = os.path.dirname(args.job_order)
8191

82-
def fixpaths(d):
83-
if isinstance(d, dict) and "location" in d:
84-
if ":" not in d["location"]:
92+
def fixpaths(d):
93+
if isinstance(d, dict):
94+
if "path" in d:
95+
if ":" not in d["path"]:
8596
local_path = os.path.normpath(
86-
os.path.join(os.getcwd(), basedir, d["location"]))
97+
os.path.join(os.getcwd(), basedir, d["path"]))
8798
d["location"] = urllib.pathname2url(local_path)
88-
visit(input, fixpaths)
99+
else:
100+
d["location"] = d["path"]
101+
del d["path"]
102+
if d.get("class") == "Directory":
103+
loc = d.get("location", "")
104+
if loc.startswith("http:") or loc.startswith("https:"):
105+
logging.error("Directory inputs not supported with http references")
106+
exit(33)
107+
108+
visit(input, fixpaths)
89109

90110
workflow_url = args.workflow_url
91111
if not workflow_url.startswith("/") and ":" not in workflow_url:
@@ -125,7 +145,7 @@ def fixpaths(d):
125145
del s["outputs"]["fields"]
126146
json.dump(s["outputs"], sys.stdout, indent=4)
127147

128-
if r["state"] == "Complete":
148+
if r["state"] == "COMPLETE":
129149
return 0
130150
else:
131151
return 1

wes_service/__init__.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
11
import argparse
22
import sys
3+
import ruamel.yaml
4+
import os
5+
import logging
6+
7+
logging.basicConfig(level=logging.INFO)
38

49
import connexion
510
import connexion.utils as utils
611
from connexion.resolver import Resolver
712

13+
def setup(args=None):
14+
if args is None:
15+
args = argparse.Namespace()
816

9-
def main(argv=sys.argv[1:]):
10-
parser = argparse.ArgumentParser(description='Workflow Execution Service')
11-
parser.add_argument(
12-
"--backend", type=str, default="wes_service.cwl_runner")
13-
parser.add_argument("--port", type=int, default=8080)
14-
parser.add_argument("--opt", type=str, action="append")
15-
parser.add_argument("--debug", action="store_true", default=False)
16-
args = parser.parse_args(argv)
17+
configfile = "config.yml"
18+
if os.path.isfile(configfile):
19+
logging.info("Loading %s", configfile)
20+
with open(configfile, "r") as f:
21+
config = ruamel.yaml.safe_load(f)
22+
for c in config:
23+
setattr(args, c, config[c])
24+
25+
26+
logging.info("Using config:")
27+
for n in args.__dict__:
28+
logging.info(" %s: %s", n, getattr(args, n))
1729

1830
app = connexion.App(__name__)
1931
backend = utils.get_function_from_name(
@@ -26,6 +38,20 @@ def rs(x):
2638
'openapi/workflow_execution_service.swagger.yaml',
2739
resolver=Resolver(rs))
2840

41+
return app
42+
43+
44+
def main(argv=sys.argv[1:]):
45+
parser = argparse.ArgumentParser(description='Workflow Execution Service')
46+
parser.add_argument(
47+
"--backend", type=str, default="wes_service.cwl_runner")
48+
parser.add_argument("--port", type=int, default=8080)
49+
parser.add_argument("--opt", type=str, action="append")
50+
parser.add_argument("--debug", action="store_true", default=False)
51+
args = parser.parse_args(argv)
52+
53+
app = setup(args)
54+
2955
app.run(port=args.port, debug=args.debug)
3056

3157

wes_service/__init__.pyc

-1.62 KB
Binary file not shown.

wes_service/arvados_wes.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import arvados
2+
import arvados.util
23
import arvados.collection
34
import os
45
import connexion
@@ -17,22 +18,22 @@ def get_api():
1718

1819

1920
statemap = {
20-
"Queued": "Queued",
21-
"Locked": "Initializing",
22-
"Running": "Running",
23-
"Complete": "Complete",
24-
"Cancelled": "Canceled"
21+
"Queued": "QUEUED",
22+
"Locked": "INITIALIZING",
23+
"Running": "RUNNING",
24+
"Complete": "COMPLETE",
25+
"Cancelled": "CANCELED"
2526
}
2627

2728

2829
class ArvadosBackend(WESBackend):
2930
def GetServiceInfo(self):
3031
return {
3132
"workflow_type_versions": {
32-
"CWL": ["v1.0"]
33+
"CWL": {"workflow_type_version": ["v1.0"]}
3334
},
34-
"supported_wes_versions": "0.1.0",
35-
"supported_filesystem_protocols": ["file"],
35+
"supported_wes_versions": "0.2.1",
36+
"supported_filesystem_protocols": ["file", "http", "https", "keep"],
3637
"engine_versions": "cwl-runner",
3738
"system_state_counts": {},
3839
"key_values": {}
@@ -41,19 +42,21 @@ def GetServiceInfo(self):
4142
def ListWorkflows(self):
4243
api = get_api()
4344

44-
requests = api.container_requests().list(
45-
filters=[["requesting_container_uuid", "=", None]],
46-
select=["uuid", "command", "container_uuid"]).execute()
47-
containers = api.containers().list(filters=[["uuid", "in", [w["container_uuid"] for w in requests["items"]]]], # NOQA
48-
select=["uuid", "state"]).execute()
45+
requests = arvados.util.list_all(api.container_requests().list,
46+
filters=[["requesting_container_uuid", "=", None],
47+
["container_uuid", "!=", None]],
48+
select=["uuid", "command", "container_uuid"])
49+
containers = arvados.util.list_all(api.containers().list,
50+
filters=[["uuid", "in", [w["container_uuid"] for w in requests]]],
51+
select=["uuid", "state"])
4952

50-
uuidmap = {c["uuid"]: statemap[c["state"]] for c in containers["items"]} # NOQA
53+
uuidmap = {c["uuid"]: statemap[c["state"]] for c in containers}
5154

5255
return {
5356
"workflows": [{"workflow_id": cr["uuid"],
54-
"state": uuidmap[cr["container_uuid"]]}
55-
for cr in requests["items"]
56-
if cr["command"][0] == "arvados-cwl-runner"],
57+
"state": uuidmap.get(cr["container_uuid"])}
58+
for cr in requests
59+
if cr["command"] and cr["command"][0] == "arvados-cwl-runner"],
5760
"next_page_token": ""
5861
}
5962

@@ -82,7 +85,7 @@ def GetWorkflowLog(self, workflow_id):
8285

8386
outputobj = {}
8487
if request["output_uuid"]:
85-
c = arvados.collection.CollectionReader(request["output_uuid"])
88+
c = arvados.collection.CollectionReader(request["output_uuid"], api_client=api)
8689
with c.open("cwl.output.json") as f:
8790
outputobj = json.load(f)
8891

@@ -94,7 +97,7 @@ def keepref(d):
9497

9598
stderr = ""
9699
if request["log_uuid"]:
97-
c = arvados.collection.CollectionReader(request["log_uuid"])
100+
c = arvados.collection.CollectionReader(request["log_uuid"], api_client=api)
98101
if "stderr.txt" in c:
99102
with c.open("stderr.txt") as f:
100103
stderr = f.read()
@@ -114,7 +117,7 @@ def keepref(d):
114117
"outputs": outputobj
115118
}
116119
if container["exit_code"] is not None:
117-
r["workflow_log"]["exitCode"] = container["exit_code"]
120+
r["workflow_log"]["exit_code"] = container["exit_code"]
118121
return r
119122

120123
def CancelJob(self, workflow_id): # NOQA

0 commit comments

Comments
 (0)