blob: 214883dd66cb48bb5656bd036dd1e9485063252d [file] [log] [blame]
koder aka kdanilovf86d7af2015-05-06 04:01:54 +03001import re
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03002from typing import Dict, Any, Iterable
koder aka kdanilovf86d7af2015-05-06 04:01:54 +03003import xml.etree.ElementTree as ET
4
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03005from . import utils
6from .inode import INode
koder aka kdanilovf86d7af2015-05-06 04:01:54 +03007
8
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03009def get_data(rr: str, data: str) -> str:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030010 match_res = re.search("(?ims)" + rr, data)
11 return match_res.group(0)
12
13
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030014class HWInfo:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030015 def __init__(self):
16 self.hostname = None
17 self.cores = []
18
19 # /dev/... devices
20 self.disks_info = {}
21
22 # real disks on raid controller
23 self.disks_raw_info = {}
24
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030025 # name => (speed, is_full_diplex, ip_addresses)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030026 self.net_info = {}
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030027
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030028 self.ram_size = 0
29 self.sys_name = None
30 self.mb = None
31 self.raw = None
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030032
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030033 self.storage_controllers = []
34
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030035 def get_hdd_count(self) -> Iterable[int]:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030036 # SATA HDD COUNT, SAS 10k HDD COUNT, SAS SSD count, PCI-E SSD count
37 return []
38
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030039 def get_summary(self) -> Dict[str, Any]:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030040 cores = sum(count for _, count in self.cores)
41 disks = sum(size for _, size in self.disks_info.values())
42
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030043 return {'cores': cores,
44 'ram': self.ram_size,
45 'storage': disks,
46 'disk_count': len(self.disks_info)}
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030047
48 def __str__(self):
49 res = []
50
51 summ = self.get_summary()
52 summary = "Simmary: {cores} cores, {ram}B RAM, {disk}B storage"
53 res.append(summary.format(cores=summ['cores'],
54 ram=utils.b2ssize(summ['ram']),
55 disk=utils.b2ssize(summ['storage'])))
56 res.append(str(self.sys_name))
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030057 if self.mb:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030058 res.append("Motherboard: " + self.mb)
59
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030060 if not self.ram_size:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030061 res.append("RAM: Failed to get RAM size")
62 else:
63 res.append("RAM " + utils.b2ssize(self.ram_size) + "B")
64
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030065 if not self.cores:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030066 res.append("CPU cores: Failed to get CPU info")
67 else:
68 res.append("CPU cores:")
69 for name, count in self.cores:
70 if count > 1:
71 res.append(" {0} * {1}".format(count, name))
72 else:
73 res.append(" " + name)
74
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030075 if self.storage_controllers:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030076 res.append("Disk controllers:")
77 for descr in self.storage_controllers:
78 res.append(" " + descr)
79
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030080 if self.disks_info:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030081 res.append("Storage devices:")
82 for dev, (model, size) in sorted(self.disks_info.items()):
83 ssize = utils.b2ssize(size) + "B"
84 res.append(" {0} {1} {2}".format(dev, ssize, model))
85 else:
86 res.append("Storage devices's: Failed to get info")
87
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030088 if self.disks_raw_info:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030089 res.append("Disks devices:")
90 for dev, descr in sorted(self.disks_raw_info.items()):
91 res.append(" {0} {1}".format(dev, descr))
92 else:
93 res.append("Disks devices's: Failed to get info")
94
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030095 if self.net_info:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030096 res.append("Net adapters:")
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030097 for name, (speed, dtype, _) in self.net_info.items():
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030098 res.append(" {0} {2} duplex={1}".format(name, dtype, speed))
99 else:
100 res.append("Net adapters: Failed to get net info")
101
102 return str(self.hostname) + ":\n" + "\n".join(" " + i for i in res)
103
104
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300105class SWInfo:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300106 def __init__(self):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300107 self.partitions = None
108 self.kernel_version = None
109 self.fio_version = None
110 self.libvirt_version = None
111 self.kvm_version = None
112 self.qemu_version = None
113 self.OS_version = None
114 self.ceph_version = None
115
116
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300117def get_sw_info(node: INode) -> SWInfo:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300118 res = SWInfo()
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300119
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300120 res.OS_version = utils.get_os()
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300121 res.kernel_version = node.get_file_content('/proc/version')
122 res.partitions = node.get_file_content('/etc/mtab')
123 res.libvirt_version = node.run("virsh -v", nolog=True)
124 res.qemu_version = node.run("qemu-system-x86_64 --version", nolog=True)
125 res.ceph_version = node.run("ceph --version", nolog=True)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300126
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300127 return res
128
129
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300130def get_hw_info(node: INode) -> HWInfo:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300131 res = HWInfo()
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300132 lshw_out = node.run('sudo lshw -xml 2>/dev/null', nolog=True)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300133
134 res.raw = lshw_out
135 lshw_et = ET.fromstring(lshw_out)
136
137 try:
138 res.hostname = lshw_et.find("node").attrib['id']
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300139 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300140 pass
141
142 try:
143 res.sys_name = (lshw_et.find("node/vendor").text + " " +
144 lshw_et.find("node/product").text)
145 res.sys_name = res.sys_name.replace("(To be filled by O.E.M.)", "")
146 res.sys_name = res.sys_name.replace("(To be Filled by O.E.M.)", "")
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300147 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300148 pass
149
150 core = lshw_et.find("node/node[@id='core']")
151 if core is None:
152 return
153
154 try:
155 res.mb = " ".join(core.find(node).text
156 for node in ['vendor', 'product', 'version'])
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300157 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300158 pass
159
160 for cpu in core.findall("node[@class='processor']"):
161 try:
162 model = cpu.find('product').text
163 threads_node = cpu.find("configuration/setting[@id='threads']")
164 if threads_node is None:
165 threads = 1
166 else:
167 threads = int(threads_node.attrib['value'])
168 res.cores.append((model, threads))
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300169 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300170 pass
171
172 res.ram_size = 0
173 for mem_node in core.findall(".//node[@class='memory']"):
174 descr = mem_node.find('description')
175 try:
176 if descr is not None and descr.text == 'System Memory':
177 mem_sz = mem_node.find('size')
178 if mem_sz is None:
179 for slot_node in mem_node.find("node[@class='memory']"):
180 slot_sz = slot_node.find('size')
181 if slot_sz is not None:
182 assert slot_sz.attrib['units'] == 'bytes'
183 res.ram_size += int(slot_sz.text)
184 else:
185 assert mem_sz.attrib['units'] == 'bytes'
186 res.ram_size += int(mem_sz.text)
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300187 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300188 pass
189
190 for net in core.findall(".//node[@class='network']"):
191 try:
192 link = net.find("configuration/setting[@id='link']")
193 if link.attrib['value'] == 'yes':
194 name = net.find("logicalname").text
195 speed_node = net.find("configuration/setting[@id='speed']")
196
197 if speed_node is None:
198 speed = None
199 else:
200 speed = speed_node.attrib['value']
201
202 dup_node = net.find("configuration/setting[@id='duplex']")
203 if dup_node is None:
204 dup = None
205 else:
206 dup = dup_node.attrib['value']
207
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300208 res.net_info[name] = (speed, dup, [])
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300209 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300210 pass
211
212 for controller in core.findall(".//node[@class='storage']"):
213 try:
214 description = getattr(controller.find("description"), 'text', "")
215 product = getattr(controller.find("product"), 'text', "")
216 vendor = getattr(controller.find("vendor"), 'text', "")
217 dev = getattr(controller.find("logicalname"), 'text', "")
218 if dev != "":
219 res.storage_controllers.append(
220 "{0}: {1} {2} {3}".format(dev, description,
221 vendor, product))
222 else:
223 res.storage_controllers.append(
224 "{0} {1} {2}".format(description,
225 vendor, product))
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300226 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300227 pass
228
229 for disk in core.findall(".//node[@class='disk']"):
230 try:
231 lname_node = disk.find('logicalname')
232 if lname_node is not None:
233 dev = lname_node.text.split('/')[-1]
234
235 if dev == "" or dev[-1].isdigit():
236 continue
237
238 sz_node = disk.find('size')
239 assert sz_node.attrib['units'] == 'bytes'
240 sz = int(sz_node.text)
241 res.disks_info[dev] = ('', sz)
242 else:
243 description = disk.find('description').text
244 product = disk.find('product').text
245 vendor = disk.find('vendor').text
246 version = disk.find('version').text
247 serial = disk.find('serial').text
248
249 full_descr = "{0} {1} {2} {3} {4}".format(
250 description, product, vendor, version, serial)
251
252 businfo = disk.find('businfo').text
253 res.disks_raw_info[businfo] = full_descr
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300254 except Exception:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300255 pass
256
257 return res