python-ipmi 0.5.5__py3-none-any.whl → 0.5.8__py3-none-any.whl

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.
pyipmi/__init__.py CHANGED
@@ -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
 
pyipmi/bmc.py CHANGED
@@ -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))
pyipmi/errors.py CHANGED
@@ -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)
pyipmi/fields.py CHANGED
@@ -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
pyipmi/fru.py CHANGED
@@ -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)
pyipmi/helper.py CHANGED
@@ -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
pyipmi/hpm.py CHANGED
@@ -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()
pyipmi/interfaces/ipmb.py CHANGED
@@ -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:
@@ -17,18 +17,22 @@ class IpmbDev(object):
17
17
  def __init__(self, slave_address=0x20, port='/dev/ipmb-0'):
18
18
  # TODO: slave address is currently not defined here
19
19
  self.slave_address = slave_address
20
+ self.port = port
20
21
  self.timeout = 0.25
21
22
  self.max_retries = 3
22
23
  self.next_sequence_number = 0
23
24
 
24
- self._dev = os.open(port, os.O_RDWR)
25
+ def open(self):
26
+ self._dev = os.open(self.port, os.O_RDWR)
27
+
28
+ def close(self):
29
+ os.close(self._dev)
25
30
 
26
31
  def establish_session(self, session):
27
- # just remember session parameters here
28
- self._session = session
32
+ pass
29
33
 
30
34
  def close_session(self):
31
- os.close(self._dev)
35
+ pass
32
36
 
33
37
  def is_ipmc_accessible(self, target):
34
38
  header = IpmbHeaderReq()
@@ -21,7 +21,12 @@ from subprocess import Popen, PIPE
21
21
  from array import array
22
22
 
23
23
  from ..session import Session
24
- from ..errors import IpmiTimeoutError, IpmiConnectionError
24
+ from ..errors import (
25
+ IpmiTimeoutError,
26
+ IpmiConnectionError,
27
+ IpmiLongPasswordError,
28
+ AuthenticationError,
29
+ )
25
30
  from ..logger import log
26
31
  from ..msgs import encode_message, decode_message, create_message
27
32
  from ..msgs.constants import CC_OK
@@ -42,12 +47,17 @@ class Ipmitool(object):
42
47
  IPMITOOL_PATH = 'ipmitool'
43
48
  supported_interfaces = ['lan', 'lanplus', 'serial-terminal', 'open']
44
49
 
45
- def __init__(self, interface_type='lan'):
50
+ def __init__(self, interface_type='lan', cipher=None):
46
51
  if interface_type in self.supported_interfaces:
47
52
  self._interface_type = interface_type
48
53
  else:
49
54
  raise RuntimeError('interface type %s not supported' %
50
55
  interface_type)
56
+ if cipher is not None and int(cipher) not in range(0, 255):
57
+ raise RuntimeError('cipher %s not in allowed range [0-255]' %
58
+ cipher)
59
+ else:
60
+ self._cipher = cipher
51
61
 
52
62
  self.re_completion_code = re.compile(
53
63
  r"Unable to send RAW command \(.*rsp=(0x[0-9a-f]+)\)")
@@ -57,13 +67,24 @@ class Ipmitool(object):
57
67
  r".*Unable to establish.*")
58
68
  self.re_could_not_open = re.compile(
59
69
  r".*Could not open device.*")
60
-
70
+ self.re_long_password = re.compile(
71
+ r".*password is longer than.*")
72
+ self.re_authentication_error = re.compile(
73
+ r".*RAKP [0-9]+ HMAC.*")
61
74
  self._session = None
62
75
 
76
+ def open(self):
77
+ pass
78
+
79
+ def close(self):
80
+ pass
81
+
63
82
  def establish_session(self, session):
64
- # just remember session parameters here
65
83
  self._session = session
66
84
 
85
+ def close_session(self):
86
+ pass
87
+
67
88
  def rmcp_ping(self):
68
89
 
69
90
  if self._interface_type == 'serial-terminal':
@@ -75,6 +96,7 @@ class Ipmitool(object):
75
96
  cmd += (' -I %s' % self._interface_type)
76
97
  cmd += (' -H %s' % self._session.rmcp_host)
77
98
  cmd += (' -p %s' % self._session.rmcp_port)
99
+ cmd += (' -v')
78
100
  if self._session.auth_type == Session.AUTH_TYPE_NONE:
