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