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