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
13
14*** Variables ***
15${dbusHostIpmicmd1}=   dbus-send --system  ${OPENBMC_BASE_URI}HostIpmi/1
16${dbusHostIpmiCmdReceivedMsg}=   ${OPENBMC_BASE_DBUS}.HostIpmi.ReceivedMessage
17${netfnByte}=          ${EMPTY}
18${cmdByte}=            ${EMPTY}
19${arrayByte}=          array:byte:
20${IPMI_USER_OPTIONS}   ${EMPTY}
21${IPMI_INBAND_CMD}=    ipmitool -C ${IPMI_CIPHER_LEVEL} -N ${IPMI_TIMEOUT} -p ${IPMI_PORT}
22${HOST}=               -H
23${RAW}=                raw
24
25*** Keywords ***
26
27Run IPMI Command
28    [Documentation]  Run the raw IPMI command.
29    [Arguments]  ${command}  ${fail_on_err}=${1}  &{options}
30
31    # Description of argument(s):
32    # command                       The IPMI command string to be executed
33    #                               (e.g. "power status").
34    # fail_on_err                   Fail if the IPMI command execution fails.
35    # options                       Additional ipmitool command options (e.g.
36    #                               -C=3, -I=lanplus, etc.).  Currently, only
37    #                               used for external IPMI commands.
38
39    ${resp}=  Run Keyword If  '${IPMI_COMMAND}' == 'External'
40    ...    Run External IPMI Raw Command  ${command}  ${fail_on_err}  &{options}
41    ...  ELSE IF  '${IPMI_COMMAND}' == 'Inband'
42    ...    Run Inband IPMI Raw Command  ${command}
43    ...  ELSE IF  '${IPMI_COMMAND}' == 'Dbus'
44    ...    Run Dbus IPMI RAW Command  ${command}
45    ...  ELSE  Fail  msg=Invalid IPMI Command type provided: ${IPMI_COMMAND}
46    [Return]  ${resp}
47
48
49Run IPMI Standard Command
50    [Documentation]  Run the standard IPMI command.
51    [Arguments]  ${command}  ${fail_on_err}=${1}  ${expected_rc}=${0}  &{options}
52
53    # Description of argument(s):
54    # command                       The IPMI command string to be executed
55    #                               (e.g. "0x06 0x36").
56    # fail_on_err                   Fail if the IPMI command execution fails.
57    # expected_rc                   The expected return code from the ipmi
58    #                               command (e.g. ${0}, ${1}, etc.).
59    # options                       Additional ipmitool command options (e.g.
60    #                               -C=3, -I=lanplus, etc.).  Currently, only
61    #                               used for external IPMI commands.
62
63    ${resp}=  Run Keyword If  '${IPMI_COMMAND}' == 'External'
64    ...    Run External IPMI Standard Command  ${command}  ${fail_on_err}  ${expected_rc}  &{options}
65    ...  ELSE IF  '${IPMI_COMMAND}' == 'Inband'
66    ...    Run Inband IPMI Standard Command  ${command}  ${fail_on_err}
67    ...  ELSE IF  '${IPMI_COMMAND}' == 'Dbus'
68    ...    Run Dbus IPMI Standard Command  ${command}
69    ...  ELSE  Fail  msg=Invalid IPMI Command type provided : ${IPMI_COMMAND}
70    [Return]  ${resp}
71
72
73Run Dbus IPMI RAW Command
74    [Documentation]  Run the raw IPMI command through dbus.
75    [Arguments]    ${command}
76    ${valueinBytes}=   Byte Conversion  ${command}
77    ${cmd}=   Catenate   ${dbushostipmicmd1} ${dbusHostIpmiCmdReceivedMsg}
78    ${cmd}=   Catenate   ${cmd} ${valueinBytes}
79    ${output}   ${stderr}=  Execute Command  ${cmd}  return_stderr=True
80    Should Be Empty      ${stderr}
81    set test variable    ${OUTPUT}     "${output}"
82
83
84Run Dbus IPMI Standard Command
85    [Documentation]  Run the standard IPMI command through dbus.
86    [Arguments]    ${command}
87    Copy ipmitool
88    ${stdout}    ${stderr}    ${output}=  Execute Command
89    ...    /tmp/ipmitool -I dbus ${command}    return_stdout=True
90    ...    return_stderr= True    return_rc=True
91    Should Be Equal    ${output}    ${0}    msg=${stderr}
92    [Return]    ${stdout}
93
94
95Run Inband IPMI Raw Command
96    [Documentation]  Run the raw IPMI command in-band.
97    [Arguments]  ${command}  ${os_host}=${OS_HOST}  ${os_username}=${OS_USERNAME}
98    ...          ${os_password}=${OS_PASSWORD}
99
100    # Description of argument(s):
101    # command                       The IPMI command string to be executed
102    #                               (e.g. "0x06 0x36").
103    # os_host                       The host name or IP address of the OS Host.
104    # os_username                   The OS host user name.
105    # os_password                   The OS host passwrd.
106
107    Login To OS Host  ${os_host}  ${os_username}  ${os_password}
108    Check If IPMI Tool Exist
109
110    ${ipmi_cmd}=  Catenate  ${IPMI_INBAND_CMD}  ${RAW}  ${command}
111    Qprint Issuing  ${ipmi_cmd}
112    ${stdout}  ${stderr}=  Execute Command  ${ipmi_cmd}  return_stderr=True
113    Should Be Empty  ${stderr}  msg=${stdout}
114    [Return]  ${stdout}
115
116
117Run Inband IPMI Standard Command
118    [Documentation]  Run the standard IPMI command in-band.
119    [Arguments]  ${command}  ${fail_on_err}=${1}  ${os_host}=${OS_HOST}
120    ...          ${os_username}=${OS_USERNAME}  ${os_password}=${OS_PASSWORD}
121    ...          ${login_host}=${1}
122
123    # Description of argument(s):
124    # command                       The IPMI command string to be executed
125    #                               (e.g. "power status").
126    # os_host                       The host name or IP address of the OS Host.
127    # os_username                   The OS host user name.
128    # os_password                   The OS host passwrd.
129    # login_host                    Indicates that this keyword should login to host OS.
130
131    Run Keyword If  ${login_host} == ${1}
132    ...  Login To OS Host  ${os_host}  ${os_username}  ${os_password}
133    Check If IPMI Tool Exist
134
135    ${ipmi_cmd}=  Catenate  ${IPMI_INBAND_CMD}  ${command}
136    Qprint Issuing  ${ipmi_cmd}
137    ${stdout}  ${stderr}=  Execute Command  ${ipmi_cmd}  return_stderr=True
138    Return From Keyword If  ${fail_on_err} == ${0}  ${stderr}
139    Should Be Empty  ${stderr}  msg=${stdout}
140    [Return]  ${stdout}
141
142
143Run External IPMI Standard Command
144    [Documentation]  Run the external IPMI standard command.
145    [Arguments]  ${command}  ${fail_on_err}=${1}  ${expected_rc}=${0}  &{options}
146
147    # Description of argument(s):
148    # command                       The IPMI command string to be executed
149    #                               (e.g. "power status").  Note that if
150    #                               ${IPMI_USER_OPTIONS} has a value (e.g.
151    #                               "-vvv"), it will be pre-pended to this
152    #                               command string.
153    # fail_on_err                   Fail if the IPMI command execution fails.
154    # expected_rc                   The expected return code from the ipmi
155    #                               command (e.g. ${0}, ${1}, etc.).
156    # options                       Additional ipmitool command options (e.g.
157    #                               -C=3, -I=lanplus, etc.).
158
159    ${command_string}=  Process IPMI User Options  ${command}
160    ${ipmi_cmd}=  Create IPMI Ext Command String  ${command_string}  &{options}
161    Qprint Issuing  ${ipmi_cmd}
162    ${rc}  ${output}=  Run And Return RC and Output  ${ipmi_cmd}
163    Return From Keyword If  ${fail_on_err} == ${0}  ${output}
164    Should Be Equal  ${rc}  ${expected_rc}  msg=${output}
165    [Return]  ${output}
166
167
168Run External IPMI Raw Command
169    [Documentation]  Run the external IPMI raw command.
170    [Arguments]  ${command}  ${fail_on_err}=${1}  &{options}
171
172    # This keyword is a wrapper for 'Run External IPMI Standard Command'. See
173    # that keyword's prolog for argument details.  This keyword will pre-pend
174    # the word "raw" plus a space to command prior to calling 'Run External
175    # IPMI Standard Command'.
176
177    ${output}=  Run External IPMI Standard Command
178    ...  raw ${command}  ${fail_on_err}  &{options}
179    [Return]  ${output}
180
181
182Check If IPMI Tool Exist
183    [Documentation]  Check if IPMI Tool installed or not.
184    ${output}=  Execute Command  which ipmitool
185    Should Not Be Empty  ${output}  msg=ipmitool not installed.
186
187
188Activate SOL Via IPMI
189    [Documentation]  Start SOL using IPMI and route output to a file.
190    [Arguments]  ${file_path}=/tmp/sol_${OPENBMC_HOST}
191
192    # Description of argument(s):
193    # file_path                     The file path on the local machine (vs.
194    #                               OBMC) to collect SOL output. By default
195    #                               SOL output is collected at
196    #                               /tmp/sol_<BMC_IP> else user input location.
197
198    ${ipmi_cmd}=  Create IPMI Ext Command String  sol activate usesolkeepalive
199    Qprint Issuing  ${ipmi_cmd}
200    Start Process  ${ipmi_cmd}  shell=True  stdout=${file_path}
201    ...  alias=sol_proc
202
203
204Deactivate SOL Via IPMI
205    [Documentation]  Stop SOL using IPMI and return SOL output.
206    [Arguments]  ${file_path}=/tmp/sol_${OPENBMC_HOST}
207
208    # Description of argument(s):
209    # file_path                     The file path on the local machine to copy
210    #                               SOL output collected by above "Activate
211    #                               SOL Via IPMI" keyword.  By default it
212    #                               copies log from /tmp/sol_<BMC_IP>.
213
214    ${ipmi_cmd}=  Create IPMI Ext Command String  sol deactivate
215    Qprint Issuing  ${ipmi_cmd}
216    ${rc}  ${output}=  Run and Return RC and Output  ${ipmi_cmd}
217    Run Keyword If  ${rc} > 0  Run Keywords
218    ...  Run Keyword And Ignore Error  Terminate Process  sol_proc
219    ...  AND  Return From Keyword  ${output}
220
221    ${output}=  OperatingSystem.Get File  ${file_path}  encoding_errors=ignore
222
223    # Logging SOL output for debug purpose.
224    Log  ${output}
225
226    [Return]  ${output}
227
228
229Byte Conversion
230    [Documentation]   Byte Conversion method receives IPMI RAW commands as
231    ...               argument in string format.
232    ...               Sample argument is as follows
233    ...               "0x04 0x30 9 0x01 0x00 0x35 0x00 0x00 0x00 0x00 0x00
234    ...               0x00"
235    ...               IPMI RAW command format is as follows
236    ...               <netfn Byte> <cmd Byte> <Data Bytes..>
237    ...               This method converts IPMI command format into
238    ...               dbus command format  as follows
239    ...               <byte:seq-id> <byte:netfn> <byte:lun> <byte:cmd>
240    ...               <array:byte:data>
241    ...               Sample dbus  Host IPMI Received Message argument
242    ...               byte:0x00 byte:0x04 byte:0x00 byte:0x30
243    ...               array:byte:9,0x01,0x00,0x35,0x00,0x00,0x00,0x00,0x00,0x00
244    [Arguments]     ${args}
245    ${argLength}=   Get Length  ${args}
246    Set Global Variable  ${arrayByte}   array:byte:
247    @{listargs}=   Split String  ${args}
248    ${index}=   Set Variable   ${0}
249    FOR  ${word}  IN  @{listargs}
250         Run Keyword if   ${index} == 0   Set NetFn Byte  ${word}
251         Run Keyword if   ${index} == 1   Set Cmd Byte    ${word}
252         Run Keyword if   ${index} > 1    Set Array Byte  ${word}
253         ${index}=    Set Variable    ${index + 1}
254    END
255    ${length}=   Get Length  ${arrayByte}
256    ${length}=   Evaluate  ${length} - 1
257    ${arrayByteLocal}=  Get Substring  ${arrayByte}  0   ${length}
258    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
259    ${valueinBytesWithArray}=   Catenate  byte:0x00   ${netfnByte}  byte:0x00
260    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray}  ${cmdByte}
261    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray} ${arrayByte}
262    ${valueinBytesWithoutArray}=   Catenate  byte:0x00 ${netfnByte}  byte:0x00
263    ${valueinBytesWithoutArray}=   Catenate  ${valueinBytesWithoutArray} ${cmdByte}
264    #   To Check scenario for smaller IPMI raw commands with only 2 arguments
265    #   instead of usual 12 arguments.
266    #   Sample small IPMI raw command: Run IPMI command 0x06 0x36
267    #   If IPMI raw argument length is only 9 then return value in bytes without
268    #   array population.
269    #   Equivalent dbus-send argument for smaller IPMI raw command:
270    #   byte:0x00 byte:0x06 byte:0x00 byte:0x36
271    Run Keyword if   ${argLength} == 9     Return from Keyword    ${valueinBytesWithoutArray}
272    [Return]    ${valueinBytesWithArray}
273
274
275Set NetFn Byte
276    [Documentation]  Set the network function byte.
277    [Arguments]    ${word}
278    ${netfnByteLocal}=  Catenate   byte:${word}
279    Set Global Variable  ${netfnByte}  ${netfnByteLocal}
280
281
282Set Cmd Byte
283    [Documentation]  Set the command byte.
284    [Arguments]    ${word}
285    ${cmdByteLocal}=  Catenate   byte:${word}
286    Set Global Variable  ${cmdByte}  ${cmdByteLocal}
287
288
289Set Array Byte
290    [Documentation]  Set the array byte.
291    [Arguments]    ${word}
292    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByte}  ${word}
293    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByteLocal}   ,
294    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
295
296
297Copy ipmitool
298    [Documentation]  Copy the ipmitool to the BMC.
299    ${ipmitool_error}=  Catenate  The ipmitool program could not be found in the tools directory.
300    ...  It is not part of the automation code by default. You must manually copy or link the correct openbmc
301    ...  version of the tool in to the tools directory in order to run this test suite.
302
303    OperatingSystem.File Should Exist  tools/ipmitool  msg=${ipmitool_error}
304
305    Import Library      SCPLibrary      WITH NAME       scp
306    scp.Open connection     ${OPENBMC_HOST}     username=${OPENBMC_USERNAME}      password=${OPENBMC_PASSWORD}
307    scp.Put File    tools/ipmitool   /tmp
308    SSHLibrary.Open Connection     ${OPENBMC_HOST}
309    Login   ${OPENBMC_USERNAME}    ${OPENBMC_PASSWORD}
310    Execute Command     chmod +x /tmp/ipmitool
311
312
313Initiate Host Boot Via External IPMI
314    [Documentation]  Initiate host power on using external IPMI.
315    [Arguments]  ${wait}=${1}
316
317    # Description of argument(s):
318    # wait                          Indicates that this keyword should wait
319    #                               for host running state.
320
321    ${output}=  Run External IPMI Standard Command  chassis power on
322    Should Not Contain  ${output}  Error
323
324    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
325    Wait Until Keyword Succeeds  10 min  10 sec  Is Host Running
326
327
328Initiate Host PowerOff Via External IPMI
329    [Documentation]  Initiate host power off using external IPMI.
330    [Arguments]  ${wait}=${1}
331
332    # Description of argument(s):
333    # wait                          Indicates that this keyword should wait
334    #                               for host off state.
335
336    ${output}=  Run External IPMI Standard Command  chassis power off
337    Should Not Contain  ${output}  Error
338
339    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
340    Wait Until Keyword Succeeds  3 min  10 sec  Is Host Off
341
342
343Is Host Off Via IPMI
344    [Documentation]  Verify if the Host is off using IPMI command.
345
346    ${status}=  Run External IPMI Standard Command  chassis power status
347    Should Contain  ${status}  off
348
349
350Get Host State Via External IPMI
351    [Documentation]  Returns host state using external IPMI.
352
353    ${output}=  Run External IPMI Standard Command  chassis power status
354    Should Not Contain  ${output}  Error
355    ${output}=  Fetch From Right  ${output}  ${SPACE}
356
357    [Return]  ${output}
358
359
360Set BMC Network From Host
361    [Documentation]  Set BMC network from host.
362    [Arguments]  ${nw_info}
363
364    # Description of argument(s):
365    # nw_info                       A dictionary containing the network
366    #                               information to apply.
367
368    Run Inband IPMI Standard Command
369    ...  lan set 1 ipaddr ${nw_info['IP Address']}
370
371    Run Inband IPMI Standard Command
372    ...  lan set 1 netmask ${nw_info['Subnet Mask']}
373
374    Run Inband IPMI Standard Command
375    ...  lan set 1 defgw ipaddr ${nw_info['Default Gateway IP']}
376
377
378Verify IPMI Username And Password
379    [Documentation]  Verify that user is able to run IPMI command
380    ...  with given username and password.
381    [Arguments]  ${username}  ${password}
382
383    # Description of argument(s):
384    # username    The user name (e.g. "root", "robert", etc.).
385    # password    The user password (e.g. "0penBmc", "0penBmc1", etc.).
386
387    ${output}=  Wait Until Keyword Succeeds  15 sec  5 sec  Run External IPMI Standard Command
388    ...  sel info  U=${username}  P=${password}
389    Should Contain  ${output}  SEL Information  msg=SEL information not present
390
391
392IPMI Create User
393    [Documentation]  Create IPMI user with given userid and username.
394    [Arguments]  ${userid}  ${username}
395
396    # Description of argument(s):
397    # userid      The user ID (e.g. "1", "2", etc.).
398    # username    The user name (e.g. "root", "robert", etc.).
399
400    ${ipmi_cmd}=  Catenate  user set name ${userid} ${username}
401    ${resp}=  Run IPMI Standard Command  ${ipmi_cmd}
402    ${user_info}=  Get User Info  ${userid}
403    Should Be Equal  ${user_info['user_name']}  ${username}
404
405
406Set Channel Access
407    [Documentation]  Verify that user is able to run IPMI command
408    ...  with given username and password.
409    [Arguments]  ${userid}  ${options}  ${channel_number}=${CHANNEL_NUMBER}
410
411    # Description of argument(s):
412    # userid          The user ID (e.g. "1", "2", etc.).
413    # options         Set channel command options (e.g.
414    #                 "link=on", "ipmi=on", etc.).
415    # channel_number  The user's channel number (e.g. "1").
416
417    ${ipmi_cmd}=  Catenate  SEPARATOR=
418    ...  channel setaccess${SPACE}${channel_number}${SPACE}${userid}
419    ...  ${SPACE}${options}
420    Run IPMI Standard Command  ${ipmi_cmd}
421
422
423Delete All Non Root IPMI User
424    [Documentation]  Delete all non-root IPMI user.
425
426    # Get complete list of user info records.
427    ${user_info}=  Get User Info  ${EMPTY}
428    # Remove header record.
429    ${user_info}=  Filter Struct  ${user_info}  [('user_name', None)]  invert=1
430    ${non_empty_user_info}=  Filter Struct  ${user_info}  [('user_name', '')]  invert=1
431    ${non_root_user_info}=  Filter Struct  ${non_empty_user_info}  [('user_name', 'root')]  invert=1
432
433    FOR  ${user_record}  IN  @{non_root_user_info}
434        Run IPMI Standard Command   user set name ${user_record['user_id']} ""
435        Sleep  5s
436    END
437