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