Example #1
0
def test_get_connection_without_variant_selection_raises_KeyError():
    from moler.connection_factory import get_connection

    with pytest.raises(KeyError) as err:
        get_connection(io_type='tcp', host='localhost', port=2345)
    assert "No variant selected (directly or via configuration) for 'tcp' connection" in str(
        err.value)
Example #2
0
def test_get_connection_may_not_use_both__name_and_io_type():
    from moler.connection_factory import get_connection

    with pytest.raises(AssertionError) as err:
        get_connection(name='www_server_1',
                       io_type='tcp', host='localhost', port=2345)
    assert "Use either 'name' or 'io_type' parameter (not both)" in str(err.value)
Example #3
0
def test_get_connection_must_use_either_name_or_io_type():
    from moler.connection_factory import get_connection

    with pytest.raises(AssertionError) as err:
        get_connection(host='localhost', port=2345)
    assert "Provide either 'name' or 'io_type' parameter (none given)" in str(
        err.value)
Example #4
0
def test_cannot_select_nonexisting_connection_variant(connections_config):
    """Non-existing means not registered inside ConnectionFactory"""
    from moler.connection_factory import get_connection

    connections_config.set_default_variant(io_type='tcp', variant='yedi_magic')
    with pytest.raises(KeyError) as err:
        get_connection(io_type='tcp', host='localhost', port=2345)
    assert "'yedi_magic' variant of 'tcp' connection is not registered inside ConnectionFactory" in str(err.value)
Example #5
0
def test_cannot_select_connection_by_nonexisting_name(connections_config):
    """Non-existing means here not defined inside configuration"""
    from moler.connection_factory import get_connection

    connections_config.set_default_variant(io_type='tcp', variant='threaded')
    with pytest.raises(KeyError) as err:
        get_connection(name='www_server_1')
    assert "Connection named 'www_server_1' was not defined inside configuration" in str(err.value)
Example #6
0
def test_connection_factory_can_build_sshshell_based_on_other_sshshell_for_sshtransport_reuse():
    from moler.connection_factory import get_connection

    conn1 = get_connection(io_type='sshshell', host='localhost', port=2222, username="******", password="******")
    conn2 = get_connection(io_type='sshshell', reuse_ssh_of_shell=conn1)
    assert conn2.sshshell.host == "localhost"
    assert conn2.sshshell.port == 2222
    assert conn2.sshshell.username == "moler"
    assert conn2.sshshell.password == "moler_passwd"
def test_factory_has_buildin_constructors_active_by_default():
    from moler.connection_factory import get_connection

    conn = get_connection(io_type='memory', variant='threaded')
    assert conn.__module__ == 'moler.io.raw.memory'
    assert conn.__class__.__name__ == 'ThreadedFifoBuffer'

    conn = get_connection(io_type='tcp', variant='threaded', host='localhost', port=2345)
    assert conn.__module__ == 'moler.io.raw.tcp'
    assert conn.__class__.__name__ == 'ThreadedTcp'
Example #8
0
def test_correct_call_of_sshshell_construction_based_on_existing_sshshell_connection():
    from moler.connection_factory import get_connection
    from moler.exceptions import MolerException

    existing_conn = get_connection(io_type='sshshell', variant='threaded',
                          host='localhost', port=2345, login='******', password='******')
    with pytest.raises(MolerException) as err:
        get_connection(io_type='sshshell', variant='threaded',
                       reuse_ssh_of_shell=existing_conn,
                       port=2345, login='******', password='******')
    assert "Don't use host/port/username/login/password when building sshshell reusing ssh of other sshshell" in str(err.value)
    conn_reusing_ssh_transport = get_connection(io_type='sshshell', variant='threaded',
                                                reuse_ssh_of_shell=existing_conn)
    assert conn_reusing_ssh_transport.__class__.__name__ == 'ThreadedSshShell'
Example #9
0
def test_can_select_connection_variant_from_buildin_connections(connections_config):
    from moler.connection_factory import get_connection

    connections_config.set_default_variant(io_type='tcp', variant='threaded')
    conn = get_connection(io_type='tcp', host='localhost', port=2345)
    assert conn.__module__ == 'moler.io.raw.tcp'
    assert conn.__class__.__name__ == 'ThreadedTcp'
def test_can_get_connection():
    from moler.connection_factory import get_connection
    tcp_connection = get_connection(io_type='tcp',
                                    variant='asyncio-in-thread',
                                    host='localhost',
                                    port=2345)
    assert tcp_connection is not None
