1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright(c) 2010-2014 Intel Corporation 3# Copyright(c) 2022-2023 PANTHEON.tech s.r.o. 4# Copyright(c) 2022-2023 University of New Hampshire 5 6""" 7A node is a generic host that DTS connects to and manages. 8""" 9 10from typing import Any, Callable 11 12from framework.config import ( 13 BuildTargetConfiguration, 14 ExecutionConfiguration, 15 NodeConfiguration, 16) 17from framework.logger import DTSLOG, getLogger 18from framework.remote_session import OSSession, create_session 19from framework.settings import SETTINGS 20 21 22class Node(object): 23 """ 24 Basic class for node management. This class implements methods that 25 manage a node, such as information gathering (of CPU/PCI/NIC) and 26 environment setup. 27 """ 28 29 main_session: OSSession 30 config: NodeConfiguration 31 name: str 32 _logger: DTSLOG 33 _other_sessions: list[OSSession] 34 35 def __init__(self, node_config: NodeConfiguration): 36 self.config = node_config 37 self.name = node_config.name 38 self._logger = getLogger(self.name) 39 self.main_session = create_session(self.config, self.name, self._logger) 40 41 self._other_sessions = [] 42 43 self._logger.info(f"Created node: {self.name}") 44 45 def set_up_execution(self, execution_config: ExecutionConfiguration) -> None: 46 """ 47 Perform the execution setup that will be done for each execution 48 this node is part of. 49 """ 50 self._set_up_execution(execution_config) 51 52 def _set_up_execution(self, execution_config: ExecutionConfiguration) -> None: 53 """ 54 This method exists to be optionally overwritten by derived classes and 55 is not decorated so that the derived class doesn't have to use the decorator. 56 """ 57 58 def tear_down_execution(self) -> None: 59 """ 60 Perform the execution teardown that will be done after each execution 61 this node is part of concludes. 62 """ 63 self._tear_down_execution() 64 65 def _tear_down_execution(self) -> None: 66 """ 67 This method exists to be optionally overwritten by derived classes and 68 is not decorated so that the derived class doesn't have to use the decorator. 69 """ 70 71 def set_up_build_target( 72 self, build_target_config: BuildTargetConfiguration 73 ) -> None: 74 """ 75 Perform the build target setup that will be done for each build target 76 tested on this node. 77 """ 78 self._set_up_build_target(build_target_config) 79 80 def _set_up_build_target( 81 self, build_target_config: BuildTargetConfiguration 82 ) -> None: 83 """ 84 This method exists to be optionally overwritten by derived classes and 85 is not decorated so that the derived class doesn't have to use the decorator. 86 """ 87 88 def tear_down_build_target(self) -> None: 89 """ 90 Perform the build target teardown that will be done after each build target 91 tested on this node. 92 """ 93 self._tear_down_build_target() 94 95 def _tear_down_build_target(self) -> None: 96 """ 97 This method exists to be optionally overwritten by derived classes and 98 is not decorated so that the derived class doesn't have to use the decorator. 99 """ 100 101 def create_session(self, name: str) -> OSSession: 102 """ 103 Create and return a new OSSession tailored to the remote OS. 104 """ 105 session_name = f"{self.name} {name}" 106 connection = create_session( 107 self.config, 108 session_name, 109 getLogger(session_name, node=self.name), 110 ) 111 self._other_sessions.append(connection) 112 return connection 113 114 def close(self) -> None: 115 """ 116 Close all connections and free other resources. 117 """ 118 if self.main_session: 119 self.main_session.close() 120 for session in self._other_sessions: 121 session.close() 122 self._logger.logger_exit() 123 124 @staticmethod 125 def skip_setup(func: Callable[..., Any]) -> Callable[..., Any]: 126 if SETTINGS.skip_setup: 127 return lambda *args: None 128 else: 129 return func 130