forked from openshift/openstack-ironic-python-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdmi_inspector.py
136 lines (109 loc) · 3.99 KB
/
dmi_inspector.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Copyright (C) 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from oslo_concurrency import processutils
from oslo_log import log as logging
from ironic_python_agent import utils
LOG = logging.getLogger(__name__)
def collect_dmidecode_info(data, failures):
"""Collect detailed processor, memory and bios info.
The data is gathered using dmidecode utility.
:param data: mutable dict that we'll send to inspector
:param failures: AccumulatedFailures object
"""
try:
shret, _err = utils.execute('dmidecode', '-t', 'bios',
'-t', 'processor', '-t', 'memory')
except (processutils.ProcessExecutionError, OSError) as exc:
failures.add('failed to run dmidecode: %s', exc)
return
data['dmi'] = {}
try:
data['dmi'] = parse_dmi(shret)
except (ValueError, IndexError) as exc:
LOG.warning('Failed to collect dmidecode info: %s', exc)
def parse_dmi(data):
"""Parse the dmidecode output.
Returns a dict.
"""
TYPE = {
'bios': 0,
'cpu': 4,
'memory': 16,
'devices': 17,
}
dmi_info = {
'bios': {},
'cpu': [],
'memory': {'devices': []},
}
memorydata, devicedata = [], []
# Dmi data blocks are separated by a blank line.
# First line in each block starts with 'Handle 0x'.
for infoblock in data.split('\n\n'):
if not len(infoblock):
continue
if not infoblock.startswith('Handle 0x'):
continue
try:
# Determine DMI type value. Handle line will look like this:
# Handle 0x0018, DMI type 17, 27 bytes
dmi_type = int(infoblock.split(',', 2)[1].strip()[
len('DMI type'):])
except (ValueError, IndexError) as exc:
LOG.warning('Failed to parse Handle type in dmi output: %s',
exc)
continue
if dmi_type in TYPE.values():
sectiondata = _parse_handle_block(infoblock)
if dmi_type == TYPE['bios']:
dmi_info['bios'] = sectiondata
elif dmi_type == TYPE['cpu']:
dmi_info['cpu'].append(sectiondata)
elif dmi_type == TYPE['memory']:
memorydata.append(sectiondata)
elif dmi_type == TYPE['devices']:
devicedata.append(sectiondata)
return _save_data(dmi_info, memorydata, devicedata)
def _parse_handle_block(lines):
rows = {}
list_value = False
for line in lines.splitlines():
line = line.strip()
if ':' in line:
list_value = False
k, v = [i.strip() for i in line.split(':', 1)]
if v:
rows[k] = v
else:
rows[k] = []
list_value = True
elif 'Handle 0x' in line:
rows['Handle'] = line
elif list_value:
rows[k].append(line)
return rows
def _save_data(dmi_info, memorydata, devicedata):
if memorydata:
try:
device_count = sum([int(d['Number Of Devices'])
for d in memorydata])
dmi_info['memory'] = memorydata[0]
dmi_info['memory']['Number Of Devices'] = device_count
dmi_info['memory'].pop('Handle')
except KeyError as exc:
LOG.warning('Failed to process memory dmi data: %s', exc)
raise
if devicedata:
dmi_info['memory']['devices'] = devicedata
return dmi_info