1*** Settings *** 2Documentation Open power domain keywords. 3 4Variables ../data/variables.py 5Resource ../lib/utils.robot 6Resource ../lib/connection_client.robot 7Library utilities.py 8 9*** Variables *** 10${functional_cpu_count} ${0} 11${active_occ_count} ${0} 12${OCC_WAIT_TIMEOUT} 4 min 13${fan_json_msg} Unable to create dump on non-JSON config based system 14 15*** Keywords *** 16 17Get OCC Objects 18 [Documentation] Get the OCC objects and return as a list. 19 20 # Example: 21 # { 22 # "/org/open_power/control/occ0": { 23 # "OccActive": 0 24 # }, 25 # "/org/open_power/control/occ1": { 26 # "OccActive": 1 27 # } 28 29 ${occ_list}= Get Endpoint Paths ${OPENPOWER_CONTROL} occ* 30 31 [Return] ${occ_list} 32 33 34Get OCC Active State 35 [Documentation] Get the OCC "OccActive" and return the attribute value. 36 [Arguments] ${value} 37 38 # Description of argument(s): 39 # value CPU position (e.g. "0, 1, 2"). 40 41 ${cmd}= Catenate busctl get-property org.open_power.OCC.Control 42 ... /org/open_power/control/occ${value} org.open_power.OCC.Status OccActive 43 44 ${cmd_output} ${stderr} ${rc} = BMC Execute Command ${cmd} 45 ... print_out=1 print_err=1 ignore_err=1 46 47 # The command returns format 'b true' 48 Return From Keyword If '${cmd_output.split(' ')[-1]}' == 'true' ${1} 49 50 [Return] ${0} 51 52 53Count Object Entries 54 [Documentation] Count the occurrence number of a given object. 55 [Arguments] ${object_base_uri_path} ${object_name} 56 57 # Description of argument(s): 58 # object_base_uri_path Object base path 59 # (e.g. "/org/open_power/control/"). 60 # object_name Object name (e.g. "occ", "cpu" etc). 61 62 ${object_list}= Get Endpoint Paths 63 ... ${object_base_uri_path} ${object_name} 64 ${list_count}= Get Length ${object_list} 65 [Return] ${list_count} 66 67 68Read Object Attribute 69 [Documentation] Return object attribute data. 70 [Arguments] ${object_base_uri_path} ${attribute_name} 71 72 # Description of argument(s): 73 # object_base_uri_path Object path. 74 # (e.g. "/org/open_power/control/occ0"). 75 # attribute_name Object attribute name. 76 77 ${resp}= OpenBMC Get Request 78 ... ${object_base_uri_path}/attr/${attribute_name} quiet=${1} 79 Return From Keyword If ${resp.status_code} != ${HTTP_OK} 80 [Return] ${resp.json()["data"]} 81 82 83Get Functional Processor Count 84 [Documentation] Get functional processor count. 85 86 ${cpu_list}= Redfish.Get Members List /redfish/v1/Systems/system/Processors/ *cpu* 87 88 FOR ${endpoint_path} IN @{cpu_list} 89 # {'Health': 'OK', 'State': 'Enabled'} get only matching status good. 90 ${cpu_status}= Redfish.Get Attribute ${endpoint_path} Status 91 Continue For Loop If '${cpu_status['Health']}' != 'OK' or '${cpu_status['State']}' != 'Enabled' 92 ${functional_cpu_count} = Evaluate ${functional_cpu_count} + 1 93 END 94 95 [Return] ${functional_cpu_count} 96 97 98Get Active OCC State Count 99 [Documentation] Get active OCC state count. 100 101 ${cpu_list}= Redfish.Get Members List /redfish/v1/Systems/system/Processors/ *cpu* 102 103 FOR ${endpoint_path} IN @{cpu_list} 104 ${num}= Set Variable ${endpoint_path[-1]} 105 ${cmd}= Catenate busctl get-property org.open_power.OCC.Control 106 ... /org/open_power/control/occ${num} org.open_power.OCC.Status OccActive 107 108 ${cmd_output} ${stderr} ${rc} = BMC Execute Command ${cmd} 109 ... print_out=1 print_err=1 ignore_err=1 110 111 # The command returns format 'b true' 112 Continue For Loop If '${cmd_output.split(' ')[-1]}' != 'true' 113 ${active_occ_count} = Evaluate ${active_occ_count} + 1 114 END 115 116 [Return] ${active_occ_count} 117 118 119Match OCC And CPU State Count 120 [Documentation] Get CPU functional count and verify OCC count active matches. 121 122 ${cpu_count}= Get Functional Processor Count 123 Log To Console Functional Processor count: ${cpu_count} 124 125 FOR ${num} IN RANGE ${0} ${cpu_count} 126 ${cmd}= Catenate busctl get-property org.open_power.OCC.Control 127 ... /org/open_power/control/occ${num} org.open_power.OCC.Status OccActive 128 129 ${cmd_output} ${stderr} ${rc} = BMC Execute Command ${cmd} 130 ... print_out=1 print_err=1 ignore_err=1 131 132 # The command returns format 'b true' 133 Continue For Loop If '${cmd_output.split(' ')[-1]}' != 'true' 134 ${active_occ_count} = Evaluate ${active_occ_count} + 1 135 END 136 137 Log To Console OCC Active count: ${active_occ_count} 138 139 Should Be Equal ${active_occ_count} ${cpu_count} 140 ... msg=OCC count ${active_occ_count} and CPU Count ${cpu_count} mismatched. 141 142 143Verify OCC State 144 [Documentation] Check OCC active state. 145 [Arguments] ${expected_occ_active}=${1} 146 # Description of Argument(s): 147 # expected_occ_active The expected occ_active value (i.e. 1/0). 148 149 # Example cpu_list data output: 150 # /redfish/v1/Systems/system/Processors/cpu0 151 # /redfish/v1/Systems/system/Processors/cpu1 152 153 ${cpu_list}= Redfish.Get Members List /redfish/v1/Systems/system/Processors/ cpu* 154 155 FOR ${endpoint_path} IN @{cpu_list} 156 # {'Health': 'OK', 'State': 'Enabled'} get only matching status good. 157 ${cpu_status}= Redfish.Get Attribute ${endpoint_path} Status 158 Continue For Loop If '${cpu_status['Health']}' != 'OK' or '${cpu_status['State']}' != 'Enabled' 159 Log To Console ${cpu_status} 160 ${num}= Set Variable ${endpoint_path[-1]} 161 ${occ_active}= Get OCC Active State ${num} 162 Should Be Equal ${occ_active} ${expected_occ_active} 163 ... msg=OCC not in right state 164 END 165 166 167Get Sensors Aggregation Data 168 [Documentation] Return open power sensors aggregation value list. 169 [Arguments] ${object_base_uri_path} 170 171 # Description of argument(s): 172 # object_base_uri_path An object path such as one of the elements 173 # returned by 'Get Sensors Aggregation URL List' 174 # (e.g. "/org/open_power/sensors/aggregation/per_30s/ps0_input_power/average"). 175 176 # Example of aggregation [epoch,time] data: 177 # "Values": [ 178 # [ 179 # 1517815708479, <-- EPOCH 180 # 282 <-- Power value in watts 181 # ], 182 # [ 183 # 1517815678238, 184 # 282 185 # ], 186 # [ 187 # 1517815648102, 188 # 282 189 # ], 190 # ], 191 192 ${resp}= Read Attribute ${object_base_uri_path} Values quiet=${1} 193 ${power_sensors_value_list}= Create List 194 FOR ${entry} IN @{resp} 195 Append To List ${power_sensors_value_list} ${entry[1]} 196 END 197 [Return] ${power_sensors_value_list} 198 199 200Get Sensors Aggregation URL List 201 [Documentation] Return the open power aggregation maximum list and the 202 ... average list URIs. 203 [Arguments] ${object_base_uri_path} 204 205 # Example of the 2 lists returned by this keyword: 206 # avgs: 207 # avgs[0]: /org/open_power/sensors/aggregation/per_30s/ps0_input_power/average 208 # avgs[1]: /org/open_power/sensors/aggregation/per_30s/ps1_input_power/average 209 # maxs: 210 # maxs[0]: /org/open_power/sensors/aggregation/per_30s/ps1_input_power/maximum 211 # maxs[1]: /org/open_power/sensors/aggregation/per_30s/ps0_input_power/maximum 212 213 # Description of argument(s): 214 # object_base_uri_path Object path. 215 # base path "/org/open_power/sensors/" 216 # (e.g. "base path + aggregation/per_30s/ps0_input_power/average") 217 218 # Example of open power sensor aggregation data as returned by the get 219 # request: 220 # /org/open_power/sensors/list 221 # [ 222 # "/org/open_power/sensors/aggregation/per_30s/ps0_input_power/average", 223 # "/org/open_power/sensors/aggregation/per_30s/ps1_input_power/maximum", 224 # "/org/open_power/sensors/aggregation/per_30s/ps0_input_power/maximum", 225 # "/org/open_power/sensors/aggregation/per_30s/ps1_input_power/average" 226 # ] 227 228 ${resp}= OpenBMC Get Request ${object_base_uri_path}list quiet=${1} 229 230 ${power_supply_avg_list}= Create List 231 ${power_supply_max_list}= Create List 232 233 FOR ${entry} IN @{resp.json()["data"]} 234 Run Keyword If 'average' in '${entry}' Append To List ${power_supply_avg_list} ${entry} 235 Run Keyword If 'maximum' in '${entry}' Append To List ${power_supply_max_list} ${entry} 236 END 237 238 [Return] ${power_supply_avg_list} ${power_supply_max_list} 239 240 241REST Verify No Gard Records 242 [Documentation] Verify no gard records are present. 243 244 ${resp}= Read Properties ${OPENPOWER_CONTROL}gard/enumerate 245 Log Dictionary ${resp} 246 Should Be Empty ${resp} msg=Found gard records. 247 248 249Inject OPAL TI 250 [Documentation] OPAL terminate immediate procedure. 251 [Arguments] ${stable_branch}=master 252 ... ${repo_dir_path}=/tmp/repository 253 ... ${repo_github_url}=https://github.com/open-power/op-test 254 255 # Description of arguments: 256 # stable_branch Git branch to clone. (default: master) 257 # repo_dir_path Directory path for repo tool (e.g. "op-test"). 258 # repo_github_url Github URL link (e.g. "https://github.com/open-power/op-test"). 259 260 ${value}= Generate Random String 4 [NUMBERS] 261 262 ${cmd_buf}= Catenate git clone --branch ${stable_branch} ${repo_github_url} ${repo_dir_path}/${value} 263 Shell Cmd ${cmd_buf} 264 265 Open Connection for SCP 266 scp.Put File ${repo_dir_path}/${value}/test_binaries/deadbeef /tmp 267 Pdbg -a putmem 0x300000f8 < /tmp/deadbeef 268 269 # Clean up the repo once done. 270 ${cmd_buf}= Catenate rm -rf ${repo_dir_path}${/}${value} 271 Shell Cmd ${cmd_buf} 272 273 274Trigger OCC Reset 275 [Documentation] Trigger OCC reset request on an active OCC. 276 [Arguments] ${occ_target}=${0} 277 278 # Description of Argument(s): 279 # occ_target Target a valid given OCC number 0,1, etc. 280 281 Log To Console OCC Reset Triggered on OCC ${occ_target} 282 283 ${cmd}= Catenate busctl call org.open_power.OCC.Control 284 ... /org/open_power/control/occ${occ_target} org.open_power.OCC.PassThrough 285 ... Send ai 8 64 0 5 20 82 83 84 0 286 287 ${cmd_output} ${stderr} ${rc} = BMC Execute Command ${cmd} print_out=1 print_err=1 288 289 Log To Console OCC wait check for disabled state. 290 Wait Until Keyword Succeeds 30 sec 5 sec Verify OCC Target State ${occ_target} 291 292 293Verify OCC Target State 294 [Documentation] Verify that the user given state matches th current OCC state. 295 [Arguments] ${occ_target}=${0} ${expected_state}=${0} 296 297 # Description of Argument(s): 298 # occ_target Target a valid given OCC number 0,1, etc. 299 # expected_state For OCC either 0 or 1. Default is 0. 300 301 ${occ_active}= Get OCC Active State ${occ_target} 302 Should Be Equal ${occ_active} ${expected_state} 303 Log To Console Target OCC ${occ_target} state is ${occ_active}. 304 305 306Trigger OCC Reset And Wait For OCC Active State 307 [Documentation] Trigger OCC reset request and wait for OCC to reset back to active state. 308 309 Trigger OCC Reset 310 311 Log To Console OCC wait check for active state. 312 Wait Until Keyword Succeeds ${OCC_WAIT_TIMEOUT} 20 sec Match OCC And CPU State Count 313 314 315Get Sensors Dbus Tree List 316 [Documentation] Get the list dbus path of the given sensor object and 317 ... return the populatedlist. 318 319 ${dbus_obj_var}= Set Variable 320 ... xyz.openbmc_project.HwmonTempSensor 321 ... xyz.openbmc_project.ADCSensor 322 ... xyz.openbmc_project.VirtualSensor 323 324 # Filter only the dbus paths service by the sensor obj. 325 ${sensors_dbus_tree_dict}= Create Dictionary 326 FOR ${dbus_obj} IN @{dbus_obj_var} 327 ${cmd}= Catenate busctl tree ${dbus_obj} --list | grep /sensors/ 328 ${cmd_output} ${stderr} ${rc} = BMC Execute Command ${cmd} 329 ... print_out=0 print_err=0 ignore_err=1 330 Set To Dictionary ${sensors_dbus_tree_dict} ${dbus_obj} ${cmd_output.splitlines()} 331 END 332 333 Rprint Vars sensors_dbus_tree_dict 334 # Key Pair: 'sensor obj":[list of obj URI] 335 # Example: 336 # sensors_dbus_tree_dict: 337 # [xyz.openbmc_project.HwmonTempSensor]: 338 # [0]: /xyz/openbmc_project/sensors/temperature/Ambient_0_Temp 339 # [1]: /xyz/openbmc_project/sensors/temperature/PCIE_0_Temp 340 # [xyz.openbmc_project.ADCSensor]: 341 # [0]: /xyz/openbmc_project/sensors/voltage/Battery_Voltage 342 # [xyz.openbmc_project.VirtualSensor]: 343 # [0]: /xyz/openbmc_project/sensors/temperature/Ambient_Virtual_Temp 344 345 [Return] ${sensors_dbus_tree_dict} 346 347 348Get Populated Sensors Dbus List 349 [Documentation] Perform GET operation on the attribute list and confirm it is 350 ... populated and does not error out during GET request.. 351 352 ${sensor_dict}= Get Sensors Dbus Tree List 353 354 # Loop through the dictionary and iterate item entries. 355 ${valid_dbus_list}= Create List 356 FOR ${key} IN @{sensor_dict.keys()} 357 FOR ${val} IN @{sensor_dict["${key}"]} 358 ${cmd}= Catenate 359 ... busctl get-property ${key} ${val} xyz.openbmc_project.Sensor.Value Value 360 ${cmd_output} ${stderr} ${rc} = BMC Execute Command ${cmd} 361 ... print_out=0 print_err=0 ignore_err=1 362 # Skip failed to get property command on Dbus object. 363 Run Keyword If ${rc} == 0 Append To List ${valid_dbus_list} ${val} 364 END 365 END 366 367 [Return] ${valid_dbus_list} 368 369 370Verify Runtime Sensors Dbus List 371 [Documentation] Load pre-defined sensor JSON Dbus data and validate against 372 ... runtime sensor list generated. 373 374 # Default path data/sensor_dbus.json else takes 375 # user CLI input -v SENSOR_DBUS_JSON_FILE_PATH:<path> 376 ${SENSOR_DBUS_JSON_FILE_PATH}= 377 ... Get Variable Value ${SENSOR_DBUS_JSON_FILE_PATH} data/sensor_dbus.json 378 379 ${json_data}= OperatingSystem.Get File ${SENSOR_DBUS_JSON_FILE_PATH} 380 ${json_sensor_data}= Evaluate json.loads('''${json_data}''') json 381 382 ${runtime_sensor_list}= Get Populated Sensors Dbus List 383 384 ${system_model}= Get BMC System Model 385 Rprint Vars system_model 386 Rprint Vars runtime_sensor_list 387 388 ${status}= Run Keyword And Return Status 389 ... Dictionary Should Contain Value ${json_sensor_data} ${runtime_sensor_list} 390 391 Run Keyword If ${status} == ${False} Log And Fail ${json_sensor_data} 392 393 Log To Console Runtime Dbus sensor list matches. 394 395 396Log And Fail 397 [Documentation] Log detailed failure log on the console. 398 [Arguments] ${json_sensor_data} 399 400 # Description of Argument(s): 401 # json_sensor_data Sensor JSON data from data/sensor_dbus.json. 402 403 Rprint Vars json_sensor_data 404 Fail Runtime generated Dbus sensors does not match 405 406 407Dump Fan Control JSON 408 [Documentation] Execute fan control on BMC to dump config with 'fanctl dump', 409 ... which makes it write a /tmp/fan_control_dump.json file. 410 411 ${output} ${stderr} ${rc} = BMC Execute Command test -f /usr/bin/fanctl 412 ... print_err=1 ignore_err=1 413 Return From Keyword If ${rc} == 1 fanctl application doesn't exist. 414 415 # This command will force a fan_control_dump.json file in temp path and 416 # takes few seconds to complete.. 417 BMC Execute Command fanctl dump 418 Sleep 10s 419 420 421Get Fan JSON Data 422 [Documentation] Read the JSON string file from BMC and return. 423 424 # Check for the generated file and return the file data as JSON and fails if 425 # it doesn't find file generated. 426 ${cmd}= Catenate test -f /tmp/fan_control_dump.json; cat /tmp/fan_control_dump.json 427 ${json_string} ${stderr} ${rc} = BMC Execute Command ${cmd} 428 ... print_out=1 print_err=1 ignore_err=1 429 430 Should Be True ${rc} == 0 msg=No Fan control config JSON file is generated. 431 ${fan_json}= Evaluate json.loads('''${json_string}''') json 432 433 [return] ${fan_json} 434 435 436Get Fan Attribute Value 437 [Documentation] Return the specified value of the matched search key in 438 ... nested dictionary data. 439 [Arguments] ${fan_dict} ${key_value} 440 441 # Description of Argument(s): 442 # key_value User input attribute value in the dictionary. 443 444 ${empty_dicts}= Create Dictionary 445 446 # Check for JSON response data. 447 # { 448 # "msg": "Unable to create dump on non-JSON config based system" 449 # } 450 451 ${status}= Run Keyword And Return Status 452 ... Should Be Equal ${fan_dict["msg"]} ${fan_json_msg} 453 IF ${status} 454 Log To Console Skipping attribute ${key_value} check. 455 Return From Keyword ${empty_dicts} 456 END 457 458 # Python module: get_value_from_nested_dict(key,dict) 459 ${value_list}= utilities.Get Value From Nested Dict ${key_value} ${fan_dict} 460 461 Should Not Be Empty ${value_list} msg=${key_value} key attribute not found. 462 463 [Return] ${value_list[0]} 464