Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/ert/config/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import contextlib
import logging
import os.path
import re
import shutil
from pathlib import Path

Expand All @@ -25,6 +26,8 @@
DEFAULT_JOBNAME_FORMAT = "<CONFIG_FILE>-<IENS>"
DEFAULT_ECLBASE_FORMAT = "ECLBASE<IENS>"

_TOKEN_REGEX = re.compile(r"<[^<>]+>")

FULL_DISK_PERCENTAGE_THRESHOLD = 0.97
MINIMUM_BYTES_LEFT_ON_DISK_THRESHOLD = 200 * 1000**3 # 200 GB
# We give warning if free disk space is less than MINIMUM_BYTES_LEFT_ON_DISK_THRESHOLD
Expand Down Expand Up @@ -74,6 +77,9 @@ def validate_runpath(cls, runpath_format_string: str) -> str:
)
ConfigWarning.warn(msg)
logger.warning(msg)

cls._validate_static_parts_exists(result)

with contextlib.suppress(Exception):
mount_dir = get_mount_directory(Path(runpath_format_string))
total_space, used_space, free_space = shutil.disk_usage(mount_dir)
Expand Down Expand Up @@ -127,6 +133,35 @@ def from_dict(cls, config_dict: ConfigDict) -> ModelConfig:
),
)

@staticmethod
def _validate_static_parts_exists(runpath_format: str) -> None:
"""
Splits the provided runpath format into parts
and verifies that the static prefix, if present,
consists of directories.

Static parts after dynamic parts are not validated,
as dynamic parts are resolved later in the application.
"""

parts = Path(runpath_format).parts

static_parts = []
for part in parts:
if _TOKEN_REGEX.search(part):
break
static_parts.append(part)

if not static_parts:
return

static_dir = Path(*static_parts)
if static_dir.exists() and not static_dir.is_dir():
Comment thread
tbwiik marked this conversation as resolved.
raise ConfigValidationError(
f"Invalid runpath format; {static_dir} exists, but is not a directory."
)
return


def _replace_runpath_format(format_string: str) -> str:
format_string = format_string.replace("%d", "<IENS>", 1)
Expand Down
19 changes: 19 additions & 0 deletions tests/ert/unit_tests/config/test_model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ def test_model_config_jobname_and_eclbase(extra_config, expected):
assert ModelConfig.from_dict(config_dict).jobname_format_string == expected


def test_that_runpath_validation_raises_error_when_static_prefix_is_not_a_dir(tmp_path):
file = tmp_path / "not_a_dir"
file.write_text("This is a file")

with pytest.raises(ValueError, match="not a directory"):
ModelConfig(runpath_format_string=str(file / "<IENS>" / "<ITER>"))


def test_that_runpath_validation_does_not_raise_error_when_static_prefix_is_a_dir(
tmp_path,
):
static_dir = tmp_path / "dir"
static_dir.mkdir()

ModelConfig(
runpath_format_string=str(static_dir / "<IENS>" / "static_part" / "<ITER>")
)


@pytest.mark.parametrize(
("total_space", "used_space", "to_warn", "expected_warning"),
[
Expand Down
Loading