Refactoring: Changed all check parameters starting with a 'g' or 'h' to new rulespec...
[check_mk.git] / inventory / dmidecode
blob74ed0a48559f6bca5578802219b612a0cf35a72d
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2013 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # Example output:
28 # BIOS Information
29 # Vendor: LENOVO
30 # Version: 6FET49WW (1.19 )
31 # Release Date: 10/17/2008
32 # Address: 0xE0000
33 # Runtime Size: 128 kB
34 # ROM Size: 8192 kB
35 # Characteristics:
36 # PCI is supported
37 # PC Card (PCMCIA) is supported
38 # PNP is supported
39 # BIOS is upgradeable
40 # BIOS shadowing is allowed
41 # ESCD support is available
42 # Boot from CD is supported
43 # Selectable boot is supported
44 # BIOS ROM is socketed
45 # EDD is supported
46 # ACPI is supported
47 # USB legacy is supported
48 # BIOS boot specification is supported
49 # Targeted content distribution is supported
50 # BIOS Revision: 1.25
51 # Firmware Revision: 1.1
53 # System Information
54 # Manufacturer: LENOVO
55 # Product Name: 4061AR7
56 # Version: ThinkPad W500
57 # Serial Number: L3AFB3L
58 # UUID: AD137E01-4A86-11CB-A580-BE0E287D2679
59 # Wake-up Type: Power Switch
60 # SKU Number: Not Specified
61 # Family: ThinkPad W500
63 # ... any many other sections...
66 # Note: on Linux \t is replaced by : and then the split
67 # is done by :. On Windows the \t comes 1:1 and no splitting
68 # is being done. So we need to split manually here
69 def inv_dmidecode(info):
70 section_name = None
71 section_lines = []
72 for line in info:
73 # Windows plugin keeps tabs and has no separator
74 if len(line) == 1:
75 parts = line[0].replace("\t", ":").split(":")
76 line = [x.strip() for x in parts]
77 if len(line) == 1:
78 if section_name:
79 inv_dmidecode_parse_section(section_name, section_lines)
80 section_name = line[0]
81 section_lines = []
82 else:
83 section_lines.append(line[1:])
84 if section_name:
85 inv_dmidecode_parse_section(section_name, section_lines)
88 def inv_dmidecode_parse_section(name, lines):
89 lines = [[w.strip() for w in words] for words in lines]
90 if name == "BIOS Information":
91 inv_dmidecode_parse_bios(lines)
92 elif name == "System Information":
93 inv_dmidecode_parse_system(lines)
94 elif name == "Chassis Information":
95 inv_dmidecode_parse_chassis(lines)
96 elif name == "Processor Information":
97 inv_dmidecode_parse_processor(lines)
100 # elif name == "Memory Controller Information":
101 # inv_dmidecode_parse_mem_controller(lines)
102 # elif name == "Memory Module Information":
103 # inv_dmidecode_parse_mem_module(lines)
104 elif name == "Physical Memory Array":
105 inv_dmidecode_parse_physical_mem_array(lines)
106 elif name == "Memory Device":
107 inv_dmidecode_parse_mem_device(lines)
109 # TODO: Summe ueber alle Arrays ausrechnen
112 def inv_dmidecode_parse_date(value):
113 try:
114 # 10/17/2008
115 return time.mktime(time.strptime(value, "%m/%d/%Y"))
116 except Exception:
117 return
120 def inv_dmidecode_parse_bios(lines):
121 inv_dmidecode_parse_generic(
122 "software.bios.", lines, {
123 "Vendor": "vendor",
124 "Version": "version",
125 "Release Date": ("date", inv_dmidecode_parse_date),
126 "BIOS Revision": "revision",
127 "Firmware Revision": "firmware",
131 def inv_dmidecode_parse_system(lines):
132 inv_dmidecode_parse_generic(
133 "hardware.system.", lines, {
134 "Manufacturer": "manufacturer",
135 "Product Name": "product",
136 "Version": "version",
137 "Serial Number": "serial",
138 "UUID": "uuid",
139 "Family": "family",
143 def inv_dmidecode_parse_chassis(lines):
144 inv_dmidecode_parse_generic("hardware.chassis.", lines, {
145 "Manufacturer": "manufacturer",
146 "Type": "type",
150 # Note: This node is also being filled by lnx_cpuinfo
151 def inv_dmidecode_parse_processor(lines):
152 cpu_info = {}
153 for line in lines:
154 if line[0] == "Manufacturer":
155 cpu_info["vendor"] = {
156 "GenuineIntel": "intel",
157 "Intel(R) Corporation": "intel",
158 "AuthenticAMD": "amd",
159 }.get(line[1], line[1])
160 elif line[0] == "Max Speed": # 2530 MHz
161 cpu_info["max_speed"] = dmidecode_parse_speed(line[1])
162 elif line[0] == "Voltage":
163 cpu_info["voltage"] = dmidecode_parse_voltage(line[1])
164 elif line[0] == "Status":
165 if line[1] == "Unpopulated":
166 return
168 # Only update our CPU information if the socket is populated
169 inv_tree("hardware.cpu.").update(cpu_info)
172 # def inv_dmidecode_parse_mem_controller(lines):
173 # # TODO: Can we have multiple memory controllers
174 # node = inv_tree("hardware.memory.")
175 # for line in lines:
176 # if line[0] == "Maximum Memory Module Size":
177 # node["max_module_size"] = dmidecode_parse_size(line[1])
178 # elif line[0] == "Maximum Total Memory Size":
179 # node["max_memory_size"] = dmidecode_parse_size(line[1])
180 # elif line[0] == "Memory Module Voltage":
181 # node["module_voltage"] = dmidecode_parse_voltage(line[1])
183 # def inv_dmidecode_parse_mem_module(lines):
184 # node = inv_tree_list("hardware.memory.modules:")
185 # module = {}
186 # node.append(module)
187 # for line in lines:
188 # if line[0] == "Socket Designation":
189 # module["disignation"] = line[1]
190 # elif line[0] == "Type":
191 # module["type"] = line[1]
192 # elif line[0] == "Installed Size":
193 # module["size"] = dmidecode_parse_size(line[1])
194 # elif line[0] == "Enabled Size":
195 # module["enabled_size"] = dmidecode_parse_size(line[1])
196 # elif line[0] == "Current Speed":
197 # time_sec = dmidecode_parse_time(line[1])
198 # speed = 1.0 / time_sec
199 # module["current_speed"] = speed
202 def inv_dmidecode_parse_physical_mem_array(lines):
203 # We expect several possible arrays
204 node = inv_tree_list("hardware.memory.arrays:")
206 # If we have a dummy entry from previous Memory Devices (see below)
207 # then we fill that entry rather than creating a new one
208 if len(node) == 1 and node[0].keys() == ["devices"]:
209 array = node[0]
210 else:
211 array = {"devices": []}
212 node.append(array)
214 for line in lines:
215 if line[0] == "Location":
216 array["location"] = line[1]
217 elif line[0] == "Use":
218 array["use"] = line[1]
219 elif line[0] == "Error Correction Type":
220 array["error_correction"] = line[1]
221 elif line[0] == "Maximum Capacity":
222 array["maximum_capacity"] = dmidecode_parse_size(line[1])
225 def inv_dmidecode_parse_mem_device(lines):
226 node = inv_tree_list("hardware.memory.arrays:")
227 device = {}
229 inv_dmidecode_parse_generic(
230 device,
231 lines,
233 "Total Width": "total_width", # 64 bits
234 "Data Width": "data_width", # 64 bits
235 "Form Factor": "form_factor", # SODIMM
236 "Set": "set", # None
237 "Locator": "locator", # PROC 1 DIMM 2
238 "Bank Locator": "bank_locator", # Bank 2/3
239 "Type": "type", # DDR2
240 "Type Detail": "type_detail", # Synchronous
241 "Manufacturer": "manufacturer", # Not Specified
242 "Serial Number": "serial", # Not Specified
243 "Asset Tag": "asset_tag", # Not Specified
244 "Part Number": "part_number", # Not Specified
245 "Speed": "speed", # 667 MHz
246 "Size": "size", # 2048 MB
249 # Do we already have an entry for a memory array? Then
250 # we assume that this device belongs to the most recently
251 # read array. Otherwise we create a dummy entry and replace
252 # that later with actual information
253 # If there are already arrays we try to find the right index of
254 # the phy. array
255 index = None
256 if device.get("locator") and device["locator"].startswith("PROC"):
257 index = device["locator"].split()[1]
259 if node:
260 try:
261 array = node[int(index) - 1]
262 except:
263 array = node[-1]
264 else:
265 array = {"devices": []}
266 node.append(array)
268 if device["size"] != "No Module Installed":
269 # Convert speed and size into numbers
270 device["speed"] = dmidecode_parse_speed(device.get("speed", "Unknown"))
271 device["size"] = dmidecode_parse_size(device.get("size", "Unknown"))
272 array["devices"].append(device)
275 def inv_dmidecode_parse_generic(node, lines, keyinfo):
276 if isinstance(node, str):
277 node = inv_tree(node)
278 for line in lines:
279 if line[0] in keyinfo:
280 key = keyinfo[line[0]]
281 if line[1] != "Not Specified":
282 value = line[1]
283 if isinstance(key, tuple):
284 key, transform = key
285 value = transform(value)
286 if value is None:
287 continue
288 node[key] = value
291 def dmidecode_parse_size(v): # into Bytes (int)
292 if v == "Unknown":
293 return None
295 parts = v.split()
296 if parts[1].lower() == "tb":
297 return int(parts[0]) * 1024 * 1024 * 1024 * 1024
298 elif parts[1].lower() == "gb":
299 return int(parts[0]) * 1024 * 1024 * 1024
300 elif parts[1].lower() == "mb":
301 return int(parts[0]) * 1024 * 1024
302 elif parts[1].lower() == "kb":
303 return int(parts[0]) * 1024
304 return int(parts[0])
307 def dmidecode_parse_speed(v): # into Hz (float)
308 if v == "Unknown":
309 return None
311 parts = v.split()
312 if parts[1] == "GHz":
313 return float(parts[0]) * 1000000000.0
314 elif parts[1] == "MHz":
315 return float(parts[0]) * 1000000.0
316 elif parts[1] == "kHz":
317 return float(parts[0]) * 1000.0
318 elif parts[1] == "Hz":
319 return float(parts[0])
322 def dmidecode_parse_voltage(v):
323 if v == "Unknown":
324 return None
325 return float(v.split()[0])
328 def dmidecode_parse_time(v): # 155 ns
329 parts = v.split()
330 if parts[1] == "ns":
331 return float(parts[0]) / 1000000000.0
332 return float(parts[0]) # assume seconds
335 inv_info['dmidecode'] = {
336 "inv_function": inv_dmidecode,