예제 #1
0
    def get_device(cls,
                   name=None,
                   device_class=None,
                   connection_desc=None,
                   connection_hops=None,
                   initial_state=None,
                   establish_connection=True):
        """
        Return connection instance of given io_type/variant.

        :param name: name of device defined in configuration.
        :param device_class: 'moler.device.unixlocal.UnixLocal', 'moler.device.unixremote.UnixRemote', ...
        :param connection_desc: 'io_type' and 'variant' of device connection.
        :param connection_hops: connection hops to create device SM.
        :param initial_state: initial state for device e.g. UNIX_REMOTE.
        :param establish_connection: True to open connection, False if it does not matter.
        :return: requested device.
        """
        if (not name) and (not device_class):
            raise WrongUsage(
                "Provide either 'name' or 'device_class' parameter (none given)"
            )
        if name and device_class:
            raise WrongUsage(
                "Use either 'name' or 'device_class' parameter (not both)")
        with cls._lock_device:
            dev = cls._get_device_without_lock(
                name=name,
                device_class=device_class,
                connection_desc=connection_desc,
                connection_hops=connection_hops,
                initial_state=initial_state,
                establish_connection=establish_connection)

        return dev
예제 #2
0
파일: __init__.py 프로젝트: nokia/moler
def load_config(config=None, from_env_var=None, *args, **kwargs):
    """
    Load Moler's configuration from config file.

    Load Moler's configuration from config file.
    :param config: either dict or config filename directly provided (overwrites 'from_env_var' if both given).
    :type config: dict or str
    :param from_env_var: name of environment variable storing config filename (file is in YAML format)
    :return: None
    """
    global loaded_config
    add_devices_only = False
    from moler.device import DeviceFactory

    if config is not None and isinstance(config, dict):
        config = copy_dict(config, deep_copy=True)

    if "NOT_LOADED_YET" in loaded_config:
        loaded_config = [config]
    elif not DeviceFactory.was_any_device_deleted() and configs_are_same(
            config_list=loaded_config, config_to_find=config):
        return
    else:
        # Config was already loaded and now we have to add new devices.
        add_devices_only = True
        if not configs_are_same(config_list=loaded_config,
                                config_to_find=config):
            loaded_config.append(config)

    wrong_type_config = not isinstance(
        config, six.string_types) and not isinstance(config, dict)
    if config is None and from_env_var is None:
        raise WrongUsage(
            "Provide either 'config' or 'from_env_var' parameter (none given)."
        )
    elif (not from_env_var and wrong_type_config) or (config
                                                      and wrong_type_config):
        raise WrongUsage(
            "Unsupported config type: '{}'. Allowed are: 'dict' or 'str' holding config filename (file is in YAML format)."
            .format(type(config)))
    if not config:
        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]
        config = read_yaml_configfile(path)
    elif isinstance(config, six.string_types):
        path = config
        config = read_yaml_configfile(path)
    # TODO: check schema
    if add_devices_only is False:
        load_logger_from_config(config)
        load_connection_from_config(config)
    load_device_from_config(config=config, add_only=add_devices_only)
예제 #3
0
    def get_cloned_device(cls,
                          source_device,
                          new_name,
                          initial_state=None,
                          establish_connection=True,
                          lazy_cmds_events=False):
        """
        Creates (if necessary) and returns new device based on existed device.

        :param source_device: Reference to base device or name of base device.
        :param new_name: Name of new device.
        :param initial_state: Initial state of created device. If None then state of source device will be used.
        :param establish_connection: True to open connection, False if it does not matter.
        :return: Device object.
        """
        with cls._lock_device:
            logger.info('START creating device {} from {}'.format(
                new_name, source_device))
            source_device_name = source_device
            if isinstance(source_device, six.string_types):
                source_device = cls._get_device_without_lock(
                    name=source_device,
                    device_class=None,
                    connection_desc=None,
                    connection_hops=None,
                    initial_state=None,
                    establish_connection=True,
                    lazy_cmds_events=lazy_cmds_events)
                logger.info('STEP 1 - creating source device {}'.format(
                    source_device_name))
            source_name = source_device.name  # name already translated to alias.
            if new_name in cls._devices.keys():
                cached_cloned_from = cls._devices_params[new_name][
                    'cloned_from']
                if cached_cloned_from == source_name:
                    return cls._devices[new_name]
                else:
                    msg = "Attempt to create device '{}' as clone of '{}' but device with such name already created " \
                          "as clone of '{}'.".format(new_name, source_name, cached_cloned_from)
                    raise WrongUsage(msg)
            if initial_state is None:
                initial_state = source_device.current_state

            device_class = cls._devices_params[source_name]['class_fullname']
            constructor_parameters = cls._devices_params[source_name][
                'constructor_parameters']
            constructor_parameters["initial_state"] = initial_state
            if constructor_parameters["name"]:
                constructor_parameters["name"] = new_name
            logger.info('STEP 2 - creating cloned device {}'.format(new_name))
            dev = cls._create_instance_and_remember_it(
                device_class=device_class,
                constructor_parameters=constructor_parameters,
                establish_connection=establish_connection,
                name=new_name)
            new_name = dev.name
            cls._devices_params[new_name]['cloned_from'] = source_name
            logger.info('DONE creating device {} from {}'.format(
                new_name, source_device_name))
        return dev