async def main(connections2observe4ip):
    logger = logging.getLogger('asyncio.main')
    logger.debug('starting jobs observing connections')
    # Starting the clients
    jobs_on_connections = []
    for _, connection_name, ping_ip in connections2observe4ip:
        # ------------------------------------------------------------------
        # This front-end code hides all details of connection.
        # We just use its name - such name should be meaningful for user.
        # like: "main_dns_server", "backup_ntp_server", ...
        # Another words, all we want here is stg like:
        # "give me connection to main_dns_server"
        # ------------------------------------------------------------------
        con_logger = logging.getLogger(
            'tcp-async-io.{}'.format(connection_name))
        tcp_connection = get_connection(name=connection_name,
                                        variant='asyncio',
                                        logger=con_logger)

        # client_task= asyncio.ensure_future(ping_observing_task(tcp_connection, ping_ip))
        jobs_on_connections.append(ping_observing_task(tcp_connection,
                                                       ping_ip))
    # await observers job to be done
    completed, pending = await asyncio.wait(jobs_on_connections)
    logger.debug('all jobs observing connections are done')
Example #12
0
def test_connection_factory_can_use_alternate_login_param_of_sshshell():
    from moler.connection_factory import get_connection

    conn = get_connection(io_type='sshshell',
                          host='localhost', port=2222, login="******", password="******")
    assert conn.__module__ == 'moler.io.raw.sshshell'
    assert conn.__class__.__name__ == 'ThreadedSshShell'
Example #13
0
def main(connections2observe4ip):
    logger = logging.getLogger('asyncio.main')
    logger.debug('starting jobs observing connections')
    # Starting the clients
    jobs_on_connections = []
    for connection_name, ping_ip in connections2observe4ip:
        # ------------------------------------------------------------------
        # This front-end code hides all details of connection.
        # We just use its name - such name should be meaningful for user.
        # like: "main_dns_server", "backup_ntp_server", ...
        # Another words, all we want here is stg like:
        # "give me connection to main_dns_server"
        # ------------------------------------------------------------------
        # con_logger = logging.getLogger('tcp-async_in_thrd-io.{}'.format(connection_name))
        # tcp_connection = get_connection(name=connection_name, variant='asyncio-in-thread', logger=con_logger)
        tcp_connection = get_connection(name=connection_name,
                                        variant='asyncio-in-thread')
        client_thread = threading.Thread(target=ping_observing_task,
                                         args=(tcp_connection, ping_ip))
        client_thread.start()
        jobs_on_connections.append(client_thread)
    # await observers job to be done
    for client_thread in jobs_on_connections:
        client_thread.join()
    logger.debug('all jobs observing connections are done')
Example #14
0
def test_connection_factory_has_threaded_registered_as_default_variant_of_sshshell():
    from moler.connection_factory import get_connection

    conn = get_connection(io_type='sshshell',
                          host='localhost', port=2222, username="******", password="******")
    assert conn.__module__ == 'moler.io.raw.sshshell'
    assert conn.__class__.__name__ == 'ThreadedSshShell'
Example #15
0
def test_returned_connections_have_moler_integrated_connection(builtin_variant,
                                                               builtin_io_type_example):
    from moler.connection_factory import get_connection

    io_type, kwargs = builtin_io_type_example
    conn = get_connection(io_type=io_type, variant=builtin_variant, **kwargs)
    assert hasattr(conn, 'moler_connection')
    assert conn.moler_connection.how2send != conn.moler_connection._unknown_send
Example #16
0
def test_can_select_connection_loaded_from_dict_as_positional_args(moler_config, args):
    from moler.connection_factory import get_connection

    moler_config.load_config(*args)

    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
Example #17
0
def test_can_select_connection_loaded_from_config_file(moler_config):
    from moler.connection_factory import get_connection

    conn_config = os.path.join(os.path.dirname(__file__), "resources", "www_servers_connections.yml")
    moler_config.load_config(config=conn_config, config_type='yaml')

    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 == 2345
Example #18
0
def test_connection_factory_has_sshshell_constructor_active_by_default():
    from moler.connection_factory import get_connection

    conn = get_connection(io_type='sshshell', variant='threaded',
                          host='localhost', port=2222, username="******", password="******")
    assert conn.__module__ == 'moler.io.raw.sshshell'
    assert conn.__class__.__name__ == 'ThreadedSshShell'
    assert hasattr(conn, 'moler_connection')
    assert conn.sshshell.host == "localhost"
    assert conn.sshshell.port == 2222
    assert conn.sshshell.username == "moler"
    assert conn.sshshell.password == "moler_passwd"
