# Gentle intro to cwltool ## Before we begin <iframe width="560" height="315" src="https://www.youtube.com/embed/86eY8xs-Vo8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> Watch the video above for a gentle intro. ## Benefits Workflows offer numerous advantages, with portability being a key benefit. When designed with flexibility, a workflow can be deployed across various environments, such as locally on a laptop, on a high-performance computing (HPC) cluster like the Brain Image Library or Bridges 2, and in cloud platforms like AWS. A second significant advantage is the efficiency with which workflows integrate tools, programs, and scripts written in different programming languages, enabling seamless interoperability. Additionally, workflows can incorporate containers, which can be published to repositories such as DockerHub. This further enhances their portability and flexibility, making workflows adaptable across diverse computational infrastructures. While workflows provide a robust method for running pipelines on Brain Image Library hardware, users also have the option to utilize traditional methods such as bash or Python scripts to execute their workflows. ::: ``` interact -p RM-shared -n 16 --mem=32000M --time "4:00:00" ``` ## Introduction ### Installing cwltool ``` module load anaconda3/2022.10 conda create -n cwltool-tutorial python=3.10 conda activate cwltool-tutorial pip install --user cwltool cwlref-runner ``` ``` (cwltool-tutorial) ➜ ~ which cwl-runner ~/.local/bin/cwl-runner ``` [`cowsay`](https://en.wikipedia.org/wiki/Cowsay) is a tool that pretty prints a cow. ## Example 1: `cowsay` <img src="https://upload.wikimedia.org/wikipedia/commons/8/80/Cowsay_Typical_Output.png" /><br> Traditionally we would install the tool locally either using a repository or pip. For example, ``` pip install cowsay ``` will install the binary in our system. Since the only input to `cowsay` is a string, a basic CWL workflow document looks like this ``` #!/usr/bin/env cwl-runner cwlVersion: v1.0 class: CommandLineTool baseCommand: cowsay inputs: message: type: string inputBinding: position: 1 outputs: [] ``` CWL documents are written either in YAML or JSON. For example, we can create the file `message.cwl` ``` message: Hello world! ``` and use it as input for the workflow ``` cwltool cowsay.cwl message.cwl INFO /bil/packages/anaconda3/4.11.0/bin/cwltool 3.1.20220210171524 INFO Resolved 'cowsay.cwl' to 'file:///bil/users/icaoberg/code/singularity-cowsay/3.04/cowsay.cwl' INFO [job cowsay.cwl] /tmp/l7knmpt3$ cowsay \ 'Hello world!' ____________ | Hello world! | ============ \ \ ^__^ (oo)\_______ (__)\ )\/\ ||----w | || || INFO [job cowsay.cwl] completed success {} INFO Final process status is success ``` ## `cowsay` on Docker :::warning This step cannot run on Brain Image Library hardware since we do not support Docker. ::: Consider the following `Dockerfile` ``` FROM ubuntu:latest RUN apt-get update && apt-get install -y cowsay --no-install-recommends && rm -rf /var/lib/apt/lists/* ENV PATH $PATH:/usr/games CMD ["cowsay"] ``` The file above creates a container with the `cowsay` binary. I can be built it using the command ``` docker build -t icaoberg/cowsay . ``` and pushed to DockerHub using the command ``` docker push icaoberg/cowsay ``` This is a dummy example but technically now there exists a container with my tool. Now, I can recycle the CWL workflow from before and it to get the container from the repo by adding the lines ``` hints: DockerRequirement: dockerPull: icaoberg/cowsay ``` The document now looks like ``` #!/usr/bin/env cwl-runner cwlVersion: v1.0 class: CommandLineTool requirements: SubworkflowFeatureRequirement: {} hints: DockerRequirement: dockerPull: icaoberg/cowsay baseCommand: cowsay inputs: message: type: string inputBinding: position: 1 outputs: [] ``` and running it will produce the same results as the previous example ``` cwltool cowsay2.cwl message.cwl INFO /Users/icaoberg/opt/anaconda3/bin/cwltool 3.1.20220210171524 INFO Resolved 'cowsay2.cwl' to 'file:///Users/icaoberg/Documents/code/singularity-cowsay/3.04/cowsay2.cwl' INFO [job cowsay2.cwl] /private/tmp/docker_tmpr_rjhbrj$ docker \ run \ -i \ --mount=type=bind,source=/private/tmp/docker_tmpr_rjhbrj,target=/xJHVRn \ --mount=type=bind,source=/private/tmp/docker_tmpzpu0ulbd,target=/tmp \ --workdir=/xJHVRn \ --read-only=true \ --user=501:20 \ --rm \ --cidfile=/private/tmp/docker_tmp07wk4ale/20220309145946-550721.cid \ --env=TMPDIR=/tmp \ --env=HOME=/xJHVRn \ icaoberg/cowsay \ cowsay \ 'Hello world!' ______________ < Hello world! > -------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || INFO [job cowsay2.cwl] Max memory used: 0MiB INFO [job cowsay2.cwl] completed success {} INFO Final process status is success ``` :::info Even though we do not support Docker, you can try installing [`uDocker`](https://github.com/indigo-dc/udocker). ::: ## `cowsay` on Singularity The main issue is that most HPC clusters do not support Docker and prefer Singularity or Apptainers. However, if the Docker image in DockerHub has proper entrypoints, then you could simply use the `--singularity` option to ask CWL tools to convert the Docker image to Singularity. :::warning If the Docker image does not a proper entry point this step might fail if you are not aware of how the image was built. Only use vetted images or public images whose Dockerfile you have seen and trust. ::: Using the option ``` cwltool --singularity cowsay2.cwl message.cwl ``` will run the workflow ``` cwltool --singularity cowsay2.cwl message.cwl INFO /bil/packages/anaconda3/4.11.0/bin/cwltool 3.1.20220210171524 INFO Resolved 'cowsay2.cwl' to 'file:///bil/users/icaoberg/code/singularity-cowsay/3.04/cowsay2.cwl' INFO ['singularity', 'pull', '--force', '--name', 'icaoberg_cowsay.sif', 'docker://icaoberg/cowsay'] INFO: Converting OCI blobs to SIF format INFO: Starting build... Getting image source signatures Copying blob 7c3b88808835 done Copying blob 6b7a6ea66907 done Copying config 063d227371 done Writing manifest to image destination Storing signatures 2022/03/09 15:17:27 info unpack layer: sha256:7c3b88808835aa80f1ef7f03083c5ae781d0f44e644537cd72de4ce6c5e62e00 2022/03/09 15:17:28 info unpack layer: sha256:6b7a6ea669076a74f122534da10e4e459f36777854e8e1529564d31c685fd9ea INFO: Creating SIF file... INFO [job cowsay2.cwl] /tmp/ceztlkix$ singularity \ --quiet \ exec \ --contain \ --ipc \ --cleanenv \ --pid \ --home \ /tmp/ceztlkix:/qxOGcV \ --bind \ /tmp/o9hfm5tx:/tmp \ --pwd \ /qxOGcV \ /bil/users/icaoberg/code/singularity-cowsay/3.04/icaoberg_cowsay.sif \ cowsay \ 'Hello world!' ______________ < Hello world! > -------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || INFO [job cowsay2.cwl] completed success {} INFO Final process status is success ``` but will create a Singularity image file on disk. ### Adding more options `cowsay` has more options than just the input string. ``` cowsay(6) Games Manual cowsay(6) NAME cowsay/cowthink - configurable speaking/thinking cow (and a bit more) SYNOPSIS cowsay [-e eye_string] [-f cowfile] [-h] [-l] [-n] [-T tongue_string] [-W column] [-bdg‐ pstwy] ``` A `cowfile` is used to change the picture. For example, running the command ``` ➜ code cowsay -f flaming-sheep "Hello World\!" ______________ < Hello World! > -------------- \ . . . \ . . . ` , \ .; . : .' : : : . \ i..`: i` i.i.,i i . \ `,--.|i |i|ii|ii|i: UooU\.'@@@@@@`.||' \__/(@@@@@@@@@@)' (@@@@@@@@) `YY~~~~YY' || || ``` will print a flaming sheep. In this example, we will expose the `[-f cowfile]` argument by adding the lines ``` format: type: string inputBinding: position: 1 prefix: -f default: "flaming-sheep" ``` to the input block, making the workflow look like ``` #!/usr/bin/env cwl-runner cwlVersion: v1.0 class: CommandLineTool requirements: SubworkflowFeatureRequirement: {} hints: DockerRequirement: dockerPull: icaoberg/cowsay baseCommand: "cowsay" inputs: message: type: string inputBinding: position: 2 format: type: string inputBinding: position: 1 prefix: -f default: "flaming-sheep" outputs: [] ``` Then you can run it ``` 05:03:16 icaoberg@workshop 3.04 ±|master ✗|→ cwltool --singularity cowsay3.cwl message3.cwl INFO /bil/users/icaoberg/.local/bin/cwltool 3.1.20220224085855 INFO Resolved 'cowsay3.cwl' to 'file:///bil/users/icaoberg/code/singularity-cowsay/3.04/cowsay3.cwl' INFO Using local copy of Singularity image found in /bil/users/icaoberg/code/singularity-cowsay/3.04 INFO [job cowsay3.cwl] /tmp/g2zknke0$ singularity \ --quiet \ exec \ --contain \ --ipc \ --cleanenv \ --pid \ --home \ /tmp/g2zknke0:/lzqerl \ --bind \ /tmp/fkb0phq4:/tmp \ --pwd \ /lzqerl \ /bil/users/icaoberg/code/singularity-cowsay/3.04/icaoberg_cowsay.sif \ cowsay \ -f \ flaming-sheep \ 'Hello world!' ______________ < Hello world! > -------------- \ . . . \ . . . ` , \ .; . : .' : : : . \ i..`: i` i.i.,i i . \ `,--.|i |i|ii|ii|i: UooU\.'@@@@@@`.||' \__/(@@@@@@@@@@)' (@@@@@@@@) `YY~~~~YY' || || INFO [job cowsay3.cwl] completed success {} INFO Final process status is success ``` Keep in mind your input argument `message3.yml` now looks like this ``` message: Hello world! format: flaming-sheep ``` You can choose to expose as many input arguments as you want or set default values. :::warning Anything below this line I am still working on ::: ## Mixing and matching Consider the following workflow, `fortune.cwl` ``` #!/usr/bin/env cwl-runner cwlVersion: v1.0 class: CommandLineTool requirements: SubworkflowFeatureRequirement: {} hints: DockerRequirement: dockerPull: grycap/cowsay baseCommand: /usr/games/fortune inputs: [] outputs: [] ``` which does something like ``` cwltool --singularity fortune.cwl INFO /bil/users/icaoberg/.local/bin/cwltool 3.1.20220224085855 INFO Resolved 'fortune.cwl' to 'file:///bil/users/icaoberg/code/singularity-cowsay/3.04/fortune.cwl' INFO Using local copy of Singularity image found in /bil/users/icaoberg/code/singularity-cowsay/3.04 INFO [job fortune.cwl] /tmp/lppo005u$ singularity \ --quiet \ exec \ --contain \ --ipc \ --cleanenv \ --pid \ --home \ /tmp/lppo005u:/jzrcyZ \ --bind \ /tmp/l0squr2a:/tmp \ --pwd \ /jzrcyZ \ /bil/users/icaoberg/code/singularity-cowsay/3.04/grycap_cowsay.sif \ /usr/games/fortune Q: How many lawyers does it take to change a light bulb? A: You won't find a lawyer who can change a light bulb. Now, if you're looking for a lawyer to screw a light bulb... INFO [job fortune.cwl] completed success {} INFO Final process status is success ```