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