Skip to content

Commit

Permalink
Added extra_volumes argument to BmiClientDocker
Browse files Browse the repository at this point in the history
Allows to attach extra volumes to Docker container

Fixes #34
  • Loading branch information
sverhoeven committed Jul 10, 2019
1 parent eb6db65 commit 6661451
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
16 changes: 15 additions & 1 deletion grpc4bmi/bmi_client_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ class BmiClientDocker(BmiClient):
output_dir (str): Directory for input files of model
user (str): Username or UID of Docker container
remove (bool): Automatically remove the container when it exits
extra_volumes (Dict[str,Dict]): Extra volumes to attach to Docker container.
The key is either the hosts path or a volume name and the value is a dictionary with the keys:
- ``bind`` The path to mount the volume inside the container
- ``mode`` Either ``rw`` to mount the volume read/write, or ``ro`` to mount it read-only.
For example:
.. code-block:: python
{'/data/shared/forcings/': {'bind': '/forcings', 'mode': 'ro'}}
"""

Expand All @@ -31,10 +42,13 @@ class BmiClientDocker(BmiClient):

def __init__(self, image, image_port=50051, host=None,
input_dir=None, output_dir=None,
user=os.getuid(), remove=True):
user=os.getuid(), remove=True,
extra_volumes=None):
port = BmiClient.get_unique_port()
client = docker.from_env()
volumes = {}
if extra_volumes is not None:
volumes.update(extra_volumes)
self.input_dir = None
if input_dir is not None:
self.input_dir = os.path.abspath(input_dir)
Expand Down
19 changes: 17 additions & 2 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import pytest

def write_config(p):
p.write_text("""data: /data/input/PEQ_Hupsel.dat

def write_config(p, data_fn='/data/input/PEQ_Hupsel.dat'):
p.write_text(f"""data: {data_fn}
parameters:
cW: 200
cV: 4
Expand Down Expand Up @@ -59,3 +60,17 @@ def walrus_input(tmp_path):
write_config(cfg)
write_datafile(tmp_path / 'PEQ_Hupsel.dat')
return cfg


@pytest.fixture()
def walrus_input_on_extra_volume(tmp_path):
# Have config in input dir and forcings data file on extra volume
input_dir = tmp_path / 'input'
input_dir.mkdir()
cfg = input_dir / 'config.yml'
write_config(cfg, '/forcings/PEQ_Hupsel.dat')
extra_dir = tmp_path / 'forcings'
extra_dir.mkdir()
write_datafile(extra_dir / 'PEQ_Hupsel.dat')
extra_volumes = {extra_dir: {'bind': '/forcings', 'mode': 'ro'}}
return input_dir, extra_volumes
17 changes: 17 additions & 0 deletions test/test_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ def walrus_model(tmp_path, walrus_input):
del model


@pytest.fixture()
def walrus_model_with_extra_volume(tmp_path, walrus_input_on_extra_volume):
(input_dir, extra_volumes) = walrus_input_on_extra_volume
model = BmiClientDocker(image="ewatercycle/walrus-grpc4bmi:v0.2.0",
image_port=55555,
input_dir=str(input_dir),
extra_volumes=extra_volumes)
yield model
del model


class TestBmiClientDocker:
def test_component_name(self, walrus_model):
assert walrus_model.get_component_name() == 'WALRUS'
Expand All @@ -26,3 +37,9 @@ def test_initialize(self, walrus_input, walrus_model):
def test_get_value_ref(self, walrus_model):
with pytest.raises(NotImplementedError):
walrus_model.get_value_ref('Q')

def test_extra_volume(self, walrus_model_with_extra_volume):
walrus_model_with_extra_volume.initialize('/data/input/config.yml')
walrus_model_with_extra_volume.update()
# After initialization and update the forcings have been read from the extra volume
assert len(walrus_model_with_extra_volume.get_value('Q')) == 1

0 comments on commit 6661451

Please sign in to comment.