Example #19
0
def test_can_select_connection_loaded_from_env_variable(moler_config, monkeypatch, params):
    from moler.connection_factory import get_connection

    conn_config = os.path.join(os.path.dirname(__file__), "resources", "www_servers_connections.yml")
    monkeypatch.setitem(os.environ, 'MOLER_CONFIG', conn_config)
    moler_config.load_config(**params)

    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 == 2345
Example #20
0
def test_can_select_connection_by_name(connections_config):
    from moler.connection_factory import get_connection

    connections_config.define_connection(name="www_server_1",
                                         io_type='tcp',
                                         host='localhost', port=2345)
    connections_config.set_default_variant(io_type='tcp', variant='threaded')
    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 == 2345
Example #21
0
def test_can_select_connection_variant_from_plugin_connections(builtin_connection_factories,
                                                               connections_config):
    from moler.connection_factory import ConnectionFactory, get_connection

    class DummyTcpConnection(object):
        def __init__(self, host, port):
            pass

    ConnectionFactory.register_construction(io_type='tcp', variant='dummy',
                                            constructor=DummyTcpConnection)
    connections_config.set_default_variant(io_type='tcp', variant='dummy')
    conn = get_connection(io_type='tcp', host='localhost', port=2345)
    assert conn.__class__.__name__ == 'DummyTcpConnection'
Example #22
0
def test_can_plugin_alternative_connection_instead_of_builtin_one(builtin_connection_factories):
    from moler.connection_factory import ConnectionFactory, get_connection
    from moler.threaded_moler_connection import ThreadedMolerConnection

    class DummyTcpConnection(object):
        def __init__(self, host, port):
            self.moler_connection = ThreadedMolerConnection(how2send=self.send)

        def send(self, data):
            pass

    ConnectionFactory.register_construction(io_type='tcp', variant='threaded',
                                            constructor=DummyTcpConnection)
    conn = get_connection(io_type='tcp', variant='threaded',
                          host='localhost', port=2345)
    assert conn.__class__.__name__ == 'DummyTcpConnection'
def main(connections2observe4ip):
    # Starting the clients
    connections = []
    for address, ping_ip in connections2observe4ip:
        host, port = address
        # ------------------------------------------------------------------
        # This front-end code hides parallelism variant
        # used to read data from connection.
        # We don't care if it is TCP connection based on threads or asyncio.
        # All we want here is "any TCP connection towards given host/port".
        # "any" means here: TCP variant as configured on backend.
        # ------------------------------------------------------------------
        tcp_connection = get_connection(io_type='tcp', host=host, port=port)
        client_thread = threading.Thread(target=ping_observing_task,
                                         args=(tcp_connection, ping_ip))
        client_thread.start()
        connections.append(client_thread)
    # await observers job to be done
    for client_thread in connections:
        client_thread.join()
Example #24
0
def main(connections2observe4ip):
    # Starting the clients
    connections = []
    for _, connection_name, ping_ip in connections2observe4ip:
        # ------------------------------------------------------------------
        # This front-end code hides all details of connection.
        # We just use its name - such name should be meaningful for user.
        # like: "main_dns_server", "backup_ntp_server", ...
        # Another words, all we want here is stg like:
        # "give me connection to main_dns_server"
        # ------------------------------------------------------------------
        tcp_connection = get_connection(name=connection_name)
        tcp_connection.moler_connection.name = connection_name
        client_thread = threading.Thread(target=ping_observing_task,
                                         args=(tcp_connection, ping_ip))
        client_thread.start()
        connections.append(client_thread)
    # await observers job to be done
    for client_thread in connections:
        client_thread.join()
Example #25
0
def test_can_select_connection_loaded_from_dict(moler_config):
    from moler.connection_factory 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
