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