+ return vpp_instance
+
+ @classmethod
+ def key_for_node_and_socket(cls, node, remote_socket):
+ """Return a hashable object to distinguish nodes.
+
+ The usual node object (of "dict" type) is not hashable,
+ and can contain mutable information (mostly virtual interfaces).
+ Use this method to get an object suitable for being a key in dict.
+
+ The fields to include are chosen by what ssh needs.
+
+ This class method is needed, for disconnect.
+
+ :param node: The node object to distinguish.
+ :param remote_socket: Path to remote socket.
+ :type node: dict
+ :type remote_socket: str
+ :return: Tuple of values distinguishing this node from similar ones.
+ :rtype: tuple of str
+ """
+ return (
+ node[u"host"],
+ node[u"port"],
+ remote_socket,
+ # TODO: Do we support sockets paths such as "~/vpp/api.socket"?
+ # If yes, add also:
+ # node[u"username"],
+ )
+
+ def key_for_self(self):
+ """Return a hashable object to distinguish nodes.
+
+ Just a wrapper around key_for_node_and_socket
+ which sets up proper arguments.
+
+ :return: Tuple of values distinguishing this node from similar ones.
+ :rtype: tuple of str
+ """
+ return self.__class__.key_for_node_and_socket(
+ self._node, self._remote_vpp_socket,
+ )
+
+ def set_connected_client(self, client):
+ """Add a connected client instance into cache.
+
+ This hides details of what the node key is.
+
+ If there already is a client for the computed key,
+ fail, as it is a sign of resource leakage.
+
+ :param client: VPP client instance in connected state.
+ :type client: vpp_papi.VPPApiClient
+ :raises RuntimeError: If related key already has a cached client.
+ """
+ key = self.key_for_self()
+ cache = self.__class__.conn_cache
+ if key in cache:
+ raise RuntimeError(f"Caching client with existing key: {key}")
+ cache[key] = client
+
+ def get_connected_client(self, check_connected=True):
+ """Return None or cached connected client.
+
+ If check_connected, RuntimeError is raised when the client is
+ not in cache. None is returned if client is not in cache
+ (and the check is disabled).
+
+ This hides details of what the node key is.
+
+ :param check_connected: Whether cache miss raises.
+ :type check_connected: bool
+ :returns: Connected client instance, or None if uncached and no check.
+ :rtype: Optional[vpp_papi.VPPApiClient]
+ :raises RuntimeError: If cache miss and check enabled.
+ """
+ key = self.key_for_self()
+ ret = self.__class__.conn_cache.get(key, None)
+
+ if ret is None:
+ if check_connected:
+ raise RuntimeError(f"Client not cached for key: {key}")
+ else:
+ # When reading logs, it is good to see which VPP is accessed.
+ logger.debug(f"Activated cached PAPI client for key: {key}")
+ return ret