예제 #4
0
def test_connection_observer_exception_do_not_remove():
    ConnectionObserver.get_unraised_exceptions(True)
    time.sleep(0.1)
    from moler.cmd.unix.ls import Ls
    from moler.exceptions import CommandTimeout
    from moler.exceptions import WrongUsage
    cmd = Ls(None)
    none_exceptions = ConnectionObserver.get_unraised_exceptions(True)
    assert 0 == len(none_exceptions)
    cmd.set_exception(CommandTimeout(cmd, 0.1))
    cmd._is_done = True
    active_exceptions = ConnectionObserver.get_unraised_exceptions(False)
    assert 1 == len(active_exceptions)
    cmd = Ls(None)
    ctoe = CommandTimeout(cmd, 0.1)
    cwue = WrongUsage(cmd, "Another exception")
    cmd.set_exception(ctoe)
    cmd._is_done = True
    cmd.set_exception(cwue)
    active_exceptions = ConnectionObserver.get_unraised_exceptions(False)
    assert ctoe == active_exceptions[1]
    assert 2 == len(active_exceptions)
    active_exceptions = ConnectionObserver.get_unraised_exceptions(True)
    assert 2 == len(active_exceptions)
    none_exceptions = ConnectionObserver.get_unraised_exceptions(True)
    assert 0 == len(none_exceptions)
