Пример #1
0
def test_register_tcp_plugins_env(grpc_timeout, mock_client_test_ok,
                                  mock_client_meta_ok):
    """Test registering TCP based plugins when multiple environment variables are specified"""
    assert len(plugin.Plugin.manager.plugins) == 0

    os.environ['SYNSE_PLUGIN_TCP'] = 'localhost:5000,localhost:5001'
    config.options.parse()

    registered = plugin.register_tcp()

    assert len(plugin.Plugin.manager.plugins) == 2
    assert isinstance(registered, list)
    assert len(registered) == 2

    assert 'vaporio/test-plugin+tcp@localhost:5000' in registered
    assert 'vaporio/test-plugin+tcp@localhost:5001' in registered

    p = plugin.get_plugin('vaporio/test-plugin+tcp@localhost:5000')
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'tcp'
    assert p.address == 'localhost:5000'

    p = plugin.get_plugin('vaporio/test-plugin+tcp@localhost:5001')
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'tcp'
    assert p.address == 'localhost:5001'
Пример #2
0
def test_register_tcp_plugins():
    """Test registering TCP based plugins when multiple configurations are specified"""
    assert len(plugin.Plugin.manager.plugins) == 0

    config.options.set('plugin.tcp.foo', 'localhost:5000')
    config.options.set('plugin.tcp.bar', 'localhost:5001')

    registered = plugin.register_tcp_plugins()

    assert len(plugin.Plugin.manager.plugins) == 2
    assert isinstance(registered, list)
    assert len(registered) == 2

    assert 'foo' in registered
    assert 'bar' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5000'

    p = plugin.get_plugin('bar')
    assert p is not None
    assert p.name == 'bar'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5001'
Пример #3
0
def test_register_tcp_plugins(grpc_timeout, mock_client_test_ok,
                              mock_client_meta_ok):
    """Test registering TCP based plugins when multiple configurations are specified"""
    assert len(plugin.Plugin.manager.plugins) == 0

    config.options.set('plugin.tcp', ['localhost:5000', 'localhost:5001'])

    registered = plugin.register_tcp()

    assert len(plugin.Plugin.manager.plugins) == 2
    assert isinstance(registered, list)
    assert len(registered) == 2

    assert 'vaporio/test-plugin+tcp@localhost:5000' in registered
    assert 'vaporio/test-plugin+tcp@localhost:5001' in registered

    p = plugin.get_plugin('vaporio/test-plugin+tcp@localhost:5000')
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'tcp'
    assert p.address == 'localhost:5000'

    p = plugin.get_plugin('vaporio/test-plugin+tcp@localhost:5001')
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'tcp'
    assert p.address == 'localhost:5001'
Пример #4
0
def test_register_tcp_plugin_already_exists():
    """Test registering TCP plugin when the plugin was already registered."""
    assert len(plugin.Plugin.manager.plugins) == 0

    config.options.set('plugin.tcp.foo', 'localhost:5000')

    # register the first time
    registered = plugin.register_tcp_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'foo' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5000'

    # register the second time
    registered = plugin.register_tcp_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'foo' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5000'
Пример #5
0
def test_register_unix_plugins(tmpsocket, grpc_timeout, mock_client_test_ok,
                               mock_client_meta_ok):
    """Test registering unix plugins when multiple configurations are specified"""

    # create the socket
    _, path1 = tmpsocket.add('foo')
    _, path2 = tmpsocket.add('bar')

    assert len(plugin.Plugin.manager.plugins) == 0

    # set configurations
    config.options.set('plugin.unix', ['foo', 'bar'])

    registered = plugin.register_unix()

    assert len(plugin.Plugin.manager.plugins) == 2
    assert isinstance(registered, list)
    assert len(registered) == 2

    assert 'vaporio/test-plugin+unix@' + path1 in registered
    assert 'vaporio/test-plugin+unix@' + path2 in registered

    p1 = plugin.get_plugin('vaporio/test-plugin+unix@' + path1)
    assert p1 is not None
    assert p1.name == 'test-plugin'
    assert p1.protocol == 'unix'
    assert p1.address == path1

    p2 = plugin.get_plugin('vaporio/test-plugin+unix@' + path2)
    assert p2 is not None
    assert p2.name == 'test-plugin'
    assert p2.protocol == 'unix'
    assert p2.address == path2
