1#!/usr/bin/env python 2 3r""" 4This module is the python counterpart to obmc_boot_test. 5""" 6 7from tally_sheet import * 8import gen_robot_print as grp 9import gen_robot_plug_in as grpi 10import state as st 11 12import os 13import time 14import subprocess 15import glob 16 17from robot.utils import DotDict 18from robot.libraries.BuiltIn import BuiltIn 19from robot.libraries.OperatingSystem import OperatingSystem 20 21# Create boot_results_fields for use in creating boot_results. 22boot_results_fields = DotDict([('total', 0), ('pass', 0), ('fail', 0)]) 23# Create boot_results which is global to this module. 24boot_results = tally_sheet('boot type', 25 boot_results_fields, 26 'boot_test_results') 27 28boot_results.set_sum_fields(['total', 'pass', 'fail']) 29boot_results.set_calc_fields(['total=pass+fail']) 30 31 32############################################################################### 33def plug_in_setup(): 34 35 r""" 36 Initialize all plug-in environment variables for use by the plug-in 37 programs. 38 """ 39 40 boot_pass = int(BuiltIn().get_variable_value("${boot_pass}")) 41 if boot_pass > 1: 42 test_really_running = 1 43 else: 44 test_really_running = 0 45 46 BuiltIn().set_global_variable("${test_really_running}", 47 test_really_running) 48 49 next_boot = BuiltIn().get_variable_value("${next_boot}") 50 BuiltIn().set_global_variable("${boot_type_desc}", next_boot) 51 52 # Setting master_pid correctly influences the behavior of plug-ins like 53 # DB_Logging 54 program_pid = BuiltIn().get_variable_value("${program_pid}") 55 try: 56 master_pid = OperatingSystem().get_environment_variable( 57 "AUTOBOOT_MASTER_PID") 58 except RuntimeError: 59 master_pid = program_pid 60 if master_pid == "": 61 master_pid = program_pid 62 63 BuiltIn().set_global_variable("${master_pid}", master_pid) 64 65 seconds = time.time() 66 loc_time = time.localtime(seconds) 67 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time) 68 69 openbmc_nickname = BuiltIn().get_variable_value("${openbmc_nickname}") 70 openbmc_host = BuiltIn().get_variable_value("${openbmc_host}") 71 if openbmc_nickname == "": 72 openbmc_nickname = openbmc_host 73 ffdc_prefix = openbmc_nickname 74 75 ffdc_prefix += "." + time_string 76 77 try: 78 ffdc_dir_path = os.environ['FFDC_DIR_PATH'] 79 # Add trailing slash. 80 ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep 81 except KeyError: 82 ffdc_dir_path = "" 83 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path) 84 85 status_dir_path = os.environ.get('STATUS_DIR_PATH', "") 86 if status_dir_path != "": 87 # Add trailing slash. 88 status_dir_path = os.path.normpath(status_dir_path) + os.sep 89 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path) 90 91 base_tool_dir_path = os.environ.get('AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp") 92 base_tool_dir_path = os.path.normpath(base_tool_dir_path) + os.sep 93 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path) 94 95 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\ 96 "/FFDC_FILE_LIST" 97 98 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}", 99 ffdc_list_file_path) 100 101 # For each program parameter, set the corresponding AUTOBOOT_ environment 102 # variable value. Also, set an AUTOBOOT_ environment variable for every 103 # element in additional_values. 104 additional_values = ["boot_type_desc", "boot_success", "boot_pass", 105 "boot_fail", "test_really_running", "program_pid", 106 "master_pid", "ffdc_prefix", "ffdc_dir_path", 107 "status_dir_path", "base_tool_dir_path", 108 "ffdc_list_file_path"] 109 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix) 110 111 parm_list = BuiltIn().get_variable_value("@{parm_list}") 112 113 plug_in_vars = parm_list + additional_values 114 115 for var_name in plug_in_vars: 116 var_value = BuiltIn().get_variable_value("${" + var_name + "}") 117 var_name = var_name.upper() 118 if var_value is None: 119 var_value = "" 120 OperatingSystem().set_environment_variable( 121 "AUTOBOOT_" + var_name, var_value) 122 123 debug = int(BuiltIn().get_variable_value("${debug}")) 124 if debug: 125 cmd_buf = "printenv | egrep AUTOBOOT_ | sort -u" 126 grp.rpissuing(cmd_buf) 127 sub_proc = subprocess.Popen(cmd_buf, shell=True, 128 stdout=subprocess.PIPE, 129 stderr=subprocess.STDOUT) 130 out_buf, err_buf = sub_proc.communicate() 131 shell_rc = sub_proc.returncode 132 grp.rprint(out_buf) 133 134############################################################################### 135 136 137############################################################################### 138def create_boot_results_table(): 139 140 r""" 141 Create our boot_results_table. 142 """ 143 144 # At some point we'll want to change to reading in our boot types from 145 # some external source (e.g. file). 146 147 boot_results.add_row('BMC Power On') 148 boot_results.add_row('BMC Power Off') 149 150############################################################################### 151 152 153############################################################################### 154def update_boot_results_table(boot_type, 155 boot_status): 156 157 r""" 158 Update our boot_results_table. This includes: 159 - Updating the record for the given boot_type by incrementing the pass or 160 fail field. 161 - Calling the calc method to have the totals, etc. calculated. 162 - Updating global variables boot_pass/boot_fail. 163 164 Description of arguments: 165 boot_type The type of boot just done (e.g. "BMC Power On"). 166 boot_status The status of the boot just done. This should be equal to 167 either "pass" or "fail" (case-insensitive). 168 """ 169 170 boot_results.inc_row_field(boot_type, boot_status.lower()) 171 totals_line = boot_results.calc() 172 173 # The caller of obmc_boot_test can pass boot_pass/boot_fail values because 174 # the caller may have already done some testing (e.g. "BMC OOB"). For the 175 # sake of DB logging done by plug-ins, we want to include these in our 176 # overall totals. 177 initial_boot_pass = int(BuiltIn().get_variable_value( 178 "${initial_boot_pass}")) 179 initial_boot_fail = int(BuiltIn().get_variable_value( 180 "${initial_boot_fail}")) 181 182 BuiltIn().set_global_variable("${boot_pass}", 183 totals_line['pass'] + initial_boot_pass) 184 BuiltIn().set_global_variable("${boot_fail}", 185 totals_line['fail'] + initial_boot_fail) 186 187############################################################################### 188 189 190############################################################################### 191def print_boot_results_table(header_footer="\n"): 192 193 r""" 194 Print the formatted boot_resuls_table to the console. 195 """ 196 197 grp.rqprint(header_footer) 198 grp.rqprint(boot_results.sprint_report()) 199 grp.rqprint(header_footer) 200 201############################################################################### 202 203 204############################################################################### 205def select_boot(state): 206 207 r""" 208 Select a boot test to be run based on our current state and return the 209 chosen boot type. 210 211 Description of arguments: 212 state The state of the machine, which will include the power state.. 213 """ 214 215 if 'chassis' in state: 216 # New style state. 217 if state['chassis'] == 'Off': 218 boot = 'BMC Power On' 219 else: 220 boot = 'BMC Power Off' 221 else: 222 # Old style state. 223 if state['power'] == 0: 224 boot = 'BMC Power On' 225 else: 226 boot = 'BMC Power Off' 227 228 return boot 229 230############################################################################### 231 232 233############################################################################### 234def my_ffdc(): 235 236 r""" 237 Collect FFDC data. 238 """ 239 240 plug_in_setup() 241 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 242 call_point='ffdc', stop_on_plug_in_failure=1) 243 244 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX'] 245 246 # FFDC_LOG_PATH is used by "FFDC" keyword. 247 FFDC_DIR_PATH = BuiltIn().get_variable_value("${FFDC_DIR_PATH}") 248 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", 249 FFDC_DIR_PATH) 250 251 cmd_buf = ["FFDC", "ffdc_prefix=" + AUTOBOOT_FFDC_PREFIX] 252 grp.rpissuing_keyword(cmd_buf) 253 BuiltIn().run_keyword(*cmd_buf) 254 255 state = st.get_state() 256 BuiltIn().set_global_variable("${state}", 257 state) 258 259 cmd_buf = ["Print Defect Report"] 260 grp.rpissuing_keyword(cmd_buf) 261 BuiltIn().run_keyword(*cmd_buf) 262 263############################################################################### 264 265 266############################################################################### 267def print_last_boots(): 268 269 r""" 270 Print the last ten boots done with their time stamps. 271 """ 272 273 # indent 0, 90 chars wide, linefeed, char is "=" 274 grp.rqprint_dashes(0, 90) 275 grp.rqprintn("Last 10 boots:\n") 276 last_ten = BuiltIn().get_variable_value("${LAST_TEN}") 277 278 for boot_entry in last_ten: 279 grp.rqprint(boot_entry) 280 grp.rqprint_dashes(0, 90) 281 282############################################################################### 283 284 285############################################################################### 286def print_test_start_message(boot_keyword): 287 288 r""" 289 Print a message indicating what boot test is about to run. 290 291 Description of arguments: 292 boot_keyword The name of the boot which is to be run 293 (e.g. "BMC Power On"). 294 """ 295 296 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".") 297 grp.rqprint(doing_msg) 298 299 last_ten = BuiltIn().get_variable_value("${LAST_TEN}") 300 last_ten.append(doing_msg) 301 302 if len(last_ten) > 10: 303 del last_ten[0] 304 305############################################################################### 306 307 308############################################################################### 309def print_defect_report(): 310 311 r""" 312 Print a defect report. 313 """ 314 315 grp.rqprintn() 316 # indent=0, width=90, linefeed=1, char="=" 317 grp.rqprint_dashes(0, 90, 1, "=") 318 grp.rqprintn("Copy this data to the defect:\n") 319 320 parm_list = BuiltIn().get_variable_value("${parm_list}") 321 322 grp.rqpvars(*parm_list) 323 324 grp.rqprintn() 325 326 print_last_boots() 327 grp.rqprintn() 328 state = BuiltIn().get_variable_value("${state}") 329 grp.rqpvar(state) 330 331 # At some point I'd like to have the 'Call FFDC Methods' return a list 332 # of files it has collected. In that case, the following "ls" command 333 # would no longer be needed. For now, however, glob shows the files 334 # named in FFDC_LIST_FILE_PATH so I will refrain from printing those 335 # out (so we don't see duplicates in the list). 336 337 LOG_PREFIX = BuiltIn().get_variable_value("${LOG_PREFIX}") 338 339 output = '\n'.join(glob.glob(LOG_PREFIX + '*')) 340 341 FFDC_LIST_FILE_PATH = \ 342 BuiltIn().get_variable_value("${FFDC_LIST_FILE_PATH}") 343 344 try: 345 ffdc_list = open(FFDC_LIST_FILE_PATH, 'r') 346 except IOError: 347 ffdc_list = "" 348 349 status_file_path = BuiltIn().get_variable_value("${status_file_path}") 350 351 grp.rqprintn() 352 grp.rqprintn("FFDC data files:") 353 if status_file_path != "": 354 grp.rqprintn(status_file_path) 355 356 grp.rqprintn(output) 357 # grp.rqprintn(ffdc_list) 358 grp.rqprintn() 359 360 grp.rqprint_dashes(0, 90, 1, "=") 361 362############################################################################### 363