Tolerate failures when setting MTU
[csit.git] / resources / libraries / python / VPPUtil.py
index 1bc1b43..03d39d3 100644 (file)
 
 """VPP util library."""
 
 
 """VPP util library."""
 
-import time
+import binascii
 
 from robot.api import logger
 
 from resources.libraries.python.Constants import Constants
 from resources.libraries.python.DUTSetup import DUTSetup
 from resources.libraries.python.PapiExecutor import PapiExecutor
 
 from robot.api import logger
 
 from resources.libraries.python.Constants import Constants
 from resources.libraries.python.DUTSetup import DUTSetup
 from resources.libraries.python.PapiExecutor import PapiExecutor
-from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error
+from resources.libraries.python.ssh import exec_cmd_no_error
 from resources.libraries.python.topology import NodeType
 from resources.libraries.python.topology import NodeType
-from resources.libraries.python.VatExecutor import VatExecutor
 
 
 class VPPUtil(object):
 
 
 class VPPUtil(object):
@@ -58,55 +57,39 @@ class VPPUtil(object):
             exec_cmd_no_error(node, command, timeout=30, sudo=True)
 
     @staticmethod
             exec_cmd_no_error(node, command, timeout=30, sudo=True)
 
     @staticmethod
-    def start_vpp_service(node, retries=60):
-        """Start VPP service on the specified node.
+    def restart_vpp_service(node):
+        """Restart VPP service on the specified topology node.
 
 
-        :param node: VPP node.
-        :param retries: Number of times (default 60) to re-try waiting.
+        :param node: Topology node.
         :type node: dict
         :type node: dict
-        :type retries: int
-        :raises RuntimeError: If VPP service fails to start.
         """
         """
-        DUTSetup.start_service(node, Constants.VPP_UNIT)
-        # Sleep 1 second, up to <retry> times,
-        # and verify if VPP is running.
-        for _ in range(retries):
-            time.sleep(1)
-            command = 'vppctl show pci'
-            ret, stdout, _ = exec_cmd(node, command, timeout=30, sudo=True)
-            if not ret and 'Connection refused' not in stdout:
-                break
-        else:
-            raise RuntimeError('VPP failed to start on host {name}'.
-                               format(name=node['host']))
-        DUTSetup.get_service_logs(node, Constants.VPP_UNIT)
+        DUTSetup.restart_service(node, Constants.VPP_UNIT)
 
     @staticmethod
 
     @staticmethod
-    def start_vpp_service_on_all_duts(nodes):
-        """Start up the VPP service on all nodes.
+    def restart_vpp_service_on_all_duts(nodes):
+        """Restart VPP service on all DUT nodes.
 
 
-        :param nodes: Nodes in the topology.
+        :param nodes: Topology nodes.
         :type nodes: dict
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
         :type nodes: dict
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
-                VPPUtil.start_vpp_service(node)
+                VPPUtil.restart_vpp_service(node)
 
     @staticmethod
     def stop_vpp_service(node):
 
     @staticmethod
     def stop_vpp_service(node):
-        """Stop VPP service on the specified node.
+        """Stop VPP service on the specified topology node.
 
 
-        :param node: VPP node.
+        :param node: Topology node.
         :type node: dict
         :type node: dict
-        :raises RuntimeError: If VPP service fails to stop.
         """
         DUTSetup.stop_service(node, Constants.VPP_UNIT)
 
     @staticmethod
     def stop_vpp_service_on_all_duts(nodes):
         """
         DUTSetup.stop_service(node, Constants.VPP_UNIT)
 
     @staticmethod
     def stop_vpp_service_on_all_duts(nodes):
-        """Stop VPP service on all nodes.
+        """Stop VPP service on all DUT nodes.
 
 
-        :param nodes: Nodes in the topology.
+        :param nodes: Topology nodes.
         :type nodes: dict
         """
         for node in nodes.values():
         :type nodes: dict
         """
         for node in nodes.values():
@@ -114,31 +97,60 @@ class VPPUtil(object):
                 VPPUtil.stop_vpp_service(node)
 
     @staticmethod
                 VPPUtil.stop_vpp_service(node)
 
     @staticmethod
-    def verify_vpp_on_dut(node):
-        """Verify that VPP is installed on DUT node.
+    def verify_vpp_installed(node):
+        """Verify that VPP is installed on the specified topology node.
+
+        :param node: Topology node.
+        :type node: dict
+        """
+        cmd = 'command -v vpp'
+        exec_cmd_no_error(
+            node, cmd, message='VPP is not installed!')
+
+    @staticmethod
+    def verify_vpp_started(node):
+        """Verify that VPP is started on the specified topology node.
+
+        :param node: Topology node.
+        :type node: dict
+        """
+        cmd = ('vppctl show pci 2>&1 | '
+               'fgrep -v "Connection refused" | '
+               'fgrep -v "No such file or directory"')
+        exec_cmd_no_error(
+            node, cmd, sudo=True, message='VPP failed to start!', retries=120)
+
+    @staticmethod
+    def verify_vpp(node):
+        """Verify that VPP is installed and started on the specified topology
+        node.
 
 
-        :param node: DUT node.
+        :param node: Topology node.
         :type node: dict
         :type node: dict
-        :raises RuntimeError: If failed to restart VPP, get VPP version
-            or get VPP interfaces.
+        :raises RuntimeError: If VPP service fails to start.
         """
         """
-        VPPUtil.vpp_show_version_verbose(node)
-        VPPUtil.vpp_show_interfaces(node)
+        VPPUtil.verify_vpp_installed(node)
+        try:
+            # Verify responsivness of vppctl.
+            VPPUtil.verify_vpp_started(node)
+            # Verify responsivness of PAPI.
+            VPPUtil.show_log(node)
+        finally:
+            DUTSetup.get_service_logs(node, Constants.VPP_UNIT)
 
     @staticmethod
     def verify_vpp_on_all_duts(nodes):
 
     @staticmethod
     def verify_vpp_on_all_duts(nodes):
-        """Verify that VPP is installed on all DUT nodes.
+        """Verify that VPP is installed and started on all DUT nodes.
 
         :param nodes: Nodes in the topology.
         :type nodes: dict
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
 
         :param nodes: Nodes in the topology.
         :type nodes: dict
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
-                VPPUtil.start_vpp_service(node)
-                VPPUtil.verify_vpp_on_dut(node)
+                VPPUtil.verify_vpp(node)
 
     @staticmethod
 
     @staticmethod
-    def vpp_show_version(node, verbose=False):
+    def vpp_show_version(node, verbose=True):
         """Run "show_version" PAPI command.
 
         :param node: Node to run command on.
         """Run "show_version" PAPI command.
 
         :param node: Node to run command on.
@@ -146,40 +158,31 @@ class VPPUtil(object):
             otherwise show only version.
         :type node: dict
         :type verbose: bool
             otherwise show only version.
         :type node: dict
         :type verbose: bool
+        :returns: VPP version.
+        :rtype: str
         """
         """
-
         with PapiExecutor(node) as papi_exec:
         with PapiExecutor(node) as papi_exec:
-            papi_resp = papi_exec.add('show_version').execute_should_pass()
-        data = papi_resp.reply[0]['api_reply']['show_version_reply']
+            data = papi_exec.add('show_version').get_replies().verify_reply()
         version = ('VPP version:      {ver}\n'.
                    format(ver=data['version'].rstrip('\0x00')))
         if verbose:
             version += ('Compile date:     {date}\n'
         version = ('VPP version:      {ver}\n'.
                    format(ver=data['version'].rstrip('\0x00')))
         if verbose:
             version += ('Compile date:     {date}\n'
-                        'Compile location: {loc}\n '.
+                        'Compile location: {cl}\n '.
                         format(date=data['build_date'].rstrip('\0x00'),
                         format(date=data['build_date'].rstrip('\0x00'),
-                               loc=data['build_directory'].rstrip('\0x00')))
+                               cl=data['build_directory'].rstrip('\0x00')))
         logger.info(version)
         logger.info(version)
-
-    @staticmethod
-    def vpp_show_version_verbose(node):
-        """Run "show_version" API command and return verbose string of version
-        data.
-
-        :param node: Node to run command on.
-        :type node: dict
-        """
-        VPPUtil.vpp_show_version(node, verbose=True)
+        return data['version'].rstrip('\0x00')
 
     @staticmethod
     def show_vpp_version_on_all_duts(nodes):
 
     @staticmethod
     def show_vpp_version_on_all_duts(nodes):
-        """Show VPP version on all DUTs.
+        """Show VPP version verbose on all DUTs.
 
 
-        :param nodes: VPP nodes.
+        :param nodes: Nodes in the topology.
         :type nodes: dict
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
         :type nodes: dict
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
-                VPPUtil.vpp_show_version_verbose(node)
+                VPPUtil.vpp_show_version(node)
 
     @staticmethod
     def vpp_show_interfaces(node):
 
     @staticmethod
     def vpp_show_interfaces(node):
@@ -188,68 +191,66 @@ class VPPUtil(object):
         :param node: Node to run command on.
         :type node: dict
         """
         :param node: Node to run command on.
         :type node: dict
         """
-        vat = VatExecutor()
-        vat.execute_script("show_interface.vat", node, json_out=False)
 
 
-        try:
-            vat.script_should_have_passed()
-        except AssertionError:
-            raise RuntimeError('Failed to get VPP interfaces on host: {name}'.
-                               format(name=node['host']))
-
-    @staticmethod
-    def vpp_show_crypto_device_mapping(node):
-        """Run "show crypto device mapping" CLI command.
-
-        :param node: Node to run command on.
-        :type node: dict
-        """
-        vat = VatExecutor()
-        vat.execute_script("show_crypto_device_mapping.vat", node,
-                           json_out=False)
-
-    @staticmethod
-    def vpp_api_trace_dump(node):
-        """Run "api trace custom-dump" CLI command.
-
-        :param node: Node to run command on.
-        :type node: dict
-        """
-        vat = VatExecutor()
-        vat.execute_script("api_trace_dump.vat", node, json_out=False)
-
-    @staticmethod
-    def vpp_api_trace_save(node):
-        """Run "api trace save" CLI command.
-
-        :param node: Node to run command on.
-        :type node: dict
-        """
-        vat = VatExecutor()
-        vat.execute_script("api_trace_save.vat", node, json_out=False)
+        cmd = 'sw_interface_dump'
+        cmd_reply = 'sw_interface_details'
+        args = dict(name_filter_valid=0, name_filter='')
+        err_msg = 'Failed to get interface dump on host {host}'.format(
+            host=node['host'])
+        with PapiExecutor(node) as papi_exec:
+            papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg)
+
+        papi_if_dump = papi_resp.reply[0]['api_reply']
+
+        if_data = list()
+        for item in papi_if_dump:
+            data = item[cmd_reply]
+            data['interface_name'] = data['interface_name'].rstrip('\x00')
+            data['tag'] = data['tag'].rstrip('\x00')
+            data['l2_address'] = str(':'.join(binascii.hexlify(
+                data['l2_address'])[i:i + 2] for i in range(0, 12, 2)).
+                                     decode('ascii'))
+            if_data.append(data)
+        # TODO: return only base data
+        logger.trace('Interface data of host {host}:\n{if_data}'.format(
+            host=node['host'], if_data=if_data))
 
     @staticmethod
 
     @staticmethod
-    def vpp_enable_traces_on_dut(node):
+    def vpp_enable_traces_on_dut(node, fail_on_error=False):
         """Enable vpp packet traces on the DUT node.
 
         :param node: DUT node to set up.
         """Enable vpp packet traces on the DUT node.
 
         :param node: DUT node to set up.
+        :param fail_on_error: If True, keyword fails if an error occurs,
+            otherwise passes.
         :type node: dict
         :type node: dict
+        :type fail_on_error: bool
         """
         """
-        vat = VatExecutor()
-        vat.execute_script("enable_dpdk_traces.vat", node, json_out=False)
-        vat.execute_script("enable_vhost_user_traces.vat", node, json_out=False)
-        vat.execute_script("enable_memif_traces.vat", node, json_out=False)
+        cmds = [
+            "trace add dpdk-input 50",
+            "trace add vhost-user-input 50",
+            "trace add memif-input 50"
+        ]
+
+        for cmd in cmds:
+            try:
+                PapiExecutor.run_cli_cmd(node, cmd)
+            except AssertionError:
+                if fail_on_error:
+                    raise
 
     @staticmethod
 
     @staticmethod
-    def vpp_enable_traces_on_all_duts(nodes):
+    def vpp_enable_traces_on_all_duts(nodes, fail_on_error=False):
         """Enable vpp packet traces on all DUTs in the given topology.
 
         :param nodes: Nodes in the topology.
         """Enable vpp packet traces on all DUTs in the given topology.
 
         :param nodes: Nodes in the topology.
+        :param fail_on_error: If True, keyword fails if an error occurs,
+            otherwise passes.
         :type nodes: dict
         :type nodes: dict
+        :type fail_on_error: bool
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
-                VPPUtil.vpp_enable_traces_on_dut(node)
+                VPPUtil.vpp_enable_traces_on_dut(node, fail_on_error)
 
     @staticmethod
     def vpp_enable_elog_traces_on_dut(node):
 
     @staticmethod
     def vpp_enable_elog_traces_on_dut(node):
@@ -258,9 +259,7 @@ class VPPUtil(object):
         :param node: DUT node to set up.
         :type node: dict
         """
         :param node: DUT node to set up.
         :type node: dict
         """
-        vat = VatExecutor()
-        vat.execute_script("elog_trace_api_cli_barrier.vat", node,
-                           json_out=False)
+        PapiExecutor.run_cli_cmd(node, "elog trace api cli barrier")
 
     @staticmethod
     def vpp_enable_elog_traces_on_all_duts(nodes):
 
     @staticmethod
     def vpp_enable_elog_traces_on_all_duts(nodes):
@@ -280,8 +279,7 @@ class VPPUtil(object):
         :param node: DUT node to show traces on.
         :type node: dict
         """
         :param node: DUT node to show traces on.
         :type node: dict
         """
-        vat = VatExecutor()
-        vat.execute_script("show_event_logger.vat", node, json_out=False)
+        PapiExecutor.run_cli_cmd(node, "show event-logger")
 
     @staticmethod
     def show_event_logger_on_all_duts(nodes):
 
     @staticmethod
     def show_event_logger_on_all_duts(nodes):
@@ -294,6 +292,17 @@ class VPPUtil(object):
             if node['type'] == NodeType.DUT:
                 VPPUtil.show_event_logger_on_dut(node)
 
             if node['type'] == NodeType.DUT:
                 VPPUtil.show_event_logger_on_dut(node)
 
+    @staticmethod
+    def show_log(node):
+        """Show log on the specified topology node.
+
+        :param node: Topology node.
+        :type node: dict
+        :returns: VPP log data.
+        :rtype: list
+        """
+        return PapiExecutor.run_cli_cmd(node, "show log")["reply"]
+
     @staticmethod
     def vpp_show_threads(node):
         """Show VPP threads on node.
     @staticmethod
     def vpp_show_threads(node):
         """Show VPP threads on node.
@@ -303,7 +312,19 @@ class VPPUtil(object):
         :returns: VPP thread data.
         :rtype: list
         """
         :returns: VPP thread data.
         :rtype: list
         """
-
         with PapiExecutor(node) as papi_exec:
         with PapiExecutor(node) as papi_exec:
-            resp = papi_exec.add('show_threads').execute_should_pass()
-        return resp.reply[0]['api_reply']['show_threads_reply']['thread_data']
+            data = papi_exec.add('show_threads').get_replies().\
+                verify_reply()["thread_data"]
+
+        threads_data = list()
+        for thread in data:
+            thread_data = list()
+            for item in thread:
+                if isinstance(item, unicode):
+                    item = item.rstrip('\x00')
+                thread_data.append(item)
+            threads_data.append(thread_data)
+
+        logger.info("show threads:\n{threads}".format(threads=threads_data))
+
+        return threads_data