Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix HPC modules #20

Merged
merged 10 commits into from
Nov 25, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Tools development version

- use major & minor version for docs website subdirectories. (#15, @kelly-sovacool)
- Fig bug where `nextflow.run()` did not import the correct HPC modules. (#20, @kelly-sovacool)

## Tools 0.1.1

Expand Down
3 changes: 2 additions & 1 deletion scripts/which_vpn.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
# trying to find out which VPN you are connected to??
set -euo pipefail

if [[ "$HOSTNAME" == "biowulf.nih.gov" ]]
then
Expand Down
58 changes: 55 additions & 3 deletions src/ccbr_tools/pipeline/hpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
which contains default attributes for supported clusters.
"""

from .util import get_hpcname
from .cache import get_singularity_cachedir
from ..shell import shell_run


class Cluster:
Expand Down Expand Up @@ -53,8 +53,16 @@
super().__init__()
self.name = "biowulf"
self.modules = {
"nxf": "ccbrpipeliner nextflow",
"smk": "ccbrpipeliner snakemake/7 singularity",
"nxf": (
"nextflow" + ""
if is_loaded(module="ccbrpipeliner")
else " ccbrpipeliner"
),
"smk": (
"snakemake/7 singularity" + ""
if is_loaded(module="ccbrpipeliner")
else " ccbrpipeliner"
),
}
self.singularity_sif_dir = "/data/CCBR_Pipeliner/SIFs"

Expand Down Expand Up @@ -102,3 +110,47 @@
hpc_options = {"biowulf": Biowulf, "frce": FRCE}
hpc_name = get_hpcname() if not debug else debug
return hpc_options.get(hpc_name, Cluster)()


def get_hpcname():
"""
Get the HPC name using scontrol

Returns:
hpcname (str): The HPC name (biowulf, frce, or an empty string)
"""
scontrol_out = scontrol_show()
hpc = scontrol_out["ClusterName"] if "ClusterName" in scontrol_out.keys() else ""
if hpc == "fnlcr":
hpc = "frce"

Check warning on line 125 in src/ccbr_tools/pipeline/hpc.py

View check run for this annotation

Codecov / codecov/patch

src/ccbr_tools/pipeline/hpc.py#L125

Added line #L125 was not covered by tests
return hpc


def scontrol_show():
"""
Run `scontrol show config` and parse the output as a dictionary

Returns:
scontrol_dict (dict): dictionary containing the output of `scontrol show config`
"""
scontrol_dict = dict()
scontrol_out = shell_run(
"scontrol show config", shell=True, capture_output=True, text=True, check=False
)
if len(scontrol_out) > 0:
for line in scontrol_out.split("\n"):
line_split = line.split("=")
if len(line_split) > 1:
scontrol_dict[line_split[0].strip()] = line_split[1].strip()

Check warning on line 144 in src/ccbr_tools/pipeline/hpc.py

View check run for this annotation

Codecov / codecov/patch

src/ccbr_tools/pipeline/hpc.py#L144

Added line #L144 was not covered by tests
return scontrol_dict


def is_loaded(module="ccbrpipeliner"):
"""
Check whether the ccbrpipeliner module is loaded

Returns:
is_loaded (bool): True if the module is loaded, False otherwise
"""
output = shell_run("bash -c 'module list'", check=False)
return module in output
10 changes: 5 additions & 5 deletions src/ccbr_tools/pipeline/nextflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def run(
mode="local",
pipeline_name=None,
debug=False,
hpc=get_hpc(),
):
"""
Run a Nextflow workflow
Expand All @@ -33,7 +34,6 @@ def run(
"""
nextflow_command = ["nextflow", "run", nextfile_path]

hpc = get_hpc()
if mode == "slurm" and not hpc:
raise ValueError("mode is 'slurm' but no HPC environment was detected")
# add any additional Nextflow commands
Expand All @@ -60,10 +60,8 @@ def run(
): # only add to the profiles if there are any. there are none when champagne is run on GitHub Actions.
args_dict["-profile"] = ",".join(sorted(profiles))
nextflow_command += list(f"{k} {v}" for k, v in args_dict.items())

# Print nextflow command
# turn command into a string
nextflow_command = " ".join(str(nf) for nf in nextflow_command)
msg_box("Nextflow command", errmsg=nextflow_command)

if mode == "slurm":
slurm_filename = "submit_slurm.sh"
Expand All @@ -83,11 +81,13 @@ def run(
msg_box("Slurm batch job", errmsg=run_command)
elif mode == "local":
if hpc:
nextflow_command = f'bash -c "module load {hpc.modules} && {hpc.env_vars} && {nextflow_command}"'
hpc_modules = hpc.modules["nxf"]
nextflow_command = f'bash -c "module load {hpc_modules} && {hpc.env_vars} && {nextflow_command}"'
run_command = nextflow_command
else:
raise ValueError(f"mode {mode} not recognized")

# Run Nextflow
msg_box("Nextflow command", errmsg=nextflow_command)
if not debug:
shell_run(run_command, capture_output=False)
34 changes: 1 addition & 33 deletions src/ccbr_tools/pipeline/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,7 @@
import yaml

from ..pkg_util import repo_base, msg


def scontrol_show():
"""
Run `scontrol show config` and parse the output as a dictionary

Returns:
scontrol_dict (dict): dictionary containing the output of `scontrol show config`
"""
scontrol_dict = dict()
scontrol_out = subprocess.run(
"scontrol show config", shell=True, capture_output=True, text=True
).stdout
if len(scontrol_out) > 0:
for line in scontrol_out.split("\n"):
line_split = line.split("=")
if len(line_split) > 1:
scontrol_dict[line_split[0].strip()] = line_split[1].strip()
return scontrol_dict


def get_hpcname():
"""
Get the HPC name using scontrol

Returns:
hpcname (str): The HPC name (biowulf, frce, or an empty string)
"""
scontrol_out = scontrol_show()
hpc = scontrol_out["ClusterName"] if "ClusterName" in scontrol_out.keys() else ""
if hpc == "fnlcr":
hpc = "frce"
return hpc
from .hpc import get_hpcname


def get_tmp_dir(tmp_dir, outdir, hpc=get_hpcname()):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ccbr_tools.shell import shell_run
from ccbr_tools.pipeline.util import get_hpcname
from ccbr_tools.pipeline.hpc import get_hpcname


def test_version():
Expand Down
6 changes: 6 additions & 0 deletions tests/test_hpc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from ccbr_tools.pipeline.hpc import get_hpc
from ccbr_tools.shell import shell_run
import subprocess


def test_hpc_biowulf():
Expand Down Expand Up @@ -27,3 +29,7 @@ def test_hpc_frce():
def test_hpc_none():
hpc = get_hpc(debug=" ")
assert not any([hpc, hpc.name, *hpc.modules.values(), hpc.singularity_sif_dir])


if __name__ == "__main__":
print(get_hpc(debug="biowulf"))
29 changes: 27 additions & 2 deletions tests/test_nextflow.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
from ccbr_tools.pipeline.nextflow import run
from ccbr_tools.pipeline.hpc import get_hpc, Biowulf, FRCE
from ccbr_tools.shell import exec_in_context

import tempfile


def test_nextflow_basic():
assert "nextflow run CCBR/CHAMPAGNE" in exec_in_context(
run, "CCBR/CHAMPAGNE", debug=True
output = exec_in_context(run, "CCBR/CHAMPAGNE", debug=True)
assert "nextflow run CCBR/CHAMPAGNE" in output


def test_nextflow_hpc():
assert all(
[
"module load"
in exec_in_context(run, "CCBR/CHAMPAGNE", debug=True, hpc=Biowulf()),
"module load"
in exec_in_context(run, "CCBR/CHAMPAGNE", debug=True, hpc=FRCE()),
]
)


def test_nextflow_slurm():
assert "sbatch submit_slurm.sh" in exec_in_context(
run, "CCBR/CHAMPAGNE", debug=True, hpc=Biowulf(), mode="slurm"
)


if __name__ == "__main__":
print(
exec_in_context(run, "CCBR/CHAMPAGNE", debug=True, hpc=Biowulf(), mode="slurm")
)
11 changes: 11 additions & 0 deletions tests/test_pipeline_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from ccbr_tools.pipeline.util import get_tmp_dir


def test_tmp_dir():
assert all(
[
get_tmp_dir("", "./out", hpc="biowulf").startswith("/lscratch"),
get_tmp_dir("", "./out", hpc="frce").startswith("./out"),
get_tmp_dir("", "./out", hpc="none") == None,
]
)
5 changes: 3 additions & 2 deletions tests/test_scripts.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from ccbr_tools.shell import shell_run
from ccbr_tools.pipeline.util import get_hpcname
from ccbr_tools.pipeline.hpc import get_hpcname


def test_scripts_help():
Expand All @@ -9,7 +10,7 @@ def test_scripts_help():


def test_which_vpn():
which_vpn = shell_run("which_vpn.sh")
which_vpn = shell_run("which_vpn.sh", check=False)
hpc = get_hpcname()
if hpc == "biowulf":
assert "DO NOT RUN THIS ON a BIOWULF interactive node!" in which_vpn
Expand Down
Loading