79
101
  cmd += (' -A NONE')
80
102
  elif self._session.auth_type == Session.AUTH_TYPE_PASSWORD:
@@ -103,6 +125,9 @@ class Ipmitool(object):
103
125
  # Don't try to parse ipmitool error messages
104
126
  if 'failed' in line:
105
127
  continue
128
+ # Don't try to parse spurious ipmitool output
129
+ if 'Received a response with unexpected ID' in line:
130
+ continue
106
131
 
107
132
  # Check for timeout
108
133
  if self.re_timeout.match(line):
@@ -122,13 +147,22 @@ class Ipmitool(object):
122
147
  if self.re_could_not_open.match(line):
123
148
  raise RuntimeError('ipmitool failed: {}'.format(output))
124
149
 
150
+ if self.re_long_password.match(line):
151
+ raise IpmiLongPasswordError(line)
152
+
153
+ if self.re_authentication_error.match(line):
154
+ raise AuthenticationError('Authentication error')
155
+
125
156
  hexstr += line.replace('\r', '').strip() + ' '
126
157
 
127
158
  hexstr = hexstr.strip()
128
159
  if len(hexstr):
129
- rsp = array('B', [
130
- int(value, 16) for value in hexstr.split(' ')
131
- ])
160
+ try:
161
+ rsp = array('B', [
162
+ int(value, 16) for value in hexstr.split(' ')
163
+ ])
164
+ except ValueError:
165
+ pass
132
166
 
133
167
  return cc, rsp
134
168
 
@@ -230,9 +264,12 @@ class Ipmitool(object):
230
264
  cmd += (' -I %s' % self._interface_type)
231
265
  cmd += (' -H %s' % self._session.rmcp_host)
232
266
  cmd += (' -p %s' % self._session.rmcp_port)
267
+ cmd += (' -v')
233
268
 
234
269
  cmd += self._build_ipmitool_priv_level(self._session.priv_level)
235
270
 
271
+ if self._cipher:
272
+ cmd += (' -C %s' % self._cipher)
236
273
  if self._session.auth_type == Session.AUTH_TYPE_NONE:
237
274
  cmd += ' -P ""'
238
275
  elif self._session.auth_type == Session.AUTH_TYPE_PASSWORD:
pyipmi/interfaces/mock.py CHANGED
@@ -6,6 +6,12 @@ class Mock(object):
6
6
  def __init__(self):
7
7
  pass
8
8
 
9
+ def open(self):
10
+ pass
11
+
12
+ def close(self):
13
+ pass
14
+
9
15
  def establish_session(self, session):
10
16
  pass
11
17
 
pyipmi/interfaces/rmcp.py CHANGED
@@ -248,7 +248,7 @@ class IpmiMsg(object):
248
248
  return struct.unpack("<I", struct.pack(">I", seq))[0]
249
249
 
250
250
  def _padd_password(self):
251
- """Padd the password.
251
+ """Pad the password.
252
252
 
253
253
  The password/key is 0 padded to 16-bytes for all specified
254
254
  authentication types.
@@ -380,15 +380,23 @@ class Rmcp(object):
380
380
  interface="rmcp",
381
381
  quirks_cfg={'rmcp_ignore_sdu_length': True}
382
382
  )
