Skip to content

Commit 8069cb5

Browse files
Server info oop (#192)
* Release(v2.7.5) * Added(server-info): server-info --rate run-tests * Added(server-info): Server class (merged from cli, Assessor, Reader and Collector) * Added(server-info): base Subsystem class * Added(server-info): CPU, Disk, Net, Memory and "System" subsystems with all of their specific * Added(server-info): Folding class with all the folding logic/constants * Refactoring(server-info): removed -f, -ff, -fff args, use --device, --subsystem, --server instead. * Refactoring(server-info): simplified any2int, dmidecode parsing and invert_dict_nesting
1 parent 49ce4f4 commit 8069cb5

28 files changed

+631
-584
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ test:
33
./tests/utils_runnable
44
./tests/rss-ladder-test
55
./tests/server-info-show
6+
./tests/server-info-rate
67
./tests/link_rate_units.sh
78

89
env:

docs/hardware.ru.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@
1212
yum -y install epel-release
1313
yum -y install python-pip
1414
pip install netutils-linux
15-
sudo server-info rate
15+
sudo server-info --rate
1616
```
1717

1818
Для более общей оценки можно:
1919

2020
```
2121
cd /root/server/
2222
# оценка с точностью до девайса
23-
server-info-rate -f
23+
server-info --rate --device
2424
# оценка с точностью до подсистемы
25-
server-info-rate -ff
25+
server-info --rate -subsystem
2626
# оценка сервера целиком
27-
server-info-rate -fff
27+
server-info --rate --server
2828
```
2929

3030
Если что-то идёт не так или оценка крайне неправильна: не стесняйтесь создавать на гитхаб репорты о проблемах: https://github.com/strizhechenko/netutils-linux/issues

netutils_linux_hardware/__init__.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
from netutils_linux_hardware import netdev
2-
from netutils_linux_hardware import parsers
3-
from netutils_linux_hardware import interrupts
4-
from netutils_linux_hardware.reader import Reader
5-
from netutils_linux_hardware.assessor import Assessor
1+
from netutils_linux_hardware.server import Server
62

7-
__all__ = ['parsers', 'netdev', 'interrupts', 'Reader', 'Assessor']
3+
__all__ = ['Server']

netutils_linux_hardware/assessor.py

-151
This file was deleted.

netutils_linux_hardware/collect.py

-29
This file was deleted.

netutils_linux_hardware/cpu.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# coding=utf-8
2+
3+
from netutils_linux_hardware.grade import Grade
4+
from netutils_linux_hardware.parser import Parser, YAMLLike
5+
from netutils_linux_hardware.rate_math import extract
6+
from netutils_linux_hardware.subsystem import Subsystem
7+
8+
9+
class CPU(Subsystem):
10+
""" Everything about CPU: layouts, NUMA, HZ, L3, lscpu """
11+
12+
def rate(self):
13+
cpuinfo = extract(self.data, ['cpu', 'info'])
14+
if cpuinfo: # None if no cpuinfo key
15+
return self.folding.fold({
16+
'CPU MHz': Grade.int(cpuinfo.get('CPU MHz'), 2000, 4000),
17+
'BogoMIPS': Grade.int(cpuinfo.get('BogoMIPS'), 4000, 8000),
18+
'CPU(s)': Grade.int(cpuinfo.get('CPU(s)'), 2, 32),
19+
'Core(s) per socket': Grade.int(cpuinfo.get('Core(s) per socket'), 1, 2),
20+
'Socket(s)': Grade.int(cpuinfo.get('Socket(s)'), 1, 2),
21+
'Thread(s) per core': Grade.int(cpuinfo.get('Thread(s) per core'), 2, 1),
22+
'L3 cache': Grade.int(cpuinfo.get('L3 cache'), 1000, 30000),
23+
'Vendor ID': Grade.str(cpuinfo.get('Vendor ID'), good=['GenuineIntel']),
24+
}, self.folding.SUBSYSTEM)
25+
26+
def parse(self):
27+
output = {
28+
'info': self.read(YAMLLike, 'lscpu_info'),
29+
'layout': self.read(CPULayout, 'lscpu_layout'),
30+
}
31+
for key in ('CPU MHz', 'BogoMIPS'):
32+
if output.get('info', {}).get(key):
33+
output['info'][key] = int(output['info'][key])
34+
return output
35+
36+
37+
class CPULayout(Parser):
38+
@staticmethod
39+
def parse(text):
40+
output = dict((line.strip().split())
41+
for line in text.strip().split('\n'))
42+
if output.get('CPU'):
43+
del output['CPU']
44+
return output

netutils_linux_hardware/disk.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# coding=utf-8
2+
3+
from collections import defaultdict
4+
5+
import yaml
6+
7+
from netutils_linux_hardware.grade import Grade
8+
from netutils_linux_hardware.parser import Parser
9+
from netutils_linux_hardware.rate_math import extract
10+
from netutils_linux_hardware.subsystem import Subsystem
11+
12+
13+
class Disk(Subsystem):
14+
def parse(self):
15+
return DiskInfo().parse(
16+
self.path('disks_types'),
17+
self.path('lsblk_sizes'),
18+
self.path('lsblk_models')
19+
)
20+
21+
def rate(self):
22+
return self.map(self.rate_disk, 'disk')
23+
24+
def rate_disk(self, disk):
25+
diskinfo = extract(self.data, ['disk', disk])
26+
return self.folding.fold({
27+
'type': Grade.str(diskinfo.get('type'), ['SDD'], ['HDD']),
28+
# 50Gb - good, 1Tb - good enough
29+
'size': Grade.int(diskinfo.get('size'), 50 * (1000 ** 3), 1000 ** 4),
30+
}, self.folding.DEVICE)
31+
32+
33+
class DiskInfo(object):
34+
@staticmethod
35+
def invert_dict_nesting(origin):
36+
"""
37+
origin = {
38+
'x': {'xx': 1, 'yy': 2},
39+
'y': {'xx': 3, 'yy': 4},
40+
}
41+
result = {
42+
'xx': {'x': 1, 'y': 3},
43+
'yy': {'x': 2, 'y': 4},
44+
}
45+
"""
46+
result = defaultdict()
47+
for out_key, out_value in origin.items():
48+
for in_key, in_value in out_value.items():
49+
result.setdefault(in_key, dict())
50+
result[in_key][out_key] = in_value
51+
return dict(result)
52+
53+
def parse(self, types, sizes, models):
54+
types_data = self.DiskTypesInfo().parse_file_safe(types)
55+
if not types_data:
56+
return
57+
disk_data = {
58+
'type': types_data,
59+
'size': self.DiskSizeInfo(types_data).parse_file_safe(sizes),
60+
'model': self.DiskModelsInfo(types_data).parse_file_safe(models),
61+
}
62+
return self.invert_dict_nesting(disk_data)
63+
64+
class DiskTypesInfo(Parser):
65+
66+
@staticmethod
67+
def parse(text):
68+
types = ['SSD', 'HDD']
69+
if not text:
70+
return dict()
71+
data = yaml.load(text.replace(':', ': ').replace('/sys/block/', '').replace('/queue/rotational', ''))
72+
return dict((k, types[v]) for k, v in data.items())
73+
74+
class DiskSizeInfo(Parser):
75+
76+
def __init__(self, types_data):
77+
self.types_data = set(types_data)
78+
79+
def parse(self, text):
80+
# split grepped text into list
81+
data = (line.split() for line in text.strip().split('\n'))
82+
# remove partitions, we're interested only in disk-drives
83+
data = (line if len(line) == 2 else [line[0], line[2]] for line in data if
84+
set(line).intersection(self.types_data))
85+
return dict((k, int(v)) for v, k in data)
86+
87+
class DiskModelsInfo(Parser):
88+
89+
def __init__(self, types_data):
90+
self.types_data = types_data
91+
92+
def parse(self, text):
93+
lines = [line.split(None, 1) for line in text.strip().split('\n')]
94+
data = dict(line if len(line) == 2 else line + [None] for line in lines)
95+
if data.get('NAME'):
96+
del data['NAME']
97+
return data

netutils_linux_hardware/folding.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# coding=utf-8
2+
3+
4+
class Folding(object):
5+
NO = 0
6+
DEVICE = 1
7+
SUBSYSTEM = 2
8+
SERVER = 3
9+
10+
def __init__(self, args):
11+
self.args = args
12+
13+
def fold(self, data, level):
14+
""" Схлапывает значения в дикте до среднего арифметического """
15+
if not data:
16+
return 1
17+
if self.args.folding < level:
18+
return data
19+
result = sum(data.values()) / len(data.keys())
20+
return result if level < Folding.SERVER else {'server': result}

netutils_linux_hardware/grade.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# coding: utf-8
2-
from netutils_linux_hardware.assessor_math import any2int, round_
2+
from netutils_linux_hardware.rate_math import any2int, round_
33

44

55
class Grade(object):

0 commit comments

Comments
 (0)