Пример #6
0
def test_register_tcp_plugins_env():
    """Test registering TCP based plugins when multiple environment variables are specified"""
    assert len(plugin.Plugin.manager.plugins) == 0

    os.environ['SYNSE_PLUGIN_TCP_FOO'] = 'localhost:5000'
    os.environ['SYNSE_PLUGIN_TCP_BAR'] = 'localhost:5001'
    config.options.parse()

    registered = plugin.register_tcp_plugins()

    assert len(plugin.Plugin.manager.plugins) == 2
    assert isinstance(registered, list)
    assert len(registered) == 2

    assert 'foo' in registered
    assert 'bar' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5000'

    p = plugin.get_plugin('bar')
    assert p is not None
    assert p.name == 'bar'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5001'
Пример #7
0
def test_register_unix_plugin(tmpsocket, grpc_timeout, mock_client_test_ok,
                              mock_client_meta_ok):
    """Test registering unix plugin when a configuration is specified"""

    # create the socket
    _, path = tmpsocket.add('foo')

    assert len(plugin.Plugin.manager.plugins) == 0

    # set a configuration
    config.options.set('plugin.unix', ['tmp'])

    registered = plugin.register_unix()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'vaporio/test-plugin+unix@' + path in registered

    p = plugin.get_plugin('vaporio/test-plugin+unix@' + path)
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'unix'
    assert p.address == path
Пример #8
0
def test_register_unix_plugin():
    """Test registering unix plugin when a configuration is specified"""
    # create the socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    path = os.path.join(data_dir, 'foo')
    sock.bind(path)

    assert len(plugin.Plugin.manager.plugins) == 0

    # set a configuration
    config.options.set('plugin.unix.foo', 'tmp')

    registered = plugin.register_unix_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'foo' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'unix'
    assert p.addr == path
Пример #9
0
def test_get_plugin2(mock_plugin):
    """Get a plugin when it does exist."""
    p = plugin.get_plugin('test-plug')
    assert isinstance(p, plugin.Plugin)
    assert p.name == 'test-plug'
    assert p.addr == 'localhost:9999'
    assert p.mode == 'tcp'
Пример #10
0
async def check_transaction(transaction_id):
    """The handler for the Synse Server "transaction" API command.

    Args:
        transaction_id (str|None): The id of the transaction to check. If
            the ID is None, a list of all transactions currently in the
            cache is returned.

    Returns:
        TransactionResponse: The "transaction" response scheme model.
        TransactionListResponse: The list of all transactions.
    """
    logger.debug(_('Transaction Command (args: {})').format(transaction_id))

    # If we are not given a transaction ID, then we want to return
    # the list of all actively tracked transactions.
    if transaction_id is None:
        all_keys = cache.transaction_cache._cache.keys()
        # Keys in the cache are prepended with 'transaction', so here we get all
        # keys with that prefix and strip the prefix.
        transaction_ids = [
            k[11:] for k in all_keys if k.startswith('transaction')
        ]
        return scheme.TransactionListResponse(transaction_ids)

    # Otherwise, get the specified transaction.
    transaction = await cache.get_transaction(transaction_id)
    if not transaction:
        raise errors.TransactionNotFoundError(
            _('Transaction with id "{}" not found').format(transaction_id))

    plugin_name = transaction.get('plugin')
    context = transaction.get('context')

    if not plugin_name:
        # TODO - in the future, what we could do is attempt sending the transaction
        #   request to *all* of the known plugins. this could be useful in the event
        #   that synse goes down. since everything is just stored in memory, a new
        #   synse instance will have lost the transaction cache.
        #
        #   alternatively, we could think about having an internal api command to
        #   essentially dump the active transactions so that we can rebuild the cache.
        raise errors.TransactionNotFoundError(
            _('Unable to determine managing plugin for transaction {}.').
            format(transaction_id))

    _plugin = plugin.get_plugin(plugin_name)
    if not _plugin:
        raise errors.PluginNotFoundError(
            _('Unable to find plugin "{}"').format(plugin_name))

    try:
        resp = _plugin.client.transaction(transaction_id)
    except grpc.RpcError as ex:
        raise errors.FailedTransactionCommandError(str(ex)) from ex

    return scheme.TransactionResponse(transaction_id, context, resp[0])
