+ self.vpp_instance.disconnect()
+ run(["ssh", "-S", self._ssh_control_socket, "-O", "exit", "0.0.0.0"],
+ check=False)
+ shutil.rmtree(self._temp_dir)
+
+ def add(self, csit_papi_command, history=True, **kwargs):
+ """Add next command to internal command list; return self.
+
+ Unless disabled, new entry to papi history is also added at this point.
+ The argument name 'csit_papi_command' must be unique enough as it cannot
+ be repeated in kwargs.
+ The kwargs dict is deep-copied, so it is safe to use the original
+ with partial modifications for subsequent commands.
+
+ Any pending conflicts from .api.json processing are raised.
+ Then the command name is checked for known CRCs.
+ Unsupported commands raise an exception, as CSIT change
+ should not start using messages without making sure which CRCs
+ are supported.
+ Each CRC issue is raised only once, so subsequent tests
+ can raise other issues.
+
+ :param csit_papi_command: VPP API command.
+ :param history: Enable/disable adding command to PAPI command history.
+ :param kwargs: Optional key-value arguments.
+ :type csit_papi_command: str
+ :type history: bool
+ :type kwargs: dict
+ :returns: self, so that method chaining is possible.
+ :rtype: PapiSocketExecutor
+ :raises RuntimeError: If unverified or conflicting CRC is encountered.
+ """
+ self.crc_checker.report_initial_conflicts()
+ if history:
+ PapiHistory.add_to_papi_history(
+ self._node, csit_papi_command, **kwargs)
+ self.crc_checker.check_api_name(csit_papi_command)
+ self._api_command_list.append(
+ dict(api_name=csit_papi_command, api_args=copy.deepcopy(kwargs)))
+ return self
+
+ def get_replies(self, err_msg="Failed to get replies."):
+ """Get replies from VPP Python API.
+
+ The replies are parsed into dict-like objects,
+ "retval" field is guaranteed to be zero on success.
+
+ :param err_msg: The message used if the PAPI command(s) execution fails.
+ :type err_msg: str
+ :returns: Responses, dict objects with fields due to API and "retval".
+ :rtype: list of dict
+ :raises RuntimeError: If retval is nonzero, parsing or ssh error.
+ """
+ return self._execute(err_msg=err_msg)
+
+ def get_reply(self, err_msg="Failed to get reply."):
+ """Get reply from VPP Python API.
+
+ The reply is parsed into dict-like object,
+ "retval" field is guaranteed to be zero on success.
+
+ TODO: Discuss exception types to raise, unify with inner methods.
+
+ :param err_msg: The message used if the PAPI command(s) execution fails.
+ :type err_msg: str
+ :returns: Response, dict object with fields due to API and "retval".
+ :rtype: dict
+ :raises AssertionError: If retval is nonzero, parsing or ssh error.
+ """
+ replies = self.get_replies(err_msg=err_msg)
+ if len(replies) != 1:
+ raise RuntimeError("Expected single reply, got {replies!r}".format(
+ replies=replies))
+ return replies[0]
+
+ def get_sw_if_index(self, err_msg="Failed to get reply."):
+ """Get sw_if_index from reply from VPP Python API.
+
+ Frequently, the caller is only interested in sw_if_index field
+ of the reply, this wrapper makes such call sites shorter.
+
+ TODO: Discuss exception types to raise, unify with inner methods.
+
+ :param err_msg: The message used if the PAPI command(s) execution fails.
+ :type err_msg: str
+ :returns: Response, sw_if_index value of the reply.
+ :rtype: int
+ :raises AssertionError: If retval is nonzero, parsing or ssh error.
+ """
+ reply = self.get_reply(err_msg=err_msg)
+ logger.trace("Getting index from {reply!r}".format(reply=reply))
+ return reply["sw_if_index"]
+
+ def get_details(self, err_msg="Failed to get dump details."):
+ """Get dump details from VPP Python API.
+
+ The details are parsed into dict-like objects.
+ The number of details per single dump command can vary,
+ and all association between details and dumps is lost,
+ so if you care about the association (as opposed to
+ logging everything at once for debugging purposes),
+ it is recommended to call get_details for each dump (type) separately.
+
+ :param err_msg: The message used if the PAPI command(s) execution fails.
+ :type err_msg: str
+ :returns: Details, dict objects with fields due to API without "retval".
+ :rtype: list of dict
+ """
+ return self._execute(err_msg)
+
+ @staticmethod
+ def run_cli_cmd(node, cli_cmd, log=True,
+ remote_vpp_socket=Constants.SOCKSVR_PATH):
+ """Run a CLI command as cli_inband, return the "reply" field of reply.
+
+ Optionally, log the field value.
+
+ :param node: Node to run command on.
+ :param cli_cmd: The CLI command to be run on the node.
+ :param remote_vpp_socket: Path to remote socket to tunnel to.
+ :param log: If True, the response is logged.
+ :type node: dict
+ :type remote_vpp_socket: str
+ :type cli_cmd: str
+ :type log: bool
+ :returns: CLI output.