diff --git a/docs/configure.rst b/docs/configure.rst
index 035652aa14..0ab47940ca 100644
--- a/docs/configure.rst
+++ b/docs/configure.rst
@@ -100,6 +100,11 @@ The valid attributes of a system are the following:
- ``tmod``: The classic Tcl implementation of the `environment modules `__ (versions older than 3.2 are not supported).
- ``tmod4``: The version 4 of the Tcl implementation of the `environment modules `__ (versions older than 4.1 are not supported).
- ``lmod``: The Lua implementation of the `environment modules `__.
+
+* ``modules``: Modules to be loaded always when running on this system.
+ These modules modify the ReFrame environment.
+ This is useful when for example a particular module is needed to submit jobs on a specific system.
+* ``variables``: Environment variables to be set always when running on this system.
* ``prefix``: Default regression prefix for this system (default ``.``).
* ``stagedir``: Default stage directory for this system (default :class:`None`).
* ``outputdir``: Default output directory for this system (default :class:`None`).
@@ -114,6 +119,11 @@ For a more detailed description of the ``prefix``, ``stagedir``, ``outputdir`` a
.. versionadded:: 2.8
The ``modules_system`` key was introduced for specifying custom modules systems for different systems.
+.. note::
+ .. versionadded:: 2.19
+ The ``modules`` and ``variables`` configuration parameters were introduced at the system level.
+
+
.. warning::
.. versionchanged:: 2.18
The ``logdir`` key is no more supported; please use ``perflogdir`` instead.
@@ -218,9 +228,15 @@ The available partition attributes are the following:
A new syntax for the ``scheduler`` values was introduced as well as more parallel program launchers.
The old values for the ``scheduler`` key will continue to be supported.
+.. note::
.. versionchanged:: 2.9
- Better support for custom job resources.
+ Better support for custom job resources.
+.. note::
+ .. versionchanged:: 2.14
+ The ``modules`` and ``variables`` partition configuration parameters do not affect the ReFrame environment anymore.
+ They essentially define an environment to be always emitted when building and/or running the test on this partition.
+ If you want to modify the environment ReFrame runs in for a particular system, define these parameters inside the `system configuration <#system-configuration>`__.
Supported scheduler backends
diff --git a/reframe/core/config.py b/reframe/core/config.py
index 491404a820..f5a0d89b3e 100644
--- a/reframe/core/config.py
+++ b/reframe/core/config.py
@@ -161,9 +161,17 @@ def create_env(system, partition, name):
if sys_resourcesdir:
sys_resourcesdir = os_ext.expandvars(sys_resourcesdir)
+ # Create the preload environment for the system
+ sys_preload_env = m_env.Environment(
+ name='__rfm_env_%s' % sys_name,
+ modules=config.get('modules', []),
+ variables=config.get('variables', {})
+ )
+
system = System(name=sys_name,
descr=sys_descr,
hostnames=sys_hostnames,
+ preload_env=sys_preload_env,
prefix=sys_prefix,
stagedir=sys_stagedir,
outputdir=sys_outputdir,
diff --git a/reframe/core/systems.py b/reframe/core/systems.py
index 193231f3c6..b9ae7a9fc7 100644
--- a/reframe/core/systems.py
+++ b/reframe/core/systems.py
@@ -166,7 +166,7 @@ class System:
_partitions = fields.TypedField('_partitions', typ.List[SystemPartition])
_modules_system = fields.TypedField('_modules_system',
typ.Str[r'(\w|-)+'], type(None))
-
+ _preload_env = fields.TypedField('_preload_env', Environment, type(None))
_prefix = fields.TypedField('_prefix', str)
_stagedir = fields.TypedField('_stagedir', str, type(None))
_outputdir = fields.TypedField('_outputdir', str, type(None))
@@ -174,13 +174,14 @@ class System:
_resourcesdir = fields.TypedField('_resourcesdir', str)
def __init__(self, name, descr=None, hostnames=[], partitions=[],
- prefix='.', stagedir=None, outputdir=None, perflogdir=None,
- resourcesdir='.', modules_system=None):
+ preload_env=None, prefix='.', stagedir=None, outputdir=None,
+ perflogdir=None, resourcesdir='.', modules_system=None):
self._name = name
self._descr = descr or name
self._hostnames = list(hostnames)
self._partitions = list(partitions)
self._modules_system = modules_system
+ self._preload_env = preload_env
self._prefix = prefix
self._stagedir = stagedir
self._outputdir = outputdir
@@ -211,6 +212,15 @@ def modules_system(self):
"""The modules system name associated with this system."""
return self._modules_system
+ @property
+ def preload_environ(self):
+ """The environment to load whenever ReFrame runs on this system.
+
+ .. note::
+ .. versionadded:: 2.19
+ """
+ return self._preload_env
+
@property
def prefix(self):
"""The ReFrame prefix associated with this system."""
diff --git a/reframe/frontend/cli.py b/reframe/frontend/cli.py
index 475965a93f..19a066d0f8 100644
--- a/reframe/frontend/cli.py
+++ b/reframe/frontend/cli.py
@@ -494,6 +494,14 @@ def main():
if options.purge_env:
rt.modules_system.unload_all()
+ # Load the environment for the current system
+ try:
+ rt.system.preload_environ.load()
+ except EnvironError as e:
+ printer.error("failed to load current's system environment; "
+ "please check your configuration")
+ raise
+
for m in options.user_modules:
try:
rt.modules_system.load_module(m, force=True)
diff --git a/unittests/resources/settings.py b/unittests/resources/settings.py
index 1d6713e37d..6046aebb9d 100644
--- a/unittests/resources/settings.py
+++ b/unittests/resources/settings.py
@@ -34,18 +34,19 @@ class ReframeSettings:
'prefix': '.rfm_testing',
'resourcesdir': '.rfm_testing/resources',
'perflogdir': '.rfm_testing/perflogs',
+ 'modules': ['foo/1.0'],
+ 'variables': {'FOO_CMD': 'foobar'},
'partitions': {
'login': {
'scheduler': 'local',
- 'modules': [],
- 'access': [],
'resources': {},
'environs': ['PrgEnv-cray', 'PrgEnv-gnu', 'builtin-gcc'],
'descr': 'Login nodes'
},
'gpu': {
'scheduler': 'nativeslurm',
- 'modules': [],
+ 'modules': ['foogpu'],
+ 'variables': {'FOO_GPU': 'yes'},
'resources': {
'gpu': ['--gres=gpu:{num_gpus_per_node}'],
'datawarp': [
diff --git a/unittests/test_config.py b/unittests/test_config.py
index a1799d88e1..0124ed3d4b 100644
--- a/unittests/test_config.py
+++ b/unittests/test_config.py
@@ -4,6 +4,7 @@
import reframe.core.config as config
import unittests.fixtures as fixtures
from reframe.core.exceptions import ConfigError
+import pytest
class TestSiteConfigurationFromDict(unittest.TestCase):
@@ -18,87 +19,94 @@ def get_partition(self, system, name):
def test_load_success(self):
self.site_config.load_from_dict(self.dict_config)
- self.assertEqual(3, len(self.site_config.systems))
+ assert len(self.site_config.systems) == 3
system = self.site_config.systems['testsys']
- self.assertEqual(2, len(system.partitions))
- self.assertEqual('.rfm_testing', system.prefix)
- self.assertEqual('.rfm_testing/resources', system.resourcesdir)
- self.assertEqual('.rfm_testing/perflogs', system.perflogdir)
+ assert len(system.partitions) == 2
+ assert system.prefix == '.rfm_testing'
+ assert system.resourcesdir == '.rfm_testing/resources'
+ assert system.perflogdir == '.rfm_testing/perflogs'
+ assert system.preload_environ.modules == ['foo/1.0']
+ assert system.preload_environ.variables == {'FOO_CMD': 'foobar'}
part_login = self.get_partition(system, 'login')
part_gpu = self.get_partition(system, 'gpu')
- self.assertIsNotNone(part_login)
- self.assertIsNotNone(part_gpu)
- self.assertEqual('testsys:login', part_login.fullname)
- self.assertEqual('testsys:gpu', part_gpu.fullname)
- self.assertEqual(3, len(part_login.environs))
- self.assertEqual(2, len(part_gpu.environs))
+ assert part_login is not None
+ assert part_gpu is not None
+ assert part_login.fullname == 'testsys:login'
+ assert part_gpu.fullname == 'testsys:gpu'
+ assert len(part_login.environs) == 3
+ assert len(part_gpu.environs) == 2
+
+ # Check local partition environment
+ assert part_gpu.local_env.modules == ['foogpu']
+ assert part_gpu.local_env.variables == {'FOO_GPU': 'yes'}
# Check that PrgEnv-gnu on login partition is resolved to the special
# version defined in the 'dom:login' section
env_login = part_login.environment('PrgEnv-gnu')
- self.assertEqual('gcc', env_login.cc)
- self.assertEqual('g++', env_login.cxx)
- self.assertEqual('gfortran', env_login.ftn)
+ assert env_login.cc == 'gcc'
+ assert env_login.cxx == 'g++'
+ assert env_login.ftn == 'gfortran'
# Check that the PrgEnv-gnu of the gpu partition is resolved to the
# default one
env_gpu = part_gpu.environment('PrgEnv-gnu')
- self.assertEqual('cc', env_gpu.cc)
- self.assertEqual('CC', env_gpu.cxx)
- self.assertEqual('ftn', env_gpu.ftn)
+ assert env_gpu.cc == 'cc'
+ assert env_gpu.cxx == 'CC'
+ assert env_gpu.ftn == 'ftn'
# Check resource instantiation
- self.assertEqual(['--gres=gpu:16'],
- part_gpu.get_resource('gpu', num_gpus_per_node=16))
- self.assertEqual(['#DW jobdw capacity=100GB',
- '#DW stage_in source=/foo'],
- part_gpu.get_resource('datawarp',
+ resource_spec = part_gpu.get_resource('gpu', num_gpus_per_node=16)
+ assert (resource_spec == ['--gres=gpu:16'])
+
+ resources_spec = part_gpu.get_resource('datawarp',
capacity='100GB',
- stagein_src='/foo'))
+ stagein_src='/foo')
+ assert (resources_spec == ['#DW jobdw capacity=100GB',
+ '#DW stage_in source=/foo'])
def test_load_failure_empty_dict(self):
dict_config = {}
- self.assertRaises(ValueError,
- self.site_config.load_from_dict, dict_config)
+ with pytest.raises(ValueError):
+ self.site_config.load_from_dict(dict_config)
def test_load_failure_no_environments(self):
dict_config = {'systems': {}}
- self.assertRaises(ValueError,
- self.site_config.load_from_dict, dict_config)
+ with pytest.raises(ValueError):
+ self.site_config.load_from_dict(dict_config)
def test_load_failure_no_systems(self):
dict_config = {'environments': {}}
- self.assertRaises(ValueError,
- self.site_config.load_from_dict, dict_config)
+ with pytest.raises(ValueError):
+ self.site_config.load_from_dict(dict_config)
def test_load_failure_environments_no_scoped_dict(self):
self.dict_config['environments'] = {
'testsys': 'PrgEnv-gnu'
}
- self.assertRaises(TypeError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(TypeError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_partitions_nodict(self):
self.dict_config['systems']['testsys']['partitions'] = ['gpu']
- self.assertRaises(ConfigError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(ConfigError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_systems_nodict(self):
self.dict_config['systems']['testsys'] = ['gpu']
- self.assertRaises(TypeError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(TypeError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_partitions_nodict(self):
self.dict_config['systems']['testsys']['partitions']['login'] = 'foo'
- self.assertRaises(TypeError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(TypeError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_partconfig_nodict(self):
self.dict_config['systems']['testsys']['partitions']['login'] = 'foo'
- self.assertRaises(TypeError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(TypeError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_unresolved_environment(self):
self.dict_config['environments'] = {
@@ -109,13 +117,13 @@ def test_load_failure_unresolved_environment(self):
}
}
}
- self.assertRaises(ConfigError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(ConfigError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_envconfig_nodict(self):
self.dict_config['environments']['*']['PrgEnv-gnu'] = 'foo'
- self.assertRaises(TypeError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(TypeError):
+ self.site_config.load_from_dict(self.dict_config)
def test_load_failure_envconfig_notype(self):
self.dict_config['environments'] = {
@@ -125,8 +133,8 @@ def test_load_failure_envconfig_notype(self):
}
}
}
- self.assertRaises(ConfigError,
- self.site_config.load_from_dict, self.dict_config)
+ with pytest.raises(ConfigError):
+ self.site_config.load_from_dict(self.dict_config)
class TestConfigLoading(unittest.TestCase):
@@ -134,12 +142,14 @@ def test_load_normal_config(self):
config.load_settings_from_file('unittests/resources/settings.py')
def test_load_unknown_file(self):
- self.assertRaises(ConfigError, config.load_settings_from_file, 'foo')
+ with pytest.raises(ConfigError):
+ config.load_settings_from_file('foo')
def test_load_no_settings(self):
- self.assertRaises(ConfigError,
- config.load_settings_from_file, 'unittests')
+ with pytest.raises(ConfigError):
+ config.load_settings_from_file('unittests')
def test_load_invalid_settings(self):
- self.assertRaises(ConfigError, config.load_settings_from_file,
- 'unittests/resources/invalid_settings.py')
+ with pytest.raises(ConfigError):
+ config.load_settings_from_file(
+ 'unittests/resources/invalid_settings.py')