예제 #5
0
def load_config(config=None, from_env_var=None, config_type='yaml'):
    """
    Load Moler's configuration from config file

    :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: 'dict' ('config' param is dict) or 'yaml' ('config' is filename of file with YAML content)
    :return: None
    """
    global loaded_config
    add_devices_only = False

    if "NOT_LOADED_YET" in loaded_config:
        loaded_config = [config]
    elif configs_are_same(config_list=loaded_config, config_to_find=config):
        return
    else:
        # Config was already loaded and now we have to add new devices.
        add_devices_only = True
        loaded_config.append(config)

    if (config_type != 'dict') and (config_type !=
                                    'yaml'):  # no other format supported yet
        raise WrongUsage(
            "Unsupported config_type: '{}'. Allowed are: 'dict' or 'yaml'.".
            format(config_type))
    if not config:
        if not from_env_var:
            raise WrongUsage(
                "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]
        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
    if add_devices_only is False:
        load_logger_from_config(config)
        load_connection_from_config(config)
    load_device_from_config(config=config, add_only=add_devices_only)
예제 #6
0
    def get_device(cls,
                   name=None,
                   device_class=None,
                   connection_desc=None,
                   connection_hops=None,
                   initial_state=None,
                   establish_connection=True,
                   lazy_cmds_events=False,
                   io_connection=None,
                   additional_params=None):
        """
        Return connection instance of given io_type/variant.

        :param name: name of device defined in configuration.
        :param device_class: 'moler.device.unixlocal.UnixLocal', 'moler.device.unixremote.UnixRemote', ...
        :param connection_desc: 'io_type' and 'variant' of device connection. Ignored if device already created or
                        argument io_connection is passed.
        :param connection_hops: connection hops to create device SM.
        :param initial_state: initial state for device e.g. UNIX_REMOTE.
        :param establish_connection: True to open connection, False if it does not matter.
        :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.
        :param io_connection: connection for device. Ignored if device is already created.
        :param additional_params: dict with parameter(s) specific for the device. Will be passed to the constructor. If no
                         specific parameter then set to None.
        :return: requested device.
        """
        if (not name) and (not device_class):
            raise WrongUsage(
                "Provide either 'name' or 'device_class' parameter (none given)"
            )
        if name and device_class:
            raise WrongUsage(
                "Use either 'name' or 'device_class' parameter (not both)")
        with cls._lock_device:
            dev = cls._get_device_without_lock(
                name=name,
                device_class=device_class,
                connection_desc=connection_desc,
                connection_hops=connection_hops,
                initial_state=initial_state,
                establish_connection=establish_connection,
                lazy_cmds_events=lazy_cmds_events,
                io_connection=io_connection,
                additional_params=additional_params)

        return dev
예제 #7
0
 def _unknown_send(self, data2send):
     err_msg = "Can't send('{}')".format(data2send)
     err_msg += "\nYou haven't installed sending method of external-IO system"
     err_msg += "\n{}: {}(how2send=external_io_send)".format(
         "Do it either during connection construction",
         self.__class__.__name__)
     err_msg += "\nor later via attribute direct set: connection.how2send = external_io_send"
     raise WrongUsage(err_msg)
예제 #8
0
파일: set_mode.py 프로젝트: nokia/moler
    def __init__(self, selected_mode, connection=None, prompt=None, newline_chars=None, runner=None):
        """Create instance of SetMode class"""
        super(SetMode, self).__init__(connection, operation='execute', prompt=prompt,
                                      newline_chars=newline_chars, runner=runner)
        self.selected_mode = selected_mode.lower()

        if self.selected_mode not in SetMode.mode2cops_value:
            raise WrongUsage('\"{}\" is not correct mode. Available modes: {}.'.format(
                self.selected_mode, list(SetMode.mode2cops_value.keys())))

        self.ret_required = False
예제 #9
0
 def _get_parser(self):
     parsers = {
         "any": self._catch_any,
         "all": self._catch_all,
         "sequence": self._catch_sequence,
     }
     if self.match in parsers:
         return parsers[self.match]
     else:
         self.set_exception(WrongUsage("'{}' is not supported. Possible choices: 'any', 'all' or 'sequence'".
                                       format(self.match)))
예제 #10
0
    def connection_closed_handler(self):
        """
        Called by Moler (ThreadedMolerConnection) when connection is closed.

        :return: None
        """
        if not self.done():
            connection_name = self.get_logger_name()
            msg = "'{}' is not done but connection '{}' is about to be closed.".format(
                self, connection_name)
            ex = WrongUsage(msg)
            self.set_exception(ex)
        self.cancel()
예제 #11
0
 def __init__(self, scheduler_type=None):
     """
     :param scheduler_type: 'thread' or 'asyncio'
     """
     with Scheduler._lock:
         if Scheduler._object:
             raise WrongUsage(
                 "Scheduler object already created. Cannot create more than one instance."
             )
         super(Scheduler, self).__init__()
         self._scheduler_type = None
         self._scheduler = None
         self._swap_scheduler(scheduler_type)
         Scheduler._object = self
예제 #12
0
 def _create_scheduler(self, scheduler_type):
     """
     :param scheduler_type: type of new scheduler: 'thread' or 'asyncio'
     :return: instance of scheduler
     """
     if self._scheduler_type == scheduler_type:
         return self._scheduler
     if scheduler_type == 'thread':
         scheduler = MolerThreadScheduler()
     elif scheduler_type == 'asyncio':
         scheduler = MolerAsyncioScheduler()
     else:
         raise WrongUsage(
             "Wrong value of 'scheduler_type': '{}'. Allowed are 'thread' or 'asyncio'"
             .format(scheduler_type))
     scheduler.start()
     return scheduler
예제 #13
0
 def _raise_wrong_usage_of_wait_for(self, connection_observer):
     import inspect  # don't import if never raising this exception
     (_, _, _, caller_name, _, _) = inspect.stack()[1]
     (_, _, _, caller_caller_name, _, _) = inspect.stack()[2]
     # Prefer to speak in observer API not runner API since user uses observers-API (runner is hidden)
     user_call_name = caller_caller_name if caller_caller_name == 'await_done' else caller_name
     err_msg = "Can't call {}() from 'async def' - it is blocking call".format(
         user_call_name)
     err_msg += "\n    observer = {}()".format(
         connection_observer.__class__.__name__)
     err_msg += "\n    observer.start()"
     err_msg += "\nconsider using:"
     err_msg += "\n    await observer"
     err_msg += "\ninstead of:"
     err_msg += "\n    observer.await_done()"
     self.logger.error(msg=err_msg)
     raise WrongUsage(err_msg)
예제 #14
0
파일: __init__.py 프로젝트: macntouch/moler
def _is_device_creation_needed(name, requested_device_def):
    """

    :param name: Name of device
    :param requested_device_def: Definition of device requested to create/
    :return: True if device doesn't exist. False if device already exists.
    :
    """
    from moler.device.device import DeviceFactory
    try:
        DeviceFactory.get_device(name)
        msg = DeviceFactory.differences_bewteen_devices_descriptions(
            name, requested_device_def)
        if msg:
            raise WrongUsage(msg)
        return False  # Device exists and have the same construct parameters
    except KeyError:
        return True
예제 #15
0
 def _validate_start(self, *args, **kwargs):
     # check base class invariants first
     if self.done():
         raise WrongUsage("You can't run same {} multiple times. It is already done.".format(self))
     if not self.connection:
         # only if we have connection we can expect some data on it
         # at the latest "just before start" we need connection
         raise NoConnectionProvided(self)
     # ----------------------------------------------------------------------
     # We intentionally do not check if connection is open here.
     # In such case net result anyway will be failed/timeouted observer -
     # - so, user will need to investigate "why".
     # Checking connection state would benefit in early detection of:
     # "error condition - no chance to succeed since connection is closed".
     # However, drawback is a requirement on connection to have is_open() API
     # We choose minimalistic dependency over better troubleshooting support.
     # ----------------------------------------------------------------------
     if self.timeout <= 0.0:
         raise ConnectionObserverTimeout(self, self.timeout, "before run", "timeout is not positive value")