1*** Settings ***
2Documentation   This module is for IPMI client for copying ipmitool to
3...             openbmc box and execute ipmitool IPMI standard
4...             command. IPMI raw command will use dbus-send command
5Resource        ../lib/resource.robot
6Resource        ../lib/connection_client.robot
7Resource        ../lib/utils.robot
8Resource        ../lib/state_manager.robot
9
10Library         String
11Library         var_funcs.py
12Library         ipmi_client.py
13Library         ../lib/bmc_ssh_utils.py
14
15*** Variables ***
16${dbusHostIpmicmd1}=   dbus-send --system  ${OPENBMC_BASE_URI}HostIpmi/1
17${dbusHostIpmiCmdReceivedMsg}=   ${OPENBMC_BASE_DBUS}.HostIpmi.ReceivedMessage
18${netfnByte}=          ${EMPTY}
19${cmdByte}=            ${EMPTY}
20${arrayByte}=          array:byte:
21${IPMI_USER_OPTIONS}   ${EMPTY}
22${IPMI_INBAND_CMD}=    ipmitool -C ${IPMI_CIPHER_LEVEL} -N ${IPMI_TIMEOUT} -p ${IPMI_PORT}
23${HOST}=               -H
24${RAW}=                raw
25${IPMITOOL_PATH}       /tmp/ipmitool
26${expected_max_ids}    15
27${empty_name_pattern}  ^User Name\\s.*\\s:\\s$
28
29*** Keywords ***
30
31Run IPMI Command
32    [Documentation]  Run the raw IPMI command.
33    [Arguments]  ${command}  ${fail_on_err}=${1}  &{options}
34
35    # Description of argument(s):
36    # command                       The IPMI command string to be executed
37    #                               (e.g. "power status").
38    # fail_on_err                   Fail if the IPMI command execution fails.
39    # options                       Additional ipmitool command options (e.g.
40    #                               -C=3, -I=lanplus, etc.).  Currently, only
41    #                               used for external IPMI commands.
42
43    ${resp}=  Run Keyword If  '${IPMI_COMMAND}' == 'External'
44    ...    Run External IPMI Raw Command  ${command}  ${fail_on_err}  &{options}
45    ...  ELSE IF  '${IPMI_COMMAND}' == 'Inband'
46    ...    Run Inband IPMI Raw Command  ${command}
47    ...  ELSE IF  '${IPMI_COMMAND}' == 'Dbus'
48    ...    Run Dbus IPMI RAW Command  ${command}
49    ...  ELSE  Fail  msg=Invalid IPMI Command type provided: ${IPMI_COMMAND}
50    RETURN  ${resp}
51
52
53Run IPMI Standard Command
54    [Documentation]  Run the standard IPMI command.
55    [Arguments]  ${command}  ${fail_on_err}=${1}  ${expected_rc}=${0}  &{options}
56
57    # Description of argument(s):
58    # command                       The IPMI command string to be executed
59    #                               (e.g. "0x06 0x36").
60    # fail_on_err                   Fail if the IPMI command execution fails.
61    # expected_rc                   The expected return code from the ipmi
62    #                               command (e.g. ${0}, ${1}, etc.).
63    # options                       Additional ipmitool command options (e.g.
64    #                               -C=3, -I=lanplus, etc.).  Currently, only
65    #                               used for external IPMI commands.
66
67    ${resp}=  Run Keyword If  '${IPMI_COMMAND}' == 'External'
68    ...    Run External IPMI Standard Command  ${command}  ${fail_on_err}  ${expected_rc}  &{options}
69    ...  ELSE IF  '${IPMI_COMMAND}' == 'Inband'
70    ...    Run Inband IPMI Standard Command  ${command}  ${fail_on_err}
71    ...  ELSE IF  '${IPMI_COMMAND}' == 'Dbus'
72    ...    Run Dbus IPMI Standard Command  ${command}
73    ...  ELSE  Fail  msg=Invalid IPMI Command type provided : ${IPMI_COMMAND}
74    RETURN  ${resp}
75
76
77Run Dbus IPMI RAW Command
78    [Documentation]  Run the raw IPMI command through dbus.
79    [Arguments]    ${command}
80    ${valueinBytes}=   Byte Conversion  ${command}
81    ${cmd}=   Catenate   ${dbushostipmicmd1} ${dbusHostIpmiCmdReceivedMsg}
82    ${cmd}=   Catenate   ${cmd} ${valueinBytes}
83    ${output}   ${stderr}=  Execute Command  ${cmd}  return_stderr=True
84    Should Be Empty      ${stderr}
85    set test variable    ${OUTPUT}     "${output}"
86
87
88Run Dbus IPMI Standard Command
89    [Documentation]  Run the standard IPMI command through dbus.
90    [Arguments]    ${command}
91    Copy ipmitool
92    ${stdout}    ${stderr}    ${output}=  Execute Command
93    ...    ${IPMITOOL_PATH} -I dbus ${command}    return_stdout=True
94    ...    return_stderr= True    return_rc=True
95    Should Be Equal    ${output}    ${0}    msg=${stderr}
96    RETURN    ${stdout}
97
98
99Run Inband IPMI Raw Command
100    [Documentation]  Run the raw IPMI command in-band.
101    [Arguments]  ${command}  ${fail_on_err}=${1}  ${os_host}=${OS_HOST}  ${os_username}=${OS_USERNAME}
102    ...          ${os_password}=${OS_PASSWORD}
103
104    # Description of argument(s):
105    # command                       The IPMI command string to be executed
106    #                               (e.g. "0x06 0x36").
107    # os_host                       The host name or IP address of the OS Host.
108    # os_username                   The OS host user name.
109    # os_password                   The OS host passwrd.
110
111    Login To OS Host  ${os_host}  ${os_username}  ${os_password}
112    Check If IPMI Tool Exist
113
114    ${ipmi_cmd}=  Catenate  ${IPMI_INBAND_CMD}  ${RAW}  ${command}
115    Qprint Issuing  ${ipmi_cmd}
116    ${stdout}  ${stderr}=  Execute Command  ${ipmi_cmd}  return_stderr=True
117    Return From Keyword If  ${fail_on_err} == ${0}  ${stderr}
118    Should Be Empty  ${stderr}  msg=${stdout}
119    RETURN  ${stdout}
120
121
122Run Inband IPMI Standard Command
123    [Documentation]  Run the standard IPMI command in-band.
124    [Arguments]  ${command}  ${fail_on_err}=${1}  ${os_host}=${OS_HOST}
125    ...          ${os_username}=${OS_USERNAME}  ${os_password}=${OS_PASSWORD}
126    ...          ${login_host}=${1}
127
128    # Description of argument(s):
129    # command                       The IPMI command string to be executed
130    #                               (e.g. "power status").
131    # os_host                       The host name or IP address of the OS Host.
132    # os_username                   The OS host user name.
133    # os_password                   The OS host passwrd.
134    # login_host                    Indicates that this keyword should login to host OS.
135
136    Run Keyword If  ${login_host} == ${1}
137    ...  Login To OS Host  ${os_host}  ${os_username}  ${os_password}
138    Check If IPMI Tool Exist
139
140    ${ipmi_cmd}=  Catenate  ${IPMI_INBAND_CMD}  ${command}
141    Qprint Issuing  ${ipmi_cmd}
142    ${stdout}  ${stderr}=  Execute Command  ${ipmi_cmd}  return_stderr=True
143    Return From Keyword If  ${fail_on_err} == ${0}  ${stderr}
144    Should Be Empty  ${stderr}  msg=${stdout}
145    RETURN  ${stdout}
146
147
148Run External IPMI Standard Command
149    [Documentation]  Run the external IPMI standard command.
150    [Arguments]  ${command}  ${fail_on_err}=${1}  ${expected_rc}=${0}  &{options}
151
152    # Description of argument(s):
153    # command                       The IPMI command string to be executed
154    #                               (e.g. "power status").  Note that if
155    #                               ${IPMI_USER_OPTIONS} has a value (e.g.
156    #                               "-vvv"), it will be pre-pended to this
157    #                               command string.
158    # fail_on_err                   Fail if the IPMI command execution fails.
159    # expected_rc                   The expected return code from the ipmi
160    #                               command (e.g. ${0}, ${1}, etc.).
161    # options                       Additional ipmitool command options (e.g.
162    #                               -C=3, -I=lanplus, etc.).
163
164    ${command_string}=  Process IPMI User Options  ${command}
165    ${ipmi_cmd}=  Create IPMI Ext Command String  ${command_string}  &{options}
166    Qprint Issuing  ${ipmi_cmd}
167    ${rc}  ${output}=  Run And Return RC and Output  ${ipmi_cmd}
168    Return From Keyword If  ${fail_on_err} == ${0}  ${output}
169    Should Be Equal  ${rc}  ${expected_rc}  msg=${output}
170    RETURN  ${output}
171
172
173Run External IPMI Raw Command
174    [Documentation]  Run the external IPMI raw command.
175    [Arguments]  ${command}  ${fail_on_err}=${1}  &{options}
176
177    # This keyword is a wrapper for 'Run External IPMI Standard Command'. See
178    # that keyword's prolog for argument details.  This keyword will pre-pend
179    # the word "raw" plus a space to command prior to calling 'Run External
180    # IPMI Standard Command'.
181
182    ${output}=  Run External IPMI Standard Command
183    ...  raw ${command}  ${fail_on_err}  &{options}
184    RETURN  ${output}
185
186
187Check If IPMI Tool Exist
188    [Documentation]  Check if IPMI Tool installed or not.
189    ${output}=  Execute Command  which ipmitool
190    Should Not Be Empty  ${output}  msg=ipmitool not installed.
191
192
193Activate SOL Via IPMI
194    [Documentation]  Start SOL using IPMI and route output to a file.
195    [Arguments]  ${file_path}=${IPMI_SOL_LOG_FILE}
196
197    # Description of argument(s):
198    # file_path                     The file path on the local machine (vs.
199    #                               OBMC) to collect SOL output. By default
200    #                               SOL output is collected at
201    #                               logs/sol_<BMC_IP> else user input location.
202
203    ${ipmi_cmd}=  Create IPMI Ext Command String  sol activate usesolkeepalive
204    Qprint Issuing  ${ipmi_cmd}
205    Start Process  ${ipmi_cmd}  shell=True  stdout=${file_path}
206    ...  alias=sol_proc
207
208
209Deactivate SOL Via IPMI
210    [Documentation]  Stop SOL using IPMI and return SOL output.
211    [Arguments]  ${file_path}=${IPMI_SOL_LOG_FILE}
212
213    # Description of argument(s):
214    # file_path                     The file path on the local machine to copy
215    #                               SOL output collected by above "Activate
216    #                               SOL Via IPMI" keyword.  By default it
217    #                               copies log from logs/sol_<BMC_IP>.
218
219    ${ipmi_cmd}=  Create IPMI Ext Command String  sol deactivate
220    Qprint Issuing  ${ipmi_cmd}
221    ${rc}  ${output}=  Run and Return RC and Output  ${ipmi_cmd}
222    Run Keyword If  ${rc} > 0  Run Keywords
223    ...  Run Keyword And Ignore Error  Terminate Process  sol_proc
224    ...  AND  Return From Keyword  ${output}
225
226    ${output}=  OperatingSystem.Get File  ${file_path}  encoding_errors=ignore
227
228    # Logging SOL output for debug purpose.
229    Log  ${output}
230
231    RETURN  ${output}
232
233
234Byte Conversion
235    [Documentation]   Byte Conversion method receives IPMI RAW commands as
236    ...               argument in string format.
237    ...               Sample argument is as follows
238    ...               "0x04 0x30 9 0x01 0x00 0x35 0x00 0x00 0x00 0x00 0x00
239    ...               0x00"
240    ...               IPMI RAW command format is as follows
241    ...               <netfn Byte> <cmd Byte> <Data Bytes..>
242    ...               This method converts IPMI command format into
243    ...               dbus command format  as follows
244    ...               <byte:seq-id> <byte:netfn> <byte:lun> <byte:cmd>
245    ...               <array:byte:data>
246    ...               Sample dbus  Host IPMI Received Message argument
247    ...               byte:0x00 byte:0x04 byte:0x00 byte:0x30
248    ...               array:byte:9,0x01,0x00,0x35,0x00,0x00,0x00,0x00,0x00,0x00
249    [Arguments]     ${args}
250    ${argLength}=   Get Length  ${args}
251    Set Global Variable  ${arrayByte}   array:byte:
252    @{listargs}=   Split String  ${args}
253    ${index}=   Set Variable   ${0}
254    FOR  ${word}  IN  @{listargs}
255         Run Keyword if   ${index} == 0   Set NetFn Byte  ${word}
256         Run Keyword if   ${index} == 1   Set Cmd Byte    ${word}
257         Run Keyword if   ${index} > 1    Set Array Byte  ${word}
258         ${index}=    Set Variable    ${index + 1}
259    END
260    ${length}=   Get Length  ${arrayByte}
261    ${length}=   Evaluate  ${length} - 1
262    ${arrayByteLocal}=  Get Substring  ${arrayByte}  0   ${length}
263    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
264    ${valueinBytesWithArray}=   Catenate  byte:0x00   ${netfnByte}  byte:0x00
265    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray}  ${cmdByte}
266    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray} ${arrayByte}
267    ${valueinBytesWithoutArray}=   Catenate  byte:0x00 ${netfnByte}  byte:0x00
268    ${valueinBytesWithoutArray}=   Catenate  ${valueinBytesWithoutArray} ${cmdByte}
269    #   To Check scenario for smaller IPMI raw commands with only 2 arguments
270    #   instead of usual 12 arguments.
271    #   Sample small IPMI raw command: Run IPMI command 0x06 0x36
272    #   If IPMI raw argument length is only 9 then return value in bytes without
273    #   array population.
274    #   Equivalent dbus-send argument for smaller IPMI raw command:
275    #   byte:0x00 byte:0x06 byte:0x00 byte:0x36
276    Run Keyword if   ${argLength} == 9     Return from Keyword    ${valueinBytesWithoutArray}
277    RETURN    ${valueinBytesWithArray}
278
279
280Set NetFn Byte
281    [Documentation]  Set the network function byte.
282    [Arguments]    ${word}
283    ${netfnByteLocal}=  Catenate   byte:${word}
284    Set Global Variable  ${netfnByte}  ${netfnByteLocal}
285
286
287Set Cmd Byte
288    [Documentation]  Set the command byte.
289    [Arguments]    ${word}
290    ${cmdByteLocal}=  Catenate   byte:${word}
291    Set Global Variable  ${cmdByte}  ${cmdByteLocal}
292
293
294Set Array Byte
295    [Documentation]  Set the array byte.
296    [Arguments]    ${word}
297    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByte}  ${word}
298    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByteLocal}   ,
299    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
300
301
302Copy ipmitool
303    [Documentation]  Copy the ipmitool to the BMC.
304    ${ipmitool_error}=  Catenate  The ipmitool program could not be found in the tools directory.
305    ...  It is not part of the automation code by default. You must manually copy or link the correct openbmc
306    ...  version of the tool in to the tools directory in order to run this test suite.
307
308    ${response}  ${stderr}  ${rc}=  BMC Execute Command
309    ...  which ipmitool  ignore_err=${1}
310    ${installed}=  Get Regexp Matches  ${response}  ipmitool
311    Run Keyword If  ${installed} == ['ipmitool']
312    ...  Run Keywords  Set Suite Variable  ${IPMITOOL_PATH}  ${response}
313    ...  AND  SSHLibrary.Open Connection     ${OPENBMC_HOST}
314    ...  AND  SSHLibrary.Login   ${OPENBMC_USERNAME}    ${OPENBMC_PASSWORD}
315    ...  AND  Return From Keyword
316
317    OperatingSystem.File Should Exist  tools/ipmitool  msg=${ipmitool_error}
318    Import Library      SCPLibrary      WITH NAME       scp
319    scp.Open connection     ${OPENBMC_HOST}     username=${OPENBMC_USERNAME}      password=${OPENBMC_PASSWORD}
320    scp.Put File    tools/ipmitool   /tmp
321    SSHLibrary.Open Connection     ${OPENBMC_HOST}
322    SSHLibrary.Login   ${OPENBMC_USERNAME}    ${OPENBMC_PASSWORD}
323    Execute Command     chmod +x ${IPMITOOL_PATH}
324
325
326Initiate Host Boot Via External IPMI
327    [Documentation]  Initiate host power on using external IPMI.
328    [Arguments]  ${wait}=${1}
329
330    # Description of argument(s):
331    # wait                          Indicates that this keyword should wait
332    #                               for host running state.
333
334    ${output}=  Run External IPMI Standard Command  chassis power on
335    Should Not Contain  ${output}  Error
336
337    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
338    Wait Until Keyword Succeeds  10 min  10 sec  Is Host Running
339
340
341Initiate Host PowerOff Via External IPMI
342    [Documentation]  Initiate host power off using external IPMI.
343    [Arguments]  ${wait}=${1}
344
345    # Description of argument(s):
346    # wait                          Indicates that this keyword should wait
347    #                               for host off state.
348
349    ${output}=  Run External IPMI Standard Command  chassis power off
350    Should Not Contain  ${output}  Error
351
352    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
353    Wait Until Keyword Succeeds  3 min  10 sec  Is Host Off
354
355
356Is Host Off Via IPMI
357    [Documentation]  Verify if the Host is off using IPMI command.
358
359    ${status}=  Run External IPMI Standard Command  chassis power status
360    Should Contain  ${status}  off
361
362
363Get Host State Via External IPMI
364    [Documentation]  Returns host state using external IPMI.
365
366    ${output}=  Run External IPMI Standard Command  chassis power status
367    Should Not Contain  ${output}  Error
368    ${output}=  Fetch From Right  ${output}  ${SPACE}
369
370    RETURN  ${output}
371
372
373Set BMC Network From Host
374    [Documentation]  Set BMC network from host.
375    [Arguments]  ${nw_info}
376
377    # Description of argument(s):
378    # nw_info                       A dictionary containing the network
379    #                               information to apply.
380
381    Run Inband IPMI Standard Command
382    ...  lan set 1 ipaddr ${nw_info['IP Address']}
383
384    Run Inband IPMI Standard Command
385    ...  lan set 1 netmask ${nw_info['Subnet Mask']}
386
387    Run Inband IPMI Standard Command
388    ...  lan set 1 defgw ipaddr ${nw_info['Default Gateway IP']}
389
390
391Verify IPMI Username And Password
392    [Documentation]  Verify that user is able to run IPMI command
393    ...  with given username and password.
394    [Arguments]  ${username}  ${password}
395
396    # Description of argument(s):
397    # username    The user name (e.g. "root", "robert", etc.).
398    # password    The user password.
399
400    ${output}=  Wait Until Keyword Succeeds  15 sec  5 sec  Run External IPMI Standard Command
401    ...  sel info  U=${username}  P=${password}
402    Should Contain  ${output}  SEL Information  msg=SEL information not present
403
404
405IPMI Create User
406    [Documentation]  Create IPMI user with given userid and username.
407    [Arguments]  ${userid}  ${username}
408
409    # Description of argument(s):
410    # userid      The user ID (e.g. "1", "2", etc.).
411    # username    The user name (e.g. "root", "robert", etc.).
412
413    ${ipmi_cmd}=  Catenate  user set name ${userid} ${username}
414    ${resp}=  Run IPMI Standard Command  ${ipmi_cmd}
415    ${user_info}=  Get User Info  ${userid}  ${CHANNEL_NUMBER}
416    Should Be Equal  ${user_info['user_name']}  ${username}
417
418
419Enable IPMI User And Verify
420    [Documentation]  Enable the userid and verify that it has been enabled.
421    [Arguments]  ${userid}
422
423    # Description of argument(s):
424    # userid   A numeric userid (e.g. "4").
425
426    Run IPMI Standard Command  user enable ${userid}
427    ${user_info}=  Get User Info  ${userid}  ${CHANNEL_NUMBER}
428    Valid Value  user_info['enable_status']  ['enabled']
429
430
431Create Random IPMI User
432    [Documentation]  Create IPMI user with random username and userid and return those fields.
433
434    ${random_username}=  Generate Random String  8  [LETTERS]
435    ${random_userid}=  Find Free User Id
436    IPMI Create User  ${random_userid}  ${random_username}
437    Wait And Confirm New User Entry  ${random_username}
438    RETURN  ${random_userid}  ${random_username}
439
440
441Find Free User Id
442    [Documentation]  Find a userid that is not being used.
443
444    Check Enabled User Count
445    FOR    ${num}    IN RANGE    300
446        ${random_userid}=  Evaluate  random.randint(1, ${expected_max_ids})  modules=random
447        ${access}=  Run IPMI Standard Command  channel getaccess ${CHANNEL_NUMBER} ${random_userid}
448
449        ${name_line}=  Get Lines Containing String  ${access}  User Name
450        Log To Console  For ID ${random_userid}: ${name_line}
451        ${is_empty}=  Run Keyword And Return Status
452        ...  Should Match Regexp  ${name_line}  ${empty_name_pattern}
453
454        Exit For Loop If  ${is_empty} == ${True}
455    END
456    RETURN  ${random_userid}
457
458
459Check Enabled User Count
460    [Documentation]  Ensure that there are available user IDs.
461
462    # Check for the enabled user count
463    ${resp}=  Run IPMI Standard Command  user summary ${CHANNEL_NUMBER}
464    ${enabled_user_count}=
465    ...  Get Lines Containing String  ${resp}  Enabled User Count
466
467    Should not contain  ${enabled_user_count}  ${expected_max_ids}
468    ...  msg=IPMI has reached maximum user count
469
470
471Wait And Confirm New User Entry
472    [Documentation]  Wait in loop until new user appears with given username.
473    [Arguments]  ${username}
474
475    # Description of argument(s):
476    # username         The user name (e.g. "root", "robert", etc.).
477
478    Wait Until Keyword Succeeds  45 sec  1 sec  Verify IPMI Username Visible
479    ...  ${username}
480
481
482Verify IPMI Username Visible
483    [Documentation]  Confirm that username is present in user list.
484    [Arguments]  ${username}
485
486    # Description of argument(s):
487    # username         The user name (e.g. "root", "robert", etc.).
488
489    ${resp}=  Run IPMI Standard Command  user list
490    Should Contain  ${resp}  ${username}
491
492
493Delete Created User
494    [Documentation]  Delete created IPMI user.
495    [Arguments]  ${userid}
496    # Description of argument(s):
497    # userid  The user ID (e.g. "1", "2", etc.).
498
499    Run IPMI Standard Command  user set name ${userid} ""
500    Sleep  5s
501
502
503Set Channel Access
504    [Documentation]  Verify that user is able to run IPMI command
505    ...  with given username and password.
506    [Arguments]  ${userid}  ${options}  ${channel_number}=${CHANNEL_NUMBER}
507
508    # Description of argument(s):
509    # userid          The user ID (e.g. "1", "2", etc.).
510    # options         Set channel command options (e.g.
511    #                 "link=on", "ipmi=on", etc.).
512    # channel_number  The user's channel number (e.g. "1").
513
514    ${ipmi_cmd}=  Catenate  SEPARATOR=
515    ...  channel setaccess${SPACE}${channel_number}${SPACE}${userid}
516    ...  ${SPACE}${options}
517    Run IPMI Standard Command  ${ipmi_cmd}
518
519
520Delete All Non Root IPMI User
521    [Documentation]  Delete all non-root IPMI user.
522
523    # Get complete list of user info records.
524    ${user_info}=  Get User Info  ${EMPTY}  ${CHANNEL_NUMBER}
525    # Remove header record.
526    ${user_info}=  Filter Struct  ${user_info}  [('user_name', None)]  invert=1
527    ${non_empty_user_info}=  Filter Struct  ${user_info}  [('user_name', '')]  invert=1
528    ${non_root_user_info}=  Filter Struct  ${non_empty_user_info}  [('user_name', 'root')]  invert=1
529
530    FOR  ${user_record}  IN  @{non_root_user_info}
531        Run IPMI Standard Command   user set name ${user_record['user_id']} ""
532        Sleep  5s
533    END
534
535
536Create SEL
537    [Documentation]  Create a SEL.
538    [Arguments]  ${sensor_type}  ${sensor_number}
539
540    # Create a SEL.
541    # Example:
542    # a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 |  | Asserted
543    # Description of argument(s):
544    #    ${sensor_type}            Type of the sensor used in hexadecimal (can be fan, temp etc.,),
545    #                              obtained from Sensor Type field in - ipmitool sdr get "sensor_name".
546    #                              Example: Sensor Type (Threshold) : Fan (0x04), here 0xHH is sensor type.
547
548    #    ${sensor_number}          Sensor number of the sensor in hexadecimal.
549    #                              obtained from Sensor ID field in - ipmitool sdr get "sensor_name".
550    #                              Example: Sensor ID : SENSOR_1 (0xHH), here 0xHH is sensor number.
551
552    ${cmd}=  Catenate  ${IPMI_RAW_CMD['SEL_entry']['Create_SEL'][0]} 0x${GEN_ID_BYTE_1} 0x${GEN_ID_BYTE_2}
553    ...  ${IPMI_RAW_CMD['SEL_entry']['Create_SEL'][1]} 0x${sensor_type} 0x${sensor_number}
554    ...  ${IPMI_RAW_CMD['SEL_entry']['Create_SEL'][2]}
555
556    ${resp}=  Run IPMI Command  ${cmd}
557
558    Should Not Contain  ${resp}  00 00  msg=SEL not created.
559
560    Sleep  5s
561
562    RETURN  ${resp}
563
564
565Fetch One Threshold Sensor From Sensor List
566    [Documentation]  Fetch one threshold sensor randomly from Sensor list.
567
568    @{sensor_name_list}=  Create List
569
570    ${resp}=  Run IPMI Standard Command  sensor
571    @{sensor_list}=  Split To Lines  ${resp}
572
573    # Omit the discrete sensor and create an threshold sensor name list
574    FOR  ${sensor}  IN  @{sensor_list}
575      ${discrete_sensor_status}=  Run Keyword And Return Status  Should Contain  ${sensor}  discrete
576      Continue For Loop If  '${discrete_sensor_status}' == 'True'
577      ${sensor_details}=  Split String  ${sensor}  |
578      ${get_sensor_name}=  Get From List  ${sensor_details}  0
579      ${sensor_name}=  Set Variable  ${get_sensor_name.strip()}
580      Append To List  ${sensor_name_list}  ${sensor_name}
581    END
582
583    ${random_sensor_name}=  Evaluate  random.choice(${sensor_name_list})  random
584
585    RETURN  ${random_sensor_name}
586
587Fetch Sensor Details From SDR
588    [Documentation]  Identify the sensors from sdr get and fetch sensor details required.
589    [Arguments]  ${sensor_name}  ${setting}
590
591    # Description of argument(s):
592    #    ${sensor_number}        Sensor number of the sensor in hexadecimal.
593    #                            obtained sensor name from - 'ipmitool sensor' command.
594    #                            Example: a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 |  | Asserted
595    #                            here, a is the sensor name.
596
597    #    ${setting}              Field to fetch data. Example : Sensor ID, Sensor Type (Threshold), etc,.
598
599    ${resp}=  Run IPMI Standard Command  sdr get "${sensor_name}"
600
601    ${setting_line}=  Get Lines Containing String  ${resp}  ${setting}
602    ...  case-insensitive
603    ${setting_status}=  Fetch From Right  ${setting_line}  :${SPACE}
604
605    RETURN  ${setting_status}
606
607
608Get Bytes From SDR Sensor
609    [Documentation]  Fetch the Field Data and hexadecimal values from given details.
610    [Arguments]  ${sensor_detail}
611
612    # Description of argument(s):
613    #    ${sensor_detail}      Requested field and the value from the sdr get ipmi command.
614    #                          Example : if Sensor ID is the requesting setting, then,
615    #                          ${sensor_detail} will be "Sensor ID : SENSOR_1 (0xHH)"
616
617    ${sensor_detail}=  Split String  ${sensor_detail}  (0x
618    ${sensor_hex}=  Replace String  ${sensor_detail[1]}  )  ${EMPTY}
619    ${sensor_hex}=  Zfill Data  ${sensor_hex}  2
620
621    RETURN  ${sensor_hex}
622
623
624Get Current Date from BMC
625    [Documentation]  Runs the date command from BMC and returns current date and time
626    [Arguments]  ${date_format}=%m/%d/%Y %H:%M:%S
627
628    # Description of argument(s):
629    # date_format    Date format of the result. E.g. %Y-%m-%d %H:%M:%S etc.
630
631    # Get Current Date from BMC
632    ${date}  ${stderr}  ${rc}=  BMC Execute Command   date
633
634    # Split the string and remove first and 2nd last value from the list and join to form %d %b %H:%M:%S %Y date format
635    ${date}=  Split String  ${date}
636    Remove From List  ${date}  0
637    Remove From List  ${date}  -2
638    ${date}=  Evaluate  " ".join(${date})
639
640    # Convert the date to specified format, default:%m/%d/%Y %H:%M:%S
641    ${date}=  Convert Date  ${date}  date_format=%b %d %H:%M:%S %Y  result_format=${date_format}  exclude_millis=True
642
643    RETURN   ${date}
644
645
646Get SEL Info Via IPMI
647    [Documentation]  Get the SEL Info via IPMI raw command
648
649    # Get SEL Info response consist of 14 bytes of hexadecimal data.
650
651    # Byte 1 - SEL Version,
652    # Byte 2 & 3 - Entry bytes - LSB MSB,
653    # Byte 4 & 5 - Free Space in bytes, LS Byte first.
654    # Byte 6 - 9 - Most recent addition timestamp,
655    # Byte 10-13 - Most recent erase timestamp,
656    # Byte 14 - Operation Support
657
658    # Example: ${resp} will be "51 XX XX XX XX ff ff ff ff ff ff ff ff XX"
659
660    ${resp}=  Run IPMI Command
661    ...  ${IPMI_RAW_CMD['SEL_entry']['SEL_info'][0]}
662    ${resp}=  Split String  ${resp}
663
664    RETURN  ${resp}
665
666
667Verify Invalid IPMI Command
668    [Documentation]  Execute invalid IPMI command and verify with given response code.
669    [Arguments]  ${ipmi_cmd}  ${error_code}=0xc9
670
671    #  Description Of Arguments.
672    #  ${ipmi_cmd}   - IPMI raw cmd with invalid data length.
673    #  ${error_code} - Expected error code e.g 0xc7, 0xcc.
674
675    ${resp}=  Run IPMI Command  ${ipmi_cmd}  fail_on_err=0
676
677    Should Contain  ${resp}  rsp=${error_code}
678
679
680Identify Request Data
681    [Documentation]  Convert text from variable declared to request data.
682    [Arguments]  ${string}
683
684    # Convert string to hexadecimal data for each character.
685    # Return the hex data with prefix of 0x as string and list of hex data.
686    # Description of argument(s):
687    #    string             Any string to be converted to hex.
688
689    # Given a string, convert to hexadecimal and prefix with 0x
690    ${hex1}=  Create List
691    ${hex2}=  Create List
692    ${resp_data}=  Split String With Index  ${string}  1
693    FOR  ${data}  IN  @{resp_data}
694        # prefixes 0x by default
695        ${hex_value}=  Evaluate  hex(ord("${data}"))
696        # prefixes string with bytes prefixed 0x by default
697        Append To List  ${hex1}  ${hex_value}
698        # provides only hexadecimal bytes
699        ${hex}=  Evaluate  hex(ord("${data}"))[2:]
700        # provides string with only hexadecimal bytes
701        Append To List  ${hex2}  ${hex}
702    END
703    ${hex1}=  Evaluate  " ".join(${hex1})
704
705    # ${hex1} will contains the data to write for fru in list.
706    # ${hex2} will contains the data to verify fru after write operation completed.
707
708    RETURN  ${hex1}  ${hex2}
709