Пример #11
0
def test_register_unix_plugin_already_exists(tmpsocket, grpc_timeout,
                                             mock_client_test_ok,
                                             mock_client_meta_ok):
    """Test registering unix plugin when the plugin was already registered."""

    # create the socket
    _, path = tmpsocket.add('test')

    assert len(plugin.Plugin.manager.plugins) == 0

    registered = plugin.register_unix()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'vaporio/test-plugin+unix@' + path in registered

    p = plugin.get_plugin('vaporio/test-plugin+unix@' + path)
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.address == path
    assert p.protocol == 'unix'

    # now, re-register
    assert len(plugin.Plugin.manager.plugins) == 1

    # set the same configuration
    config.options.set('plugin.unix', [str(tmpsocket.socket_dir)])

    registered = plugin.register_unix()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'vaporio/test-plugin+unix@' + path in registered

    p = plugin.get_plugin('vaporio/test-plugin+unix@' + path)
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.address == path
    assert p.protocol == 'unix'
Пример #12
0
def test_register_unix_plugin_already_exists():
    """Test registering unix plugin when the plugin was already registered."""
    # create the socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    path = '{}/test'.format(data_dir)
    sock.bind(path)

    assert len(plugin.Plugin.manager.plugins) == 0

    registered = plugin.register_unix_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'test' in registered

    p = plugin.get_plugin('test')
    assert p is not None
    assert p.name == 'test'
    assert p.addr == path
    assert p.mode == 'unix'

    # now, re-register
    assert len(plugin.Plugin.manager.plugins) == 1

    # set the same configuration
    config.options.set('plugin.unix.test', data_dir)

    registered = plugin.register_unix_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'test' in registered

    p = plugin.get_plugin('test')
    assert p is not None
    assert p.name == 'test'
    assert p.addr == path
    assert p.mode == 'unix'
Пример #13
0
def test_register_unix_plugins():
    """Test registering unix plugins when multiple configurations are specified"""
    # create sockets
    sock1 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    path1 = os.path.join(data_dir, 'foo')
    sock1.bind(path1)

    sock2 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    path2 = os.path.join(data_dir, 'bar')
    sock2.bind(path2)

    assert len(plugin.Plugin.manager.plugins) == 0

    # set configurations
    config.options.set('plugin.unix.foo', 'tmp')
    config.options.set('plugin.unix.bar', 'tmp')

    registered = plugin.register_unix_plugins()

    assert len(plugin.Plugin.manager.plugins) == 2
    assert isinstance(registered, list)
    assert len(registered) == 2

    assert 'foo' in registered
    assert 'bar' in registered

    p1 = plugin.get_plugin('foo')
    assert p1 is not None
    assert p1.name == 'foo'
    assert p1.mode == 'unix'
    assert p1.addr == path1

    p2 = plugin.get_plugin('bar')
    assert p2 is not None
    assert p2.name == 'bar'
    assert p2.mode == 'unix'
    assert p2.addr == path2
