+from resources.libraries.python.Constants import Constants
+from resources.libraries.python.ssh import SSH, exec_cmd, exec_cmd_no_error
+from resources.libraries.python.topology import NodeType, Topology
+
+
+class DUTSetup:
+ """Contains methods for setting up DUTs."""
+
+ @staticmethod
+ def get_service_logs(node, service):
+ """Get specific service unit logs from node.
+
+ :param node: Node in the topology.
+ :param service: Service unit name.
+ :type node: dict
+ :type service: str
+ """
+ command = u"echo $(< /tmp/*supervisor*.log)"\
+ if DUTSetup.running_in_container(node) \
+ else f"journalctl --no-pager --unit={service} " \
+ f"--since=\"$(echo `systemctl show -p ActiveEnterTimestamp " \
+ f"{service}` | awk \'{{print $2 $3}}\')\""
+ message = f"Node {node[u'host']} failed to get logs from unit {service}"
+
+ exec_cmd_no_error(
+ node, command, timeout=30, sudo=True, message=message
+ )
+
+ @staticmethod
+ def get_service_logs_on_all_duts(nodes, service):
+ """Get specific service unit logs from all DUTs.
+
+ :param nodes: Nodes in the topology.
+ :param service: Service unit name.
+ :type nodes: dict
+ :type service: str
+ """
+ for node in nodes.values():
+ if node[u"type"] == NodeType.DUT:
+ DUTSetup.get_service_logs(node, service)
+
+ @staticmethod
+ def restart_service(node, service):
+ """Restart the named service on node.
+
+ :param node: Node in the topology.
+ :param service: Service unit name.
+ :type node: dict
+ :type service: str
+ """
+ command = f"supervisorctl restart {service}" \
+ if DUTSetup.running_in_container(node) \
+ else f"service {service} restart"
+ message = f"Node {node[u'host']} failed to restart service {service}"
+
+ exec_cmd_no_error(
+ node, command, timeout=180, sudo=True, message=message
+ )
+
+ DUTSetup.get_service_logs(node, service)
+
+ @staticmethod
+ def restart_service_on_all_duts(nodes, service):
+ """Restart the named service on all DUTs.
+
+ :param nodes: Nodes in the topology.
+ :param service: Service unit name.
+ :type nodes: dict
+ :type service: str
+ """
+ for node in nodes.values():
+ if node[u"type"] == NodeType.DUT:
+ DUTSetup.restart_service(node, service)
+
+ @staticmethod
+ def start_service(node, service):
+ """Start up the named service on node.
+
+ :param node: Node in the topology.
+ :param service: Service unit name.
+ :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"
+ message = f"Node {node[u'host']} failed to start service {service}"
+
+ exec_cmd_no_error(
+ node, command, timeout=180, sudo=True, message=message
+ )
+
+ DUTSetup.get_service_logs(node, service)
+
+ @staticmethod
+ def start_service_on_all_duts(nodes, service):
+ """Start up the named service on all DUTs.
+
+ :param nodes: Nodes in the topology.
+ :param service: Service unit name.
+ :type nodes: dict
+ :type service: str
+ """
+ for node in nodes.values():
+ if node[u"type"] == NodeType.DUT:
+ DUTSetup.start_service(node, service)
+
+ @staticmethod
+ def stop_service(node, service):
+ """Stop the named service on node.
+
+ :param node: Node in the topology.
+ :param service: Service unit name.
+ :type node: dict
+ :type service: str
+ """
+ DUTSetup.get_service_logs(node, service)
+
+ command = f"supervisorctl stop {service}" \
+ if DUTSetup.running_in_container(node) \
+ else f"service {service} stop"
+ message = f"Node {node[u'host']} failed to stop service {service}"
+
+ exec_cmd_no_error(
+ node, command, timeout=180, sudo=True, message=message
+ )
+
+ @staticmethod
+ def stop_service_on_all_duts(nodes, service):
+ """Stop the named service on all DUTs.
+
+ :param nodes: Nodes in the topology.
+ :param service: Service unit name.
+ :type nodes: dict
+ :type service: str
+ """
+ for node in nodes.values():
+ if node[u"type"] == NodeType.DUT:
+ DUTSetup.stop_service(node, service)
+
+ @staticmethod
+ def kill_program(node, program, namespace=None):
+ """Kill program on the specified topology node.
+
+ :param node: Topology node.
+ :param program: Program name.
+ :param namespace: Namespace program is running in.
+ :type node: dict
+ :type program: str
+ :type namespace: str
+ """
+ host = node[u"host"]
+ cmd_timeout = 5
+ if namespace in (None, u"default"):
+ shell_cmd = u"sh -c"
+ else:
+ shell_cmd = f"ip netns exec {namespace} sh -c"
+
+ pgrep_cmd = f"{shell_cmd} \'pgrep {program}\'"
+ ret_code, _, _ = exec_cmd(node, pgrep_cmd, timeout=cmd_timeout,
+ sudo=True)
+ if ret_code == 0:
+ logger.trace(f"{program} is not running on {host}")
+ return
+ ret_code, _, _ = exec_cmd(node, f"{shell_cmd} \'pkill {program}\'",
+ timeout=cmd_timeout, sudo=True)
+ for attempt in range(5):
+ ret_code, _, _ = exec_cmd(node, pgrep_cmd, timeout=cmd_timeout,
+ sudo=True)
+ if ret_code != 0:
+ logger.trace(f"Attempt {attempt}: {program} is dead on {host}")
+ return
+ sleep(1)
+ logger.trace(f"SIGKILLing {program} on {host}")
+ ret_code, _, _ = exec_cmd(node, f"{shell_cmd} \'pkill -9 {program}\'",
+ timeout=cmd_timeout, sudo=True)