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'
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'
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'
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'
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
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'
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
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
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'
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])
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'
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'
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
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'
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'
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)
def test_get_plugin1(): """Get a plugin when it doesn't exist.""" p = plugin.get_plugin('test') assert p is None
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)
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)