Пример #14
0
def test_register_tcp_plugin_already_exists(grpc_timeout, mock_client_test_ok,
                                            mock_client_meta_ok):
    """Test registering TCP plugin when the plugin was already registered."""
    assert len(plugin.Plugin.manager.plugins) == 0

    config.options.set('plugin.tcp', ['localhost:5000'])

    # register the first time
    registered = plugin.register_tcp()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'vaporio/test-plugin+tcp@localhost:5000' in registered

    p = plugin.get_plugin('vaporio/test-plugin+tcp@localhost:5000')
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'tcp'
    assert p.address == 'localhost:5000'

    # register the second time
    registered = plugin.register_tcp()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'vaporio/test-plugin+tcp@localhost:5000' in registered

    p = plugin.get_plugin('vaporio/test-plugin+tcp@localhost:5000')
    assert p is not None
    assert p.name == 'test-plugin'
    assert p.protocol == 'tcp'
    assert p.address == 'localhost:5000'
Пример #15
0
def test_register_tcp_plugin_env():
    """Test registering TCP based plugin when an environment variable is set"""
    assert len(plugin.Plugin.manager.plugins) == 0

    os.environ['SYNSE_PLUGIN_TCP_FOO'] = 'localhost:5000'
    config.options.parse()

    registered = plugin.register_tcp_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'foo' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'tcp'
    assert p.addr == 'localhost:5000'
Пример #16
0
def test_register_unix_plugin_no_config_path():
    """Test registering unix plugin when a configuration without a path is specified"""
    # create the socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    path = '{}/foo'.format(data_dir)
    sock.bind(path)

    assert len(plugin.Plugin.manager.plugins) == 0

    config.options.set('plugin.unix.foo', None)

    registered = plugin.register_unix_plugins()

    assert len(plugin.Plugin.manager.plugins) == 1
    assert isinstance(registered, list)
    assert len(registered) == 1

    assert 'foo' in registered

    p = plugin.get_plugin('foo')
    assert p is not None
    assert p.name == 'foo'
    assert p.mode == 'unix'
    assert p.addr == '{}/foo'.format(data_dir)
Пример #17
0
def test_get_plugin1():
    """Get a plugin when it doesn't exist."""
    p = plugin.get_plugin('test')
    assert p is None
Пример #18
0
async def write(rack, board, device, data):
    """The handler for the Synse Server "write" API command.

    Args:
        rack (str): The rack which the device resides on.
        board (str): The board which the device resides on.
        device (str): The device to write to.
        data (dict): The data to write to the device.

    Returns:
        WriteResponse: The "write" response scheme model.
    """
    logger.debug(
        _('Write Command (args: {}, {}, {}, data: {})').format(
            rack, board, device, data))

    # Lookup the known info for the specified device
    plugin_name, __ = await cache.get_device_info(rack, board, device)  # pylint: disable=unused-variable

    # Get the plugin context for the device's specified protocol
    _plugin = plugin.get_plugin(plugin_name)
    if not _plugin:
        raise errors.PluginNotFoundError(
            _('Unable to find plugin named "{}"').format(plugin_name))

    # The data comes in as the POSTed dictionary which includes an 'action'
    # and/or 'raw'/'data' field. Here, we convert it to the appropriate modeling for
    # transport to the plugin.
    write_action = data.get('action')
    if not isinstance(write_action, str):
        raise errors.InvalidArgumentsError(
            _('"action" value must be a string, but was {}').format(
                type(write_action)))

    # Get the data out. If the 'data' field is present, we will use it. Otherwise, we will
    # look for a 'raw' field, for backwards compatibility. If 'data' exists, 'raw' is ignored.
    write_data = data.get('data')
    if write_data is None:
        write_data = data.get('raw')

    if write_data is not None:
        # The data should be an instance of bytes, which in python is a string
        if not isinstance(write_data, str):
            raise errors.InvalidArgumentsError(
                _('"raw"/"data" value must be a string, but was {}').format(
                    type(write_data)))
        write_data = str.encode(write_data)

    wd = WriteData(action=write_action, data=write_data)
    logger.info(
        _('Writing to {}: {}').format('/'.join((rack, board, device)), wd))

    # Perform a gRPC write on the device's managing plugin
    try:
        t = _plugin.client.write(rack, board, device, [wd])
    except grpc.RpcError as ex:
        raise errors.FailedWriteCommandError(str(ex)) from ex

    # Now that we have the transaction info, we want to map it to the corresponding
    # process so any subsequent transaction check will know where to look.
    for _id, ctx in t.transactions.items():
        context = {'action': ctx.action, 'data': ctx.data}
        ok = await cache.add_transaction(_id, context, _plugin.id())
        if not ok:
            logger.error(
                _('Failed to add transaction {} to the cache').format(_id))

    return WriteResponse(transactions=t.transactions)
