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