Set version to 1.5.0b9
[check_mk.git] / inventory / dmidecode
blob86404a244f93292eef68d33ee04f04b1fc037283
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...
65 # Note: on Linux \t is replaced by : and then the split
66 # is done by :. On Windows the \t comes 1:1 and no splitting
67 # is being done. So we need to split manually here
68 def inv_dmidecode(info):
69 section_name = None
70 section_lines = []
71 for line in info:
72 # Windows plugin keeps tabs and has no separator
73 if len(line) == 1:
74 parts = line[0].replace("\t", ":").split(":")
75 line = [ x.strip() for x in parts ]
76 if len(line) == 1:
77 if section_name:
78 inv_dmidecode_parse_section(section_name, section_lines)
79 section_name = line[0]
80 section_lines = []
81 else:
82 section_lines.append(line[1:])
83 if section_name:
84 inv_dmidecode_parse_section(section_name, section_lines)
86 node = inv_tree("hardware.")
89 def inv_dmidecode_parse_section(name, lines):
90 lines = [ [ w.strip() for w in words ] for words in lines ]
91 if name == "BIOS Information":
92 inv_dmidecode_parse_bios(lines)
93 elif name == "System Information":
94 inv_dmidecode_parse_system(lines)
95 elif name == "Chassis Information":
96 inv_dmidecode_parse_chassis(lines)
97 elif name == "Processor Information":
98 inv_dmidecode_parse_processor(lines)
99 # elif name == "Memory Controller Information":
100 # inv_dmidecode_parse_mem_controller(lines)
101 # elif name == "Memory Module Information":
102 # inv_dmidecode_parse_mem_module(lines)
103 elif name == "Physical Memory Array":
104 inv_dmidecode_parse_physical_mem_array(lines)
105 elif name == "Memory Device":
106 inv_dmidecode_parse_mem_device(lines)
108 # TODO: Summe über alle Arrays ausrechnen
110 def inv_dmidecode_parse_date(value):
111 try:
112 # 10/17/2008
113 return time.mktime(time.strptime(value, "%m/%d/%Y"))
114 except Exception, e:
115 return
117 def inv_dmidecode_parse_bios(lines):
118 inv_dmidecode_parse_generic("hardware.bios.", lines, {
119 "Vendor" : "vendor",
120 "Version" : "version",
121 "Release Date" : ("date", inv_dmidecode_parse_date),
122 "BIOS Revision" : "revision",
123 "Firmware Revision" : "firmware",
126 def inv_dmidecode_parse_system(lines):
127 inv_dmidecode_parse_generic("hardware.system.", lines, {
128 "Manufacturer" : "manufacturer",
129 "Product Name" : "product",
130 "Version" : "version",
131 "Serial Number" : "serial",
132 "UUID" : "uuid",
133 "Family" : "family",
136 def inv_dmidecode_parse_chassis(lines):
137 inv_dmidecode_parse_generic("hardware.chassis.", lines, {
138 "Manufacturer" : "manufacturer",
139 "Type" : "type",
142 # Note: This node is also being filled by lnx_cpuinfo
143 def inv_dmidecode_parse_processor(lines):
144 cpu_info = {}
145 for line in lines:
146 if line[0] == "Manufacturer":
147 cpu_info["vendor"] = {
148 "GenuineIntel" : "intel",
149 "Intel(R) Corporation" : "intel",
150 "AuthenticAMD" : "amd",
151 }.get(line[1], line[1])
152 elif line[0] == "Max Speed": # 2530 MHz
153 cpu_info["max_speed"] = dmidecode_parse_speed(line[1])
154 elif line[0] == "Voltage":
155 cpu_info["voltage"] = dmidecode_parse_voltage(line[1])
156 elif line[0] == "Status":
157 if line[1] == "Unpopulated":
158 return
160 # Only update our CPU information if the socket is populated
161 inv_tree("hardware.cpu.").update(cpu_info)
163 # def inv_dmidecode_parse_mem_controller(lines):
164 # # TODO: Can we have multiple memory controllers
165 # node = inv_tree("hardware.memory.")
166 # for line in lines:
167 # if line[0] == "Maximum Memory Module Size":
168 # node["max_module_size"] = dmidecode_parse_size(line[1])
169 # elif line[0] == "Maximum Total Memory Size":
170 # node["max_memory_size"] = dmidecode_parse_size(line[1])
171 # elif line[0] == "Memory Module Voltage":
172 # node["module_voltage"] = dmidecode_parse_voltage(line[1])
174 # def inv_dmidecode_parse_mem_module(lines):
175 # node = inv_tree_list("hardware.memory.modules:")
176 # module = {}
177 # node.append(module)
178 # for line in lines:
179 # if line[0] == "Socket Designation":
180 # module["disignation"] = line[1]
181 # elif line[0] == "Type":
182 # module["type"] = line[1]
183 # elif line[0] == "Installed Size":
184 # module["size"] = dmidecode_parse_size(line[1])
185 # elif line[0] == "Enabled Size":
186 # module["enabled_size"] = dmidecode_parse_size(line[1])
187 # elif line[0] == "Current Speed":
188 # time_sec = dmidecode_parse_time(line[1])
189 # speed = 1.0 / time_sec
190 # module["current_speed"] = speed
192 def inv_dmidecode_parse_physical_mem_array(lines):
193 # We expect several possible arrays
194 node = inv_tree_list("hardware.memory.arrays:")
196 # If we have a dummy entry from previous Memory Devices (see below)
197 # then we fill that entry rather than creating a new one
198 if len(node) == 1 and node[0].keys() == [ "devices" ]:
199 array = node[0]
200 else:
201 array = {
202 "devices" : []
204 node.append(array)
206 for line in lines:
207 if line[0] == "Location":
208 array["location"] = line[1]
209 elif line[0] == "Use":
210 array["use"] = line[1]
211 elif line[0] == "Error Correction Type":
212 array["error_correction"] = line[1]
213 elif line[0] == "Maximum Capacity":
214 array["maximum_capacity"] = dmidecode_parse_size(line[1])
216 def inv_dmidecode_parse_mem_device(lines):
217 node = inv_tree_list("hardware.memory.arrays:")
218 device = {}
220 inv_dmidecode_parse_generic(device, lines, {
221 "Total Width" : "total_width", # 64 bits
222 "Data Width" : "data_width", # 64 bits
223 "Form Factor" : "form_factor", # SODIMM
224 "Set" : "set", # None
225 "Locator" : "locator", # PROC 1 DIMM 2
226 "Bank Locator" : "bank_locator", # Bank 2/3
227 "Type" : "type", # DDR2
228 "Type Detail" : "type_detail", # Synchronous
229 "Manufacturer" : "manufacturer", # Not Specified
230 "Serial Number" : "serial", # Not Specified
231 "Asset Tag" : "asset_tag", # Not Specified
232 "Part Number" : "part_number", # Not Specified
233 "Speed" : "speed", # 667 MHz
234 "Size" : "size", # 2048 MB
237 # Do we already have an entry for a memory array? Then
238 # we assume that this device belongs to the most recently
239 # read array. Otherwise we create a dummy entry and replace
240 # that later with actual information
241 # If there are already arrays we try to find the right index of
242 # the phy. array
243 index = None
244 if device.get("locator") and device["locator"].startswith("PROC"):
245 index = device["locator"].split()[1]
247 if node:
248 try:
249 array = node[int(index) - 1]
250 except:
251 array = node[-1]
252 else:
253 array = { "devices": [] }
254 node.append(array)
256 if device["size"] != "No Module Installed":
257 # Convert speed and size into numbers
258 device["speed"] = dmidecode_parse_speed(device.get("speed", "Unknown"))
259 device["size"] = dmidecode_parse_size(device.get("size", "Unknown"))
260 array["devices"].append(device)
263 def inv_dmidecode_parse_generic(node, lines, keyinfo):
264 if type(node) == str:
265 node = inv_tree(node)
266 for line in lines:
267 if line[0] in keyinfo:
268 key = keyinfo[line[0]]
269 if line[1] != "Not Specified":
270 value = line[1]
271 if type(key) == tuple:
272 key, transform = key
273 value = transform(value)
274 if value == None:
275 continue
276 node[key] = value
279 def dmidecode_parse_size(v): # into Bytes (int)
280 if v == "Unknown":
281 return None
283 parts = v.split()
284 if parts[1].lower() == "tb":
285 return int(parts[0]) * 1024 * 1024 * 1024 * 1024
286 elif parts[1].lower() == "gb":
287 return int(parts[0]) * 1024 * 1024 * 1024
288 elif parts[1].lower() == "mb":
289 return int(parts[0]) * 1024 * 1024
290 elif parts[1].lower() == "kb":
291 return int(parts[0]) * 1024
292 else:
293 return int(parts[0])
295 def dmidecode_parse_speed(v): # into Hz (float)
296 if v == "Unknown":
297 return None
299 parts = v.split()
300 if parts[1] == "GHz":
301 return float(parts[0]) * 1000000000.0
302 elif parts[1] == "MHz":
303 return float(parts[0]) * 1000000.0
304 elif parts[1] == "kHz":
305 return float(parts[0]) * 1000.0
306 elif parts[1] == "Hz":
307 return float(parts[0])
309 def dmidecode_parse_voltage(v):
310 if v == "Unknown":
311 return None
312 return float(v.split()[0])
314 def dmidecode_parse_time(v): # 155 ns
315 parts = v.split()
316 if parts[1] == "ns":
317 return float(parts[0]) / 1000000000.0
318 else:
319 return float(parts[0]) # assume seconds
322 inv_info['dmidecode'] = {
323 "inv_function" : inv_dmidecode,