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