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.txt
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_EXT_CMD}        ${EMPTY}
20${IPMI_USER_OPTIONS}   ${EMPTY}
21${IPMI_INBAND_CMD}=    ipmitool -C ${IPMI_CIPHER_LEVEL}
22${HOST}=               -H
23${RAW}=                raw
24
25*** Keywords ***
26
27Run IPMI Command
28    [Documentation]  Run the given IPMI command.
29    [Arguments]  ${args}
30    ${resp}=  Run Keyword If  '${IPMI_COMMAND}' == 'External'
31    ...  Run External IPMI Raw Command  ${args}
32    ...  ELSE IF  '${IPMI_COMMAND}' == 'Inband'
33    ...  Run Inband IPMI Raw Command  ${args}
34    ...  ELSE IF  '${IPMI_COMMAND}' == 'Dbus'
35    ...  Run Dbus IPMI RAW Command  ${args}
36    ...  ELSE  Fail  msg=Invalid IPMI Command type provided : ${IPMI_COMMAND}
37    [Return]  ${resp}
38
39Run IPMI Standard Command
40    [Documentation]  Run the standard IPMI command.
41    [Arguments]  ${args}  ${fail_on_err}=${1}
42
43    # Description of argument(s):
44    # args         IPMI command to be executed.
45    # fail_on_err  Fail if keyword the IPMI command fails
46
47    ${resp}=  Run Keyword If  '${IPMI_COMMAND}' == 'External'
48    ...  Run External IPMI Standard Command  ${args}  ${fail_on_err}
49    ...  ELSE IF  '${IPMI_COMMAND}' == 'Inband'
50    ...  Run Inband IPMI Standard Command  ${args}  ${fail_on_err}
51    ...  ELSE IF  '${IPMI_COMMAND}' == 'Dbus'
52    ...  Run Dbus IPMI Standard Command  ${args}
53    ...  ELSE  Fail  msg=Invalid IPMI Command type provided : ${IPMI_COMMAND}
54
55    [Return]  ${resp}
56
57Run Dbus IPMI RAW Command
58    [Documentation]  Run the raw IPMI command through dbus.
59    [Arguments]    ${args}
60    ${valueinBytes}=   Byte Conversion  ${args}
61    ${cmd}=   Catenate   ${dbushostipmicmd1} ${dbusHostIpmiCmdReceivedMsg}
62    ${cmd}=   Catenate   ${cmd} ${valueinBytes}
63    ${output}   ${stderr}=  Execute Command  ${cmd}  return_stderr=True
64    Should Be Empty      ${stderr}
65    set test variable    ${OUTPUT}     "${output}"
66
67Run Dbus IPMI Standard Command
68    [Documentation]  Run the standard IPMI command through dbus.
69    [Arguments]    ${args}
70    Copy ipmitool
71    ${stdout}    ${stderr}    ${output}=  Execute Command
72    ...    /tmp/ipmitool -I dbus ${args}    return_stdout=True
73    ...    return_stderr= True    return_rc=True
74    Should Be Equal    ${output}    ${0}    msg=${stderr}
75    [Return]    ${stdout}
76
77Run Inband IPMI Raw Command
78    [Documentation]  Run the raw IPMI command in-band.
79    [Arguments]  ${args}  ${os_host}=${OS_HOST}  ${os_username}=${OS_USERNAME}
80    ...          ${os_password}=${OS_PASSWORD}
81
82    # Description of arguments:
83    # ${args}  parameters to IPMI command.
84    # ${os_host} IP address of the OS Host.
85    # ${os_username}  OS Host Login user name.
86    # ${os_password}  OS Host Login passwrd.
87
88    Login To OS Host  ${os_host}  ${os_username}  ${os_password}
89    Check If IPMI Tool Exist
90
91    ${inband_raw_cmd}=  Catenate  ${IPMI_INBAND_CMD}  ${RAW}  ${args}
92    ${stdout}  ${stderr}=  Execute Command  ${inband_raw_cmd}  return_stderr=True
93    Should Be Empty  ${stderr}  msg=${stdout}
94    [Return]  ${stdout}
95
96Run Inband IPMI Standard Command
97    [Documentation]  Run the standard IPMI command in-band.
98    [Arguments]  ${args}  ${fail_on_err}=${1}  ${os_host}=${OS_HOST}
99    ...          ${os_username}=${OS_USERNAME}  ${os_password}=${OS_PASSWORD}
100
101    # Description of arguments:
102    # ${args}  parameters to IPMI command.
103    # ${os_host} IP address of the OS Host.
104    # ${os_username}  OS Host Login user name.
105    # ${os_password}  OS Host Login passwrd.
106
107    Login To OS Host  ${os_host}  ${os_username}  ${os_password}
108    Check If IPMI Tool Exist
109
110    ${inband_std_cmd}=  Catenate  ${IPMI_INBAND_CMD}  ${args}
111    ${stdout}  ${stderr}=  Execute Command  ${inband_std_cmd}  return_stderr=True
112    Return From Keyword If  ${fail_on_err} == ${0}  ${stderr}
113    Should Be Empty  ${stderr}  msg=${stdout}
114    [Return]  ${stdout}
115
116Run External IPMI Raw Command
117    [Documentation]  Run the raw IPMI command externally.
118    [Arguments]    ${args}
119
120    ${ipmi_raw_cmd}=   Catenate  SEPARATOR=
121    ...    ${IPMI_EXT_CMD} -P${SPACE}${IPMI_PASSWORD}${SPACE}
122    ...    ${HOST}${SPACE}${OPENBMC_HOST}${SPACE}${RAW}${SPACE}${args}
123    ${rc}    ${output}=    Run and Return RC and Output    ${ipmi_raw_cmd}
124    Should Be Equal    ${rc}    ${0}    msg=${output}
125    [Return]    ${output}
126
127Run External IPMI Standard Command
128    [Documentation]  Run the standard IPMI command in-band.
129    [Arguments]  ${args}  ${fail_on_err}=${1}
130
131    # Description of argument(s):
132    # args         IPMI command to be executed.
133    # fail_on_err  Fail if keyword the IPMI command fails
134
135    ${ipmi_cmd}=  Catenate  SEPARATOR=
136    ...  ${IPMI_EXT_CMD} ${IPMI_USER_OPTIONS} -P${SPACE}${IPMI_PASSWORD}
137    ...  ${SPACE}${HOST}${SPACE}${OPENBMC_HOST}${SPACE}${args}
138    ${rc}  ${output}=  Run And Return RC and Output  ${ipmi_cmd}
139    Return From Keyword If  ${fail_on_err} == ${0}  ${output}
140    Should Be Equal  ${rc}  ${0}  msg=${output}
141    [Return]  ${output}
142
143Check If IPMI Tool Exist
144    [Documentation]  Check if IPMI Tool installed or not.
145    ${output}=  Execute Command  which ipmitool
146    Should Not Be Empty  ${output}  msg=ipmitool not installed.
147
148
149Activate SOL Via IPMI
150    [Documentation]  Start SOL using IPMI and route output to a file.
151    [Arguments]  ${file_path}=/tmp/sol_${OPENBMC_HOST}
152    # Description of argument(s):
153    # file_path  The file path on the local machine (vs OBMC) to collect SOL
154    #            output. By default SOL output is collected at
155    #            /tmp/sol_<BMC_IP> else user input location.
156
157    ${ipmi_cmd}=  Catenate  SEPARATOR=
158    ...  ${IPMI_EXT_CMD} -P${SPACE}${IPMI_PASSWORD}${SPACE}${HOST}
159    ...  ${SPACE}${OPENBMC_HOST}${SPACE}sol activate usesolkeepalive
160
161    Start Process  ${ipmi_cmd}  shell=True  stdout=${file_path}
162    ...  alias=sol_proc
163
164
165Deactivate SOL Via IPMI
166    [Documentation]  Stop SOL using IPMI and return SOL output.
167    [Arguments]  ${file_path}=/tmp/sol_${OPENBMC_HOST}
168    # Description of argument(s):
169    # file_path  The file path on the local machine to copy SOL output
170    #            collected by above "Activate SOL Via IPMI" keyword.
171    #            By default it copies log from /tmp/sol_<BMC_IP>.
172
173    ${ipmi_cmd}=  Catenate  SEPARATOR=
174    ...  ${IPMI_EXT_CMD} -P${SPACE}${IPMI_PASSWORD}${SPACE}
175    ...  ${HOST}${SPACE}${OPENBMC_HOST}${SPACE}sol deactivate
176
177    ${rc}  ${output}=  Run and Return RC and Output  ${ipmi_cmd}
178    Run Keyword If  ${rc} > 0  Run Keywords
179    ...  Run Keyword And Ignore Error  Terminate Process  sol_proc
180    ...  AND  Return From Keyword  ${output}
181
182    ${rc}  ${output}=  Run and Return RC and Output  cat ${file_path}
183    Should Be Equal  ${rc}  ${0}  msg=${output}
184
185    # Logging SOL output for debug purpose.
186    Log  ${output}
187
188    [Return]  ${output}
189
190
191Byte Conversion
192    [Documentation]   Byte Conversion method receives IPMI RAW commands as
193    ...               argument in string format.
194    ...               Sample argument is as follows
195    ...               "0x04 0x30 9 0x01 0x00 0x35 0x00 0x00 0x00 0x00 0x00
196    ...               0x00"
197    ...               IPMI RAW command format is as follows
198    ...               <netfn Byte> <cmd Byte> <Data Bytes..>
199    ...               This method converts IPMI command format into
200    ...               dbus command format  as follows
201    ...               <byte:seq-id> <byte:netfn> <byte:lun> <byte:cmd>
202    ...               <array:byte:data>
203    ...               Sample dbus  Host IPMI Received Message argument
204    ...               byte:0x00 byte:0x04 byte:0x00 byte:0x30
205    ...               array:byte:9,0x01,0x00,0x35,0x00,0x00,0x00,0x00,0x00,0x00
206    [Arguments]     ${args}
207    ${argLength}=   Get Length  ${args}
208    Set Global Variable  ${arrayByte}   array:byte:
209    @{listargs}=   Split String  ${args}
210    ${index}=   Set Variable   ${0}
211    :FOR  ${word}  IN  @{listargs}
212    \    Run Keyword if   ${index} == 0   Set NetFn Byte  ${word}
213    \    Run Keyword if   ${index} == 1   Set Cmd Byte    ${word}
214    \    Run Keyword if   ${index} > 1    Set Array Byte  ${word}
215    \    ${index}=    Set Variable    ${index + 1}
216    ${length}=   Get Length  ${arrayByte}
217    ${length}=   Evaluate  ${length} - 1
218    ${arrayByteLocal}=  Get Substring  ${arrayByte}  0   ${length}
219    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
220    ${valueinBytesWithArray}=   Catenate  byte:0x00   ${netfnByte}  byte:0x00
221    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray}  ${cmdByte}
222    ${valueinBytesWithArray}=   Catenate  ${valueinBytesWithArray} ${arrayByte}
223    ${valueinBytesWithoutArray}=   Catenate  byte:0x00 ${netfnByte}  byte:0x00
224    ${valueinBytesWithoutArray}=   Catenate  ${valueinBytesWithoutArray} ${cmdByte}
225#   To Check scenario for smaller IPMI raw commands with only 2 arguments
226#   instead of usual 12 arguments.
227#   Sample small IPMI raw command: Run IPMI command 0x06 0x36
228#   If IPMI raw argument length is only 9 then return value in bytes without
229#   array population.
230#   Equivalent dbus-send argument for smaller IPMI raw command:
231#   byte:0x00 byte:0x06 byte:0x00 byte:0x36
232    Run Keyword if   ${argLength} == 9     Return from Keyword    ${valueinBytesWithoutArray}
233    [Return]    ${valueinBytesWithArray}
234
235
236Set NetFn Byte
237    [Documentation]  Set the network function byte.
238    [Arguments]    ${word}
239    ${netfnByteLocal}=  Catenate   byte:${word}
240    Set Global Variable  ${netfnByte}  ${netfnByteLocal}
241
242Set Cmd Byte
243    [Documentation]  Set the command byte.
244    [Arguments]    ${word}
245    ${cmdByteLocal}=  Catenate   byte:${word}
246    Set Global Variable  ${cmdByte}  ${cmdByteLocal}
247
248Set Array Byte
249    [Documentation]  Set the array byte.
250    [Arguments]    ${word}
251    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByte}  ${word}
252    ${arrayByteLocal}=   Catenate   SEPARATOR=  ${arrayByteLocal}   ,
253    Set Global Variable  ${arrayByte}   ${arrayByteLocal}
254
255Copy ipmitool
256    [Documentation]  Copy the ipmitool to the BMC.
257    ${ipmitool_error}=  Catenate  The ipmitool program could not be found in the tools directory.
258    ...  It is not part of the automation code by default. You must manually copy or link the correct openbmc
259    ...  version of the tool in to the tools directory in order to run this test suite.
260
261    OperatingSystem.File Should Exist  tools/ipmitool  msg=${ipmitool_error}
262
263    Import Library      SCPLibrary      WITH NAME       scp
264    scp.Open connection     ${OPENBMC_HOST}     username=${OPENBMC_USERNAME}      password=${OPENBMC_PASSWORD}
265    scp.Put File    tools/ipmitool   /tmp
266    SSHLibrary.Open Connection     ${OPENBMC_HOST}
267    Login   ${OPENBMC_USERNAME}    ${OPENBMC_PASSWORD}
268    Execute Command     chmod +x /tmp/ipmitool
269
270Initiate Host Boot Via External IPMI
271    [Documentation]  Initiate host power on using external IPMI.
272    [Arguments]  ${wait}=${1}
273    # Description of argument(s):
274    # wait  Indicates that this keyword should wait for host running state.
275
276    ${output}=  Run External IPMI Standard Command  chassis power on
277    Should Not Contain  ${output}  Error
278
279    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
280    Wait Until Keyword Succeeds  10 min  10 sec  Is Host Running
281
282Initiate Host PowerOff Via External IPMI
283    [Documentation]  Initiate host power off using external IPMI.
284    [Arguments]  ${wait}=${1}
285    # Description of argument(s):
286    # wait  Indicates that this keyword should wait for host off state.
287
288    ${output}=  Run External IPMI Standard Command  chassis power off
289    Should Not Contain  ${output}  Error
290
291    Run Keyword If  '${wait}' == '${0}'  Return From Keyword
292    Wait Until Keyword Succeeds  3 min  10 sec  Is Host Off
293
294Get Host State Via External IPMI
295    [Documentation]  Returns host state using external IPMI.
296
297    ${output}=  Run External IPMI Standard Command  chassis power status
298    Should Not Contain  ${output}  Error
299    ${output}=  Fetch From Right  ${output}  ${SPACE}
300
301    [Return]  ${output}
302
303
304Set BMC Network From Host
305    [Documentation]  Set BMC network from host.
306    [Arguments]  ${nw_info}
307
308    # Description of argument(s):
309    # nw_info    A dictionary containing the network information to apply.
310
311    Run Inband IPMI Standard Command
312    ...  lan set 1 ipaddr ${nw_info['IP Address']}
313
314    Run Inband IPMI Standard Command
315    ...  lan set 1 netmask ${nw_info['Subnet Mask']}
316
317    Run Inband IPMI Standard Command
318    ...  lan set 1 defgw ipaddr ${nw_info['Default Gateway IP']}
319