383
+
384
+ - `rmcp_ignore_rq_seq: bool` wheater or not to verify the req_seq field
385
+ for rx_filter. The default value is `False`.
386
+
387
+ Example:
388
+
389
+ interfaces.create_interface(
390
+ interface="rmcp",
391
+ quirks_cfg={'rmcp_ignore_rq_seq': True}
392
+ )
383
393
  """
384
394
  self.host = None
385
395
  self.port = None
386
- self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
387
396
  self.seq_number = 0xff
388
397
  self.slave_address = slave_address
389
398
  self.host_target = Target(host_target_address)
390
399
  self.max_retries = max_retries
391
- self.set_timeout(2.0)
392
400
  self.next_sequence_number = 0
393
401
  self.keep_alive_interval = keep_alive_interval
394
402
  self._stop_keep_alive = None
@@ -396,6 +404,14 @@ class Rmcp(object):
396
404
  self.transaction_lock = threading.Lock()
397
405
  self.quirks_cfg = quirks_cfg
398
406
  self.ignore_sdu_length = quirks_cfg.get('rmcp_ignore_sdu_length', False)
407
+ self.ignore_rq_seq = quirks_cfg.get('rmcp_ignore_rq_seq', False)
408
+
409
+ def open(self):
410
+ self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
411
+ self.set_timeout(2.0)
412
+
413
+ def close(self):
414
+ pass
399
415
 
400
416
  def _send_rmcp_msg(self, sdu, class_of_msg):
401
417
  rmcp = RmcpMsg(class_of_msg)
@@ -476,8 +492,7 @@ class Rmcp(object):
476
492
  req = create_request_by_name('ActivateSession')
477
493
  req.target = self.host_target
478
494
  req.authentication.type = session.auth_type
479
- req.privilege_level.maximum_requested =\
480
- Session.PRIV_LEVEL_ADMINISTRATOR
495
+ req.privilege_level.maximum_requested = session.priv_level
481
496
  req.challenge_string = challenge
482
497
  req.session_id = self._session.sid
483
498
  req.initial_outbound_sequence_number = random.randrange(1, 0xffffffff)
@@ -610,7 +625,8 @@ class Rmcp(object):
610
625
  # it's not really a retry
611
626
  continue
612
627
 
613
- received = rx_filter(header, rx_data)
628
+ received = rx_filter(header, rx_data,
629
+ rq_seq=not self.ignore_rq_seq)
614
630
 
615
631
  if not received:
616
632
  self._q.put(rx_data)
pyipmi/ipmitool.py CHANGED
@@ -474,7 +474,7 @@ Options:
474
474
  -I <interface> Set interface (available: rmcp, aardvark, ipmitool, ipmbdev)
475
475
  -H <host> Set RMCP host
476
476
  -U <user> Set RMCP user
477
- -L <level> Set RMCP priviledge level
477
+ -L <level> Set RMCP privilege level
478
478
  -P <password> Set RMCP password
479
479
  -o <options> Set interface specific options (name=value, separated
480
480
  by commas, see below for available options).
@@ -488,6 +488,7 @@ Aardvark interface options:
488
488
 
489
489
  Ipmitool interface options:
490
490
  interface_type Set the interface type to be used (lan, lanplus, serial, open)
491
+ cipher Set the cipher to be used (0-255)
491
492
 
492
493
  Ipmbdev interface options:
493
494
  port=<path> Specify path to Linux IPMB device (/dev/ipmb-0 by default)
@@ -533,6 +534,8 @@ def parse_interface_options(interface_name, options):
533
534
  elif interface_name == 'ipmitool':
534
535
  if name == 'interface_type':
535
536
  interface_options['interface_type'] = value
537
+ elif name == 'cipher':
538
+ interface_options['cipher'] = value
536
539
  else:
537
540
  print('Warning: unknown option %s' % name)
538
541
  elif interface_name == 'ipmbdev':
@@ -641,9 +644,8 @@ def main():
641
644
  if rmcp_priv_level is not None:
642
645
  ipmi.session.set_priv_level(rmcp_priv_level)
643
646
 
644
- ipmi.session.establish()
645
-
646
647
  try:
648
+ ipmi.open() # this will open interface and session
647
649
  cmd(ipmi, args)
648
650
  except pyipmi.errors.CompletionCodeError as e:
649
651
  print('Command returned with completion code 0x%02x' % e.cc)
@@ -661,8 +663,7 @@ def main():
661
663
  sys.exit(1)
662
664
 
663
665
  finally:
664
- if rmcp_host is not None:
665
- ipmi.session.close()
666
+ ipmi.close() # this will close interface and session
666
667
 
667
668
 
668
669
  COMMANDS = (
pyipmi/messaging.py CHANGED
@@ -196,3 +196,4 @@ class UserAccess(State):
196
196
  s += ' IPMI messaging: %s\n' % self.ipmi_messaging
197
197
  s += ' Link Auth.: %s\n' % self.link_auth
198
198
  s += ' Callback only: %s' % self.callback_only
199
+ return s
pyipmi/msgs/bmc.py CHANGED
@@ -14,9 +14,6 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- from __future__ import absolute_import
18
-
19
-
20
17
  from . import constants
21
18
  from . import register_message_class
22
19
  from . import Message
@@ -174,17 +171,19 @@ class GetAcpiPowerStateRsp(Message):
174
171
 
175
172
 
176
173
  @register_message_class
177
- class GetDeviceGuideReq(Message):
174
+ class GetDeviceGuidReq(Message):
178
175
  __cmdid__ = constants.CMDID_GET_DEVICE_GUID
179
176
  __netfn__ = constants.NETFN_APP
180
- __not_implemented__ = True
181
177
 
182
178
 
183
179
  @register_message_class
184
- class GetDeviceGuideRsp(Message):
180
+ class GetDeviceGuidRsp(Message):
185
181
  __cmdid__ = constants.CMDID_GET_DEVICE_GUID
186
182
  __netfn__ = constants.NETFN_APP | 1
187
- __not_implemented__ = True
183
+ __fields__ = (
184
+ CompletionCode(),
185
+ ByteArray('device_guid', 16),
186
+ )
188
187
 
189
188
 
190
189
  @register_message_class
pyipmi/msgs/chassis.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/dcmi.py CHANGED
@@ -14,8 +14,6 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- from __future__ import absolute_import
18
-
19
17
 
20
18
  from . import constants
21
19
  from . import register_message_class
pyipmi/msgs/event.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/fru.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/hpm.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/lan.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/message.py CHANGED
@@ -14,9 +14,6 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
-
18
- from __future__ import absolute_import
19
-
20
17
  from array import array
21
18
 
22
19
  from . import constants
@@ -57,7 +54,7 @@ class ByteArray(BaseField):
57
54
  def encode(self, obj, data):
58
55
  a = getattr(obj, self.name)
59
56
  if len(a) != self._length(obj):
60
- raise EncodingError('Array must be exaclty %d bytes long '
57
+ raise EncodingError('Array must be exactly %d bytes long '
61
58
  '(but is %d long)' %
62
59
  (self._length(obj), len(a)))
63
60
  for i in range(self._length(obj)):
@@ -73,7 +70,7 @@ class ByteArray(BaseField):
73
70
  if self.default is not None:
74
71
  return array('B', self.default)
75
72
  else:
76
- return array('B', self.length * '\x00')
73
+ return array('B', self.length * b'\x00')
77
74
 
78
75
 
79
76
  class VariableByteArray(ByteArray):
@@ -323,7 +320,7 @@ class Message(object):
323
320
 
324
321
  buf -- option message buffer to decode
325
322
 
326
- Optional keyword arguments corresponts to members to set (matching
323
+ Optional keyword arguments corresponds to members to set (matching
327
324
  fields in self.__fields__, or 'data').
328
325
  """
