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