Skip to content

Commit 2bf2cb1

Browse files
Adding dmidecode support in server-info for better view of memory subsystem (#178)
* Added(server-info): reminder about installation pcituils and dmidecode. * Added(server-info): using dmidecode memory data file (type, speed and size). for -show and -rate * Added(test-data): server-info archive from cheapest vscale CentOS 7 * Added(assessor): Grade by known values * Fixed(test-data): server-info show expected output changed * Refactoring(dmi): parser complexity fighting * Refactoring(parsers): provide optional simplier way of initialisation for any Parser-based class * Incremented version #37
1 parent 81d35b8 commit 2bf2cb1

File tree

31 files changed

+321
-28
lines changed

31 files changed

+321
-28
lines changed

netutils_linux_hardware/assessor.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,33 @@ def assess_cpu(self):
3939
'Vendor ID': Grade.str(cpuinfo.get('Vendor ID'), good=['GenuineIntel']),
4040
}
4141

42+
def assess_memory_device(self, device):
43+
return {
44+
'size': Grade.int(device.get('size', 0), 512, 8196),
45+
'type': Grade.known_values(device.get('type', 'RAM'), {
46+
'DDR1': 2,
47+
'DDR2': 3,
48+
'DDR3': 6,
49+
'DDR4': 10,
50+
}),
51+
'speed': Grade.int(device.get('speed', 0), 200, 4000),
52+
}
53+
54+
def assess_memory_devices(self, devices):
55+
return dict((handle, self.assess_memory_device(device)) for handle, device in devices.items())
56+
57+
def assess_memory_size(self, size):
58+
return {
59+
'MemTotal': Grade.int(size.get('MemTotal'), 2 * (1024 ** 2), 16 * (1024 ** 2)),
60+
'SwapTotal': Grade.int(size.get('SwapTotal'), 512 * 1024, 4 * (1024 ** 2)),
61+
}
62+
4263
def assess_memory(self):
4364
meminfo = self.data.get('memory')
4465
if meminfo:
4566
return {
46-
'MemTotal': Grade.int(meminfo.get('MemTotal'), 2 * (1024 ** 2), 16 * (1024 ** 2)),
47-
'SwapTotal': Grade.int(meminfo.get('SwapTotal'), 512 * 1024, 4 * (1024 ** 2)),
67+
'devices': self.assess_memory_devices(meminfo.get('devices')),
68+
'size': self.assess_memory_size(meminfo.get('size')),
4869
}
4970

5071
def assess_system(self):

netutils_linux_hardware/grade.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ def str(value, good=None, bad=None):
1818
@staticmethod
1919
def fact(value, mode=False):
2020
return 10 if (value is None) != mode else 1
21+
22+
@staticmethod
23+
def known_values(value, _dict):
24+
return _dict.get(value, 1)

netutils_linux_hardware/parsers.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99

1010
class Parser(object):
11-
@staticmethod
11+
def __init__(self, filepath=None):
12+
self.result = self.parse_file_safe(filepath) if filepath else None
13+
1214
def parse(text, **kwargs):
1315
raise NotImplementedError
1416

@@ -122,6 +124,48 @@ def parse(self, text):
122124
return dict((k, int(v.replace(' kB', ''))) for k, v in iteritems(yaml.load(text)) if k in self.keys_required)
123125

124126

127+
class MemInfoDMIDevice(object):
128+
def __init__(self, text):
129+
self.data = {
130+
'speed': 0,
131+
'type': 'RAM',
132+
'size': 0,
133+
}
134+
self.type = 'RAM'
135+
self.handle = None
136+
self.size = 0
137+
self.parse_text(text)
138+
139+
def parse_text(self, text):
140+
""" Разбор описания плашки памяти от dmidecode """
141+
for line in map(str.strip, text.split('\n')):
142+
self.parse_line(line)
143+
144+
def parse_line(self, line):
145+
for key in ('Speed', 'Type', 'Size'):
146+
if line.startswith(key + ':'):
147+
self.data[key.lower()] = line.split()[1]
148+
break
149+
if line.startswith('Handle'):
150+
self.handle = line.split(' ')[1].strip(',')
151+
152+
153+
class MemInfoDMI(Parser):
154+
@staticmethod
155+
def parse(text):
156+
""" Разбор всего вывода dmidecode --type memory """
157+
return MemInfoDMI.__parse(text.split('\n\n')) if text else None
158+
159+
@staticmethod
160+
def __parse(devices):
161+
output = dict()
162+
for device in devices:
163+
if 'Memory Device' in device:
164+
mem_dev = MemInfoDMIDevice(device)
165+
output[mem_dev.handle] = mem_dev
166+
return output
167+
168+
125169
class CPULayout(Parser):
126170
@staticmethod
127171
def parse(text):