329
326
  # create message fields
pyipmi/msgs/picmg.py CHANGED
@@ -14,8 +14,6 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- from __future__ import absolute_import
18
-
19
17
  from . import constants
20
18
  from . import register_message_class
21
19
  from . import Message
pyipmi/msgs/registry.py CHANGED
@@ -14,7 +14,6 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
-
18
17
  from functools import partial
19
18
  from ..errors import DescriptionError
20
19
 
pyipmi/msgs/sdr.py CHANGED
@@ -13,7 +13,6 @@
13
13
  # You should have received a copy of the GNU Lesser General Public
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
- from __future__ import absolute_import
17
16
 
18
17
  from . import constants
19
18
  from . import register_message_class
pyipmi/msgs/sel.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/sensor.py CHANGED
@@ -1,4 +1,3 @@
1
- from __future__ import absolute_import
2
1
  # Copyright (c) 2014 Kontron Europe GmbH
3
2
  #
4
3
  # This library is free software; you can redistribute it and/or
pyipmi/msgs/vita.py CHANGED
@@ -14,8 +14,6 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- from __future__ import absolute_import
18
-
19
17
  from . import constants
20
18
  from . import register_message_class
21
19
  from . import Message
pyipmi/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # This file was autogenerated by setup.py
2
- __version__ = '0.5.5'
2
+ __version__ = '0.5.8'
@@ -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:
@@ -0,0 +1,56 @@
1
+ pyipmi/__init__.py,sha256=3Pi4ZuxaLCa6eB0nFAMNtUjbadXw-z1OkBO2bCiK8fw,8456
2
+ pyipmi/bmc.py,sha256=k5ctloS-EMFybiLJIXNz0u_PpmDJwPRZnroI-1lv6LM,6715
3
+ pyipmi/chassis.py,sha256=pWxPm5Vtc6NlTNWyV2lqOR-73UUOf3hJ4pXypC_uV3k,9977
4
+ pyipmi/constants.py,sha256=3Opcz-XtjcxvYRCV5JCPkIYcNLkEutYwdk8XE2bHm9U,1421
5
+ pyipmi/dcmi.py,sha256=9hPYe7gfFqtX-VOkZ0cKG-LLVkwqOlYXS4UQLcny8zE,2359
6
+ pyipmi/emulation.py,sha256=bc4Pk1uOkqJjFdd-GrwJDCAT_u8jmezilJUbl_ibPWw,11363
7
+ pyipmi/errors.py,sha256=GUSGSSeFZyGomErAme3EiomBUuVQdTiYPZLLvZZtzvk,3046
8
+ pyipmi/event.py,sha256=BAgUSxcUwChAimHWFO3D4JAHOdEy_ZrNehl-Uq0RRvM,1537
9
+ pyipmi/fields.py,sha256=AVgX0TB5R0_v9ZJDffKjfgtraxAGQqHJSw8LtqHOFxo,3571
10
+ pyipmi/fru.py,sha256=xGbWCfYeYeL3zzeblszOl2TrEtw1w1g84QR3W5MP8Vw,18347
11
+ pyipmi/helper.py,sha256=n0B3jeYrrz_YB6w3-0yt-ffnqQIlY3TDE82p3nftLmM,4673
12
+ pyipmi/hpm.py,sha256=Wp-JBsiMxPlXQST2wVgGCBs8DsKiDry5Mr4UvsmW2hw,26070
13
+ pyipmi/ipmitool.py,sha256=3DCOFNe49dfl60HCRKtzXrMS656Cu9MX1bHkPD2IF0I,24491
14
+ pyipmi/lan.py,sha256=sC-hsKohIJ-i84Tm-VKwiElalmJSr77b8ckmNgAznpo,9592
15
+ pyipmi/logger.py,sha256=AKzJVgn9MWUE54jQjfDNWmUccYy7r-YsGKSU_-lr2QE,1067
16
+ pyipmi/messaging.py,sha256=NnIBb0hBRLqeI4oYvkNX4w18nfoQWxwXy8hzndKrF7s,7421
17
+ pyipmi/picmg.py,sha256=YQI4hndGW0TalBjngOvbLLwkgadEvhPm-mtwGDstuJQ,19352
18
+ pyipmi/sdr.py,sha256=YAA1V5Had6Scvp47ZZRa_DEQzDI6_9I7kYWepsx8n-c,24121
19
+ pyipmi/sel.py,sha256=CVtZIBIkHKb3LaQtkVc5wakVrKQXxzxdQz3mOJ4fjos,8154
20
+ pyipmi/sensor.py,sha256=J8uULOg_JUhRlRQymKQxeSAnEwI92i8qPtlCMEXft8k,8528
21
+ pyipmi/session.py,sha256=RGVl4BtN1QXR_Rs1RUGPzN8NZPEsm2qcm-aZSSFg2_M,4175
22
+ pyipmi/state.py,sha256=_gKAN1P-8wjDyn7cbn5ibKdusHNBlQqushOrAb5PCBo,615
23
+ pyipmi/utils.py,sha256=-CVekdRcG70Wrosx4InplKGd18U6acaLbVdInw2JE1c,4862
24
+ pyipmi/version.py,sha256=IJKpcQb6bs8LmpRUR1RL6EeKjO3qQEgZKlf_CM2LEGQ,64
25
+ pyipmi/interfaces/__init__.py,sha256=T8xUc-ymnmgkdZZ-yNIJBPSf2aEme5dhbx-jFMyXaC8,1238
26
+ pyipmi/interfaces/aardvark.py,sha256=BwwX8BVhmCgSakeSHtSqphC3tynlU3xtP_3Ou_mYaEU,7454
27
+ pyipmi/interfaces/ipmb.py,sha256=RLJQtZzKJB2RQsjvWeYcVh1fhVYszGpbu_edwitOevg,8340
28
+ pyipmi/interfaces/ipmbdev.py,sha256=12TJfl0GesSGpH6OxuhpqGY6cEN5jl3bHtDuYkRVV3g,5364
29
+ pyipmi/interfaces/ipmitool.py,sha256=krqZwurwl5sRiEof5CSro_caB4U5wFchDoiCowe-_-E,11663
30
+ pyipmi/interfaces/mock.py,sha256=omuyNTcg7nGdgJDZvKwhE6I96G5yWw2Qgb9o_OZ3CqE,432
31
+ pyipmi/interfaces/rmcp.py,sha256=7yTnHypHPNDf0tWzClBhYUPwwpmSqPMtrjItqBgx6SQ,23066
32
+ pyipmi/msgs/__init__.py,sha256=wGyXNh3MmElwTjgi2Mi1rhFaORz1UcSoD82BJD5-U7Q,2334
33
+ pyipmi/msgs/bmc.py,sha256=pVpgSpX-GrKxkXQQlLAde_avuvN1O-VD7kjRAqk3PQI,8089
34
+ pyipmi/msgs/chassis.py,sha256=OVZSnN3_EOmChSpTzewKj6qAkUgW70GK9d-w7RPZm-A,6299
35
+ pyipmi/msgs/constants.py,sha256=spdEf-tXN8E8zwrgfKzwBX_blhJmynPCqFb3FnuDi10,16342
36
+ pyipmi/msgs/dcmi.py,sha256=avf3JC4oD_iFm3AcBX2xIvY_q2SoVeilPI0MxAGgFzE,8245
37
+ pyipmi/msgs/device_messaging.py,sha256=sPzEsh6zDck_leqI-4o0-V7_jQnr62wMOVGenvgnpMM,16413
38
+ pyipmi/msgs/event.py,sha256=Ljo7I4UZDSGwzFQYkZZ35ER9kH0Guct1zX15NRc6xxo,2148
39
+ pyipmi/msgs/fru.py,sha256=88FsQ6f-mNM-abtnj0rEJbLRHTxwNC5gCKdSTDkK7J0,2725
40
+ pyipmi/msgs/hpm.py,sha256=fUIgu9Sr6Lu_vwkKUOepUdLp18vTqo3VSn0G9I_6IkA,10432
41
+ pyipmi/msgs/lan.py,sha256=uUTkDTh9zkxy4GjmmRufQrJOYrGAk5bJtn0124nE0FU,2568
42
+ pyipmi/msgs/message.py,sha256=rzgBy-A4sFqc4lzrKeih2HmP-yAg1RrFmO3Y4HENTA4,12212
43
+ pyipmi/msgs/picmg.py,sha256=_t0qye3mNUlZ-0v5hCOBW0xWOAQUnmij4S-Nq1WFL2U,25955
44
+ pyipmi/msgs/registry.py,sha256=oAfyJzev7nMFWELPq6kwc7kScYweh86keVjhD0O4Vsg,3639
45
+ pyipmi/msgs/sdr.py,sha256=NJcGN5QvieDSQ5KbOFvp_ZfsonQhrM5lwEoXzf89Qnw,6623
46
+ pyipmi/msgs/sel.py,sha256=1KgWUgc7W46sZJbLToxdi9mFYwDESfXoEUPJbcWg_oo,5949
47
+ pyipmi/msgs/sensor.py,sha256=mEa9nYkqC2Zh7t7uCGmjKHDx1hMQ9nwQ9Rq1yl25U-A,10624
48
+ pyipmi/msgs/session.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ pyipmi/msgs/vita.py,sha256=qcLdPZoERdYKxAkiWprRS-MWiINFovcTUKaJNG0L62A,19870
50
+ python_ipmi-0.5.8.dist-info/licenses/AUTHORS,sha256=VHH-OfOeVpe3OMDYh_z0IvLpVeVw6gqyswTIQIFFmfE,82
51
+ python_ipmi-0.5.8.dist-info/licenses/COPYING,sha256=AKibDRiqzUEU3s95Ei24e_Nb3a8rxQ44PJyfTCYzkLI,24486
52
+ python_ipmi-0.5.8.dist-info/METADATA,sha256=HNScvJdNELL0BZOe8-fk_AK0GUgJWoiGA8to7qA0Wog,7120
53
+ python_ipmi-0.5.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
+ python_ipmi-0.5.8.dist-info/entry_points.txt,sha256=2FOtnrLsQRRQDmQbVn_jInKHMch43rHzGZpyQ-TU3PM,53
55
+ python_ipmi-0.5.8.dist-info/top_level.txt,sha256=ssvC5TF8PN_MCctWAT9Z8jKsKsP2ulOTm6JN_I3EoDM,7
56
+ python_ipmi-0.5.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,56 +0,0 @@
1
- pyipmi/__init__.py,sha256=fKok5-j0Yc57qmnOioSB703BhoG7qpT_9ye9uDQNgKc,7779
2
- pyipmi/bmc.py,sha256=or2Dh0gDquDHYPMICWmxhgpuvz54JIGLbwyut4v-3Ds,6178
3
- pyipmi/chassis.py,sha256=pWxPm5Vtc6NlTNWyV2lqOR-73UUOf3hJ4pXypC_uV3k,9977
4
- pyipmi/constants.py,sha256=3Opcz-XtjcxvYRCV5JCPkIYcNLkEutYwdk8XE2bHm9U,1421
5
- pyipmi/dcmi.py,sha256=9hPYe7gfFqtX-VOkZ0cKG-LLVkwqOlYXS4UQLcny8zE,2359
6
- pyipmi/emulation.py,sha256=bc4Pk1uOkqJjFdd-GrwJDCAT_u8jmezilJUbl_ibPWw,11363
7
- pyipmi/errors.py,sha256=kQtsjnmpEnA5TkHCNwUXfl_zFr-47eXtgQ-QUq4_iYk,2654
8
- pyipmi/event.py,sha256=BAgUSxcUwChAimHWFO3D4JAHOdEy_ZrNehl-Uq0RRvM,1537
9
- pyipmi/fields.py,sha256=CmbJ6OCSLgFkwVLCBr4wYXNzUzApHhfeFqAe7vGJuZ4,3570
10
- pyipmi/fru.py,sha256=6FzX8UNZgptpHnO-c14v4AZcU-ToPC1C5mWWeX_xgxo,16518
11
- pyipmi/helper.py,sha256=UcmwJ4ATMzxvkz7u3xXjSqkYgTi0K-vSzTAyb0JuslM,4673
12
- pyipmi/hpm.py,sha256=W5tlU-zlEkIuz3-UYfTWnHApOV4HHdJ0jDaDKLCkYsc,26069
13
- pyipmi/ipmitool.py,sha256=S0irUDzOUUBUol0N8AAAJboFwzL_YW4bzP1QMNlvcBM,24330
14
- pyipmi/lan.py,sha256=sC-hsKohIJ-i84Tm-VKwiElalmJSr77b8ckmNgAznpo,9592
15
- pyipmi/logger.py,sha256=AKzJVgn9MWUE54jQjfDNWmUccYy7r-YsGKSU_-lr2QE,1067
16
- pyipmi/messaging.py,sha256=t2pcH0HDPaMu3lMgthKNrRdXMS52q0P_B2grPziyNhM,7404
17
- pyipmi/picmg.py,sha256=YQI4hndGW0TalBjngOvbLLwkgadEvhPm-mtwGDstuJQ,19352
18
- pyipmi/sdr.py,sha256=YAA1V5Had6Scvp47ZZRa_DEQzDI6_9I7kYWepsx8n-c,24121
19
- pyipmi/sel.py,sha256=CVtZIBIkHKb3LaQtkVc5wakVrKQXxzxdQz3mOJ4fjos,8154
20
- pyipmi/sensor.py,sha256=J8uULOg_JUhRlRQymKQxeSAnEwI92i8qPtlCMEXft8k,8528
21
- pyipmi/session.py,sha256=RGVl4BtN1QXR_Rs1RUGPzN8NZPEsm2qcm-aZSSFg2_M,4175
22
- pyipmi/state.py,sha256=_gKAN1P-8wjDyn7cbn5ibKdusHNBlQqushOrAb5PCBo,615
23
- pyipmi/utils.py,sha256=-CVekdRcG70Wrosx4InplKGd18U6acaLbVdInw2JE1c,4862
24
- pyipmi/version.py,sha256=YmCwXMhmfj68EZx9jcxGphvl079mMItVt-sflF5hjTY,64
25
- pyipmi/interfaces/__init__.py,sha256=T8xUc-ymnmgkdZZ-yNIJBPSf2aEme5dhbx-jFMyXaC8,1238
26
- pyipmi/interfaces/aardvark.py,sha256=gReGcWjhgtEhpYw61UExtNZ52b-uI2ONkT_TeGLspMI,7266
27
- pyipmi/interfaces/ipmb.py,sha256=kKFbaAIy8MoSiKaIUOCwhXPD1QRfkwIpnEL8sXDHSyg,7800
28
- pyipmi/interfaces/ipmbdev.py,sha256=uBVKGloOUDig6nK2V8Gi6tJJimzGFo30CtP2RLV7gQU,5346
29
- pyipmi/interfaces/ipmitool.py,sha256=oN9_N1jh7ts77Kc2AqTEYmmmLSBS5h97ZaSQPmPpC8g,10539
30
- pyipmi/interfaces/mock.py,sha256=5IPQd7VlWVTFvvhppCs7SPiDkJAmAjG6v0RXeXjTEFs,363
31
- pyipmi/interfaces/rmcp.py,sha256=fxYeR4U03uz5Df98kzyPRmLIRp0c8CAWnpEFbwdmIHA,22587
32
- pyipmi/msgs/__init__.py,sha256=wGyXNh3MmElwTjgi2Mi1rhFaORz1UcSoD82BJD5-U7Q,2334
33
- pyipmi/msgs/bmc.py,sha256=6uBIScBm7gMKHHsq5qNcgf_ZkTaVlCG8dTf1sSdyyE0,8105
34
- pyipmi/msgs/chassis.py,sha256=UcxGNkfiwbe_2JVNpi3pHwHcP4uev9X6vuHzvDhsDTY,6338
35
- pyipmi/msgs/constants.py,sha256=spdEf-tXN8E8zwrgfKzwBX_blhJmynPCqFb3FnuDi10,16342
36
- pyipmi/msgs/dcmi.py,sha256=M6OWg0NFibToibn4j4Gv08Dvuc7lwMQZ7LoxpJgNr7g,8285
37
- pyipmi/msgs/device_messaging.py,sha256=sPzEsh6zDck_leqI-4o0-V7_jQnr62wMOVGenvgnpMM,16413
38
- pyipmi/msgs/event.py,sha256=tGja_XhFeXhefQ5QTWFxj8VeSbMly6y_rICf7eVdpIo,2187
39
- pyipmi/msgs/fru.py,sha256=0H-EztVb-tJwdWoxCTOpqlyIeAWQvdf_vYc5UGwNSpI,2764
40
- pyipmi/msgs/hpm.py,sha256=BiO2LwkuWflhEuI2na6ncgxBaKXZ8PpTArLEaA5BWWc,10471
41
- pyipmi/msgs/lan.py,sha256=hC-uX5h9yD2qI_Nk76NRkldK4X9nYM-TRiLOrU4ndq4,2607
42
- pyipmi/msgs/message.py,sha256=xWk7073-kgwDl0n9JgFsKuJ3zE3REsvCkEkHOUcbhNk,12252
43
- pyipmi/msgs/picmg.py,sha256=oZIlKDdq1r0qBl-dliAsRTiLRJOwZXNQVpsW3aWnjaE,25995
44
- pyipmi/msgs/registry.py,sha256=oifolLJgg0DQwpCte2CbNM7Ua4XGABzGiWYJIFfgijQ,3640
45
- pyipmi/msgs/sdr.py,sha256=JZ-p5-BbjDg4R2YpwdTz11arQcRMyAvOGg0VuSq6jn8,6662
46
- pyipmi/msgs/sel.py,sha256=ON5YRoI9-WVMT09IqduK0AR28-rPcXOSzSWS3rcYBzw,5988
47
- pyipmi/msgs/sensor.py,sha256=nP1JohRg5jSz23SFoOMQONojROodOSRCuaDR8tpCxjI,10663
48
- pyipmi/msgs/session.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- pyipmi/msgs/vita.py,sha256=7NgFaB1Gy2vlerzM4pzZtpEs5Tc4T0_1EZqu2_K2fMw,19910
50
- python_ipmi-0.5.5.dist-info/AUTHORS,sha256=VHH-OfOeVpe3OMDYh_z0IvLpVeVw6gqyswTIQIFFmfE,82
51
- python_ipmi-0.5.5.dist-info/COPYING,sha256=AKibDRiqzUEU3s95Ei24e_Nb3a8rxQ44PJyfTCYzkLI,24486
52
- python_ipmi-0.5.5.dist-info/METADATA,sha256=MrYP4DtPchuUNo-dA9R3DNMf2r2Pg9MyvcbGNdOAeW8,6801
53
- python_ipmi-0.5.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
54
- python_ipmi-0.5.5.dist-info/entry_points.txt,sha256=2FOtnrLsQRRQDmQbVn_jInKHMch43rHzGZpyQ-TU3PM,53
55
- python_ipmi-0.5.5.dist-info/top_level.txt,sha256=ssvC5TF8PN_MCctWAT9Z8jKsKsP2ulOTm6JN_I3EoDM,7
56
- python_ipmi-0.5.5.dist-info/RECORD,,