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.
Files changed (77) hide show
  1. {python-ipmi-0.5.5/python_ipmi.egg-info → python_ipmi-0.5.8}/PKG-INFO +16 -4
  2. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/README.rst +2 -1
  3. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/__init__.py +32 -9
  4. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/bmc.py +16 -1
  5. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/errors.py +19 -1
  6. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/fields.py +1 -1
  7. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/fru.py +73 -49
  8. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/helper.py +1 -1
  9. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/hpm.py +1 -1
  10. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/aardvark.py +18 -10
  11. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/ipmb.py +31 -12
  12. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/ipmbdev.py +8 -4
  13. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/ipmitool.py +44 -7
  14. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/mock.py +6 -0
  15. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/rmcp.py +22 -6
  16. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/ipmitool.py +6 -5
  17. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/messaging.py +1 -0
  18. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/bmc.py +6 -7
  19. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/chassis.py +0 -1
  20. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/dcmi.py +0 -2
  21. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/event.py +0 -1
  22. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/fru.py +0 -1
  23. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/hpm.py +0 -1
  24. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/lan.py +0 -1
  25. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/message.py +3 -6
  26. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/picmg.py +0 -2
  27. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/registry.py +0 -1
  28. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/sdr.py +0 -1
  29. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/sel.py +0 -1
  30. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/sensor.py +0 -1
  31. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/vita.py +0 -2
  32. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/version.py +1 -1
  33. {python-ipmi-0.5.5 → python_ipmi-0.5.8/python_ipmi.egg-info}/PKG-INFO +16 -4
  34. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/SOURCES.txt +1 -0
  35. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/setup.py +1 -1
  36. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_bmc.py +9 -1
  37. python_ipmi-0.5.8/tests/test_event.py +38 -0
  38. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_fru.py +31 -9
  39. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_helper.py +1 -1
  40. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_hpm.py +1 -1
  41. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_ipmi.py +38 -2
  42. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_ipmitool.py +3 -2
  43. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_sel.py +4 -4
  44. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_sensor.py +2 -2
  45. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/AUTHORS +0 -0
  46. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/COPYING +0 -0
  47. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/chassis.py +0 -0
  48. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/constants.py +0 -0
  49. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/dcmi.py +0 -0
  50. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/emulation.py +0 -0
  51. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/event.py +0 -0
  52. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/interfaces/__init__.py +0 -0
  53. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/lan.py +0 -0
  54. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/logger.py +0 -0
  55. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/__init__.py +0 -0
  56. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/constants.py +0 -0
  57. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/device_messaging.py +0 -0
  58. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/msgs/session.py +0 -0
  59. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/picmg.py +0 -0
  60. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/sdr.py +0 -0
  61. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/sel.py +0 -0
  62. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/sensor.py +0 -0
  63. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/session.py +0 -0
  64. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/state.py +0 -0
  65. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/pyipmi/utils.py +0 -0
  66. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/dependency_links.txt +0 -0
  67. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/entry_points.txt +0 -0
  68. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/python_ipmi.egg-info/top_level.txt +0 -0
  69. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/setup.cfg +0 -0
  70. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_chassis.py +0 -0
  71. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_device_messaging.py +0 -0
  72. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_errors.py +0 -0
  73. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_fields.py +0 -0
  74. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_lan.py +0 -0
  75. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_picmg.py +0 -0
  76. {python-ipmi-0.5.5 → python_ipmi-0.5.8}/tests/test_sdr.py +0 -0
  77. {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
1
+ Metadata-Version: 2.4
2
2
  Name: python-ipmi
3
- Version: 0.5.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.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
- ipmi = Ipmi()
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
- self._interface = None
169
- self._session = None
170
- self._target = None
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
- # (propery, description)
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
- """Maxium number of retries exceeded."""
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 represenation according the
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
- header = self.get_fru_inventory_header(fru_id=fru_id)
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(fru_id=fru_id)
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(fru_id=fru_id)
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(fru_id=fru_id)
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(fru_id=fru_id)
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) != 8:
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 lenght
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 earlist comp rev
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
- self._dev = pyaardvark.open(port, serial_number)
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 enable_i2c_pullups:
55
- self.enable_pullups(enable_i2c_pullups)
56
- if enable_target_power:
57
- self.enable_target_power(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 enable_fastmode is not None:
60
- self.enable_fastmode(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
- # just remember session parameters here
81
- self._session = session
89
+ pass
82
90
 
83
91
  def close_session(self):
84
- self._dev.close()
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 embedd the message to be send.
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 embedd the message to be send.
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: