fix(core): Add vpp log path
[csit.git] / resources / libraries / python / DUTSetup.py
index 712da63..300248c 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2023 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
@@ -17,7 +17,7 @@ from time import sleep
 from robot.api import logger
 
 from resources.libraries.python.Constants import Constants
-from resources.libraries.python.ssh import SSH, exec_cmd, exec_cmd_no_error
+from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error
 from resources.libraries.python.topology import NodeType, Topology
 
 
@@ -33,11 +33,13 @@ class DUTSetup:
         :type node: dict
         :type service: str
         """
-        command = u"cat /tmp/*supervisor*.log"\
-            if DUTSetup.running_in_container(node) \
-            else f"journalctl --no-pager _SYSTEMD_INVOCATION_ID=$(systemctl " \
-            f"show -p InvocationID --value {service})"
-
+        if DUTSetup.running_in_container(node):
+            command = u"cat /var/log/vpp/vpp.log"
+        else:
+            command = (
+                f"journalctl --no-pager _SYSTEMD_INVOCATION_ID=$(systemctl "
+                f"show -p InvocationID --value {service})"
+            )
         message = f"Node {node[u'host']} failed to get logs from unit {service}"
 
         exec_cmd_no_error(
@@ -66,9 +68,10 @@ class DUTSetup:
         :type node: dict
         :type service: str
         """
-        command = f"supervisorctl restart {service}" \
-            if DUTSetup.running_in_container(node) \
-            else f"service {service} restart"
+        if DUTSetup.running_in_container(node):
+            command = f"supervisorctl restart {service}"
+        else:
+            command = f"systemctl restart {service}"
         message = f"Node {node[u'host']} failed to restart service {service}"
 
         exec_cmd_no_error(
@@ -99,10 +102,10 @@ class DUTSetup:
         :type node: dict
         :type service: str
         """
-        # TODO: change command to start once all parent function updated.
-        command = f"supervisorctl restart {service}" \
-            if DUTSetup.running_in_container(node) \
-            else f"service {service} restart"
+        if DUTSetup.running_in_container(node):
+            command = f"supervisorctl restart {service}"
+        else:
+            command = f"systemctl restart {service}"
         message = f"Node {node[u'host']} failed to start service {service}"
 
         exec_cmd_no_error(
@@ -135,9 +138,10 @@ class DUTSetup:
         """
         DUTSetup.get_service_logs(node, service)
 
-        command = f"supervisorctl stop {service}" \
-            if DUTSetup.running_in_container(node) \
-            else f"service {service} stop"
+        if DUTSetup.running_in_container(node):
+            command = f"supervisorctl stop {service}"
+        else:
+            command = f"systemctl stop {service}"
         message = f"Node {node[u'host']} failed to stop service {service}"
 
         exec_cmd_no_error(
@@ -207,42 +211,25 @@ class DUTSetup:
         exec_cmd_no_error(node, cmd, message=f"{program} is not installed")
 
     @staticmethod
-    def get_pid(node, process):
+    def get_pid(node, process, retries=3):
         """Get PID of running process.
 
         :param node: DUT node.
         :param process: process name.
+        :param retries: How many times to retry on failure.
         :type node: dict
         :type process: str
+        :type retries: int
         :returns: PID
         :rtype: int
         :raises RuntimeError: If it is not possible to get the PID.
         """
-        ssh = SSH()
-        ssh.connect(node)
-
-        retval = None
-        for i in range(3):
-            logger.trace(f"Try {i}: Get {process} PID")
-            ret_code, stdout, stderr = ssh.exec_command(f"pidof {process}")
-
-            if int(ret_code):
-                raise RuntimeError(
-                    f"Not possible to get PID of {process} process on node: "
-                    f"{node[u'host']}\n {stdout + stderr}"
-                )
-
-            pid_list = stdout.split()
-            if len(pid_list) == 1:
-                return [int(stdout)]
-            if not pid_list:
-                logger.debug(f"No {process} PID found on node {node[u'host']}")
-                continue
-            logger.debug(f"More than one {process} PID found " \
-                         f"on node {node[u'host']}")
-            retval = [int(pid) for pid in pid_list]
-
-        return retval
+        cmd = f"pidof {process}"
+        stdout, _ = exec_cmd_no_error(
+            node, cmd, retries=retries,
+            message=f"No {process} PID found on node {node[u'host']}")
+        pid_list = stdout.split()
+        return [int(pid) for pid in pid_list]
 
     @staticmethod
     def get_vpp_pids(nodes):
@@ -266,7 +253,7 @@ class DUTSetup:
         initialize or remove VFs on QAT.
 
         :param node: DUT node.
-        :crypto_type: Crypto device type - HW_DH895xcc or HW_C3xxx.
+        :crypto_type: Crypto device type - HW_DH895xcc, HW_C3xxx or HW_C4xxx.
         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
         :param force_init: If True then try to initialize to specific value.
         :type node: dict
@@ -294,7 +281,7 @@ class DUTSetup:
         """Init Crypto QAT device virtual functions on DUT.
 
         :param node: DUT node.
-        :crypto_type: Crypto device type - HW_DH895xcc or HW_C3xxx.
+        :crypto_type: Crypto device type - HW_DH895xcc, HW_C3xxx or HW_C4xxx.
         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
         :type node: dict
         :type crypto_type: string
@@ -308,6 +295,9 @@ class DUTSetup:
         elif crypto_type == u"HW_C3xxx":
             kernel_mod = u"qat_c3xxx"
             kernel_drv = u"c3xxx"
+        elif crypto_type == u"HW_C4xxx":
+            kernel_mod = u"qat_c4xxx"
+            kernel_drv = u"c4xxx"
         else:
             raise RuntimeError(
                 f"Unsupported crypto device type on {node[u'host']}"
@@ -400,6 +390,20 @@ class DUTSetup:
         :type numvfs: int
         :raises RuntimeError: Failed to create VFs on PCI.
         """
+        cmd = f"test -f /sys/bus/pci/devices/{pf_pci_addr}/sriov_numvfs"
+        sriov_unsupported, _, _ = exec_cmd(node, cmd)
+        # if sriov_numvfs doesn't exist, then sriov_unsupported != 0
+        if int(sriov_unsupported):
+            if numvfs == 0:
+                # sriov is not supported and we want 0 VFs
+                # no need to do anything
+                return
+
+            raise RuntimeError(
+                f"Can't configure {numvfs} VFs on {pf_pci_addr} device "
+                f"on {node[u'host']} since it doesn't support SR-IOV."
+            )
+
         pci = pf_pci_addr.replace(u":", r"\:")
         command = f"sh -c \"echo {numvfs} | " \
             f"tee /sys/bus/pci/devices/{pci}/sriov_numvfs\""
@@ -430,16 +434,23 @@ class DUTSetup:
         )
 
     @staticmethod
-    def pci_driver_unbind_list(node, *pci_addrs):
-        """Unbind PCI devices from current driver on node.
+    def unbind_pci_devices_from_other_driver(node, driver, *pci_addrs):
+        """Unbind PCI devices from driver other than input driver on node.
 
         :param node: DUT node.
+        :param driver: Driver to not unbind from. If None or empty string,
+            will attempt to unbind from the current driver.
         :param pci_addrs: PCI device addresses.
         :type node: dict
+        :type driver: str
         :type pci_addrs: list
         """
         for pci_addr in pci_addrs:
-            DUTSetup.pci_driver_unbind(node, pci_addr)
+            cur_driver = DUTSetup.get_pci_dev_driver(node, pci_addr)
+            if not cur_driver:
+                return
+            if not driver or cur_driver != driver:
+                DUTSetup.pci_driver_unbind(node, pci_addr)
 
     @staticmethod
     def pci_driver_bind(node, pci_addr, driver):
@@ -543,61 +554,24 @@ class DUTSetup:
     def get_pci_dev_driver(node, pci_addr):
         """Get current PCI device driver on node.
 
-        .. note::
-            # lspci -vmmks 0000:00:05.0
-            Slot:   00:05.0
-            Class:  Ethernet controller
-            Vendor: Red Hat, Inc
-            Device: Virtio network device
-            SVendor:        Red Hat, Inc
-            SDevice:        Device 0001
-            PhySlot:        5
-            Driver: virtio-pci
-
         :param node: DUT node.
         :param pci_addr: PCI device address.
         :type node: dict
         :type pci_addr: str
         :returns: Driver or None
-        :raises RuntimeError: If PCI rescan or lspci command execution failed.
         :raises RuntimeError: If it is not possible to get the interface driver
             information from the node.
         """
-        ssh = SSH()
-        ssh.connect(node)
-
-        for i in range(3):
-            logger.trace(f"Try number {i}: Get PCI device driver")
-
-            cmd = f"lspci -vmmks {pci_addr}"
-            ret_code, stdout, _ = ssh.exec_command(cmd)
-            if int(ret_code):
-                raise RuntimeError(f"'{cmd}' failed on '{node[u'host']}'")
-
-            for line in stdout.splitlines():
-                if not line:
-                    continue
-                name = None
-                value = None
-                try:
-                    name, value = line.split(u"\t", 1)
-                except ValueError:
-                    if name == u"Driver:":
-                        return None
-                if name == u"Driver:":
-                    return value
-
-            if i < 2:
-                logger.trace(
-                    f"Driver for PCI device {pci_addr} not found, "
-                    f"executing pci rescan and retrying"
-                )
-                cmd = u"sh -c \"echo 1 > /sys/bus/pci/rescan\""
-                ret_code, _, _ = ssh.exec_command_sudo(cmd)
-                if int(ret_code) != 0:
-                    raise RuntimeError(f"'{cmd}' failed on '{node[u'host']}'")
-
-        return None
+        driver_path = f"/sys/bus/pci/devices/{pci_addr}/driver"
+        cmd = f"test -d {driver_path}"
+        ret_code, ret_val, _ = exec_cmd(node, cmd)
+        if int(ret_code):
+            # the directory doesn't exist which means the device is not bound
+            # to any driver
+            return None
+        cmd = f"basename $(readlink -f {driver_path})"
+        ret_val, _ = exec_cmd_no_error(node, cmd)
+        return ret_val.strip()
 
     @staticmethod
     def verify_kernel_module(node, module, force_load=False):
@@ -686,6 +660,9 @@ class DUTSetup:
         for node in nodes.values():
             message = f"Failed to install VPP on host {node[u'host']}!"
             if node[u"type"] == NodeType.DUT:
+                command = "mkdir -p /var/log/vpp/"
+                exec_cmd(node, command, sudo=True)
+
                 command = u"ln -s /dev/null /etc/sysctl.d/80-vpp.conf || true"
                 exec_cmd_no_error(node, command, sudo=True)
 
@@ -699,7 +676,7 @@ class DUTSetup:
                     )
                     # workaround to avoid installation of vpp-api-python
                     exec_cmd_no_error(
-                        node, u"rm -f {vpp_pkg_dir}vpp-api-python.deb",
+                        node, f"rm -f {vpp_pkg_dir}vpp-api-python.deb",
                         timeout=120, sudo=True
                     )
                     exec_cmd_no_error(
@@ -716,7 +693,7 @@ class DUTSetup:
                     )
                     # workaround to avoid installation of vpp-api-python
                     exec_cmd_no_error(
-                        node, u"rm -f {vpp_pkg_dir}vpp-api-python.rpm",
+                        node, f"rm -f {vpp_pkg_dir}vpp-api-python.rpm",
                         timeout=120, sudo=True
                     )
                     exec_cmd_no_error(