diff --git a/README.md b/README.md index daf043361..6abf13b1d 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,6 @@ on that machine (and some info about the file): remote_unix.goto_state(state="UNIX_REMOTE") # make it go to remote shell ls_cmd = remote_unix.get_cmd(cmd_name="ls", cmd_params={"options": "-l"}) - ls_cmd.connection.newline = '\r\n' # tweak since rebex remote console uses such one remote_files = ls_cmd() @@ -134,7 +133,6 @@ ping_cmd = my_unix.get_cmd(cmd_name="ping", cmd_params={"destination": host, "op remote_unix = DeviceFactory.get_device(name='RebexTestMachine') remote_unix.goto_state(state="UNIX_REMOTE") ls_cmd = remote_unix.get_cmd(cmd_name="ls", cmd_params={"options": "-l"}) -ls_cmd.connection.newline = '\r\n' # tweak since rebex remote console uses such one print("Start pinging {} ...".format(host)) ping_cmd.start() # run command in background @@ -318,6 +316,11 @@ Please note also that connection is context manager doing open/close actions. ## Reuse freedom Library gives you freedom which part you want to reuse. We are fan's of "take what you need only". * You may use configuration files or configure things by Python calls. + + ```python + load_config(config={'DEVICES': {'MyMachine': {'DEVICE_CLASS': 'moler.device.unixremote.UnixLocal'}}}, + config_type='dict') + ``` * You may use devices or create commands manually * You can take connection or build it yourself: diff --git a/examples/command/my_devices.yml b/examples/command/my_devices.yml index a5478e1f6..740cc7caf 100755 --- a/examples/command/my_devices.yml +++ b/examples/command/my_devices.yml @@ -15,11 +15,6 @@ DEVICES: RebexTestMachine: DEVICE_CLASS: moler.device.unixremote.UnixRemote - STATE_PARAMS: # modify defaults - UNIX_LOCAL: - newline: \n # default (may be skipped) - UNIX_REMOTE: - newline: \r\n CONNECTION_HOPS: UNIX_LOCAL: # from state UNIX_REMOTE: # to state diff --git a/examples/command/unix_ls_on_device.py b/examples/command/unix_ls_on_device.py index 95956ed34..aa8b78c2c 100644 --- a/examples/command/unix_ls_on_device.py +++ b/examples/command/unix_ls_on_device.py @@ -1,13 +1,25 @@ from moler.config import load_config from moler.device.device import DeviceFactory -load_config(path='my_devices.yml') +# configure library directly from dict +load_config(config={'DEVICES': {'DEFAULT_CONNECTION': + {'CONNECTION_DESC': {'io_type': 'terminal', 'variant': 'threaded'}}, + 'RebexTestMachine': + {'DEVICE_CLASS': 'moler.device.unixremote.UnixRemote', + 'CONNECTION_HOPS': {'UNIX_LOCAL': + {'UNIX_REMOTE': + {'execute_command': 'ssh', + 'command_params': {'expected_prompt': 'demo@', + 'host': 'test.rebex.net', + 'login': 'demo', + 'password': 'password', + 'set_timeout': None}}}}}}}, + config_type='dict') remote_unix = DeviceFactory.get_device(name='RebexTestMachine') # it starts in local shell remote_unix.goto_state(state="UNIX_REMOTE") # make it go to remote shell ls_cmd = remote_unix.get_cmd(cmd_name="ls", cmd_params={"options": "-l"}) -ls_cmd.connection.newline = '\r\n' # tweak since rebex remote console uses such one remote_files = ls_cmd() diff --git a/examples/command/unix_ping_and_ls.py b/examples/command/unix_ping_and_ls.py index 4cd19733f..437c41a59 100644 --- a/examples/command/unix_ping_and_ls.py +++ b/examples/command/unix_ping_and_ls.py @@ -1,7 +1,7 @@ from moler.config import load_config from moler.device.device import DeviceFactory -load_config(path='my_devices.yml') +load_config(config='my_devices.yml') my_unix = DeviceFactory.get_device(name='MyMachine') host = 'www.google.com' @@ -10,7 +10,6 @@ remote_unix = DeviceFactory.get_device(name='RebexTestMachine') remote_unix.goto_state(state="UNIX_REMOTE") ls_cmd = remote_unix.get_cmd(cmd_name="ls", cmd_params={"options": "-l"}) -ls_cmd.connection.newline = '\r\n' # tweak since rebex remote console uses such one print("Start pinging {} ...".format(host)) ping_cmd.start() # run command in background diff --git a/examples/command/unix_ps_on_device.py b/examples/command/unix_ps_on_device.py index 5367bd680..a36dd726a 100644 --- a/examples/command/unix_ps_on_device.py +++ b/examples/command/unix_ps_on_device.py @@ -1,7 +1,9 @@ from moler.config import load_config from moler.device.device import DeviceFactory -load_config(path='my_devices.yml') # description of available devices +load_config(config='my_devices.yml') # description of available devices +# load_config(config={'DEVICES': {'MyMachine': {'DEVICE_CLASS': 'moler.device.unixremote.UnixLocal'}}}, +# config_type='dict') my_unix = DeviceFactory.get_device(name='MyMachine') # take specific device out of available ones ps_cmd = my_unix.get_cmd(cmd_name="ps", # take command of that device cmd_params={"options": "-ef"}) diff --git a/examples/layer_3/network_down_detectors_on_named_conn_v1.py b/examples/layer_3/network_down_detectors_on_named_conn_v1.py index ad7d0d806..d727cf985 100644 --- a/examples/layer_3/network_down_detectors_on_named_conn_v1.py +++ b/examples/layer_3/network_down_detectors_on_named_conn_v1.py @@ -226,7 +226,7 @@ def ping_observing_task(ext_io_connection, ping_ip): # ------------------------------------------------------------------- # Configure moler connections (backend code) # 1) select variant of TCP - load_config(path=os.path.join(os.path.dirname(__file__), "connection_variant.yml")) + load_config(config=os.path.join(os.path.dirname(__file__), "connection_variant.yml")) # 2) ver.1 - configure named connections by python code conn_cfg.define_connection(name='net_1', io_type='tcp', host='localhost', port=5671) diff --git a/examples/layer_3/network_down_detectors_on_named_conn_v2.py b/examples/layer_3/network_down_detectors_on_named_conn_v2.py index 5995de06d..dadaa0fc1 100644 --- a/examples/layer_3/network_down_detectors_on_named_conn_v2.py +++ b/examples/layer_3/network_down_detectors_on_named_conn_v2.py @@ -226,7 +226,7 @@ def ping_observing_task(ext_io_connection, ping_ip): # Configure moler connections (backend code) # 1) configure variant by YAML config file # 2) ver.2 - configure named connections by YAML config file - load_config(path=os.path.join(os.path.dirname(__file__), "named_connections.yml")) + load_config(config=os.path.join(os.path.dirname(__file__), "named_connections.yml")) # 3) take default class used to realize tcp-threaded-connection # ------------------------------------------------------------------- diff --git a/examples/layer_3/network_down_detectors_on_tcp_conn_v3.py b/examples/layer_3/network_down_detectors_on_tcp_conn_v3.py index 0fae7baf4..f038dc17e 100644 --- a/examples/layer_3/network_down_detectors_on_tcp_conn_v3.py +++ b/examples/layer_3/network_down_detectors_on_tcp_conn_v3.py @@ -225,7 +225,7 @@ def ping_observing_task(ext_io_connection, ping_ip): # ------------------------------------------------------------------- # Configure moler connections (backend code) # ver.3 - configure by YAML config file - load_config(path=os.path.join(os.path.dirname(__file__), "connections_new_variant.yml")) + load_config(config=os.path.join(os.path.dirname(__file__), "connections_new_variant.yml")) # configure class used to realize tcp-threaded-connection # (default one tcp.ThreadedTcp has no logger) diff --git a/moler/config/__init__.py b/moler/config/__init__.py index da14c546a..7951b106f 100644 --- a/moler/config/__init__.py +++ b/moler/config/__init__.py @@ -9,6 +9,7 @@ __email__ = 'grzegorz.latuszek@nokia.com, marcin.usielski@nokia.com, michal.ernst@nokia.com' import yaml +import six from contextlib import contextmanager from . import connections as conn_cfg @@ -40,23 +41,29 @@ def read_yaml_configfile(path): return yaml.load(content) -def load_config(path=None, from_env_var=None, config_type='yaml'): +def load_config(config=None, from_env_var=None, config_type='yaml'): """ Load Moler's configuration from config file - :param path: config filename directly provided (overwrites 'from_env_var' if both given) + :param config: either dict or config filename directly provided (overwrites 'from_env_var' if both given) :param from_env_var: name of environment variable storing config filename - :param config_type: 'yaml' (the only one supported now) + :param config_type: 'dict' ('config' param is dict) or 'yaml' ('config' is filename of file with YAML content) :return: None """ - if (not path) and (not from_env_var): - raise AssertionError("Provide either 'path' or 'from_env_var' parameter (none given)") - if (not path): + assert (config_type == 'dict') or (config_type == 'yaml') # no other format supported yet + if not config: + if not from_env_var: + raise AssertionError("Provide either 'config' or 'from_env_var' parameter (none given)") if from_env_var not in os.environ: raise KeyError("Environment variable '{}' is not set".format(from_env_var)) path = os.environ[from_env_var] - assert config_type == 'yaml' # no other format supported yet - config = read_yaml_configfile(path) + config = read_yaml_configfile(path) + elif config_type == 'yaml': + assert isinstance(config, six.string_types) + path = config + config = read_yaml_configfile(path) + elif config_type == 'dict': + assert isinstance(config, dict) # TODO: check schema load_logger_from_config(config) load_connection_from_config(config) diff --git a/setup.py b/setup.py index acfcd2e2b..90925da4d 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='moler', # Required - version='0.5.1', # Required + version='0.5.2', # Required description='Moler is library to help in building automated tests', # Required long_description=long_description, # Optional long_description_content_type='text/markdown', # Optional (see note above) diff --git a/test/test_connection_configuration.py b/test/test_connection_configuration.py index 6a593ce08..c2650b13b 100644 --- a/test/test_connection_configuration.py +++ b/test/test_connection_configuration.py @@ -98,7 +98,7 @@ def test_can_select_connection_loaded_from_config_file(moler_config): from moler.connection import get_connection conn_config = os.path.join(os.path.dirname(__file__), "resources", "www_servers_connections.yml") - moler_config.load_config(path=conn_config, config_type='yaml') + moler_config.load_config(config=conn_config, config_type='yaml') conn = get_connection(name='www_server_1') assert conn.__module__ == 'moler.io.raw.tcp' @@ -121,6 +121,22 @@ def test_can_select_connection_loaded_from_env_variable(moler_config, monkeypatc assert conn.port == 2345 +def test_can_select_connection_loaded_from_dict(moler_config): + from moler.connection import get_connection + + configuration_in_dict = {'NAMED_CONNECTIONS': + {'www_server_1': {'io_type': 'tcp', 'host': 'localhost', 'port': 2344}}, + 'IO_TYPES': + {'default_variant': {'tcp': 'threaded'}}} + moler_config.load_config(config=configuration_in_dict, config_type='dict') + + conn = get_connection(name='www_server_1') + assert conn.__module__ == 'moler.io.raw.tcp' + assert conn.__class__.__name__ == 'ThreadedTcp' + assert conn.host == 'localhost' + assert conn.port == 2344 + + def test_load_config_checks_env_variable_existence(moler_config): with pytest.raises(KeyError) as err: moler_config.load_config(from_env_var="MOLER_CONFIG", config_type='yaml') diff --git a/test/test_device_configuration.py b/test/test_device_configuration.py index 27bde7f33..da7fe018c 100644 --- a/test/test_device_configuration.py +++ b/test/test_device_configuration.py @@ -111,7 +111,7 @@ def test_cannot_select_device_by_nonexisting_name(device_factory): def test_can_select_device_loaded_from_config_file(moler_config, device_factory): conn_config = os.path.join(os.path.dirname(__file__), "resources", "device_config.yml") - moler_config.load_config(path=conn_config, config_type='yaml') + moler_config.load_config(config=conn_config, config_type='yaml') device = device_factory.get_device(name='UNIX') @@ -121,7 +121,7 @@ def test_can_select_device_loaded_from_config_file(moler_config, device_factory) def test_can_select_all_devices_loaded_from_config_file(moler_config, device_factory): conn_config = os.path.join(os.path.dirname(__file__), "resources", "device_config.yml") - moler_config.load_config(path=conn_config, config_type='yaml') + moler_config.load_config(config=conn_config, config_type='yaml') device_factory.create_all_devices() @@ -151,7 +151,7 @@ def test_load_config_checks_env_variable_existence(moler_config): def test_return_created_device_when_call_another_time_for_same_named_device(moler_config, device_factory): conn_config = os.path.join(os.path.dirname(__file__), "resources", "device_config.yml") - moler_config.load_config(path=conn_config, config_type='yaml') + moler_config.load_config(config=conn_config, config_type='yaml') device = device_factory.get_device(name='UNIX') same_device = device_factory.get_device(name='UNIX') @@ -197,7 +197,7 @@ def test_cannot_load_config_from_when_path_or_from_env_var_not_provide(moler_con with pytest.raises(AssertionError) as err: moler_config.load_config() - assert "Provide either 'path' or 'from_env_var' parameter (none given)" in str(err.value) + assert "Provide either 'config' or 'from_env_var' parameter (none given)" in str(err.value) # --------------------------- resources ---------------------------