Пример #19
0
async def read(rack, board, device):
    """The handler for the Synse Server "read" API command.

    Args:
        rack (str): The rack which the device resides on.
        board (str): The board which the device resides on.
        device (str): The device to read.

    Returns:
        ReadResponse: The "read" response scheme model.
    """
    logger.debug(
        _('Read Command (args: {}, {}, {})').format(rack, board, device))

    # Lookup the known info for the specified device.
    plugin_name, dev = await cache.get_device_info(rack, board, device)
    logger.debug(
        _('Device {} is managed by plugin {}').format(device, plugin_name))

    # Get the plugin context for the device's specified protocol.
    _plugin = plugin.get_plugin(plugin_name)
    logger.debug(_('Got plugin: {}').format(_plugin))
    if not _plugin:
        raise errors.PluginNotFoundError(
            _('Unable to find plugin named "{}" to read').format(plugin_name))

    try:
        # Perform a gRPC read on the device's managing plugin
        read_data = _plugin.client.read(rack, board, device)
    except grpc.RpcError as ex:

        # FIXME (etd) - this isn't the nicest way of doing this check.
        # this string is returned from the SDK, and its not likely to change
        # anytime soon, so this is "safe" for now, but we should see if there
        # is a better way to check this other than comparing strings..
        if hasattr(ex, 'code') and hasattr(ex, 'details'):
            if grpc.StatusCode.NOT_FOUND == ex.code(
            ) and 'no readings found' in ex.details().lower():

                # FIXME (etd) - with SDK v1.0, is the below correct? We should not longer
                # have to pass the "null" string. I think an empty string should also not
                # indicate no readings.. it should be the NOT_FOUND error (or, at least
                # some kind of error).

                # Currently, in the SDK, there are three different behaviors for
                # devices that do not have readings. Either (a). "null" is returned,
                # (b). an empty string ("") is returned, or (c). a gRPC error is
                # returned with the NOT_FOUND status code. Cases (a) and (b) are
                # handled in the ReadResponse initialization (below). This block
                # handles case (c).
                #
                # The reason for the difference between (a) and (b) is just one
                # of implementation. The empty string is the default value for the
                # gRPC read response, but sometimes it is useful to have an explict
                # value set to make things easier to read.
                #
                # The difference between those and (c) is more distinct. (c) should
                # only happen when a configured device is not being read from at all.
                # Essentially, (c) is the fallback for when device-specific handlers
                # fail to read a configured device.
                #
                # To summarize:
                #   (a), (b)
                #       A device is configured and the plugin's device handlers
                #       can operate on the device. This indicates that the plugin
                #       is working, but the device could be failing or disconnected.
                #
                #   (c)
                #       A device is configured, but the plugin's device handler
                #       can not (or is not) able to operate on the device. This
                #       could indicate either a plugin configuration error or
                #       an error with the plugin logic itself.

                # Create empty readings for each of the device's readings.
                logger.warning(
                    _('Read for {}/{}/{} returned gRPC "no readings found". Will '
                      'apply None as reading value. Note that this response might '
                      'indicate plugin error/misconfiguration.').format(
                          rack, board, device))
                read_data = []
                for output in dev.output:
                    read_data.append(
                        api.Reading(
                            timestamp=utils.rfc3339now(),
                            type=output.type,
                        ))
            else:
                raise errors.FailedReadCommandError(str(ex)) from ex
        else:
            raise errors.FailedReadCommandError(str(ex)) from ex

    return ReadResponse(device=dev, readings=read_data)