Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a0cf25b
Add tool that converts the old configuration to json object
ekouts Feb 19, 2020
eb31343
Minor fixes
ekouts Feb 19, 2020
09cf1a2
Fix boolean values
ekouts Feb 20, 2020
666790d
Change interface of the tool
ekouts Feb 24, 2020
6815be5
Change json dump function
ekouts Feb 24, 2020
e0cc3b5
Fix PEP8 issues
ekouts Feb 24, 2020
381895e
Address PR comments
ekouts Feb 26, 2020
5f2aea3
Add printing function for the configuration
ekouts Mar 5, 2020
76fcedd
Fix typo in formatting function
ekouts Mar 5, 2020
97f8fe0
Fix formatting issues
ekouts Mar 6, 2020
4a46f46
Fixes in the formatting function
ekouts Mar 11, 2020
de05bbc
Merge branch 'master' of https://github.com/eth-cscs/reframe into fea…
ekouts Mar 11, 2020
4907255
Add a stand-alone tool for converting configuration files
Mar 13, 2020
4e926e4
Add copyright notice
Mar 13, 2020
74ce4d7
Validate the converted configuration file
Mar 13, 2020
879a7ce
Fix ppretty
ekouts Mar 13, 2020
ece4731
Merge branch 'feat/json-config-tool' of https://github.com/ekouts/ref…
ekouts Mar 13, 2020
9e634ce
Fix convert_old_config
ekouts Mar 13, 2020
41b7ef2
Add unittests for ppretty
ekouts Mar 13, 2020
a421414
Fix ppretty docstring
ekouts Mar 17, 2020
1dbbb5f
Add more unittests for ppretty
ekouts Mar 17, 2020
d2bd624
Minor fixes in config.py
ekouts Mar 17, 2020
22e3490
Add nested dictionary and custom repr unittests
ekouts Mar 18, 2020
74a5efc
Fix unittest for class pprint
ekouts Mar 18, 2020
a212600
Merge branch 'master' into feat/json-config-tool
Mar 18, 2020
7599c24
Always install ReFrame's requirements in CI
Mar 23, 2020
540bf56
Merge branch 'master' into feat/json-config-tool
Mar 23, 2020
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
8 changes: 5 additions & 3 deletions ci-scripts/ci-runner.bash
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,15 @@ fi
if [[ $(hostname) =~ tsa ]]; then
# FIXME: Temporary workaround until we have a reframe module on Tsa
module load python
python3 -m venv venv.unittests
source venv.unittests/bin/activate
pip install -r requirements.txt
else
module load reframe
fi

# Always install our requirements
python3 -m venv venv.unittests
source venv.unittests/bin/activate
pip install -r requirements.txt

echo "=============="
echo "Loaded Modules"
echo "=============="
Expand Down
152 changes: 151 additions & 1 deletion reframe/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@
# SPDX-License-Identifier: BSD-3-Clause

import collections.abc
import json
import jsonschema
import os
import re
import tempfile

import reframe
import reframe.core.debug as debug
import reframe.core.fields as fields
import reframe.utility as util
import reframe.utility.os_ext as os_ext
import reframe.utility.typecheck as types
from reframe.core.exceptions import (ConfigError, ReframeFatalError)
from reframe.core.exceptions import (ConfigError, ReframeError,
ReframeFatalError)


_settings = None
Expand Down Expand Up @@ -222,3 +228,147 @@ def create_env(system, partition, name):
system.add_partition(part)

self._systems[sys_name] = system


def convert_old_config(filename):
old_config = load_settings_from_file(filename)
converted = {
'systems': [],
'environments': [],
'logging': [],
'perf_logging': [],
}
old_systems = old_config.site_configuration['systems'].items()
for sys_name, sys_specs in old_systems:
sys_dict = {'name': sys_name}
sys_dict.update(sys_specs)

# Make variables dictionary into a list of lists
if 'variables' in sys_specs:
sys_dict['variables'] = [
[vname, v] for vname, v in sys_dict['variables'].items()
]

