Repository 'docker_scriptrunner'
hg clone https://toolshed.g2.bx.psu.edu/repos/mvdbeek/docker_scriptrunner

Changeset 2:495946ffc2d6 (2018-07-22)
Previous changeset 1:315a7e9ed6eb (2016-07-09)
Commit message:
planemo upload for repository https://github.com/mvdbeek/docker_scriptrunner/ commit dded837d19aeb3f06b84e5076282cedeeaf713fa
modified:
README.md
dockerfiles/build.sh
dockerfiles/scriptrunner/Dockerfile
planemo_serve_script.sh
scriptrunner.py
scriptrunner.xml
test-data/tf2_test.html
test.sh
removed:
tool_dependencies.xml
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 README.md
--- a/README.md Sat Jul 09 17:00:06 2016 -0400
+++ b/README.md Sun Jul 22 13:38:01 2018 -0400
[
@@ -1,6 +1,35 @@
+[![Build Status](https://travis-ci.org/ARTbio/docker-scriptrunner.svg?branch=master)](https://travis-ci.org/ARTbio/docker-scriptrunner)
+
+You need to have docker 
 Docker scriptrunner for galaxy
 -----------------------------
 
 This is a [galaxy](https://github.com/galaxyproject/galaxy) tool that allows
 users to submit random scripts.
-You can install it on your galaxy server from the [galaxy toolshed]()
+You can install it on your galaxy server from the [galaxy toolshed] (https://toolshed.g2.bx.psu.edu/view/mvdbeek/docker_scriptrunner/).
+
+
+This tool is heavily inspired by Ross Lazarus' tool factory
+(https://www.ncbi.nlm.nih.gov/pubmed/23024011), but removes the ability to
+create galaxy tools. (If you are looking at creating galaxy tools, you may want 
+to use [planemo](https://planemo.readthedocs.io/en/latest/)).
+
+
+You need to have docker installed on any machine that can run
+galaxy jobs, or route this tool to a dedicated docker host
+in galaxy's job_conf.xml. Note that the tool itself talks
+to the docker daemon and bypasses galaxy's docker configuration.
+Making use of galaxy's docker capabilities is on the roadmap.
+
+
+The tool comes with two docker images that can be easily extended.
+"artbio/scriptrunner" is a base image, that has very few dependencies installed.
+You can extend the image by following the example in the dockerfiles/r-bioperl-python
+folder.
+
+
+All security relies on docker; the container only mounts those files that the user
+has selected as input files, and the script itself drops privileged inside
+the container. This should be secure, but caution should be taken on public servers.
+By default the container has networking enabled, so make sure your firewall rules
+forbid traffic to the local network.
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 dockerfiles/build.sh
--- a/dockerfiles/build.sh Sat Jul 09 17:00:06 2016 -0400
+++ b/dockerfiles/build.sh Sun Jul 22 13:38:01 2018 -0400
b
@@ -1,3 +1,4 @@
 #!/usr/bin/env bash
+cd "${0%/*}"
 docker build -t artbio/scriptrunner scriptrunner && \
 docker build -t artbio/scriptrunner-r-bioperl-python r-bioperl-python
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 dockerfiles/scriptrunner/Dockerfile
--- a/dockerfiles/scriptrunner/Dockerfile Sat Jul 09 17:00:06 2016 -0400
+++ b/dockerfiles/scriptrunner/Dockerfile Sun Jul 22 13:38:01 2018 -0400
b
@@ -26,8 +26,8 @@
 
 RUN curl https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -L -o miniconda.sh 
 RUN bash miniconda.sh -b -p "$CONDA_PREFIX" && rm miniconda.sh
-RUN bash -c "conda create -y -q -c bioconda --name default samtools==0.1.19 bcftools && \
-    conda config --add channels r && \
+RUN bash -c "conda create -y -q -c bioconda --name default samtools bcftools && \
+    conda config --add channels conda-forge && \
     conda config --add channels bioconda && \
     conda config --add channels iuc && \
     . activate default && \
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 planemo_serve_script.sh
--- a/planemo_serve_script.sh Sat Jul 09 17:00:06 2016 -0400
+++ b/planemo_serve_script.sh Sun Jul 22 13:38:01 2018 -0400
b
@@ -1,1 +1,1 @@
-planemo serve --galaxy_branch dev --conda_prefix=/conda --conda_dependency_resolution --profile tf --port 80 --host 0.0.0.0 --job_config_file ~/mydisk/job_conf.xml --tool_data_table tool_data_table_conf.xml.sample.test
+planemo serve --tool_data_table tool_data_table_conf.xml.sample.test "$@"
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 scriptrunner.py
--- a/scriptrunner.py Sat Jul 09 17:00:06 2016 -0400
+++ b/scriptrunner.py Sun Jul 22 13:38:01 2018 -0400
[
b'@@ -1,213 +1,195 @@\n # DockerToolFactory.py\n # see https://github.com/mvdbeek/scriptrunner\n \n-import sys \n-import shutil \n-import subprocess \n-import os \n-import time \n-import tempfile \n+from __future__ import print_function\n+import sys\n+import shutil\n+import subprocess\n+import os\n+import time\n+import tempfile\n import argparse\n-import getpass\n-import tarfile\n-import re\n-import shutil\n import math\n-import fileinput\n-from os.path import abspath \n-\n+from os.path import abspath\n \n-progname = os.path.split(sys.argv[0])[1] \n-verbose = False \n+progname = os.path.split(sys.argv[0])[1]\n+verbose = False\n debug = False\n \n-def timenow():\n-    """return current time as a string\n-    """\n-    return time.strftime(\'%d/%m/%Y %H:%M:%S\', time.localtime(time.time()))\n-\n html_escape_table = {\n-     "&": "&amp;",\n-     ">": "&gt;",\n-     "<": "&lt;",\n-     "$": "\\$"\n-     }\n+    "&": "&amp;",\n+    ">": "&gt;",\n+    "<": "&lt;",\n+    "$": "\\$"\n+}\n+\n+\n+def timenow():\n+    """Return current time as a string."""\n+    return time.strftime(\'%d/%m/%Y %H:%M:%S\', time.localtime(time.time()))\n+\n \n def html_escape(text):\n-     """Produce entities within text."""\n-     return "".join(html_escape_table.get(c,c) for c in text)\n+    """Produce entities within text."""\n+    return "".join(html_escape_table.get(c, c) for c in text)\n+\n \n def cmd_exists(cmd):\n-     return subprocess.call("type " + cmd, shell=True, \n-           stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0\n+    return subprocess.call("type " + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0\n+\n \n def construct_bind(host_path, container_path=False, binds=None, ro=True):\n-    #TODO remove container_path if it\'s alwyas going to be the same as host_path\n-    \'\'\'build or extend binds dictionary with container path. binds is used\n-    to mount all files using the docker-py client.\'\'\'\n+    # TODO remove container_path if it\'s alwyas going to be the same as host_path\n+    """Build or extend binds dictionary with container path. binds is used\n+    to mount all files using the docker-py client."""\n     if not binds:\n-        binds={}\n+        binds = {}\n     if isinstance(host_path, list):\n-        for k,v in enumerate(host_path):\n+        for k, v in enumerate(host_path):\n             if not container_path:\n-                container_path=host_path[k]\n-            binds[host_path[k]]={\'bind\':container_path, \'ro\':ro}\n-            container_path=False #could be more elegant\n+                container_path = host_path[k]\n+            binds[host_path[k]] = {\'bind\': container_path, \'ro\': ro}\n+            container_path = False  # could be more elegant\n         return binds\n     else:\n         if not container_path:\n-            container_path=host_path\n-        binds[host_path]={\'bind\':container_path, \'ro\':ro}\n+            container_path = host_path\n+        binds[host_path] = {\'bind\': container_path, \'ro\': ro}\n         return binds\n \n+\n def switch_to_docker(opts):\n-    import docker #need local import, as container does not have docker-py\n+    import docker  # need local import, as container does not have docker-py\n     user_id = os.getuid()\n     group_id = os.getgid()\n-    docker_client=docker.Client()\n-    toolfactory_path=abspath(sys.argv[0])\n-    binds=construct_bind(host_path=opts.script_path, ro=False)\n-    binds=construct_bind(binds=binds, host_path=abspath(opts.output_dir), ro=False)\n-    if len(opts.input_tab)>0:\n-        binds=construct_bind(binds=binds, host_path=opts.input_tab, ro=True)\n-    if not opts.output_tab == \'None\':\n-        binds=construct_bind(binds=binds, host_path=opts.output_tab, ro=False)\n+    docker_client = docker.APIClient()\n+    toolfactory_path = abspath(sys.argv[0])\n+    binds = construct_bind(host_path=opts.script_path, ro=False)\n+    binds = construct_bind(binds=binds, host_path=abspath(opts.output_dir), ro=False)\n+    if len(opts.input_file) > 0:\n+        binds = construct_bind(binds=binds, host_path=opts.input_file, ro=True)\n+    if not opts.output'..b'file=sys.stderr)  # same problem, need to capture docker stdin/stdout\n             if self.opts.make_HTML:\n                 self.makeHtml()\n         return retval\n@@ -359,19 +338,19 @@\n         """\n         if self.opts.output_dir:\n             s = \'## Toolfactory generated command line = %s\\n\' % \' \'.join(self.cl)\n-            sto = open(self.tlog,\'w\')\n+            sto = open(self.tlog, \'w\')\n             sto.write(s)\n             sto.flush()\n-            p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir)\n+            p = subprocess.Popen(self.cl, shell=False, stdout=sto, stderr=sto, cwd=self.opts.output_dir)\n         else:\n-            p = subprocess.Popen(self.cl,shell=False)            \n+            p = subprocess.Popen(self.cl, shell=False)\n         retval = p.wait()\n         if self.opts.output_dir:\n             sto.close()\n         if self.opts.make_HTML:\n             self.makeHtml()\n         return retval\n-  \n+\n \n def change_user_id(new_uid, new_gid):\n     """\n@@ -386,42 +365,37 @@\n \n \n def main():\n-    u = """\n-    This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml as:\n-    <command interpreter="python">rgBaseScriptWrapper.py --script_path "$scriptPath" --tool_name "foo" --interpreter "Rscript"\n-    </command>\n-    """\n     op = argparse.ArgumentParser()\n     a = op.add_argument\n-    a(\'--docker_image\',default=None)\n-    a(\'--script_path\',default=None)\n-    a(\'--tool_name\',default=None)\n-    a(\'--interpreter\',default=None)\n-    a(\'--output_dir\',default=\'./\')\n-    a(\'--output_html\',default=None)\n-    a(\'--input_tab\',default=\'None\', nargs=\'*\')\n-    a(\'--output_tab\',default=\'None\')\n-    a(\'--user_email\',default=\'Unknown\')\n-    a(\'--bad_user\',default=None)\n-    a(\'--make_HTML\',default=None)\n-    a(\'--new_tool\',default=None)\n-    a(\'--dockerized\',default=0)\n-    a(\'--group_id\',default=None)\n-    a(\'--user_id\',default=None)\n+    a(\'--docker_image\', default=None)\n+    a(\'--script_path\', default=None)\n+    a(\'--tool_name\', default=None)\n+    a(\'--interpreter\', default=None)\n+    a(\'--output_dir\', default=\'./\')\n+    a(\'--output_html\', default=None)\n+    a(\'--input_file\', default=\'None\', nargs=\'*\')\n+    a(\'--output_file\', default=\'None\')\n+    a(\'--user_email\', default=\'Unknown\')\n+    a(\'--bad_user\', default=None)\n+    a(\'--make_HTML\', default=None)\n+    a(\'--new_tool\', default=None)\n+    a(\'--dockerized\', default=0)\n+    a(\'--group_id\', default=None)\n+    a(\'--user_id\', default=None)\n     a(\'--output_format\', default=\'tabular\')\n     a(\'--input_format\', dest=\'input_formats\', action=\'append\', default=[])\n     a(\'--additional_parameters\', dest=\'additional_parameters\', action=\'append\', default=[])\n     opts = op.parse_args()\n-    assert not opts.bad_user,\'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to admin_users in universe_wsgi.ini\' % (opts.bad_user,opts.bad_user)\n-    assert os.path.isfile(opts.script_path),\'## Tool Factory wrapper expects a script path - eg --script_path=foo.R\'\n+    assert not opts.bad_user, \'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to admin_users in universe_wsgi.ini\' % (opts.bad_user, opts.bad_user)\n+    assert os.path.isfile(opts.script_path), \'## Tool Factory wrapper expects a script path - eg --script_path=foo.R\'\n     if opts.output_dir:\n         try:\n             os.makedirs(opts.output_dir)\n-        except:\n+        except Exception:\n             pass\n-    if opts.dockerized==0:\n-      switch_to_docker(opts)\n-      return\n+    if opts.dockerized == 0:\n+        retcode = switch_to_docker(opts)\n+        sys.exit(retcode)\n     change_user_id(opts.user_id, opts.group_id)\n     os.setgid(int(opts.group_id))\n     os.setuid(int(opts.user_id))\n@@ -429,7 +403,7 @@\n     retcode = r.run()\n     os.unlink(r.sfile)\n     if retcode:\n-        sys.exit(retcode) # indicate failure to job runner\n+        sys.exit(retcode)  # indicate failure to job runner\n \n \n if __name__ == "__main__":\n'
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 scriptrunner.xml
--- a/scriptrunner.xml Sat Jul 09 17:00:06 2016 -0400
+++ b/scriptrunner.xml Sun Jul 22 13:38:01 2018 -0400
[
@@ -1,40 +1,40 @@
-<tool id="docker_scriptrunner" name="docker scriptrunner" version="1.1.6">
+<tool id="docker_scriptrunner" name="docker scriptrunner" version="0.1.7">
   <description>Runs scripts using docker</description>
   <macros>
     <import>macros.xml</import>
   </macros>
    <requirements>
-      <requirement type="package" version="1.8.1">docker-py</requirement>
+      <requirement type="package" version="3.4.1">docker-py</requirement>
   </requirements>
-  <command>
-    python "$__tool_directory__/scriptrunner.py"
-    --script_path "$runme"
-    --interpreter "$interpreter"
-    --user_email "$__user_email__"
-    #if $generate_simple_output.make_TAB=="yes":
-       --output_tab "$tab_file"
-    #end if
-    #if $make_HTML.value=="yes":
-      --output_dir "$html_file.files_path" --output_html "$html_file" --make_HTML "yes"
-    #else:
-       --output_dir "."
-    #end if
-    #if $additional_parameters != 'None':
-      #for i in $additional_parameters:
- --additional_parameters
-        "$i.param_name, $i.param_value"
-      #end for
-    #end if
-    #if $input_files != 'None':
-       --input_tab 
- #for i in $input_files:
-   $i.input
- #end for
-        #for i in $input_files:
-          --input_format "Any"
-        #end for
-    #end if
-    --docker_image "$docker_image" 
+  <command detect_errors="exit_code">
+python '$__tool_directory__/scriptrunner.py'
+--script_path '$runme'
+--interpreter '$interpreter'
+--user_email '$__user_email__'
+#if $generate_simple_output.make_file=="yes":
+   --output_file "$output_file"
+#end if
+#if $make_HTML.value=="yes":
+  --output_dir "$html_file.files_path" --output_html "$html_file" --make_HTML "yes"
+#else:
+   --output_dir "."
+#end if
+#if $additional_parameters != 'None':
+  #for i in $additional_parameters:
+    --additional_parameters
+    "$i.param_name, $i.param_value"
+  #end for
+#end if
+#if $input_files != 'None':
+   --input_file
+   #for i in $input_files:
+     $i.input
+   #end for
+   #for i in $input_files:
+     --input_format "Any"
+   #end for
+#end if
+--docker_image "$docker_image" 
   </command>
 <configfiles>
   <configfile name="runme">$dynScript</configfile>
@@ -64,8 +64,8 @@
         <option value="" selected="true">No, no HTML output file thanks</option>
     </param>
     <conditional name="generate_simple_output">
-      <param name="make_TAB" type="select" label="Create a new history output alongside the HTML file specified above" 
-           help="This is useful if your script creates a single new tabular file you want to appear in the history after the tool executes">
+      <param name="make_file" type="select" label="Create a new history output alongside the HTML file specified above"
+           help="This is useful if your script creates a single new file that you want to appear in the history after the tool executes">
           <option value="yes" selected="true">My script writes to a new history output</option>
           <option value="">I do not want a new history output file</option>
       </param>
@@ -89,7 +89,7 @@
         <options from_data_table="docker_scriptrunner_images"/>
     </param>
     <param name="dynScript" label="Copy and paste the script to be executed here" type="text" value="" area="True" size="8x120"  
-      help="Script must deal with two command line parameters: Path to input tabular file path (or 'None' if none selected) and path to output tabular history file (or 'None').">
+      help="Script must deal with two command line parameters: Path to input file path (or 'None' if none selected) and path to output tabular history file (or 'None').">
       <sanitizer>
          <valid initial="string.printable">
          </valid>
@@ -98,8 +98,8 @@
      </param>
   </inputs>
   <outputs>
-    <data format_source="input" name="tab_file">
-      <filter>generate_simple_output['make_TAB'] == "yes"</filter>
+    <data format_source="input" name="output_file">
+      <filter>generate_simple_output['make_file'] == "yes"</filter>
         <actions>
           <action type="format">
                 <option type="from_param" name="generate_simple_output.out_format" />
@@ -112,14 +112,14 @@
  </outputs>
 <tests>
     <test>
-        <param name='input_tab' value='tf2_test_in.xls' ftype='tabular' />
-        <param name="make_TAB" value="yes" />
-        <param name="make_HTML" value="yes" />
-        <param name="out_format" value="tabular" />
-        <param name="interpreter" value='python' />
+        <param name="input_file" value="tf2_test_in.xls" ftype="tabular"/>
+        <param name="make_file" value="yes"/>
+        <param name="make_HTML" value="yes"/>
+        <param name="out_format" value="tabular"/>
+        <param name="interpreter" value="python"/>
         <param name="runme" value="tf2_test_runme.py"/>
-        <output name='output1' file='tf2_test_out.xls' compare='diff' lines_diff = '10'/>
-        <output name='html_file' file="tf2_test.html" compare='diff' lines_diff = '10'/>
+        <output name="output_file" file="tf2_test_out.xls" compare="diff" lines_diff="10"/>
+        <output name="html_file" file="tf2_test.html" compare="diff" lines_diff="10"/>
     </test>
 </tests>
 <expand macro="help_macro" />
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 test-data/tf2_test.html
--- a/test-data/tf2_test.html Sat Jul 09 17:00:06 2016 -0400
+++ b/test-data/tf2_test.html Sun Jul 22 13:38:01 2018 -0400
b
@@ -1,25 +1,25 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
-        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
-        <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
-        <meta name="generator" content="Galaxy scriptrunner.py tool output - see http://g2.trac.bx.psu.edu/" /> 
-        <title></title> 
-        <link rel="stylesheet" href="/static/style/base.css" type="text/css" /> 
-        </head> 
-        <body> 
-        <div class="toolFormBody"> 
-        
-<div class="infomessage">Galaxy Tool "script" run at 09/07/2016 11:37:54</div><br/>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+        <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <meta name="generator" content="Galaxy scriptrunner.py tool output - see http://g2.trac.bx.psu.edu/" />
+        <title></title>
+        <link rel="stylesheet" href="/static/style/base.css" type="text/css" />
+        </head>
+        <body>
+        <div class="toolFormBody">
+
+<div class="infomessage">Galaxy Tool "script" run at 22/07/2018 17:09:47</div><br/>
 <div class="toolFormTitle">script log output</div>
 script_error.log is empty<br/>
 <div class="toolFormTitle">Other log output</div>
-/tmp/tmpG7m9zp/job_working_directory/000/1/dataset_2_files/script_runner.log is empty<br/>
+/private/var/folders/df/6xqpqpcd7h73b6jpx9t6cwhw0000gn/T/tmptx2hJF/job_working_directory/000/1/dataset_2_files/script_runner.log is empty<br/>
 <div class="toolFormTitle">All output files available for downloading</div>
 
 <div><table class="colored" cellpadding="3" cellspacing="3"><tr><th>Output File Name (click to view)</th><th>Size</th></tr>
 
 <tr><td><a href="script.python">script.python</a></td><td>0 B</td></tr>
 <tr class="odd_row"><td><a href="script_error.log">script_error.log</a></td><td>0 B</td></tr>
-<tr><td><a href="script_runner.log">script_runner.log</a></td><td>100 B</td></tr>
+<tr><td><a href="script_runner.log">script_runner.log</a></td><td>140 B</td></tr>
 </table></div><br/>
 </div></body></html>
 
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 test.sh
--- a/test.sh Sat Jul 09 17:00:06 2016 -0400
+++ b/test.sh Sun Jul 22 13:38:01 2018 -0400
b
@@ -1,7 +1,2 @@
 #!/usr/bin/env bash
-planemo test --galaxy_branch dev \
-             --conda_auto_init \
-             --conda_dependency_resolution \
-             --conda_auto_install \
-             --conda_ensure_channels scrapinghub \
-             --tool_data_table tool_data_table_conf.xml.sample.test
+planemo test --tool_data_table tool_data_table_conf.xml.sample.test "$@"
b
diff -r 315a7e9ed6eb -r 495946ffc2d6 tool_dependencies.xml
--- a/tool_dependencies.xml Sat Jul 09 17:00:06 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
b
@@ -1,14 +0,0 @@
-<?xml version="1.0"?>
-<tool_dependency>
-    <package name="docker-py" version="1.8.1">
-        <install version="1.0">
-            <actions>
-                <action type="setup_virtualenv">docker-py==1.8.1
-                </action>
-            </actions>
-        </install>
-    </package>
-        <readme>
-            Only Admins can use this tool generator but please do NOT install o
-       </readme>
-</tool_dependency>