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    ${rc}  ${output}=  Run and Return RC and Output  cat ${file_path}
219    Should Be Equal  ${rc}  ${0}  msg=${output}
220
221    # Logging SOL output for debug purpose.
222    Log  ${output}
223
224    [Return]  ${output}
225
226
227Byte Conversion
228    [Documentation]   Byte Conversion method receives IPMI RAW commands as
229    ...               argument in string format.
230    ...               Sample argument is as follows
231    ...               "0x04 0x30 9 0x01 0x00 0x35 0x00 0x00 0x00 0x00 0x00
232    ...               0x00"
233    ...               IPMI RAW command format is as follows
234    ...               <netfn Byte> <cmd Byte> <Data Bytes..>
235    ...               This method converts IPMI command format into
236    ...               dbus command format  as follows
237    ...               <byte:seq-id> <byte:netfn> <byte:lun> <byte:cmd>
238    ...               <array:byte:data>
239    ...               Sample dbus  Host IPMI Received Message argument
240    ...               byte:0x00 byte:0x04 byte:0x00 byte:0x30
241    ...               array:byte:9,0x01,0x00,0x35,0x00,0x00,0x00,0x00,0x00,0x00
242    [Arguments]     ${args}
243    ${argLength}=   Get Length  ${args}
244    Set Global Variable  ${arrayByte}   array:byte:
245    @{listargs}=   Split String  ${args}
246    ${index}=   Set Variable   ${0}
247    :FOR  ${word}  IN  @{listargs}
248    \    Run Keyword if   ${index} == 0   Set NetFn Byte  ${word}
249    \    Run Keyword if   ${index} == 1   Set Cmd Byte    ${word}
250    \    Run Keyword if   ${index} > 1    Set Array Byte  ${word}
251    \    ${index}=    Set Variable    ${index + 1}
252    ${length}=   Get Length  ${arrayByte}
253    ${length}=   Evaluate  ${length} - 1
254    ${arrayByteLocal}=  Get Substring  ${arrayByte}  0   ${length}
255    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
256    ${valueinBytesWithArray}=   Catenate  byte:0x00   ${netfnByte}  byte:0x00
257    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray}  ${cmdByte}
258    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray} ${arrayByte}
259    ${valueinBytesWithoutArray}=   Catenate  byte:0x00 ${netfnByte}  byte:0x00
260    ${valueinBytesWithoutArray}=   Catenate  ${valueinBytesWithoutArray} ${cmdByte}
261    #   To Check scenario for smaller IPMI raw commands with only 2 arguments
262    #   instead of usual 12 arguments.
263    #   Sample small IPMI raw command: Run IPMI command 0x06 0x36
264    #   If IPMI raw argument length is only 9 then return value in bytes without
265    #   array population.
266    #   Equivalent dbus-send argument for smaller IPMI raw command:
267    #   byte:0x00 byte:0x06 byte:0x00 byte:0x36
268    Run Keyword if   ${argLength} == 9     Return from Keyword    ${valueinBytesWithoutArray}
269    [Return]    ${valueinBytesWithArray}
270
271
272Set NetFn Byte
273    [Documentation]  Set the network function byte.
274    [Arguments]    ${word}
275    ${netfnByteLocal}=  Catenate   byte:${word}
276    Set Global Variable  ${netfnByte}  ${netfnByteLocal}
277
278
279Set Cmd Byte
280    [Documentation]  Set the command byte.
281    [Arguments]    ${word}
282    ${cmdByteLocal}=  Catenate   byte:${word}
283    Set Global Variable  ${cmdByte}  ${cmdByteLocal}
284
285
286Set Array Byte
287    [Documentation]  Set the array byte.
288    [Arguments]    ${word}
289    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByte}  ${word}
290    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByteLocal}   ,
291    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
292
293
294Copy ipmitool
295    [Documentation]  Copy the ipmitool to the BMC.
296    ${ipmitool_error}=  Catenate  The ipmitool program could not be found in the tools directory.
297    ...  It is not part of the automation code by default. You must manually copy or link the correct openbmc
298    ...  version of the tool in to the tools directory in order to run this test suite.
299
300    OperatingSystem.File Should Exist  tools/ipmitool  msg=${ipmitool_error}
301
302    Import Library      SCPLibrary      WITH NAME       scp
303    scp.Open connection     ${OPENBMC_HOST}     username=${OPENBMC_USERNAME}      password=${OPENBMC_PASSWORD}
304    scp.Put File    tools/ipmitool   /tmp
305    SSHLibrary.Open Connection     ${OPENBMC_HOST}
306    Login   ${OPENBMC_USERNAME}    ${OPENBMC_PASSWORD}
307    Execute Command     chmod +x /tmp/ipmitool
308
309
310Initiate Host Boot Via External IPMI
311    [Documentation]  Initiate host power on using external IPMI.
312    [Arguments]  ${wait}=${1}
313
314    # Description of argument(s):
315    # wait                          Indicates that this keyword should wait
316    #                               for host running state.
317
318    ${output}=  Run External IPMI Standard Command  chassis power on
319    Should Not Contain  ${output}  Error
320
321    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
322    Wait Until Keyword Succeeds  10 min  10 sec  Is Host Running
323
324
325Initiate Host PowerOff Via External IPMI
326    [Documentation]  Initiate host power off using external IPMI.
327    [Arguments]  ${wait}=${1}
328
329    # Description of argument(s):
330    # wait                          Indicates that this keyword should wait
331    #                               for host off state.
332
333    ${output}=  Run External IPMI Standard Command  chassis power off
334    Should Not Contain  ${output}  Error
335
336    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
337    Wait Until Keyword Succeeds  3 min  10 sec  Is Host Off
338
339
340Get Host State Via External IPMI
341    [Documentation]  Returns host state using external IPMI.
342
343    ${output}=  Run External IPMI Standard Command  chassis power status
344    Should Not Contain  ${output}  Error
345    ${output}=  Fetch From Right  ${output}  ${SPACE}
346
347    [Return]  ${output}
348
349
350Set BMC Network From Host
351    [Documentation]  Set BMC network from host.
352    [Arguments]  ${nw_info}
353
354    # Description of argument(s):
355    # nw_info                       A dictionary containing the network
356    #                               information to apply.
357
358    Run Inband IPMI Standard Command
359    ...  lan set 1 ipaddr ${nw_info['IP Address']}
360
361    Run Inband IPMI Standard Command
362    ...  lan set 1 netmask ${nw_info['Subnet Mask']}
363
364    Run Inband IPMI Standard Command
365    ...  lan set 1 defgw ipaddr ${nw_info['Default Gateway IP']}
366
367
368Verify IPMI Username And Password
369    [Documentation]  Verify that user is able to run IPMI command
370    ...  with given username and password.
371    [Arguments]  ${username}  ${password}
372
373    # Description of argument(s):
374    # username    The user name (e.g. "root", "robert", etc.).
375    # password    The user password (e.g. "0penBmc", "0penBmc1", etc.).
376
377    ${output}=  Run External IPMI Standard Command
378    ...  sel info  U=${username}  P=${password}
379    Should Contain  ${output}  SEL Information  msg=SEL information not present
380
381
382IPMI Create User
383    [Documentation]  Create IPMI user with given userid and username.
384    [Arguments]  ${userid}  ${username}
385
386    # Description of argument(s):
387    # userid      The user ID (e.g. "1", "2", etc.).
388    # username    The user name (e.g. "root", "robert", etc.).
389
390    ${ipmi_cmd}=  Catenate  user set name ${userid} ${username}
391    ${resp}=  Run IPMI Standard Command  ${ipmi_cmd}
392    ${user_info}=  Get User Info  ${userid}
393    Should Be Equal  ${user_info['user_name']}  ${username}
394
395
396Set Channel Access
397    [Documentation]  Verify that user is able to run IPMI command
398    ...  with given username and password.
399    [Arguments]  ${userid}  ${options}  ${channel}=1
400
401    # Description of argument(s):
402    # userid          The user ID (e.g. "1", "2", etc.).
403    # options         Set channel command options (e.g.
404    #                 "link=on", "ipmi=on", etc.).
405    # channel_number  The user's channel number (e.g. "1").
406
407    ${ipmi_cmd}=  Catenate  SEPARATOR=
408    ...  channel setaccess${SPACE}${channel}${SPACE}${userid}
409    ...  ${SPACE}${options}
410    Run IPMI Standard Command  ${ipmi_cmd}
411
412
413Delete All Non Root IPMI User
414    [Documentation]  Delete all non-root IPMI user.
415
416    FOR  ${userid}  IN RANGE  2  16
417      ${user_info}=  Get User Info  ${userid}
418      Run Keyword If  "${user_info['user_name']}" != ""
419      ...  Run IPMI Standard Command  user set name ${userid} ""
420    END
421