1#!/usr/bin/env python3 2 3import os 4import sys 5 6from ffdc_collector import ffdc_collector 7from robot.libraries.BuiltIn import BuiltIn as robotBuildIn 8from ssh_utility import SSHRemoteclient 9 10sys.path.append(__file__.split(__file__.split("/")[-1])[0] + "../ffdc") 11 12# (Sub) String constants used for input dictionary key search 13HOST = "HOST" 14USER = "USERNAME" 15PASSWD = "PASSWORD" 16CONFIG = "CONFIG" 17TYPE = "TYPE" 18LOC = "LOCATION" 19PROTOCOL = "PROTOCOL" 20ENV_VARS = "ENV_VARS" 21ECONFIG = "ECONFIG" 22LOGLEVEL = "LOG" 23 24 25def ffdc_robot_script_cli(**kwargs): 26 r""" 27 28 For the specified host, this method provide automation testcases the interface to 29 the new ffdc collector ../ffdc/ffdc_collector.py via robot variable FFDC_DEFAULT 30 31 variable FFDC_DEFAULT:1, by default use the existing ffdc collection method. 32 variable FFDC_DEFAULT:0 use the new ffdc method 33 34 Command examples: 35 (1) Legacy ffdc collection 36 python3 -m robot -v OPENBMC_HOST:<> -v OPENBMC_USERNAME:<> \ 37 -v OPENBMC_PASSWORD:<> ./tools/myffdc.robot 38 (2) New ffdc collection 39 python3 -m robot -v OPENBMC_HOST:<> -v OPENBMC_USERNAME:<> \ 40 -v OPENBMC_PASSWORD:<> -v FFDC_DEFAULT:0 ./tools/myffdc.robot 41 42 Description of argument(s)in dictionary: xx can be anything appropriate 43 44 xx_HOST:hostname name/ip of the targeted (remote) system 45 xx_USERNAME:username user on the targeted system with access to FFDC files 46 xx_PASSWORD:password password for user on targeted system 47 xx_CONFIG:ffdc_config configuration file listing commands and files for FFDC 48 xx_LOCATION:location where to store collected FFDC. Default: <current dir>/logs/ 49 xx_TYPE:remote_type os type of the remote host. 50 xx_PROTOCOL:remote_protocol Protocol to use to collect data. Default: 'ALL' 51 ENV_VAR:env_vars User define CLI env vars '{"key : "value"}'. Default: "" 52 ECONFIG:econfig User define env vars YAML file. Default: "" 53 LOG_LEVEL:log_level CRITICAL, ERROR, WARNING, INFO, DEBUG. Default: INFO 54 55 Code examples: 56 (1) openbmc_ffdc.robot activate this method with no parm 57 Run Keyword If ${FFDC_DEFAULT} == ${1} FFDC 58 ... ELSE ffdc_robot_script_cli 59 60 (2) Method invocation with parms 61 ffdc_from = {'OS_HOST' : 'os host name or ip', 62 'OS_USERNAME' : 'os username', 63 'OS_PASSWORD' : 'password for os_username', 64 'OS_TYPE' : 'os_type, ubuntu, rhel, aix, etc', 65 } 66 ffdc_robot_script_cli(ffdc_from) 67 68 """ 69 70 robotBuildIn().log_to_console("Collecting FFDC - CLI log collector script") 71 72 if not kwargs: 73 dict_of_parms = {} 74 # When method is invoked with no parm, 75 # use robot variables 76 # OPENBMC_HOST, OPENBMC_USERNAME, OPENBMC_PASSWORD, OPENBMC (type) 77 dict_of_parms["OPENBMC_HOST"] = robotBuildIn().get_variable_value( 78 "${OPENBMC_HOST}", default=None 79 ) 80 dict_of_parms["OPENBMC_USERNAME"] = robotBuildIn().get_variable_value( 81 "${OPENBMC_USERNAME}", default=None 82 ) 83 dict_of_parms["OPENBMC_PASSWORD"] = robotBuildIn().get_variable_value( 84 "${OPENBMC_PASSWORD}", default=None 85 ) 86 dict_of_parms["REMOTE_TYPE"] = "OPENBMC" 87 88 run_ffdc_collector(dict_of_parms) 89 90 else: 91 if isinstance(kwargs, dict): 92 # When method is invoked with user defined dictionary, 93 # dictionary keys has the following format 94 # xx_HOST; xx_USERNAME, xx_PASSWORD, xx_TYPE 95 # where xx is one of OPENBMC, OS, or os_type LINUX/UBUNTU/AIX 96 run_ffdc_collector(**kwargs) 97 98 99def run_ffdc_collector(dict_of_parm): 100 r""" 101 102 Process input parameters and collect information 103 104 Description of argument(s)in dictionary: xx can be anything appropriate 105 106 xx_HOST:hostname name/ip of the targeted (remote) system 107 xx_USERNAME:username user on the targeted system with access to FFDC files 108 xx_PASSWORD:password password for user on targeted system 109 xx_CONFIG:ffdc_config configuration file listing commands and files for FFDC 110 xx_LOCATION:location where to store collected FFDC. Default: <current dir>/logs/ 111 xx_TYPE:remote_type os type of the remote host. 112 xx_PROTOCOL:remote_protocol Protocol to use to collect data. Default: 'ALL' 113 ENV_VAR:env_vars User define CLI env vars '{"key : "value"}'. Default: "" 114 ECONFIG:econfig User define env vars YAML file. Default: "" 115 LOG_LEVEL:log_level CRITICAL, ERROR, WARNING, INFO, DEBUG. Default: INFO 116 117 """ 118 119 # Clear local variables 120 remote = None 121 username = None 122 password = None 123 config = None 124 location = None 125 remote_type = None 126 protocol = None 127 env_vars = None 128 econfig = None 129 log_level = None 130 131 # Process input key/value pairs 132 for key in dict_of_parm.keys(): 133 if HOST in key: 134 remote = dict_of_parm[key] 135 elif USER in key: 136 username = dict_of_parm[key] 137 elif PASSWD in key: 138 password = dict_of_parm[key] 139 elif CONFIG in key: 140 config = dict_of_parm[key] 141 elif LOC in key: 142 location = dict_of_parm[key] 143 elif TYPE in key: 144 remote_type = dict_of_parm[key] 145 elif PROTOCOL in key: 146 protocol = dict_of_parm[key] 147 elif ENV_VARS in key: 148 env_vars = dict_of_parm[key] 149 elif ECONFIG in key: 150 econfig = dict_of_parm[key] 151 elif LOGLEVEL in key: 152 log_level = dict_of_parm[key] 153 154 # Set defaults values for parms 155 # that are not specified with input and have acceptable defaults. 156 if not location: 157 # Default FFDC store location 158 location = ( 159 robotBuildIn().get_variable_value("${EXECDIR}", default=None) 160 + "/logs" 161 ) 162 ffdc_collector.validate_local_store(location) 163 164 if not config: 165 # Default FFDC configuration 166 script_path = os.path.dirname(os.path.abspath(__file__)) 167 config = script_path + "/../ffdc/ffdc_config.yaml" 168 169 if not protocol: 170 protocol = "ALL" 171 172 if not env_vars: 173 env_vars = "" 174 175 if not econfig: 176 econfig = "" 177 178 if not log_level: 179 log_level = "INFO" 180 181 # If minimum required inputs are met, go collect. 182 if remote and username and password and remote_type: 183 # Execute data collection 184 this_ffdc = ffdc_collector( 185 remote, 186 username, 187 password, 188 config, 189 location, 190 remote_type, 191 protocol, 192 env_vars, 193 econfig, 194 log_level, 195 ) 196 this_ffdc.collect_ffdc() 197 198 # If original ffdc request is for BMC, 199 # attempt to also collect ffdc for HOST_OS if possible. 200 if remote_type.upper() == "OPENBMC": 201 os_host = robotBuildIn().get_variable_value( 202 "${OS_HOST}", default=None 203 ) 204 os_username = robotBuildIn().get_variable_value( 205 "${OS_USERNAME}", default=None 206 ) 207 os_password = robotBuildIn().get_variable_value( 208 "${OS_PASSWORD}", default=None 209 ) 210 211 if os_host and os_username and os_password: 212 os_type = get_os_type(os_host, os_username, os_password) 213 if os_type: 214 os_ffdc = ffdc_collector( 215 os_host, 216 os_username, 217 os_password, 218 config, 219 location, 220 os_type, 221 protocol, 222 env_vars, 223 econfig, 224 log_level, 225 ) 226 os_ffdc.collect_ffdc() 227 228 229def get_os_type(os_host, os_username, os_password): 230 os_type = None 231 232 # If HOST_OS is pingable 233 if os.system("ping -c 1 " + os_host) == 0: 234 r""" 235 Open a ssh connection to targeted system. 236 """ 237 ssh_remoteclient = SSHRemoteclient(os_host, os_username, os_password) 238 239 if ssh_remoteclient.ssh_remoteclient_login(): 240 # Find OS_TYPE 241 cmd_exit_code, err, response = ssh_remoteclient.execute_command( 242 "uname" 243 ) 244 os_type = response.strip() 245 246 # If HOST_OS is linux, expands os_type to one of 247 # the 2 linux distros that have more details in ffdc_config.yaml 248 if os_type.upper() == "LINUX": 249 ( 250 cmd_exit_code, 251 err, 252 response, 253 ) = ssh_remoteclient.execute_command("cat /etc/os-release") 254 linux_distro = response 255 if "redhat" in linux_distro: 256 os_type = "RHEL" 257 elif "ubuntu" in linux_distro: 258 os_type = "UBUNTU" 259 260 if ssh_remoteclient: 261 ssh_remoteclient.ssh_remoteclient_disconnect() 262 263 return os_type 264