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