blob: 73226e3db8d3014450d41ffe94abef46e7469b84 [file] [log] [blame]
koder aka kdanilovf86d7af2015-05-06 04:01:54 +03001import re
2import xml.etree.ElementTree as ET
3
4from wally import ssh_utils, utils
5
6
7def get_data(rr, data):
8 match_res = re.search("(?ims)" + rr, data)
9 return match_res.group(0)
10
11
12class HWInfo(object):
13 def __init__(self):
14 self.hostname = None
15 self.cores = []
16
17 # /dev/... devices
18 self.disks_info = {}
19
20 # real disks on raid controller
21 self.disks_raw_info = {}
22
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030023 # name => (speed, is_full_diplex, ip_addresses)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030024 self.net_info = {}
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030025
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030026 self.ram_size = 0
27 self.sys_name = None
28 self.mb = None
29 self.raw = None
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030030
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030031 self.storage_controllers = []
32
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030033 def get_HDD_count(self):
34 # SATA HDD COUNT, SAS 10k HDD COUNT, SAS SSD count, PCI-E SSD count
35 return []
36
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030037 def get_summary(self):
38 cores = sum(count for _, count in self.cores)
39 disks = sum(size for _, size in self.disks_info.values())
40
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030041 return {'cores': cores,
42 'ram': self.ram_size,
43 'storage': disks,
44 'disk_count': len(self.disks_info)}
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030045
46 def __str__(self):
47 res = []
48
49 summ = self.get_summary()
50 summary = "Simmary: {cores} cores, {ram}B RAM, {disk}B storage"
51 res.append(summary.format(cores=summ['cores'],
52 ram=utils.b2ssize(summ['ram']),
53 disk=utils.b2ssize(summ['storage'])))
54 res.append(str(self.sys_name))
55 if self.mb is not None:
56 res.append("Motherboard: " + self.mb)
57
58 if self.ram_size == 0:
59 res.append("RAM: Failed to get RAM size")
60 else:
61 res.append("RAM " + utils.b2ssize(self.ram_size) + "B")
62
63 if self.cores == []:
64 res.append("CPU cores: Failed to get CPU info")
65 else:
66 res.append("CPU cores:")
67 for name, count in self.cores:
68 if count > 1:
69 res.append(" {0} * {1}".format(count, name))
70 else:
71 res.append(" " + name)
72
73 if self.storage_controllers != []:
74 res.append("Disk controllers:")
75 for descr in self.storage_controllers:
76 res.append(" " + descr)
77
78 if self.disks_info != {}:
79 res.append("Storage devices:")
80 for dev, (model, size) in sorted(self.disks_info.items()):
81 ssize = utils.b2ssize(size) + "B"
82 res.append(" {0} {1} {2}".format(dev, ssize, model))
83 else:
84 res.append("Storage devices's: Failed to get info")
85
86 if self.disks_raw_info != {}:
87 res.append("Disks devices:")
88 for dev, descr in sorted(self.disks_raw_info.items()):
89 res.append(" {0} {1}".format(dev, descr))
90 else:
91 res.append("Disks devices's: Failed to get info")
92
93 if self.net_info != {}:
94 res.append("Net adapters:")
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030095 for name, (speed, dtype, _) in self.net_info.items():
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030096 res.append(" {0} {2} duplex={1}".format(name, dtype, speed))
97 else:
98 res.append("Net adapters: Failed to get net info")
99
100 return str(self.hostname) + ":\n" + "\n".join(" " + i for i in res)
101
102
103class SWInfo(object):
104 def __init__(self):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300105 self.partitions = None
106 self.kernel_version = None
107 self.fio_version = None
108 self.libvirt_version = None
109 self.kvm_version = None
110 self.qemu_version = None
111 self.OS_version = None
112 self.ceph_version = None
113
114
115def get_sw_info(conn):
116 res = SWInfo()
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300117 res.OS_version = utils.get_os()
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300118
119 with conn.open_sftp() as sftp:
120 def get(fname):
121 try:
122 return ssh_utils.read_from_remote(sftp, fname)
123 except:
124 return None
125
126 res.kernel_version = get('/proc/version')
127 res.partitions = get('/etc/mtab')
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300128
129 def rr(cmd):
130 try:
131 return ssh_utils.run_over_ssh(conn, cmd, nolog=True)
132 except:
133 return None
134
135 res.libvirt_version = rr("virsh -v")
136 res.qemu_version = rr("qemu-system-x86_64 --version")
137 res.ceph_version = rr("ceph --version")
138
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300139 return res
140
141
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300142def get_network_info():
143 pass
144
145
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300146def get_hw_info(conn):
147 res = HWInfo()
148 lshw_out = ssh_utils.run_over_ssh(conn, 'sudo lshw -xml 2>/dev/null',
149 nolog=True)
150
151 res.raw = lshw_out
152 lshw_et = ET.fromstring(lshw_out)
153
154 try:
155 res.hostname = lshw_et.find("node").attrib['id']
156 except:
157 pass
158
159 try:
160 res.sys_name = (lshw_et.find("node/vendor").text + " " +
161 lshw_et.find("node/product").text)
162 res.sys_name = res.sys_name.replace("(To be filled by O.E.M.)", "")
163 res.sys_name = res.sys_name.replace("(To be Filled by O.E.M.)", "")
164 except:
165 pass
166
167 core = lshw_et.find("node/node[@id='core']")
168 if core is None:
169 return
170
171 try:
172 res.mb = " ".join(core.find(node).text
173 for node in ['vendor', 'product', 'version'])
174 except:
175 pass
176
177 for cpu in core.findall("node[@class='processor']"):
178 try:
179 model = cpu.find('product').text
180 threads_node = cpu.find("configuration/setting[@id='threads']")
181 if threads_node is None:
182 threads = 1
183 else:
184 threads = int(threads_node.attrib['value'])
185 res.cores.append((model, threads))
186 except:
187 pass
188
189 res.ram_size = 0
190 for mem_node in core.findall(".//node[@class='memory']"):
191 descr = mem_node.find('description')
192 try:
193 if descr is not None and descr.text == 'System Memory':
194 mem_sz = mem_node.find('size')
195 if mem_sz is None:
196 for slot_node in mem_node.find("node[@class='memory']"):
197 slot_sz = slot_node.find('size')
198 if slot_sz is not None:
199 assert slot_sz.attrib['units'] == 'bytes'
200 res.ram_size += int(slot_sz.text)
201 else:
202 assert mem_sz.attrib['units'] == 'bytes'
203 res.ram_size += int(mem_sz.text)
204 except:
205 pass
206
207 for net in core.findall(".//node[@class='network']"):
208 try:
209 link = net.find("configuration/setting[@id='link']")
210 if link.attrib['value'] == 'yes':
211 name = net.find("logicalname").text
212 speed_node = net.find("configuration/setting[@id='speed']")
213
214 if speed_node is None:
215 speed = None
216 else:
217 speed = speed_node.attrib['value']
218
219 dup_node = net.find("configuration/setting[@id='duplex']")
220 if dup_node is None:
221 dup = None
222 else:
223 dup = dup_node.attrib['value']
224
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300225 res.net_info[name] = (speed, dup, [])
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300226 except:
227 pass
228
229 for controller in core.findall(".//node[@class='storage']"):
230 try:
231 description = getattr(controller.find("description"), 'text', "")
232 product = getattr(controller.find("product"), 'text', "")
233 vendor = getattr(controller.find("vendor"), 'text', "")
234 dev = getattr(controller.find("logicalname"), 'text', "")
235 if dev != "":
236 res.storage_controllers.append(
237 "{0}: {1} {2} {3}".format(dev, description,
238 vendor, product))
239 else:
240 res.storage_controllers.append(
241 "{0} {1} {2}".format(description,
242 vendor, product))
243 except:
244 pass
245
246 for disk in core.findall(".//node[@class='disk']"):
247 try:
248 lname_node = disk.find('logicalname')
249 if lname_node is not None:
250 dev = lname_node.text.split('/')[-1]
251
252 if dev == "" or dev[-1].isdigit():
253 continue
254
255 sz_node = disk.find('size')
256 assert sz_node.attrib['units'] == 'bytes'
257 sz = int(sz_node.text)
258 res.disks_info[dev] = ('', sz)
259 else:
260 description = disk.find('description').text
261 product = disk.find('product').text
262 vendor = disk.find('vendor').text
263 version = disk.find('version').text
264 serial = disk.find('serial').text
265
266 full_descr = "{0} {1} {2} {3} {4}".format(
267 description, product, vendor, version, serial)
268
269 businfo = disk.find('businfo').text
270 res.disks_raw_info[businfo] = full_descr
271 except:
272 pass
273
274 return res
275
276# import traceback
277# print ET.tostring(disk)
278# traceback.print_exc()
279
280# print get_hw_info(None)
281
282# def get_hw_info(conn):
283# res = HWInfo(None)
284# remote_run = functools.partial(ssh_utils.run_over_ssh, conn, nolog=True)
285
286# # some data
287# with conn.open_sftp() as sftp:
288# proc_data = ssh_utils.read_from_remote(sftp, '/proc/cpuinfo')
289# mem_data = ssh_utils.read_from_remote(sftp, '/proc/meminfo')
290
291# # cpu info
292# curr_core = {}
293# for line in proc_data.split("\n"):
294# if line.strip() == "":
295# if curr_core != {}:
296# res.cores.append(curr_core)
297# curr_core = {}
298# else:
299# param, val = line.split(":", 1)
300# curr_core[param.strip()] = val.strip()
301
302# if curr_core != {}:
303# res.cores.append(curr_core)
304
305# # RAM info
306# for line in mem_data.split("\n"):
307# if line.startswith("MemTotal"):
308# res.ram_size = int(line.split(":", 1)[1].split()[0]) * 1024
309# break
310
311# # HDD info
312# for dev in remote_run('ls /dev').split():
313# if dev[-1].isdigit():
314# continue
315
316# if dev.startswith('sd') or dev.startswith('hd'):
317# model = None
318# size = None
319
320# for line in remote_run('sudo hdparm -I /dev/' + dev).split("\n"):
321# if "Model Number:" in line:
322# model = line.split(':', 1)[1]
323# elif "device size with M = 1024*1024" in line:
324# size = int(line.split(':', 1)[1].split()[0])
325# size *= 1024 ** 2
326
327# res.disks_info[dev] = (model, size)
328
329# # Network info
330# separator = '*-network'
331# net_info = remote_run('sudo lshw -class network')
332# for net_dev_info in net_info.split(separator):
333# if net_dev_info.strip().startswith("DISABLED"):
334# continue
335
336# if ":" not in net_dev_info:
337# continue
338
339# dev_params = {}
340# for line in net_dev_info.split("\n"):
341# line = line.strip()
342# if ':' in line:
343# key, data = line.split(":", 1)
344# dev_params[key.strip()] = data.strip()
345
346# if 'configuration' not in dev_params:
347# print "!!!!!", net_dev_info
348# continue
349
350# conf = dev_params['configuration']
351# if 'link=yes' in conf:
352# if 'speed=' in conf:
353# speed = conf.split('speed=', 1)[1]
354# speed = speed.strip().split()[0]
355# else:
356# speed = None
357
358# if "duplex=" in conf:
359# dtype = conf.split("duplex=", 1)[1]
360# dtype = dtype.strip().split()[0]
361# else:
362# dtype = None
363
364# res.net_info[dev_params['logical name']] = (speed, dtype)
365# return res