netutils_linux_hardware/reader.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
# pylint: disable=C0111, C0103
33

44
import os
5+
56
import yaml
6-
from netutils_linux_hardware.parsers import YAMLLike, CPULayout, DiskInfo, MemInfo
7+
78
from netutils_linux_hardware.netdev import ReaderNet
9+
from netutils_linux_hardware.parsers import YAMLLike, CPULayout, DiskInfo, MemInfo, MemInfoDMI
810

911

1012
class Reader(object):
11-
1213
info = None
1314

1415
def __init__(self, datadir):
@@ -25,12 +26,15 @@ def gather_info(self):
2526

2627
self.info = {
2728
'cpu': {
28-
'info': YAMLLike().parse_file_safe(self.path('lscpu_info')),
29-
'layout': CPULayout().parse_file_safe(self.path('lscpu_layout')),
29+
'info': YAMLLike(self.path('lscpu_info')).result,
30+
'layout': CPULayout(self.path('lscpu_layout')).result,
3031
},
3132
'net': ReaderNet(self.datadir, self.path).netdevs,
3233
'disk': DiskInfo().parse(self.path('disks_types'), self.path('lsblk_sizes'), self.path('lsblk_models')),
33-
'memory': MemInfo().parse_file_safe(self.path('meminfo')),
34+
'memory': {
35+
'size': MemInfo(self.path('meminfo')).result,
36+
'devices': MemInfoDMI(self.path('dmidecode')).result,
37+
},
3438
}
3539
for key in ('CPU MHz', 'BogoMIPS'):
3640
if self.info.get('cpu', {}).get('info', {}).get(key):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def read(*paths):
1616

1717
setuptools.setup(
1818
name='netutils-linux',
19-
version='2.5.2',
19+
version='2.6.1',
2020
author='Oleg Strizhechenko',
2121
author_email='oleg.strizhechenko@gmail.com',
2222
license='MIT',

tests/server-info-show.tests/1xE3-1271.I217_and_X710.L2_mixed.masterconf/expected_output

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ disk:
3333
size: 120034123776
3434
type: SSD
3535
memory:
36-
MemFree: 14142256
37-
MemTotal: 16290904
38-
SwapFree: 8216572
39-
SwapTotal: 8216572
36+
devices: null
37+
size:
38+
MemFree: 14142256
39+
MemTotal: 16290904
40+
SwapFree: 8216572
41+
SwapTotal: 8216572
4042
net:
4143
eth0:
4244
buffers:

tests/server-info-show.tests/1xE31240.2x82576.L2.manual/expected_output

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ cpu:
3131
'6': '0'
3232
'7': '0'
3333
disk: null
34-
memory: null
34+
memory:
35+
devices: null
36+
size: null
3537
net:
3638
eth0:
3739
buffers:

tests/server-info-show.tests/1xE5200.82571EB_and_AR8121.L2.manual/expected_output

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ cpu:
2424
'0': '0'
2525
'1': '0'
2626
disk: null
27-
memory: null
27+
memory:
28+
devices: null
29+
size: null
2830
net:
2931
eth1:
3032
buffers:

tests/server-info-show.tests/1xi3.single_i350.l2_mixed.manual/expected_output

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ cpu:
2828
'2': '0'
2929
'3': '0'
3030
disk: null
31-
memory: null
31+
memory:
32+
devices: null
33+
size: null
3234
net:
3335
eth6:
3436
buffers:

tests/server-info-show.tests/1xi7-4770K.1x82541PI.L2.manual/expected_output

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ cpu:
3232
'6': '0'
3333
'7': '0'
3434
disk: null
35-
memory: null
35+
memory:
36+
devices: null
37+
size: null
3638
net:
3739
eth0:
3840
buffers:

0 commit comments

Comments
 (0)