blob: 085ca2a5754d0f4e3a306c3b8b6267b7e6212718 [file] [log] [blame]
Michael Walshed5b46e2017-05-24 11:49:14 -05001#!/usr/bin/env python
2
3r"""
4Provide useful ipmi functions.
5"""
6
Michael Walshf4098fb2018-02-28 10:54:46 -06007import re
Michael Walsh4481b932018-02-08 11:45:15 -06008import gen_print as gp
Michael Walshed5b46e2017-05-24 11:49:14 -05009import gen_misc as gm
10import gen_robot_keyword as grk
11import gen_robot_utils as gru
Michael Walsh4481b932018-02-08 11:45:15 -060012import bmc_ssh_utils as bsu
13import var_funcs as vf
Michael Walshed5b46e2017-05-24 11:49:14 -050014import tempfile
15gru.my_import_resource("ipmi_client.robot")
Michael Walsh4481b932018-02-08 11:45:15 -060016from robot.libraries.BuiltIn import BuiltIn
Michael Walshed5b46e2017-05-24 11:49:14 -050017
18
Michael Walshed5b46e2017-05-24 11:49:14 -050019def get_sol_info():
Michael Walshed5b46e2017-05-24 11:49:14 -050020 r"""
21 Get all SOL info and return it as a dictionary.
22
23 Example use:
24
25 Robot code:
26 ${sol_info}= get_sol_info
27 Rpvars sol_info
28
29 Output:
30 sol_info:
31 sol_info[Info]: SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e
32 sol_info[Character Send Threshold]: 1
33 sol_info[Force Authentication]: true
34 sol_info[Privilege Level]: USER
35 sol_info[Set in progress]: set-complete
36 sol_info[Retry Interval (ms)]: 100
37 sol_info[Non-Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
38 sol_info[Character Accumulate Level (ms)]: 100
39 sol_info[Enabled]: true
40 sol_info[Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
41 sol_info[Payload Channel]: 14 (0x0e)
42 sol_info[Payload Port]: 623
43 sol_info[Force Encryption]: true
44 sol_info[Retry Count]: 7
45 """
46
47 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol info")
48
49 # Create temp file path.
50 temp = tempfile.NamedTemporaryFile()
51 temp_file_path = temp.name
52
53 # Write sol info to temp file path.
54 text_file = open(temp_file_path, "w")
55 text_file.write(ret_values)
56 text_file.close()
57
58 # Use my_parm_file to interpret data.
59 sol_info = gm.my_parm_file(temp_file_path)
60
61 return sol_info
62
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050063
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050064def set_sol_setting(setting_name, setting_value):
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050065 r"""
66 Set SOL setting with given value.
67
68 # Description of argument(s):
69 # setting_name SOL setting which needs to be set (e.g. "retry-count").
70 # setting_value Value which needs to be set (e.g. "7").
71 """
72
73 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol set " +
74 setting_name + " " + setting_value)
75
76 return status
77
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050078
Michael Walsh4481b932018-02-08 11:45:15 -060079def get_lan_print_dict():
Michael Walsh4481b932018-02-08 11:45:15 -060080 r"""
81 Get IPMI 'lan print' output and return it as a dictionary.
82
83 Here is an example of the IPMI lan print output:
84
85 Set in Progress : Set Complete
86 Auth Type Support : MD5
87 Auth Type Enable : Callback : MD5
88 : User : MD5
89 : Operator : MD5
90 : Admin : MD5
91 : OEM : MD5
92 IP Address Source : Static Address
93 IP Address : x.x.x.x
94 Subnet Mask : x.x.x.x
95 MAC Address : xx:xx:xx:xx:xx:xx
96 Default Gateway IP : x.x.x.x
97 802.1q VLAN ID : Disabled
98 Cipher Suite Priv Max : Not Available
99 Bad Password Threshold : Not Available
100
101 Given that data, this function will return the following dictionary.
102
103 lan_print_dict:
104 [Set in Progress]: Set Complete
105 [Auth Type Support]: MD5
106 [Auth Type Enable]:
107 [Callback]: MD5
108 [User]: MD5
109 [Operator]: MD5
110 [Admin]: MD5
111 [OEM]: MD5
112 [IP Address Source]: Static Address
113 [IP Address]: x.x.x.x
114 [Subnet Mask]: x.x.x.x
115 [MAC Address]: xx:xx:xx:xx:xx:xx
116 [Default Gateway IP]: x.x.x.x
117 [802.1q VLAN ID]: Disabled
118 [Cipher Suite Priv Max]: Not Available
119 [Bad Password Threshold]: Not Available
120
121 """
122
123 IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
124
125 # Notice in the example of data above that 'Auth Type Enable' needs some
126 # special processing. We essentially want to isolate its data and remove
127 # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
128 # process it as a sub-dictionary.
129 cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E '^(Auth Type Enable)" +\
130 "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
131 stdout1, stderr, rc = bsu.os_execute_command(cmd_buf)
132
133 # Now get the remainder of the data and exclude the lines with no field
134 # names (i.e. the 'Auth Type Enable' sub-fields).
135 cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E -v '^[ ]+: '"
136 stdout2, stderr, rc = bsu.os_execute_command(cmd_buf)
137
138 # Make auth_type_enable_dict sub-dictionary...
139 auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0,
140 underscores=0)
141
142 # Create the lan_print_dict...
143 lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0,
144 underscores=0)
145 # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
146 lan_print_dict['Auth Type Enable'] = auth_type_enable_dict
147
148 return lan_print_dict
Michael Walshd59ed7c2018-02-15 10:19:38 -0600149
150
Michael Walshf4098fb2018-02-28 10:54:46 -0600151def get_ipmi_power_reading(strip_watts=1):
Michael Walshd59ed7c2018-02-15 10:19:38 -0600152 r"""
153 Get IPMI power reading data and return it as a dictionary.
154
155 The data is obtained by issuing the IPMI "power reading" command. An
156 example is shown below:
157
158 Instantaneous power reading: 234 Watts
159 Minimum during sampling period: 234 Watts
160 Maximum during sampling period: 234 Watts
161 Average power reading over sample period: 234 Watts
162 IPMI timestamp: Thu Jan 1 00:00:00 1970
163 Sampling period: 00000000 Seconds.
164 Power reading state is: deactivated
165
166 For the data shown above, the following dictionary will be returned.
167
168 result:
169 [instantaneous_power_reading]: 238 Watts
170 [minimum_during_sampling_period]: 238 Watts
171 [maximum_during_sampling_period]: 238 Watts
172 [average_power_reading_over_sample_period]: 238 Watts
173 [ipmi_timestamp]: Thu Jan 1 00:00:00 1970
174 [sampling_period]: 00000000 Seconds.
175 [power_reading_state_is]: deactivated
Michael Walshf4098fb2018-02-28 10:54:46 -0600176
177 Description of argument(s):
178 strip_watts Strip all dictionary values of the trailing " Watts"
179 substring.
Michael Walshd59ed7c2018-02-15 10:19:38 -0600180 """
181
182 status, ret_values = \
183 grk.run_key_u("Run IPMI Standard Command dcmi power reading")
184 result = vf.key_value_outbuf_to_dict(ret_values)
185
Michael Walshf4098fb2018-02-28 10:54:46 -0600186 if strip_watts:
187 result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items())
188
Michael Walshd59ed7c2018-02-15 10:19:38 -0600189 return result
Michael Walshaf5607e2018-02-19 17:37:20 -0600190
191
192def get_mc_info():
Michael Walshaf5607e2018-02-19 17:37:20 -0600193 r"""
194 Get IPMI mc info data and return it as a dictionary.
195
196 The data is obtained by issuing the IPMI "mc info" command. An
197 example is shown below:
198
199 Device ID : 0
200 Device Revision : 0
201 Firmware Revision : 2.01
202 IPMI Version : 2.0
203 Manufacturer ID : 42817
204 Manufacturer Name : Unknown (0xA741)
205 Product ID : 16975 (0x424f)
206 Product Name : Unknown (0x424F)
207 Device Available : yes
208 Provides Device SDRs : yes
209 Additional Device Support :
210 Sensor Device
211 SEL Device
212 FRU Inventory Device
213 Chassis Device
214 Aux Firmware Rev Info :
215 0x00
216 0x00
217 0x00
218 0x00
219
220 For the data shown above, the following dictionary will be returned.
221 mc_info:
222 [device_id]: 0
223 [device_revision]: 0
224 [firmware_revision]: 2.01
225 [ipmi_version]: 2.0
226 [manufacturer_id]: 42817
227 [manufacturer_name]: Unknown (0xA741)
228 [product_id]: 16975 (0x424f)
229 [product_name]: Unknown (0x424F)
230 [device_available]: yes
231 [provides_device_sdrs]: yes
232 [additional_device_support]:
233 [additional_device_support][0]: Sensor Device
234 [additional_device_support][1]: SEL Device
235 [additional_device_support][2]: FRU Inventory Device
236 [additional_device_support][3]: Chassis Device
237 [aux_firmware_rev_info]:
238 [aux_firmware_rev_info][0]: 0x00
239 [aux_firmware_rev_info][1]: 0x00
240 [aux_firmware_rev_info][2]: 0x00
241 [aux_firmware_rev_info][3]: 0x00
242 """
243
244 status, ret_values = \
245 grk.run_key_u("Run IPMI Standard Command mc info")
246 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
247
248 return result
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500249
250
251def get_sdr_info():
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500252 r"""
253 Get IPMI sdr info data and return it as a dictionary.
254
255 The data is obtained by issuing the IPMI "sdr info" command. An
256 example is shown below:
257
258 SDR Version : 0x51
259 Record Count : 216
260 Free Space : unspecified
261 Most recent Addition :
262 Most recent Erase :
263 SDR overflow : no
264 SDR Repository Update Support : unspecified
265 Delete SDR supported : no
266 Partial Add SDR supported : no
267 Reserve SDR repository supported : no
268 SDR Repository Alloc info supported : no
269
270 For the data shown above, the following dictionary will be returned.
271 mc_info:
272
273 [sdr_version]: 0x51
274 [record_Count]: 216
275 [free_space]: unspecified
276 [most_recent_addition]:
277 [most_recent_erase]:
278 [sdr_overflow]: no
279 [sdr_repository_update_support]: unspecified
280 [delete_sdr_supported]: no
281 [partial_add_sdr_supported]: no
282 [reserve_sdr_repository_supported]: no
283 [sdr_repository_alloc_info_supported]: no
284 """
285
286 status, ret_values = \
287 grk.run_key_u("Run IPMI Standard Command sdr info")
288 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
289
290 return result
George Keishing3511a3f2018-04-19 10:38:30 -0500291
292
293def get_aux_version(version_id):
294 r"""
295 Get IPMI Aux version info data and return it.
296
297 Description of argument(s):
298 version_id The data is obtained by from BMC /etc/os-release
299 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
300
301 In the prior example, the 3rd field is "438" is the commit version and
302 the 5th field is "r3" and value "3" is the release version.
303
304 Aux version return from this function 4380003.
305 """
306
307 # Commit version.
308 count = re.findall("-(\d{1,4})-", version_id)
309
310 # Release version.
311 release = re.findall("-r(\d{1,4})", version_id)
312 if release:
313 aux_version = count[0] + "{0:0>4}".format(release[0])
314 else:
315 aux_version = count[0] + "0000"
316
317 return aux_version
Michael Walsh27b14a62018-05-24 11:05:07 -0500318
319
320def get_fru_info():
321 r"""
322 Get fru info and return it as a list of dictionaries.
323
324 The data is obtained by issuing the IPMI "fru print -N 50" command. An
325 example is shown below:
326
327 FRU Device Description : Builtin FRU Device (ID 0)
328 Device not present (Unspecified error)
329
330 FRU Device Description : cpu0 (ID 1)
331 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500332 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500333 Board Product : PROCESSOR MODULE
334 Board Serial : YA1934315964
335 Board Part Number : 02CY209
336
337 FRU Device Description : cpu1 (ID 2)
338 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500339 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500340 Board Product : PROCESSOR MODULE
341 Board Serial : YA1934315965
342 Board Part Number : 02CY209
343
344 For the data shown above, the following list of dictionaries will be
345 returned.
346
347 fru_obj:
348 fru_obj[0]:
349 [fru_device_description]: Builtin FRU Device (ID 0)
350 [state]: Device not present (Unspecified error)
351 fru_obj[1]:
352 [fru_device_description]: cpu0 (ID 1)
353 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500354 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500355 [board_product]: PROCESSOR MODULE
356 [board_serial]: YA1934315964
357 [board_part_number]: 02CY209
358 fru_obj[2]:
359 [fru_device_description]: cpu1 (ID 2)
360 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500361 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500362 [board_product]: PROCESSOR MODULE
363 [board_serial]: YA1934315965
364 [board_part_number]: 02CY209
365 """
366
367 status, ret_values = \
368 grk.run_key_u("Run IPMI Standard Command fru print -N 50")
369
370 # Manipulate the "Device not present" line to create a "state" key.
371 ret_values = re.sub("Device not present", "state : Device not present",
372 ret_values)
373
374 return [vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n",
375 ret_values)]
Michael Walsh61224e62018-05-30 17:58:42 -0500376
377
Michael Walsha95e4ef2018-06-06 17:53:04 -0500378def get_component_fru_info(component='cpu',
379 fru_objs=None):
Michael Walsh61224e62018-05-30 17:58:42 -0500380 r"""
381 Get fru info for the given component and return it as a list of
382 dictionaries.
383
384 This function calls upon get_fru_info and then filters out the unwanted
385 entries. See get_fru_info's prolog for a layout of the data.
386
387 Description of argument(s):
388 component The component (e.g. "cpu", "dimm", etc.).
Michael Walsha95e4ef2018-06-06 17:53:04 -0500389 fru_objs A fru_objs list such as the one returned by get_fru_info. If
390 this is None, then this function will call get_fru_info to
391 obtain such a list. Supplying this argument may improve
392 performance if this function is to be called multiple times.
Michael Walsh61224e62018-05-30 17:58:42 -0500393 """
394
Michael Walsha95e4ef2018-06-06 17:53:04 -0500395 if fru_objs is None:
396 fru_objs = get_fru_info()
Michael Walsh61224e62018-05-30 17:58:42 -0500397 return\
398 [x for x in fru_objs
399 if re.match(component + '([0-9]+)? ', x['fru_device_description'])]