Example #26
0
    def __init__(self, sm_params=None, name=None, io_connection=None, io_type=None, variant=None,
                 io_constructor_kwargs=None, initial_state=None, lazy_cmds_events=False):
        """
        Create Device communicating over io_connection
        CAUTION: Device owns (takes over ownership) of connection. It will be open when device "is born" and close when
        device "dies".

        :param sm_params: dict with parameters of state machine for device
        :param name: name of device
        :param io_connection: External-IO connection having embedded moler-connection
        :param io_type: type of connection - tcp, udp, ssh, telnet, ...
        :param variant: connection implementation variant, ex. 'threaded', 'twisted', 'asyncio', ...
                        (if not given then default one is taken)
        :param io_constructor_kwargs: additional parameter into constructor of selected connection type
                        (if not given then default one is taken)
        :param initial_state: name of initial state. State machine tries to enter this state just after creation.
        :param lazy_cmds_events: set False to load all commands and events when device is initialized, set True to load
                        commands and events when they are required for the first time.
        """
        super(TextualDevice, self).__init__()
        if io_constructor_kwargs is None:
            io_constructor_kwargs = dict()
        sm_params = copy_dict(sm_params, deep_copy=True)
        io_constructor_kwargs = copy_dict(io_constructor_kwargs, deep_copy=True)
        self.initial_state = initial_state if initial_state is not None else "NOT_CONNECTED"
        self.states = [TextualDevice.not_connected]
        self.goto_states_triggers = []
        self._name = name
        self.device_data_logger = None
        self.timeout_keep_state = 10  # Timeout for background goto state after unexpected state change.
        self.lazy_cmds_events = lazy_cmds_events  # Set True to lazy load commands and events.

        # Below line will modify self extending it with methods and attributes od StateMachine
        # For eg. it will add attribute self.state
        self.SM = StateMachine(model=self, states=self.states, initial=TextualDevice.not_connected,
                               auto_transitions=False,
                               queued=True)

        self._state_hops = dict()
        self._state_prompts = dict()
        self._state_prompts_lock = threading.Lock()
        self._reverse_state_prompts_dict = dict()
        self._prompts_event = None
        self._kept_state = None
        self._configurations = dict()
        self._newline_chars = dict()  # key is state, value is chars to send as newline
        if io_connection:
            self.io_connection = io_connection
        else:
            self.io_connection = get_connection(io_type=io_type, variant=variant, **io_constructor_kwargs)

        self.io_connection.name = self.name
        self.io_connection.moler_connection.name = self.name
        self.logger = logging.getLogger('moler.connection.{}'.format(self.name))
        self.configure_logger(name=self.name, propagate=False)

        self._prepare_transitions()
        self._prepare_state_hops()
        self._configure_state_machine(sm_params)
        self._prepare_newline_chars()

        # TODO: Need test to ensure above sentence for all connection
        self.io_connection.notify(callback=self.on_connection_made, when="connection_made")
        self.io_connection.notify(callback=self.on_connection_lost, when="connection_lost")

        self._cmdnames_available_in_state = dict()
        self._eventnames_available_in_state = dict()
        self._default_prompt = re.compile(r'^[^<]*[\$|%|#|>|~]\s*$')
        self._neighbour_devices = None
        self._established = False
        msg = "Created device '{}' as instance of class '{}.{}'.".format(
            self.name,
            self.__class__.__module__,
            self.__class__.__name__,
        )
        self._log(level=logging.DEBUG, msg=msg)
        self._public_name = None
        self._warning_was_sent = False
        self._goto_state_lock = threading.Lock()
        self._goto_state_thread_manipulation_lock = threading.Lock()
        self._queue_states = queue.Queue()
        self._thread_for_goto_state = None
        self.SM.state_change_log_callable = self._log
        self.SM.current_state_callable = self._get_current_state
Example #27
0
 def from_named_connection(cls, connection_name):
     io_conn = get_connection(name=connection_name)
     return cls(io_connection=io_conn)
Example #28
0
import time
from moler.cmd.unix.ping import Ping
from moler.connection_factory import get_connection

host = 'www.google.com'
terminal = get_connection(io_type='terminal', variant='threaded')
with terminal.open():
    ping_cmd = Ping(connection=terminal.moler_connection,
                    destination=host,
                    options="-w 6")
    print("Start pinging {} ...".format(host))
    ping_cmd.start()
    print("Doing other stuff while pinging {} ...".format(host))
    time.sleep(3)
    ping_stats = ping_cmd.await_done(timeout=4)
    print("ping {}: {}={}, {}={} [{}]".format(host, 'packet_loss',
                                              ping_stats['packet_loss'],
                                              'time_avg',
                                              ping_stats['time_avg'],
                                              ping_stats['time_unit']))
# result:
"""
Start pinging www.google.com ...
Doing other stuff while pinging www.google.com ...
ping www.google.com: packet_loss=0, time_avg=50.000 [ms]
"""
Example #29
0
def test_user_is_informed_about_terminal_io_unavailable_on_windows():
    from moler.connection_factory import get_connection
    with mock.patch("moler.connection_factory.platform.system", return_value='Windows'):
        with pytest.raises(AttributeError) as err:
            get_connection(io_type='terminal', variant='threaded')
    assert "No 'terminal' connection available on Windows (try using 'sshshell' connection instead)" in str(err.value)