# Make partitions dictionary into a list
if 'partitions' in sys_specs:
sys_dict['partitions'] = []
for pname, p in sys_specs['partitions'].items():
new_p = {'name': pname}
new_p.update(p)
if p['scheduler'] == 'nativeslurm':
new_p['scheduler'] = 'slurm'
new_p['launcher'] = 'srun'
elif p['scheduler'] == 'local':
new_p['scheduler'] = 'local'
new_p['launcher'] = 'local'
else:
sched, launch, *_ = p['scheduler'].split('+')
new_p['scheduler'] = sched
new_p['launcher'] = launch

# Make resources dictionary into a list
if 'resources' in p:
new_p['resources'] = [
{'name': rname, 'options': r}
for rname, r in p['resources'].items()
]

# Make variables dictionary into a list of lists
if 'variables' in p:
new_p['variables'] = [
[vname, v] for vname, v in p['variables'].items()
]

if 'container_platforms' in p:
new_p['container_platforms'] = []
for cname, c in p['container_platforms'].items():
new_c = {'name': cname}
new_c.update(c)
if 'variables' in c:
new_c['variables'] = [
[vn, v] for vn, v in c['variables'].items()
]

new_p['container_platforms'].append(new_c)

sys_dict['partitions'].append(new_p)

converted['systems'].append(sys_dict)

old_environs = old_config.site_configuration['environments'].items()
for env_target, env_entries in old_environs:
for ename, e in env_entries.items():
new_env = {'name': ename}
if env_target != '*':
new_env['target_systems'] = [env_target]

new_env.update(e)

# Convert variables dictionary to a list of lists
if 'variables' in e:
new_env['variables'] = [
[vname, v] for vname, v in e['variables'].items()
]

# Type attribute is not used anymore
if 'type' in new_env:
del new_env['type']

converted['environments'].append(new_env)

if 'modes' in old_config.site_configuration:
converted['modes'] = []
old_modes = old_config.site_configuration['modes'].items()
for target_mode, mode_entries in old_modes:
for mname, m in mode_entries.items():
new_mode = {'name': mname, 'options': m}
if target_mode != '*':
new_mode['target_systems'] = [target_mode]

converted['modes'].append(new_mode)

def update_logging_config(log_name, original_log):
new_handlers = []
for h in original_log['handlers']:
new_h = h
new_h['level'] = h['level'].lower()
new_handlers.append(new_h)

converted[log_name].append(
{
'level': original_log['level'].lower(),
'handlers': new_handlers
}
)

update_logging_config('logging', old_config.logging_config)
update_logging_config('perf_logging', old_config.perf_logging_config)
converted['general'] = [{}]
if hasattr(old_config, 'checks_path'):
converted['general'][0][
'check_search_path'
] = old_config.checks_path

if hasattr(old_config, 'checks_path_recurse'):
converted['general'][0][
'check_search_recursive'
] = old_config.checks_path_recurse

if converted['general'] == [{}]:
del converted['general']

# Validate the converted file
schema_filename = os.path.join(reframe.INSTALL_PREFIX,
'schemas', 'config.json')

# We let the following statements raise, because if they do, that's a BUG
with open(schema_filename) as fp:
schema = json.loads(fp.read())

jsonschema.validate(converted, schema)
with tempfile.NamedTemporaryFile(mode='w', delete=False) as fp:
fp.write(f"#\n# This file was automatically generated "
f"by ReFrame based on '{filename}'.\n#\n\n")
fp.write(f'site_configuration = {util.ppretty(converted)}\n')

return fp.name
58 changes: 58 additions & 0 deletions reframe/utility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,64 @@ def toalphanum(s):
return re.sub(r'\W', '_', s)


