From: Ondrej Lichtner olichtne@redhat.com
nettestctl now reads the default.conf file. I postponed adding other config files for later when we have agreed on which ones we really want. As we agreed, the loaded configs will be distributed as function parameters, therefore I made the necessary changes to functions process_recipe and get_recipe_result.
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- Common/Config.py | 5 ----- nettestctl.py | 20 +++++++++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/Common/Config.py b/Common/Config.py index 8a1ad56..8ef2452 100644 --- a/Common/Config.py +++ b/Common/Config.py @@ -24,12 +24,7 @@ class Config():
def __init__(self): self._parser = ConfigParser(dict_type=dict) - - # defaults.conf should contain all possible sections and options - # sections and options not listed there will be undefined which - # can cause problems self.options = dict() - self.load_config("default.conf")
def get_config(self): return self.options diff --git a/nettestctl.py b/nettestctl.py index de07911..21fdefc 100755 --- a/nettestctl.py +++ b/nettestctl.py @@ -21,6 +21,7 @@ from NetTest.NetTestResultSerializer import NetTestResultSerializer from Common.Logs import Logs from Common.LoggingServer import LoggingServer import Common.ProcessManager +from Common.Config import Config
def usage(): """ @@ -45,7 +46,7 @@ def usage(): sys.exit()
def process_recipe(action, file_path, remoteexec, cleanup, - res_serializer, packet_capture): + res_serializer, packet_capture, config): nettestctl = NetTestController(os.path.realpath(file_path), remoteexec=remoteexec, cleanup=cleanup, res_serializer=res_serializer) @@ -70,14 +71,14 @@ def print_summary(summary): logging.info("=====================================================")
def get_recipe_result(args, file_path, remoteexec, cleanup, - res_serializer, packet_capture): + res_serializer, packet_capture, config): res_serializer.add_recipe(file_path) Logs.set_logging_root_path(file_path) loggingServer = LoggingServer(LoggingServer.DEFAULT_PORT, Logs.root_path, Logs.debug) loggingServer.start() res = process_recipe(args, file_path, remoteexec, cleanup, - res_serializer, packet_capture) + res_serializer, packet_capture, config) loggingServer.stop() return ((file_path, res))
@@ -97,6 +98,13 @@ def main(): usage() sys.exit()
+ # defaults.conf should contain all possible sections and options + # sections and options not listed there will be undefined which + # can cause problems + config = Config() + default_cfg = os.path.join(os.path.dirname(sys.argv[0]), 'default.conf') + config.load_config(default_cfg) + debug = 0 recipe_path = None remoteexec = False @@ -144,12 +152,14 @@ def main(): summary.append(get_recipe_result(action, recipe_file, remoteexec, cleanup, res_serializer, - packet_capture)) + packet_capture, + config)) Logs.set_logging_root_path(clean=False) else: summary.append(get_recipe_result(action, recipe_path, remoteexec, cleanup, res_serializer, - packet_capture)) + packet_capture, + config))
Logs.set_logging_root_path(clean=False)
From: Ondrej Lichtner olichtne@redhat.com
I made a small mistake in verification of mac range. This commit fixes that.
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- Common/Config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Common/Config.py b/Common/Config.py index 8ef2452..85b6794 100644 --- a/Common/Config.py +++ b/Common/Config.py @@ -104,7 +104,10 @@ class Config(): msg = "Option mac_pool_range expects 2"\ " values sepparated by whitespaces." raise ConfigError(msg) - if not verify_mac_address(option): + if not verify_mac_address(vals[0]): + msg = "Invalid MAC address: %s" % option + raise ConfigError(msg) + if not verify_mac_address(vals[1]): msg = "Invalid MAC address: %s" % option raise ConfigError(msg) return vals
From: Ondrej Lichtner olichtne@redhat.com
Logs are now saved to location specified in the config files by option 'path' in section 'log'. The port on which the logging server is listening on can now be changed by option 'port' in the same section.
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- Common/Logs.py | 7 +++++-- NetTest/NetTestController.py | 5 +++-- nettestctl.py | 7 ++++--- 3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/Common/Logs.py b/Common/Logs.py index 0772f1f..11ff638 100644 --- a/Common/Logs.py +++ b/Common/Logs.py @@ -187,7 +187,7 @@ class Logs: @classmethod def __init__(cls,debug=0, waitForNet=False, logger=logging.getLogger(), recipe_path=None, log_root="Logs", to_display=True, date=None, - nameExtend=None): + nameExtend=None, log_folder=None): logging.addLevelName(5, "DEBUG2") logging.DEBUG2 = 5 if nameExtend is None: @@ -200,7 +200,10 @@ class Logs: ':%(lineno)4.4d| %(levelname)s: ' '%(message)s', '%d/%m %H:%M:%S', " "*4) cls.log_root = log_root - cls.logFolder = os.path.dirname(sys.argv[0]) + if log_folder != None: + cls.logFolder = os.path.expanduser(log_folder) + else: + cls.logFolder = os.path.dirname(sys.argv[0]) cls.logger = logger cls.debug = debug if date is None: diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index b028e35..4269fb2 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -38,11 +38,12 @@ def ignore_event(**kwarg):
class NetTestController: def __init__(self, recipe_path, remoteexec=False, cleanup=False, - res_serializer=None): + res_serializer=None, config=None): self._remoteexec = remoteexec self._docleanup = cleanup self._res_serializer = res_serializer self._remote_capture_files = {} + self._config = config
self._machine_pool = MachinePool([])
@@ -259,7 +260,7 @@ class NetTestController: logging.info("Setting logging server on machine %s", hostname) rpc = self._get_machinerpc(machine_id) ip_addr = get_corespond_local_ip(hostname) - rpc.set_logging(ip_addr, LoggingServer.DEFAULT_PORT) + rpc.set_logging(ip_addr, self._config.get_option('log', 'port'))
def _deconfigure_slaves(self): for machine_id in self._recipe["machines"]: diff --git a/nettestctl.py b/nettestctl.py index 21fdefc..831a07d 100755 --- a/nettestctl.py +++ b/nettestctl.py @@ -49,7 +49,8 @@ def process_recipe(action, file_path, remoteexec, cleanup, res_serializer, packet_capture, config): nettestctl = NetTestController(os.path.realpath(file_path), remoteexec=remoteexec, cleanup=cleanup, - res_serializer=res_serializer) + res_serializer=res_serializer, + config=config) if action == "run": return nettestctl.run_recipe(packet_capture) elif action == "dump": @@ -74,7 +75,7 @@ def get_recipe_result(args, file_path, remoteexec, cleanup, res_serializer, packet_capture, config): res_serializer.add_recipe(file_path) Logs.set_logging_root_path(file_path) - loggingServer = LoggingServer(LoggingServer.DEFAULT_PORT, + loggingServer = LoggingServer(config.get_option('log', 'port'), Logs.root_path, Logs.debug) loggingServer.start() res = process_recipe(args, file_path, remoteexec, cleanup, @@ -126,7 +127,7 @@ def main(): packet_capture = True
- Logs(debug) + Logs(debug, log_folder=config.get_option('log', 'path'))
if not args: logging.error("No action command passed")
From: Ondrej Lichtner olichtne@redhat.com
Ranges of mac pool are now defined in config files, by option 'mac_pool_range' in section 'environment'. Format of this option is mac_pool_range = <starting_mac_address> <ending_mac_address>
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- NetTest/NetTestController.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index 4269fb2..b516f3b 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -28,8 +28,6 @@ from Common.VirtUtils import VirtNetCtl, VirtDomainCtl, BridgeCtl from Common.Utils import wait_for from NetTest.MachinePool import MachinePool
-MAC_POOL_RANGE = {"start": "52:54:01:00:00:01", "end": "52:54:01:FF:FF:FF"} - class NetTestError(Exception): pass
@@ -51,8 +49,10 @@ class NetTestController: definitions = {"recipe": self._recipe}
self._recipe["networks"] = {} - self._mac_pool = MacPool(MAC_POOL_RANGE["start"], - MAC_POOL_RANGE["end"]) + + mac_pool_range = config.get_option('environment', 'mac_pool_range') + self._mac_pool = MacPool(mac_pool_range[0], + mac_pool_range[1])
ntparse = NetTestParse(recipe_path) ntparse.set_recipe(self._recipe)
From: Ondrej Lichtner olichtne@redhat.com
This patch adds support for option 'machine_pool_dirs' in section 'environment' of config files. This option is a list of directories separated by whitespace. Whitespaces in names need to be escaped with ''. Behaviour for this option is also a bit different, config files with higher priority don't overwrite the previous value but instead are added to the list.
This list is later passed to class MachinePool. Currently this class doesn't check for the existence of these directories. Nonexistent directories will cause a crash of the application so be sure to create them before trying to use them.
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- Common/Config.py | 10 ++++++++++ NetTest/NetTestController.py | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/Common/Config.py b/Common/Config.py index 85b6794..477b3f9 100644 --- a/Common/Config.py +++ b/Common/Config.py @@ -12,6 +12,7 @@ olichtne@redhat.com (Ondrej Lichtner)
import os import logging +import re from ConfigParser import ConfigParser from NetUtils import verify_ip_address, verify_mac_address
@@ -77,6 +78,8 @@ class Config(): section['mac_pool_range'] = self.optionMacRange(config[option]) elif option == 'rpcport': section['rpcport'] = self.optionPort(config[option]) + elif option == 'machine_pool_dirs': + section['pool_dirs'] = self.optionPoolDirs(config[option]) else: msg = "Unknown option: %s in section environment" % option raise ConfigError(msg) @@ -111,3 +114,10 @@ class Config(): msg = "Invalid MAC address: %s" % option raise ConfigError(msg) return vals + + def optionPoolDirs(self, option): + env = self.get_section('environment') + if 'pool_dirs' not in env: + env['pool_dirs'] = [] + opts = re.split(r'(?<!\)\s', option) + return env['pool_dirs'] + opts diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index b516f3b..1cd849c 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -43,7 +43,8 @@ class NetTestController: self._remote_capture_files = {} self._config = config
- self._machine_pool = MachinePool([]) + self._machine_pool = MachinePool(config.get_option('environment', + 'pool_dirs'))
self._recipe = {} definitions = {"recipe": self._recipe}
From: Ondrej Lichtner olichtne@redhat.com
In this patch I removed the support for option 'local_ip' ip section 'log' because this value is only used in one place as part of output string.
I also added proper initialization of the data structure that stores loaded configuration values. The parser is now a local object of the function load_config, previously it would cause problems by using old values when nonexistant files were to be parsed.
Finally I modified the way paths are handled- relative paths should be relative to the location of the config file they are specified in.
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- Common/Config.py | 63 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 30 deletions(-)
diff --git a/Common/Config.py b/Common/Config.py index 477b3f9..6874d49 100644 --- a/Common/Config.py +++ b/Common/Config.py @@ -21,12 +21,19 @@ class ConfigError(Exception):
class Config(): options = None - _parser = None
def __init__(self): - self._parser = ConfigParser(dict_type=dict) self.options = dict()
+ self.options['log'] = dict() + self.options['log']['port'] = None + self.options['log']['path'] = None + + self.options['environment'] = dict() + self.options['environment']['mac_pool_range'] = None + self.options['environment']['rpcport'] = None + self.options['environment']['pool_dirs'] = [] + def get_config(self): return self.options
@@ -38,38 +45,34 @@ class Config():
def load_config(self, path): '''Parse and load the config file''' - self._parser.read(path) + path = os.path.abspath(path) + parser = ConfigParser(dict_type=dict) + parser.read(path)
- sections = self._parser._sections + sections = parser._sections for section in sections: if section == "log": - self.sectionLogs(sections[section]) + self.sectionLogs(sections[section], path) elif section == "environment": - self.sectionEnvironment(sections[section]) + self.sectionEnvironment(sections[section], path) else: msg = "Unknown section: %s" % section raise ConfigError(msg)
- def sectionLogs(self, config): - if 'log' not in self.options: - self.options['log'] = dict() + def sectionLogs(self, config, cfg_path): section = self.options['log']
config.pop('__name__', None) for option in config: - if option == 'local_ip': - section['local_ip'] = self.optionLocalIP(config[option]) - elif option == 'port': + if option == 'port': section['port'] = self.optionPort(config[option]) elif option == 'path': - section['path'] = self.optionLogPath(config[option]) + section['path'] = self.optionLogPath(config[option], cfg_path) else: msg = "Unknown option: %s in section log" % option raise ConfigError(msg)
- def sectionEnvironment(self, config): - if 'environment' not in self.options: - self.options['environment'] = dict() + def sectionEnvironment(self, config, cfg_path): section = self.options['environment']
config.pop('__name__', None) @@ -79,17 +82,12 @@ class Config(): elif option == 'rpcport': section['rpcport'] = self.optionPort(config[option]) elif option == 'machine_pool_dirs': - section['pool_dirs'] = self.optionPoolDirs(config[option]) + section['pool_dirs'] = self.optionPoolDirs(config[option], + cfg_path) else: msg = "Unknown option: %s in section environment" % option raise ConfigError(msg)
- def optionLocalIP(self, option): - if not verify_ip_address(option): - msg = "Invalid IP address: %s" % option - raise ConfigError(msg) - return option - def optionPort(self, option): try: int(option) @@ -98,8 +96,8 @@ class Config(): raise ConfigError(msg) return int(option)
- def optionLogPath(self, option): - return option + def optionLogPath(self, option, cfg_path): + return os.path.join(os.path.dirname(cfg_path), option)
def optionMacRange(self, option): vals = option.split() @@ -115,9 +113,14 @@ class Config(): raise ConfigError(msg) return vals
- def optionPoolDirs(self, option): + def optionPoolDirs(self, option, cfg_path): env = self.get_section('environment') - if 'pool_dirs' not in env: - env['pool_dirs'] = [] - opts = re.split(r'(?<!\)\s', option) - return env['pool_dirs'] + opts + paths = re.split(r'(?<!\)\s', option) + + pool_dirs = env['pool_dirs'] + for path in paths: + if path == '': + continue + pool_dirs.append(os.path.join(os.path.dirname(cfg_path), path)) + + return pool_dirs
From: Ondrej Lichtner olichtne@redhat.com
This file contains the default configuration values used by lnst. This file is required as the rest of the program will not work without it.
Values set inside are values that have been used up to this point as global variables/constants so the functionality should not change.
The value of rpc port is not used yet because it is intended for slave machines and we are not sure of how we want to deal with them yet.
Signed-off-by: Ondrej Lichtner olichtne@redhat.com --- default.conf | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 default.conf
diff --git a/default.conf b/default.conf new file mode 100644 index 0000000..af64aa8 --- /dev/null +++ b/default.conf @@ -0,0 +1,7 @@ +[environment] +mac_pool_range = 52:54:01:00:00:01 52:54:01:FF:FF:FF +rpcport = 9999 +machine_pool_dirs = +[log] +path = ./ +port = 9998
lnst-developers@lists.fedorahosted.org