python-ipmi 0.5.5__tar.gz → 0.5.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python-ipmi-0.5.5/python_ipmi.egg-info → python_ipmi-0.5.8}/PKG-INFO +16 -4
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/README.rst +2 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/__init__.py +32 -9
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/bmc.py +16 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/errors.py +19 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/fields.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/fru.py +73 -49
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/helper.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/hpm.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/aardvark.py +18 -10
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/ipmb.py +31 -12
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/ipmbdev.py +8 -4
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/ipmitool.py +44 -7
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/mock.py +6 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/rmcp.py +22 -6
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/ipmitool.py +6 -5
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/messaging.py +1 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/bmc.py +6 -7
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/chassis.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/dcmi.py +0 -2
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/event.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/fru.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/hpm.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/lan.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/message.py +3 -6
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/picmg.py +0 -2
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/registry.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/sdr.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/sel.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/sensor.py +0 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/vita.py +0 -2
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/version.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8/python_ipmi.egg-info}/PKG-INFO +16 -4
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/SOURCES.txt +1 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/setup.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_bmc.py +9 -1
- python_ipmi-0.5.8/tests/test_event.py +38 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_fru.py +31 -9
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_helper.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_hpm.py +1 -1
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_ipmi.py +38 -2
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_ipmitool.py +3 -2
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_sel.py +4 -4
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_sensor.py +2 -2
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/AUTHORS +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/COPYING +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/chassis.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/constants.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/dcmi.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/emulation.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/event.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/__init__.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/lan.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/logger.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/__init__.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/constants.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/device_messaging.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/session.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/picmg.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/sdr.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/sel.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/sensor.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/session.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/state.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/utils.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/dependency_links.txt +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/entry_points.txt +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/top_level.txt +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/setup.cfg +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_chassis.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_device_messaging.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_errors.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_fields.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_lan.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_picmg.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_sdr.py +0 -0
- {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_utils.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-ipmi
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: Pure python IPMI library
|
|
5
5
|
Home-page: https://github.com/kontron/python-ipmi
|
|
6
|
-
Download-URL: https://github.com/kontron/python-ipmi/tarball/0.5.
|
|
6
|
+
Download-URL: https://github.com/kontron/python-ipmi/tarball/0.5.8
|
|
7
7
|
Author: Michael Walle, Heiko Thiery
|
|
8
8
|
Author-email: michael.walle@kontron.com, heiko.thiery@kontron.com
|
|
9
9
|
License: LGPLv2+
|
|
@@ -20,9 +20,20 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
25
|
License-File: COPYING
|
|
25
26
|
License-File: AUTHORS
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: download-url
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
Dynamic: platform
|
|
36
|
+
Dynamic: summary
|
|
26
37
|
|
|
27
38
|
Pure Python IPMI Library
|
|
28
39
|
========================
|
|
@@ -105,6 +116,7 @@ Example with lan interface:
|
|
|
105
116
|
|
|
106
117
|
connection.session.set_session_type_rmcp('10.0.0.1', port=623)
|
|
107
118
|
connection.session.set_auth_type_user('admin', 'admin')
|
|
119
|
+
connection.session.set_priv_level("ADMINISTRATOR")
|
|
108
120
|
connection.session.establish()
|
|
109
121
|
|
|
110
122
|
connection.get_device_id()
|
|
@@ -113,7 +125,7 @@ ipmitool command:
|
|
|
113
125
|
|
|
114
126
|
.. code:: shell
|
|
115
127
|
|
|
116
|
-
ipmitool -I lan -H 10.0.0.1 -p 623 -U "admin" -P "admin" -t 0x82 -b 0 -l 0 raw 0x06 0x01
|
|
128
|
+
ipmitool -I lan -H 10.0.0.1 -p 623 -L "ADMINISTRATOR" -U "admin" -P "admin" -t 0x82 -b 0 -l 0 raw 0x06 0x01
|
|
117
129
|
|
|
118
130
|
|
|
119
131
|
Example with serial interface:
|
|
@@ -79,6 +79,7 @@ Example with lan interface:
|
|
|
79
79
|
|
|
80
80
|
connection.session.set_session_type_rmcp('10.0.0.1', port=623)
|
|
81
81
|
connection.session.set_auth_type_user('admin', 'admin')
|
|
82
|
+
connection.session.set_priv_level("ADMINISTRATOR")
|
|
82
83
|
connection.session.establish()
|
|
83
84
|
|
|
84
85
|
connection.get_device_id()
|
|
@@ -87,7 +88,7 @@ ipmitool command:
|
|
|
87
88
|
|
|
88
89
|
.. code:: shell
|
|
89
90
|
|
|
90
|
-
ipmitool -I lan -H 10.0.0.1 -p 623 -U "admin" -P "admin" -t 0x82 -b 0 -l 0 raw 0x06 0x01
|
|
91
|
+
ipmitool -I lan -H 10.0.0.1 -p 623 -L "ADMINISTRATOR" -U "admin" -P "admin" -t 0x82 -b 0 -l 0 raw 0x06 0x01
|
|
91
92
|
|
|
92
93
|
|
|
93
94
|
Example with serial interface:
|
|
@@ -48,11 +48,7 @@ except ImportError:
|
|
|
48
48
|
def create_connection(interface):
|
|
49
49
|
session = Session()
|
|
50
50
|
session.interface = interface
|
|
51
|
-
|
|
52
|
-
ipmi.interface = interface
|
|
53
|
-
ipmi.session = session
|
|
54
|
-
ipmi.requester = NullRequester()
|
|
55
|
-
return ipmi
|
|
51
|
+
return Ipmi(interface=interface, session=session)
|
|
56
52
|
|
|
57
53
|
|
|
58
54
|
class Requester(object):
|
|
@@ -164,14 +160,41 @@ class Ipmi(bmc.Bmc, chassis.Chassis, dcmi.Dcmi, fru.Fru, picmg.Picmg, hpm.Hpm,
|
|
|
164
160
|
sdr.Sdr, sensor.Sensor, event.Event, sel.Sel, lan.Lan,
|
|
165
161
|
messaging.Messaging):
|
|
166
162
|
|
|
167
|
-
def __init__(self)
|
|
168
|
-
|
|
169
|
-
self.
|
|
170
|
-
|
|
163
|
+
def __init__(self, interface=None, target=None, session=Session(),
|
|
164
|
+
requester=NullRequester()):
|
|
165
|
+
self._interface = interface
|
|
166
|
+
|
|
167
|
+
# we need a session, set if not passed
|
|
168
|
+
if session is None:
|
|
169
|
+
session = Session()
|
|
170
|
+
self._session = session
|
|
171
|
+
# session needs an interface
|
|
172
|
+
self._session.interface = interface
|
|
173
|
+
|
|
174
|
+
self._target = target
|
|
175
|
+
self.requester = requester
|
|
171
176
|
|
|
172
177
|
for base in Ipmi.__bases__:
|
|
173
178
|
base.__init__(self)
|
|
174
179
|
|
|
180
|
+
def __enter__(self):
|
|
181
|
+
self.open()
|
|
182
|
+
return self
|
|
183
|
+
|
|
184
|
+
def __exit__(self, exception_type, exception_value, traceback):
|
|
185
|
+
self.close()
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
def open(self):
|
|
189
|
+
self.interface.open()
|
|
190
|
+
if self.session is not None:
|
|
191
|
+
self.session.establish()
|
|
192
|
+
|
|
193
|
+
def close(self):
|
|
194
|
+
if self.session is not None:
|
|
195
|
+
self.session.close()
|
|
196
|
+
self.interface.close()
|
|
197
|
+
|
|
175
198
|
def is_ipmc_accessible(self):
|
|
176
199
|
return self.interface.is_ipmc_accessible(self.target)
|
|
177
200
|
|
|
@@ -24,6 +24,9 @@ class Bmc(object):
|
|
|
24
24
|
def get_device_id(self):
|
|
25
25
|
return DeviceId(self.send_message_with_name('GetDeviceId'))
|
|
26
26
|
|
|
27
|
+
def get_device_guid(self):
|
|
28
|
+
return DeviceGuid(self.send_message_with_name('GetDeviceGuid'))
|
|
29
|
+
|
|
27
30
|
def cold_reset(self):
|
|
28
31
|
self.send_message_with_name('ColdReset')
|
|
29
32
|
|
|
@@ -86,7 +89,7 @@ class Watchdog(State):
|
|
|
86
89
|
TIMEOUT_ACTION_POWER_CYCLE = 3
|
|
87
90
|
|
|
88
91
|
__properties__ = [
|
|
89
|
-
# (
|
|
92
|
+
# (property, description)
|
|
90
93
|
('timer_use', ''),
|
|
91
94
|
('dont_stop', ''),
|
|
92
95
|
('is_running', ''),
|
|
@@ -121,6 +124,7 @@ class DeviceId(State):
|
|
|
121
124
|
string += ' ipmi: %s' % self.ipmi_version
|
|
122
125
|
string += ' manufacturer: %d' % self.manufacturer_id
|
|
123
126
|
string += ' product: %d' % self.product_id
|
|
127
|
+
string += ' functions: %s' % ','.join(self.supported_functions)
|
|
124
128
|
return string
|
|
125
129
|
|
|
126
130
|
def supports_function(self, name):
|
|
@@ -164,3 +168,14 @@ class DeviceId(State):
|
|
|
164
168
|
self.aux = None
|
|
165
169
|
if rsp.auxiliary is not None:
|
|
166
170
|
self.aux = list(rsp.auxiliary)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class DeviceGuid(State):
|
|
174
|
+
def __str__(self):
|
|
175
|
+
return 'Device GUID: %s' % self.device_guid_string
|
|
176
|
+
|
|
177
|
+
def _from_response(self, rsp):
|
|
178
|
+
self.device_guid = rsp.device_guid
|
|
179
|
+
self.device_guid_string = \
|
|
180
|
+
'%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-' \
|
|
181
|
+
'%02x%02x%02x%02x%02x%02x' % tuple(reversed(self.device_guid))
|
|
@@ -69,7 +69,7 @@ class DescriptionError(Exception):
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
class RetryError(Exception):
|
|
72
|
-
"""
|
|
72
|
+
"""Maximum number of retries exceeded."""
|
|
73
73
|
pass
|
|
74
74
|
|
|
75
75
|
|
|
@@ -90,3 +90,21 @@ class IpmiConnectionError(Exception):
|
|
|
90
90
|
|
|
91
91
|
def __str__(self):
|
|
92
92
|
return "{}".format(self.msg)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class IpmiLongPasswordError(Exception):
|
|
96
|
+
"""Password longer than 20 bytes."""
|
|
97
|
+
def __init__(self, msg=None):
|
|
98
|
+
self.msg = msg
|
|
99
|
+
|
|
100
|
+
def __str__(self):
|
|
101
|
+
return "{}".format(self.msg)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class AuthenticationError(Exception):
|
|
105
|
+
"""Authentication error."""
|
|
106
|
+
def __init__(self, msg=None):
|
|
107
|
+
self.msg = msg
|
|
108
|
+
|
|
109
|
+
def __str__(self):
|
|
110
|
+
return "{}".format(self.msg)
|
|
@@ -64,7 +64,7 @@ def _unpack6bitascii(data):
|
|
|
64
64
|
|
|
65
65
|
class TypeLengthString(object):
|
|
66
66
|
"""
|
|
67
|
-
This is the TYPE/LENGTH BYTE FORMAT field
|
|
67
|
+
This is the TYPE/LENGTH BYTE FORMAT field representation according the
|
|
68
68
|
Platform Management FRU Information Storage Definition v1.0.
|
|
69
69
|
|
|
70
70
|
In addition the difference to the 'FRU Information Storage Definition' to
|
|
@@ -88,9 +88,9 @@ class Fru(object):
|
|
|
88
88
|
def read_fru_data_full(self, fru_id=0):
|
|
89
89
|
return self.read_fru_data(fru_id=fru_id)
|
|
90
90
|
|
|
91
|
-
def get_fru_inventory_header(self, fru_id=0):
|
|
91
|
+
def get_fru_inventory_header(self, fru_id=0, ignore_checksum=False):
|
|
92
92
|
data = self.read_fru_data(offset=0, count=8, fru_id=fru_id)
|
|
93
|
-
return InventoryCommonHeader(data)
|
|
93
|
+
return InventoryCommonHeader(data, ignore_checksum=ignore_checksum)
|
|
94
94
|
|
|
95
95
|
def _read_fru_area(self, offset, fru_id=0):
|
|
96
96
|
# read the area header
|
|
@@ -99,26 +99,30 @@ class Fru(object):
|
|
|
99
99
|
count = data[1] * 8
|
|
100
100
|
return self.read_fru_data(offset=offset, count=count, fru_id=fru_id)
|
|
101
101
|
|
|
102
|
-
def get_fru_chassis_area(self, fru_id=0):
|
|
103
|
-
header = self.get_fru_inventory_header(fru_id=fru_id
|
|
102
|
+
def get_fru_chassis_area(self, fru_id=0, ignore_checksum=False):
|
|
103
|
+
header = self.get_fru_inventory_header(fru_id=fru_id,
|
|
104
|
+
ignore_checksum=ignore_checksum)
|
|
104
105
|
data = self._read_fru_area(offset=header.chassis_info_area_offset,
|
|
105
106
|
fru_id=fru_id)
|
|
106
|
-
return InventoryChassisInfoArea(data)
|
|
107
|
+
return InventoryChassisInfoArea(data, ignore_checksum=ignore_checksum)
|
|
107
108
|
|
|
108
|
-
def get_fru_board_area(self, fru_id=0):
|
|
109
|
-
header = self.get_fru_inventory_header(fru_id=fru_id
|
|
109
|
+
def get_fru_board_area(self, fru_id=0, ignore_checksum=False):
|
|
110
|
+
header = self.get_fru_inventory_header(fru_id=fru_id,
|
|
111
|
+
ignore_checksum=ignore_checksum)
|
|
110
112
|
data = self._read_fru_area(offset=header.board_info_area_offset,
|
|
111
113
|
fru_id=fru_id)
|
|
112
|
-
return InventoryBoardInfoArea(data)
|
|
114
|
+
return InventoryBoardInfoArea(data, ignore_checksum=ignore_checksum)
|
|
113
115
|
|
|
114
|
-
def get_fru_product_area(self, fru_id=0):
|
|
115
|
-
header = self.get_fru_inventory_header(fru_id=fru_id
|
|
116
|
+
def get_fru_product_area(self, fru_id=0, ignore_checksum=False):
|
|
117
|
+
header = self.get_fru_inventory_header(fru_id=fru_id,
|
|
118
|
+
ignore_checksum=ignore_checksum)
|
|
116
119
|
data = self._read_fru_area(offset=header.product_info_area_offset,
|
|
117
120
|
fru_id=fru_id)
|
|
118
|
-
return InventoryProductInfoArea(data)
|
|
121
|
+
return InventoryProductInfoArea(data, ignore_checksum=ignore_checksum)
|
|
119
122
|
|
|
120
|
-
def get_fru_multirecord_area(self, fru_id=0):
|
|
121
|
-
header = self.get_fru_inventory_header(fru_id=fru_id
|
|
123
|
+
def get_fru_multirecord_area(self, fru_id=0, ignore_checksum=False):
|
|
124
|
+
header = self.get_fru_inventory_header(fru_id=fru_id,
|
|
125
|
+
ignore_checksum=ignore_checksum)
|
|
122
126
|
|
|
123
127
|
# we have to determine the length of the area first
|
|
124
128
|
offset = header.multirecord_area_offset
|
|
@@ -137,31 +141,47 @@ class Fru(object):
|
|
|
137
141
|
# now read the full area
|
|
138
142
|
offset = header.multirecord_area_offset
|
|
139
143
|
data = self.read_fru_data(offset=offset, count=count)
|
|
140
|
-
return InventoryMultiRecordArea(data)
|
|
144
|
+
return InventoryMultiRecordArea(data, ignore_checksum=ignore_checksum)
|
|
141
145
|
|
|
142
|
-
def get_fru_inventory(self, fru_id=0):
|
|
146
|
+
def get_fru_inventory(self, fru_id=0, ignore_checksum=False):
|
|
143
147
|
"""
|
|
144
148
|
Get the full parsed FRU inventory data.
|
|
145
149
|
"""
|
|
146
150
|
fru = FruInventory()
|
|
147
|
-
|
|
151
|
+
|
|
152
|
+
header = self.get_fru_inventory_header(
|
|
153
|
+
fru_id=fru_id,
|
|
154
|
+
ignore_checksum=ignore_checksum
|
|
155
|
+
)
|
|
148
156
|
|
|
149
157
|
if header.chassis_info_area_offset:
|
|
150
|
-
fru.chassis_info_area = self.get_fru_chassis_area(
|
|
158
|
+
fru.chassis_info_area = self.get_fru_chassis_area(
|
|
159
|
+
fru_id=fru_id,
|
|
160
|
+
ignore_checksum=ignore_checksum
|
|
161
|
+
)
|
|
151
162
|
|
|
152
163
|
if header.board_info_area_offset:
|
|
153
|
-
fru.board_info_area = self.get_fru_board_area(
|
|
164
|
+
fru.board_info_area = self.get_fru_board_area(
|
|
165
|
+
fru_id=fru_id,
|
|
166
|
+
ignore_checksum=ignore_checksum
|
|
167
|
+
)
|
|
154
168
|
|
|
155
169
|
if header.product_info_area_offset:
|
|
156
|
-
fru.product_info_area = self.get_fru_product_area(
|
|
170
|
+
fru.product_info_area = self.get_fru_product_area(
|
|
171
|
+
fru_id=fru_id,
|
|
172
|
+
ignore_checksum=ignore_checksum
|
|
173
|
+
)
|
|
157
174
|
|
|
158
175
|
if header.multirecord_area_offset:
|
|
159
|
-
fru.multirecord_area = self.get_fru_multirecord_area(
|
|
176
|
+
fru.multirecord_area = self.get_fru_multirecord_area(
|
|
177
|
+
fru_id=fru_id,
|
|
178
|
+
ignore_checksum=ignore_checksum
|
|
179
|
+
)
|
|
160
180
|
|
|
161
181
|
return fru
|
|
162
182
|
|
|
163
183
|
|
|
164
|
-
def get_fru_inventory_from_file(filename):
|
|
184
|
+
def get_fru_inventory_from_file(filename, ignore_checksum=False):
|
|
165
185
|
try:
|
|
166
186
|
file = open(filename, "rb")
|
|
167
187
|
except IOError:
|
|
@@ -173,7 +193,7 @@ def get_fru_inventory_from_file(filename):
|
|
|
173
193
|
file_data = file.read(file_size)
|
|
174
194
|
data = array.array('B', file_data)
|
|
175
195
|
file.close()
|
|
176
|
-
return FruInventory(data)
|
|
196
|
+
return FruInventory(data, ignore_checksum=ignore_checksum)
|
|
177
197
|
|
|
178
198
|
|
|
179
199
|
CUSTOM_FIELD_END = 0xc1
|
|
@@ -190,18 +210,18 @@ def _decode_custom_fields(data):
|
|
|
190
210
|
|
|
191
211
|
|
|
192
212
|
class FruData(object):
|
|
193
|
-
def __init__(self, data=None):
|
|
213
|
+
def __init__(self, data=None, ignore_checksum=False):
|
|
194
214
|
if data:
|
|
195
215
|
if isinstance(data, str):
|
|
196
216
|
data = [ord(c) for c in data]
|
|
197
217
|
self.data = data
|
|
198
218
|
if hasattr(self, '_from_data'):
|
|
199
|
-
self._from_data(data)
|
|
219
|
+
self._from_data(data, ignore_checksum=ignore_checksum)
|
|
200
220
|
|
|
201
221
|
|
|
202
222
|
class InventoryCommonHeader(FruData):
|
|
203
|
-
def _from_data(self, data):
|
|
204
|
-
if len(data)
|
|
223
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
224
|
+
if len(data) < 8:
|
|
205
225
|
raise DecodingError('InventoryCommonHeader length != 8')
|
|
206
226
|
self.format_version = data[0] & 0x0f
|
|
207
227
|
self.internal_use_area_offset = data[1] * 8 or None
|
|
@@ -209,18 +229,18 @@ class InventoryCommonHeader(FruData):
|
|
|
209
229
|
self.board_info_area_offset = data[3] * 8 or None
|
|
210
230
|
self.product_info_area_offset = data[4] * 8 or None
|
|
211
231
|
self.multirecord_area_offset = data[5] * 8 or None
|
|
212
|
-
if sum(data) % 256 != 0:
|
|
213
|
-
raise DecodingError('InventoryCommonHeader checksum failed')
|
|
232
|
+
if sum(data[:8]) % 256 != 0 and ignore_checksum is False:
|
|
233
|
+
raise DecodingError(f'InventoryCommonHeader checksum failed {sum(data) % 0x10}')
|
|
214
234
|
|
|
215
235
|
|
|
216
236
|
class CommonInfoArea(FruData):
|
|
217
|
-
def _from_data(self, data):
|
|
237
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
218
238
|
self.format_version = data[0] & 0x0f
|
|
219
239
|
if self.format_version != 1:
|
|
220
240
|
raise DecodingError('unsupported format version (%d)' %
|
|
221
241
|
self.format_version)
|
|
222
242
|
self.length = data[1] * 8
|
|
223
|
-
if sum(data[:self.length]) % 256 != 0:
|
|
243
|
+
if sum(data[:self.length]) % 256 != 0 and ignore_checksum is False:
|
|
224
244
|
raise DecodingError('checksum failed')
|
|
225
245
|
|
|
226
246
|
|
|
@@ -249,7 +269,7 @@ class InventoryChassisInfoArea(CommonInfoArea):
|
|
|
249
269
|
TYPE_RAID_CHASSIS = 22
|
|
250
270
|
TYPE_RACK_MOUNT_CHASSIS = 23
|
|
251
271
|
|
|
252
|
-
def _from_data(self, data):
|
|
272
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
253
273
|
CommonInfoArea._from_data(self, data)
|
|
254
274
|
self.type = data[2]
|
|
255
275
|
offset = 3
|
|
@@ -261,8 +281,8 @@ class InventoryChassisInfoArea(CommonInfoArea):
|
|
|
261
281
|
|
|
262
282
|
|
|
263
283
|
class InventoryBoardInfoArea(CommonInfoArea):
|
|
264
|
-
def _from_data(self, data):
|
|
265
|
-
CommonInfoArea._from_data(self, data)
|
|
284
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
285
|
+
CommonInfoArea._from_data(self, data, ignore_checksum=ignore_checksum)
|
|
266
286
|
self.language_code = data[2]
|
|
267
287
|
minutes = data[5] << 16 | data[4] << 8 | data[3]
|
|
268
288
|
self.mfg_date = (datetime.datetime(1996, 1, 1)
|
|
@@ -282,7 +302,7 @@ class InventoryBoardInfoArea(CommonInfoArea):
|
|
|
282
302
|
|
|
283
303
|
|
|
284
304
|
class InventoryProductInfoArea(CommonInfoArea):
|
|
285
|
-
def _from_data(self, data):
|
|
305
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
286
306
|
CommonInfoArea._from_data(self, data)
|
|
287
307
|
self.language_code = data[2]
|
|
288
308
|
offset = 3
|
|
@@ -318,17 +338,17 @@ class FruDataMultiRecord(FruData):
|
|
|
318
338
|
return '%02x: %s' % (self.record_type_id,
|
|
319
339
|
' '.join('%02x' % b for b in self.raw))
|
|
320
340
|
|
|
321
|
-
def _from_data(self, data):
|
|
341
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
322
342
|
if len(data) < 5:
|
|
323
343
|
raise DecodingError('data too short')
|
|
324
344
|
self.record_type_id = data[0]
|
|
325
345
|
self.format_version = data[1] & 0x0f
|
|
326
346
|
self.end_of_list = bool(data[1] & 0x80)
|
|
327
347
|
self.length = data[2]
|
|
328
|
-
if sum(data[:5]) % 256 != 0:
|
|
348
|
+
if sum(data[:5]) % 256 != 0 and ignore_checksum is False:
|
|
329
349
|
raise DecodingError('FruDataMultiRecord header checksum failed')
|
|
330
350
|
self.raw = data[5:5+self.length]
|
|
331
|
-
if (sum(self.raw) + data[3]) % 256 != 0:
|
|
351
|
+
if (sum(self.raw) + data[3]) % 256 != 0 and ignore_checksum is False:
|
|
332
352
|
raise DecodingError('FruDataMultiRecord record checksum failed')
|
|
333
353
|
|
|
334
354
|
@staticmethod
|
|
@@ -386,11 +406,11 @@ class FruPicmgRecord(FruDataMultiRecord):
|
|
|
386
406
|
|
|
387
407
|
return FruPicmgRecord(data)
|
|
388
408
|
|
|
389
|
-
def _from_data(self, data):
|
|
409
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
390
410
|
if len(data) < 10:
|
|
391
411
|
raise DecodingError('data too short')
|
|
392
412
|
data = array.array('B', data)
|
|
393
|
-
FruDataMultiRecord._from_data(self, data)
|
|
413
|
+
FruDataMultiRecord._from_data(self, data, ignore_checksum=ignore_checksum)
|
|
394
414
|
self.manufacturer_id = \
|
|
395
415
|
data[5] | data[6] << 8 | data[7] << 16
|
|
396
416
|
self.picmg_record_type_id = data[8]
|
|
@@ -398,7 +418,7 @@ class FruPicmgRecord(FruDataMultiRecord):
|
|
|
398
418
|
|
|
399
419
|
|
|
400
420
|
class FruPicmgPowerModuleCapabilityRecord(FruPicmgRecord):
|
|
401
|
-
def _from_data(self, data):
|
|
421
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
402
422
|
if len(data) < 12:
|
|
403
423
|
raise DecodingError('data too short')
|
|
404
424
|
FruPicmgRecord._from_data(self, data)
|
|
@@ -407,11 +427,11 @@ class FruPicmgPowerModuleCapabilityRecord(FruPicmgRecord):
|
|
|
407
427
|
|
|
408
428
|
|
|
409
429
|
class InventoryMultiRecordArea(object):
|
|
410
|
-
def __init__(self, data):
|
|
430
|
+
def __init__(self, data, ignore_checksum=False):
|
|
411
431
|
if data:
|
|
412
432
|
self._from_data(data)
|
|
413
433
|
|
|
414
|
-
def _from_data(self, data):
|
|
434
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
415
435
|
self.records = list()
|
|
416
436
|
offset = 0
|
|
417
437
|
while True:
|
|
@@ -423,31 +443,35 @@ class InventoryMultiRecordArea(object):
|
|
|
423
443
|
|
|
424
444
|
|
|
425
445
|
class FruInventory(object):
|
|
426
|
-
def __init__(self, data=None):
|
|
446
|
+
def __init__(self, data=None, ignore_checksum=False):
|
|
427
447
|
self.chassis_info_area = None
|
|
428
448
|
self.board_info_area = None
|
|
429
449
|
self.product_info_area = None
|
|
430
450
|
self.multirecord_area = None
|
|
431
451
|
|
|
432
452
|
if data:
|
|
433
|
-
self._from_data(data)
|
|
453
|
+
self._from_data(data, ignore_checksum=ignore_checksum)
|
|
434
454
|
|
|
435
|
-
def _from_data(self, data):
|
|
455
|
+
def _from_data(self, data, ignore_checksum=False):
|
|
436
456
|
self.raw = data
|
|
437
457
|
self.common_header = InventoryCommonHeader(data[:8])
|
|
438
458
|
|
|
439
459
|
if self.common_header.chassis_info_area_offset:
|
|
440
460
|
self.chassis_info_area = InventoryChassisInfoArea(
|
|
441
|
-
data[self.common_header.chassis_info_area_offset:]
|
|
461
|
+
data[self.common_header.chassis_info_area_offset:],
|
|
462
|
+
ignore_checksum=ignore_checksum)
|
|
442
463
|
|
|
443
464
|
if self.common_header.board_info_area_offset:
|
|
444
465
|
self.board_info_area = InventoryBoardInfoArea(
|
|
445
|
-
data[self.common_header.board_info_area_offset:]
|
|
466
|
+
data[self.common_header.board_info_area_offset:],
|
|
467
|
+
ignore_checksum=ignore_checksum)
|
|
446
468
|
|
|
447
469
|
if self.common_header.product_info_area_offset:
|
|
448
470
|
self.product_info_area = InventoryProductInfoArea(
|
|
449
|
-
data[self.common_header.product_info_area_offset:]
|
|
471
|
+
data[self.common_header.product_info_area_offset:],
|
|
472
|
+
ignore_checksum=ignore_checksum)
|
|
450
473
|
|
|
451
474
|
if self.common_header.multirecord_area_offset:
|
|
452
475
|
self.multirecord_area = InventoryMultiRecordArea(
|
|
453
|
-
data[self.common_header.multirecord_area_offset:]
|
|
476
|
+
data[self.common_header.multirecord_area_offset:],
|
|
477
|
+
ignore_checksum=ignore_checksum)
|
|
@@ -85,7 +85,7 @@ def get_sdr_data_helper(reserve_fn, get_fn, record_id, reservation_id=None):
|
|
|
85
85
|
(next_id, data) = get_fn(reservation_id, record_id, offset, length)
|
|
86
86
|
except CompletionCodeError as e:
|
|
87
87
|
if e.cc == constants.CC_CANT_RET_NUM_REQ_BYTES:
|
|
88
|
-
# reduce max
|
|
88
|
+
# reduce max length
|
|
89
89
|
max_req_len -= 4
|
|
90
90
|
if max_req_len <= 0:
|
|
91
91
|
retry = 0
|
|
@@ -314,7 +314,7 @@ class Hpm(object):
|
|
|
314
314
|
# tbd check version
|
|
315
315
|
|
|
316
316
|
####################################################
|
|
317
|
-
# compare current revision with upgrade image
|
|
317
|
+
# compare current revision with upgrade image earliest comp rev
|
|
318
318
|
targetCap = self.get_target_upgrade_capabilities()
|
|
319
319
|
# tbd check version
|
|
320
320
|
|
|
@@ -44,23 +44,32 @@ class Aardvark(object):
|
|
|
44
44
|
'use this interface.')
|
|
45
45
|
|
|
46
46
|
self.slave_address = slave_address
|
|
47
|
+
self.port = port
|
|
48
|
+
self.serial_number = serial_number
|
|
49
|
+
self.i2c_pullups = enable_i2c_pullups
|
|
50
|
+
self.target_power = enable_target_power
|
|
51
|
+
self.fastmode = enable_fastmode
|
|
47
52
|
self.timeout = 0.25
|
|
48
53
|
self.max_retries = 3
|
|
49
54
|
self.next_sequence_number = 0
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
def open(self):
|
|
57
|
+
self._dev = pyaardvark.open(self.port, self.serial_number)
|
|
52
58
|
self._dev.enable_i2c_slave(self.slave_address >> 1)
|
|
53
59
|
|
|
54
|
-
if
|
|
55
|
-
self.enable_pullups(
|
|
56
|
-
if
|
|
57
|
-
self.enable_target_power(
|
|
60
|
+
if self.i2c_pullups:
|
|
61
|
+
self.enable_pullups(self.i2c_pullups)
|
|
62
|
+
if self.target_power:
|
|
63
|
+
self.enable_target_power(self.target_power)
|
|
58
64
|
|
|
59
|
-
if
|
|
60
|
-
self.enable_fastmode(
|
|
65
|
+
if self.fastmode is not None:
|
|
66
|
+
self.enable_fastmode(self.fastmode)
|
|
61
67
|
else:
|
|
62
68
|
self.enable_fastmode(False)
|
|
63
69
|
|
|
70
|
+
def close(self):
|
|
71
|
+
self._dev.close()
|
|
72
|
+
|
|
64
73
|
def enable_pullups(self, enabled):
|
|
65
74
|
self._dev.i2c_pullups = enabled
|
|
66
75
|
|
|
@@ -77,11 +86,10 @@ class Aardvark(object):
|
|
|
77
86
|
self._dev.i2c_master_write(address, data)
|
|
78
87
|
|
|
79
88
|
def establish_session(self, session):
|
|
80
|
-
|
|
81
|
-
self._session = session
|
|
89
|
+
pass
|
|
82
90
|
|
|
83
91
|
def close_session(self):
|
|
84
|
-
|
|
92
|
+
pass
|
|
85
93
|
|
|
86
94
|
def is_ipmc_accessible(self, target):
|
|
87
95
|
header = IpmbHeaderReq()
|
|
@@ -45,10 +45,6 @@ class IpmbHeader(object):
|
|
|
45
45
|
*-------*--------------*----------*-------*---------------*-------*
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
|
-
def __init__(self, data=None):
|
|
49
|
-
if data:
|
|
50
|
-
self.decode(data)
|
|
51
|
-
|
|
52
48
|
rs_sa = None
|
|
53
49
|
rs_lun = None
|
|
54
50
|
rq_sa = None
|
|
@@ -58,6 +54,17 @@ class IpmbHeader(object):
|
|
|
58
54
|
cmdid = None
|
|
59
55
|
checksum = None
|
|
60
56
|
|
|
57
|
+
def __init__(self, data=None):
|
|
58
|
+
if data:
|
|
59
|
+
self.decode(data)
|
|
60
|
+
|
|
61
|
+
def __str__(self):
|
|
62
|
+
return f'rs_sa=0x{self.rs_sa:02x}, rs_lun={self.rs_lun}, ' \
|
|
63
|
+
f'rq_sa=0x{self.rq_sa:02x}, rq_lun={self.rq_lun}, ' \
|
|
64
|
+
f'rq_seq={self.rq_seq}, ' \
|
|
65
|
+
f'netfn=0x{self.netfn:02x}, ' \
|
|
66
|
+
f'cmdid=0x{self.cmdid:02x}'
|
|
67
|
+
|
|
61
68
|
|
|
62
69
|
class IpmbHeaderReq(IpmbHeader):
|
|
63
70
|
"""Representation of the IPMI request message header."""
|
|
@@ -142,7 +149,7 @@ def encode_ipmb_msg(header, data):
|
|
|
142
149
|
|
|
143
150
|
|
|
144
151
|
def encode_send_message(payload, rq_sa, rs_sa, channel, seq, tracking=1):
|
|
145
|
-
"""Encode a send message command and
|
|
152
|
+
"""Encode a send message command and embed the message to be send.
|
|
146
153
|
|
|
147
154
|
payload: the message to be send as bytestring
|
|
148
155
|
rq_sa: the requester source address
|
|
@@ -171,7 +178,7 @@ def encode_send_message(payload, rq_sa, rs_sa, channel, seq, tracking=1):
|
|
|
171
178
|
|
|
172
179
|
|
|
173
180
|
def encode_bridged_message(routing, header, payload, seq):
|
|
174
|
-
"""Encode a (multi-)bridged command and
|
|
181
|
+
"""Encode a (multi-)bridged command and embed the message to be send.
|
|
175
182
|
|
|
176
183
|
routing:
|
|
177
184
|
payload: the message to be send as bytestring
|
|
@@ -214,7 +221,8 @@ def decode_bridged_message(rx_data):
|
|
|
214
221
|
return rx_data
|
|
215
222
|
|
|
216
223
|
|
|
217
|
-
def rx_filter(header, data
|
|
224
|
+
def rx_filter(header, data, rq_sa=False, rs_sa=False, rq_lun=False,
|
|
225
|
+
rs_lun=True, rq_seq=True):
|
|
218
226
|
"""Check if the message in rx_data matches to the information in header.
|
|
219
227
|
|
|
220
228
|
The following checks are done:
|
|
@@ -234,15 +242,26 @@ def rx_filter(header, data):
|
|
|
234
242
|
checks = [
|
|
235
243
|
(checksum(data[0:3]), 0, 'Header checksum failed'),
|
|
236
244
|
(checksum(data[3:]), 0, 'payload checksum failed'),
|
|
237
|
-
# rsp_header.rq_sa, header.rq_sa, 'slave address mismatch'),
|
|
238
245
|
(rsp_header.netfn, header.netfn | 1, 'NetFn mismatch'),
|
|
239
|
-
# rsp_header.rs_sa, header.rs_sa, 'target address mismatch'),
|
|
240
|
-
# rsp_header.rq_lun, header.rq_lun, 'request LUN mismatch'),
|
|
241
|
-
(rsp_header.rs_lun, header.rs_lun, 'responder LUN mismatch'),
|
|
242
|
-
(rsp_header.rq_seq, header.rq_seq, 'sequence number mismatch'),
|
|
243
246
|
(rsp_header.cmdid, header.cmdid, 'command id mismatch'),
|
|
244
247
|
]
|
|
245
248
|
|
|
249
|
+
# optional checks
|
|
250
|
+
if rq_sa:
|
|
251
|
+
checks.append((rsp_header.rq_sa, header.rq_sa, 'slave address mismatch'))
|
|
252
|
+
|
|
253
|
+
if rs_sa:
|
|
254
|
+
checks.append((rsp_header.rs_sa, header.rs_sa, 'target address mismatch'))
|
|
255
|
+
|
|
256
|
+
if rq_lun:
|
|
257
|
+
checks.append((rsp_header.rq_lun, header.rq_lun, 'request LUN mismatch'))
|
|
258
|
+
|
|
259
|
+
if rs_lun:
|
|
260
|
+
checks.append((rsp_header.rs_lun, header.rs_lun, 'responder LUN mismatch'))
|
|
261
|
+
|
|
262
|
+
if rq_seq:
|
|
263
|
+
checks.append((rsp_header.rq_seq, header.rq_seq, 'sequence number mismatch'))
|
|
264
|
+
|
|
246
265
|
match = True
|
|
247
266
|
|
|
248
267
|
for left, right, msg in checks:
|