def ppretty(value, htchar=' ', lfchar='\n', indent=4, basic_offset=0):
'''Format string of dictionaries, lists and tuples

:arg value: The value to be formatted.
:arg htchar: Horizontal-tab character.
:arg lfchar: Linefeed character.
:arg indent: Number of htchar characters for every indentation level.
:arg basic_offset: Basic offset for the representation, any additional
indentation space is added to the ``basic_offset``.
:returns: a formatted string of the ``value``.
'''

nlch = lfchar + htchar * indent * (basic_offset + 1)
if isinstance(value, tuple):
if value == ():
return '()'

items = [
nlch + ppretty(item, htchar, lfchar, indent, basic_offset + 1)
for item in value
]
return '(%s)' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
elif isinstance(value, list):
if value == []:
return '[]'

items = [
nlch + ppretty(item, htchar, lfchar, indent, basic_offset + 1)
for item in value
]
return '[%s]' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
elif isinstance(value, dict):
if value == {}:
return '{}'

items = [
nlch + repr(key) + ': ' +
ppretty(value[key], htchar, lfchar, indent, basic_offset + 1)
for key in value
]
return '{%s}' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
elif isinstance(value, set):
if value == set():
return 'set()'

items = [
nlch + ppretty(item, htchar, lfchar, indent, basic_offset + 1)
for item in value
]
return '{%s}' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
else:
return repr(value)


class ScopedDict(UserDict):
'''This is a special dict that imposes scopes on its keys.

Expand Down
8 changes: 4 additions & 4 deletions schemas/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
"descr": {"type": "string"},
"scheduler": {
"type": "string",
"enum": ["local", "pbs", "slurm", "squeue"]
"enum": ["local", "pbs", "slurm", "squeue", "torque"]
},
"launcher": {
"type": "string",
Expand Down Expand Up @@ -310,7 +310,7 @@
"modes": {
"type": "array",
"items": {
"type": "object",
"type": "object",
"properties": {
"name": {"type": "string"},
"options": {
Expand Down Expand Up @@ -350,13 +350,13 @@
"general/check_search_recursive": "true",
"general/target_systems": ["*"],
"perf_logging/target_systems": ["*"],
"logging/handlers/level": "DEBUG",
"logging/handlers/level": "debug",
"logging/handlers/file/append": false,
"logging/handlers/file/timestamp": false,
"logging/handlers/stream/name": "stdout",
"logging/handlers/syslog/socktype": "udp",
"logging/handlers/syslog/facility": "user",
"logging/level": "INFO",
"logging/level": "info",
"logging/target_systems": ["*"],
"modes/target_systems": ["*"],
"schedulers/job_submit_timeout": 60,
Expand Down
2 changes: 1 addition & 1 deletion schemas/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
},
{
'name': 'sys0',
'descr': 'System for testing check dependencies',
'descr': 'System for checking test dependencies',
'hostnames': [r'sys\d+'],
'partitions': [
{
Expand Down
32 changes: 32 additions & 0 deletions tools/convert_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2016-2020 Swiss National Supercomputing Centre (CSCS/ETH Zurich)
# ReFrame Project Developers. See the top-level LICENSE file for details.
#
# SPDX-License-Identifier: BSD-3-Clause

import os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

import reframe.core.config as config # noqa: F401, F403


if __name__ == '__main__':
try:
old_config = sys.argv[1]
except IndexError:
print(f'{sys.argv[0]}: too few arguments', file=sys.stderr)
print(f'Usage: {sys.argv[0]} OLD_CONFIG_FILE', file=sys.stderr)
sys.exit(1)

try:
new_config = config.convert_old_config(old_config)
except Exception as e:
print(f'{sys.argv[0]}: could not convert file: {e}',
file=sys.stderr)
sys.exit(1)

print(
f"Conversion successful! "
f"Please find the converted file at '{new_config}'."
)
2 changes: 1 addition & 1 deletion unittests/resources/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ReframeSettings:
},
'sys0': {
# System used for dependency checking
'descr': 'System for test dependencies unit tests',
'descr': 'System for checking test dependencies',
'hostnames': [r'sys\d+'],
'partitions': {
'p0': {
Expand Down
Loading