pyghmi 1.5.70__py3-none-any.whl → 1.5.72__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
pyghmi/ipmi/command.py CHANGED
@@ -849,9 +849,9 @@ class Command(object):
849
849
  else:
850
850
  raise Exception("Unrecognized data format " + repr(fetchdata))
851
851
 
852
- def get_extended_bmc_configuration(self):
852
+ def get_extended_bmc_configuration(self, hideadvanced=True):
853
853
  self.oem_init()
854
- return self._oem.get_extended_bmc_configuration()
854
+ return self._oem.get_extended_bmc_configuration(hideadvanced=hideadvanced)
855
855
 
856
856
  def get_bmc_configuration(self):
857
857
  self.oem_init()
@@ -272,7 +272,9 @@ class LenovoFirmwareConfig(object):
272
272
  cfgfilename = "config"
273
273
  options = {}
274
274
  data = None
275
- if self.connection:
275
+ if not hasattr(self.xc, 'grab_redfish_response_with_status'):
276
+ rsp = ({}, 500)
277
+ elif self.connection:
276
278
  rsp = ({}, 200)
277
279
  else:
278
280
  rsp = self.xc.grab_redfish_response_with_status(
@@ -1194,9 +1194,9 @@ class OEMHandler(generic.OEMHandler):
1194
1194
  return {'height': self._fpc_variant & 0xf, 'slot': 0}
1195
1195
  return super(OEMHandler, self).get_description()
1196
1196
 
1197
- def get_extended_bmc_configuration(self):
1197
+ def get_extended_bmc_configuration(self, hideadvanced=True):
1198
1198
  if self.has_xcc:
1199
- return self.immhandler.get_extended_bmc_configuration()
1199
+ return self.immhandler.get_extended_bmc_configuration(hideadvanced=hideadvanced)
1200
1200
  return super(OEMHandler, self).get_extended_bmc_configuration()
1201
1201
 
1202
1202
  def get_bmc_configuration(self):
@@ -978,8 +978,8 @@ class XCCClient(IMMClient):
978
978
  return {}
979
979
  return {'height': int(dsc['u-height']), 'slot': int(dsc['slot'])}
980
980
 
981
- def get_extended_bmc_configuration(self):
982
- immsettings = self.get_system_configuration(fetchimm=True)
981
+ def get_extended_bmc_configuration(self, hideadvanced=True):
982
+ immsettings = self.get_system_configuration(fetchimm=True, hideadvanced=hideadvanced)
983
983
  for setting in list(immsettings):
984
984
  if not setting.startswith('IMM.'):
985
985
  del immsettings[setting]
pyghmi/redfish/command.py CHANGED
@@ -81,20 +81,6 @@ def _mask_to_cidr(mask):
81
81
  return cidr
82
82
 
83
83
 
84
- def _to_boolean(attrval):
85
- attrval = attrval.lower()
86
- if not attrval:
87
- return False
88
- if ('true'.startswith(attrval) or 'yes'.startswith(attrval)
89
- or 'enabled'.startswith(attrval) or attrval == '1'):
90
- return True
91
- if ('false'.startswith(attrval) or 'no'.startswith(attrval)
92
- or 'disabled'.startswith(attrval) or attrval == '0'):
93
- return False
94
- raise Exception(
95
- 'Unrecognized candidate for boolean: {0}'.format(attrval))
96
-
97
-
98
84
  def _cidr_to_mask(cidr):
99
85
  return socket.inet_ntop(
100
86
  socket.AF_INET, struct.pack(
@@ -547,7 +533,7 @@ class Command(object):
547
533
  msgid = ','.join(msgid)
548
534
  raise exc.RedfishError(errmsg, msgid=msgid)
549
535
  except (ValueError, KeyError):
550
- raise exc.PyghmiException(str(url) + ":" + res[0])
536
+ raise exc.PyghmiException(str(url) + ":" + str(res[0]))
551
537
  if payload is None and method is None:
552
538
  self._urlcache[url] = {'contents': res[0],
553
539
  'vintage': os.times()[4]}
@@ -789,6 +775,9 @@ class Command(object):
789
775
  def get_health(self, verbose=True):
790
776
  return self.oem.get_health(self, verbose)
791
777
 
778
+ def get_extended_bmc_configuration(self, hideadvanced=True):
779
+ return self.oem.get_extended_bmc_configuration(self, hideadvanced=hideadvanced)
780
+
792
781
  def get_bmc_configuration(self):
793
782
  """Get miscellaneous BMC configuration
794
783
 
@@ -823,8 +812,16 @@ class Command(object):
823
812
  In many cases, this may render remote network access impracticle or
824
813
  impossible."
825
814
  """
815
+ bmcinfo = self._do_web_request(self._bmcurl)
816
+ rc = bmcinfo.get('Actions', {}).get('#Manager.ResetToDefaults', {})
817
+ actinf = rc.get('ResetType@Redfish.AllowableValues', [])
818
+ if 'ResetAll' in actinf:
819
+ acturl = actinf.get('target', None)
820
+ if acturl:
821
+ self._do_web_request(acturl, {'ResetType': 'ResetAll'})
822
+ return
826
823
  raise exc.UnsupportedFunctionality(
827
- 'Clear BMC configuration not supported in redfish yet')
824
+ 'Clear BMC configuration not supported on this platform')
828
825
 
829
826
  def get_system_configuration(self, hideadvanced=True):
830
827
  return self.oem.get_system_configuration(hideadvanced, self)
@@ -966,7 +963,7 @@ class Command(object):
966
963
 
967
964
  def get_firmware(self, components=()):
968
965
  try:
969
- for firminfo in self.oem.get_firmware_inventory(components):
966
+ for firminfo in self.oem.get_firmware_inventory(components, self):
970
967
  yield firminfo
971
968
  except exc.BypassGenericBehavior:
972
969
  return
@@ -1081,7 +1078,7 @@ class Command(object):
1081
1078
  return self._oem
1082
1079
 
1083
1080
  def get_description(self):
1084
- return self.oem.get_description()
1081
+ return self.oem.get_description(self)
1085
1082
 
1086
1083
  def get_event_log(self, clear=False):
1087
1084
  bmcinfo = self._do_web_request(self._bmcurl)
@@ -1413,20 +1410,20 @@ class Command(object):
1413
1410
  return self.oem.get_diagnostic_data(savefile, progress, autosuffix)
1414
1411
 
1415
1412
  def get_licenses(self):
1416
- return self.oem.get_licenses()
1413
+ return self.oem.get_licenses(self)
1417
1414
 
1418
1415
  def delete_license(self, name):
1419
- return self.oem.delete_license(name)
1416
+ return self.oem.delete_license(name, self)
1420
1417
 
1421
1418
  def save_licenses(self, directory):
1422
1419
  if os.path.exists(directory) and not os.path.isdir(directory):
1423
1420
  raise exc.InvalidParameterValue(
1424
1421
  'Not allowed to overwrite existing file: {0}'.format(
1425
1422
  directory))
1426
- return self.oem.save_licenses(directory)
1423
+ return self.oem.save_licenses(directory, self)
1427
1424
 
1428
1425
  def apply_license(self, filename, progress=None, data=None):
1429
- return self.oem.apply_license(filename, progress, data)
1426
+ return self.oem.apply_license(filename, self, progress, data)
1430
1427
 
1431
1428
 
1432
1429
  if __name__ == '__main__':
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import base64
15
16
  from fnmatch import fnmatch
16
17
  import json
17
18
  import os
@@ -43,6 +44,29 @@ class SensorReading(object):
43
44
  self.units = units
44
45
  self.unavailable = unavailable
45
46
 
47
+
48
+ def _to_boolean(attrval):
49
+ attrval = attrval.lower()
50
+ if not attrval:
51
+ return False
52
+ if ('true'.startswith(attrval) or 'yes'.startswith(attrval)
53
+ or 'enabled'.startswith(attrval) or attrval == '1'):
54
+ return True
55
+ if ('false'.startswith(attrval) or 'no'.startswith(attrval)
56
+ or 'disabled'.startswith(attrval) or attrval == '0'):
57
+ return False
58
+ raise Exception(
59
+ 'Unrecognized candidate for boolean: {0}'.format(attrval))
60
+
61
+
62
+ def _normalize_mac(mac):
63
+ if ':' not in mac:
64
+ mac = ':'.join((
65
+ mac[:2], mac[2:4], mac[4:6],
66
+ mac[6:8], mac[8:10], mac[10:12]))
67
+ return mac.lower()
68
+
69
+
46
70
  _healthmap = {
47
71
  'Critical': const.Health.Critical,
48
72
  'Unknown': const.Health.Warning,
@@ -339,6 +363,38 @@ class OEMHandler(object):
339
363
  def get_system_configuration(self, hideadvanced=True, fishclient=None):
340
364
  return self._getsyscfg(fishclient)[0]
341
365
 
366
+ def _get_attrib_registry(self, fishclient, attribreg):
367
+ overview = fishclient._do_web_request('/redfish/v1/')
368
+ reglist = overview['Registries']['@odata.id']
369
+ reglist = fishclient._do_web_request(reglist)
370
+ regurl = None
371
+ for cand in reglist.get('Members', []):
372
+ cand = cand.get('@odata.id', '')
373
+ candname = cand.split('/')[-1]
374
+ if candname == '': # implementation uses trailing slash
375
+ candname = cand.split('/')[-2]
376
+ if candname == attribreg:
377
+ regurl = cand
378
+ break
379
+ if not regurl:
380
+ # Workaround a vendor bug where they link to a
381
+ # non-existant name
382
+ for cand in reglist.get('Members', []):
383
+ cand = cand.get('@odata.id', '')
384
+ candname = cand.split('/')[-1]
385
+ candname = candname.split('.')[0]
386
+ if candname == attribreg.split('.')[0]:
387
+ regurl = cand
388
+ break
389
+ if regurl:
390
+ reginfo = fishclient._do_web_request(regurl)
391
+ for reg in reginfo.get('Location', []):
392
+ if reg.get('Language', 'en').startswith('en'):
393
+ reguri = reg['Uri']
394
+ reginfo = self._get_biosreg(reguri, fishclient)
395
+ return reginfo
396
+ extrainfo, valtodisplay, _, self.attrdeps = reginfo
397
+
342
398
  def _getsyscfg(self, fishclient):
343
399
  biosinfo = self._do_web_request(fishclient._biosurl, cache=False)
344
400
  reginfo = ({}, {}, {}, {})
@@ -346,36 +402,9 @@ class OEMHandler(object):
346
402
  valtodisplay = {}
347
403
  self.attrdeps = {'Dependencies': [], 'Attributes': []}
348
404
  if 'AttributeRegistry' in biosinfo:
349
- overview = fishclient._do_web_request('/redfish/v1/')
350
- reglist = overview['Registries']['@odata.id']
351
- reglist = fishclient._do_web_request(reglist)
352
- regurl = None
353
- for cand in reglist.get('Members', []):
354
- cand = cand.get('@odata.id', '')
355
- candname = cand.split('/')[-1]
356
- if candname == '': # implementation uses trailing slash
357
- candname = cand.split('/')[-2]
358
- if candname == biosinfo['AttributeRegistry']:
359
- regurl = cand
360
- break
361
- if not regurl:
362
- # Workaround a vendor bug where they link to a
363
- # non-existant name
364
- for cand in reglist.get('Members', []):
365
- cand = cand.get('@odata.id', '')
366
- candname = cand.split('/')[-1]
367
- candname = candname.split('.')[0]
368
- if candname == biosinfo[
369
- 'AttributeRegistry'].split('.')[0]:
370
- regurl = cand
371
- break
372
- if regurl:
373
- reginfo = fishclient._do_web_request(regurl)
374
- for reg in reginfo.get('Location', []):
375
- if reg.get('Language', 'en').startswith('en'):
376
- reguri = reg['Uri']
377
- reginfo = self._get_biosreg(reguri, fishclient)
378
- extrainfo, valtodisplay, _, self.attrdeps = reginfo
405
+ reginfo = self._get_attrib_registry(fishclient, biosinfo['AttributeRegistry'])
406
+ if reginfo:
407
+ extrainfo, valtodisplay, _, self.attrdeps = reginfo
379
408
  currsettings = {}
380
409
  try:
381
410
  pendingsettings = fishclient._do_web_request(
@@ -412,10 +441,19 @@ class OEMHandler(object):
412
441
  rawsettings = fishclient._do_web_request(fishclient._biosurl,
413
442
  cache=False)
414
443
  rawsettings = rawsettings.get('Attributes', {})
415
- pendingsettings = fishclient._do_web_request(fishclient._setbiosurl)
444
+ pendingsettings = fishclient._do_web_request(
445
+ fishclient._setbiosurl)
446
+ return self._set_redfish_settings(
447
+ changeset, fishclient, currsettings, rawsettings,
448
+ pendingsettings, self.attrdeps, reginfo,
449
+ fishclient._setbiosurl)
450
+
451
+ def _set_redfish_settings(self, changeset, fishclient, currsettings,
452
+ rawsettings, pendingsettings, attrdeps, reginfo,
453
+ seturl):
416
454
  etag = pendingsettings.get('@odata.etag', None)
417
455
  pendingsettings = pendingsettings.get('Attributes', {})
418
- dephandler = AttrDependencyHandler(self.attrdeps, rawsettings,
456
+ dephandler = AttrDependencyHandler(attrdeps, rawsettings,
419
457
  pendingsettings)
420
458
  for change in list(changeset):
421
459
  if change not in currsettings:
@@ -434,7 +472,7 @@ class OEMHandler(object):
434
472
  changeval = changeset[change]
435
473
  overrides, blameattrs = dephandler.get_overrides(change)
436
474
  meta = {}
437
- for attr in self.attrdeps['Attributes']:
475
+ for attr in attrdeps['Attributes']:
438
476
  if attr['AttributeName'] == change:
439
477
  meta = dict(attr)
440
478
  break
@@ -473,7 +511,7 @@ class OEMHandler(object):
473
511
  changeset[change] = _to_boolean(changeset[change])
474
512
  redfishsettings = {'Attributes': changeset}
475
513
  fishclient._do_web_request(
476
- fishclient._setbiosurl, redfishsettings, 'PATCH', etag=etag)
514
+ seturl, redfishsettings, 'PATCH', etag=etag)
477
515
 
478
516
  def attach_remote_media(self, url, username, password, vmurls):
479
517
  return None
@@ -481,10 +519,10 @@ class OEMHandler(object):
481
519
  def detach_remote_media(self):
482
520
  return None
483
521
 
484
- def get_description(self):
522
+ def get_description(self, fishclient):
485
523
  return {}
486
524
 
487
- def get_firmware_inventory(self, components):
525
+ def get_firmware_inventory(self, components, fishclient):
488
526
  return []
489
527
 
490
528
  def set_credentials(self, username, password):
@@ -533,6 +571,12 @@ class OEMHandler(object):
533
571
  'Model': self._varsysinfo.get(
534
572
  'SKU', self._varsysinfo.get('PartNumber', '')),
535
573
  }
574
+ if sysinfo['UUID'] and '-' not in sysinfo['UUID']:
575
+ sysinfo['UUID'] = '-'.join((
576
+ sysinfo['UUID'][:8], sysinfo['UUID'][8:12],
577
+ sysinfo['UUID'][12:16], sysinfo['UUID'][16:20],
578
+ sysinfo['UUID'][20:]))
579
+ sysinfo['UUID'] = sysinfo['UUID'].lower()
536
580
  return sysinfo
537
581
  else:
538
582
  for invpair in self.get_inventory():
@@ -548,6 +592,12 @@ class OEMHandler(object):
548
592
  'Model': self._varsysinfo.get(
549
593
  'SKU', self._varsysinfo.get('PartNumber', '')),
550
594
  }
595
+ if sysinfo['UUID'] and '-' not in sysinfo['UUID']:
596
+ sysinfo['UUID'] = '-'.join((
597
+ sysinfo['UUID'][:8], sysinfo['UUID'][8:12],
598
+ sysinfo['UUID'][12:16], sysinfo['UUID'][16:20],
599
+ sysinfo['UUID'][20:]))
600
+ sysinfo['UUID'] = sysinfo['UUID'].lower()
551
601
  yield ('System', sysinfo)
552
602
  self._hwnamemap = {}
553
603
  cpumemurls = []
@@ -599,22 +649,39 @@ class OEMHandler(object):
599
649
  yield (dname, ddata)
600
650
 
601
651
  def _get_adp_inventory(self, onlyname=False, withids=False, urls=None):
652
+ foundmacs = False
653
+ macinfobyadpname = {}
654
+ if 'NetworkInterfaces' in self._varsysinfo:
655
+ nifurls = self._do_web_request(self._varsysinfo['NetworkInterfaces']['@odata.id'])
656
+ nifurls = nifurls.get('Members', [])
657
+ nifurls = [x['@odata.id'] for x in nifurls]
658
+ for nifurl in nifurls:
659
+ nifinfo = self._do_web_request(nifurl)
660
+
661
+ nadurl = nifinfo.get('Links', {}).get('NetworkAdapter', {}).get("@odata.id")
662
+ if nadurl:
663
+ nadinfo = self._do_web_request(nadurl)
664
+ if 'Name' not in nadinfo:
665
+ continue
666
+ nicname = nadinfo['Name']
667
+ yieldinf = {}
668
+ macidx = 1
669
+ for ctrlr in nadinfo.get('Controllers', []):
670
+ porturls = [x['@odata.id'] for x in ctrlr.get(
671
+ 'Links', {}).get('Ports', [])]
672
+ for porturl in porturls:
673
+ portinfo = self._do_web_request(porturl)
674
+ macs = [x for x in portinfo.get(
675
+ 'Ethernet', {}).get(
676
+ 'AssociatedMACAddresses', [])]
677
+ for mac in macs:
678
+ label = 'MAC Address {}'.format(macidx)
679
+ yieldinf[label] = _normalize_mac(mac)
680
+ macidx += 1
681
+ foundmacs = True
682
+ macinfobyadpname[nicname] = yieldinf
602
683
  if not urls:
603
684
  urls = self._get_adp_urls()
604
- if not urls:
605
- # No PCIe device inventory, but *maybe* ethernet inventory...
606
- aidx = 1
607
- for nicinfo in self._get_eth_urls():
608
- nicinfo = self._do_web_request(nicinfo)
609
- nicname = nicinfo.get('Name', None)
610
- nicinfo = nicinfo.get('MACAddress', None)
611
- if not nicname:
612
- nicname = 'NIC'
613
- if nicinfo:
614
- yield (nicname,
615
- {'MAC Address {0}'.format(aidx): nicinfo})
616
- aidx += 1
617
- return
618
685
  for inf in self._do_bulk_requests(urls):
619
686
  adpinfo, url = inf
620
687
  aname = adpinfo.get('Name', 'Unknown')
@@ -636,6 +703,8 @@ class OEMHandler(object):
636
703
  yieldinf = {'Id': adpinfo.get('Id', aname)}
637
704
  else:
638
705
  yieldinf = {}
706
+ if aname in macinfobyadpname:
707
+ yieldinf.update(macinfobyadpname[aname])
639
708
  funurls = [x['@odata.id'] for x in functions]
640
709
  for fun in self._do_bulk_requests(funurls):
641
710
  funinfo, url = fun
@@ -648,14 +717,42 @@ class OEMHandler(object):
648
717
  yieldinf['PCI Subsystem Vendor ID'] = funinfo[
649
718
  'SubsystemVendorId'].replace('0x', '')
650
719
  yieldinf['Type'] = funinfo['DeviceClass']
651
- for nicinfo in funinfo.get('Links', {}).get(
652
- 'EthernetInterfaces', []):
653
- nicinfo = self._do_web_request(nicinfo['@odata.id'])
654
- macaddr = nicinfo.get('MACAddress', None)
655
- if macaddr:
656
- yieldinf['MAC Address {0}'.format(nicidx)] = macaddr
657
- nicidx += 1
720
+ if aname not in macinfobyadpname:
721
+ for nicinfo in funinfo.get('Links', {}).get(
722
+ 'EthernetInterfaces', []):
723
+ nicinfo = self._do_web_request(nicinfo['@odata.id'])
724
+ macaddr = nicinfo.get('MACAddress', None)
725
+ if macaddr:
726
+ macaddr = _normalize_mac(macaddr)
727
+ foundmacs = True
728
+ yieldinf['MAC Address {0}'.format(nicidx)] = macaddr
729
+ nicidx += 1
730
+ if aname in macinfobyadpname:
731
+ del macinfobyadpname[aname]
658
732
  yield aname, yieldinf
733
+ if macinfobyadpname:
734
+ for adp in macinfobyadpname:
735
+ yield adp, macinfobyadpname[adp]
736
+ if not foundmacs:
737
+ # No PCIe device inventory, but *maybe* ethernet inventory...
738
+ idxsbyname = {}
739
+ for nicinfo in self._get_eth_urls():
740
+ nicinfo = self._do_web_request(nicinfo)
741
+ nicname = nicinfo.get('Name', None)
742
+ nicinfo = nicinfo.get('MACAddress', nicinfo.get('PermanentAddress', None))
743
+ if nicinfo and ':' not in nicinfo:
744
+ nicinfo = ':'.join((
745
+ nicinfo[:2], nicinfo[2:4], nicinfo[4:6], nicinfo[6:8],
746
+ nicinfo[8:10], nicinfo[10:12]))
747
+ if not nicname:
748
+ nicname = 'NIC'
749
+ if nicinfo:
750
+ if nicname not in idxsbyname:
751
+ idxsbyname[nicname] = 0
752
+ idxsbyname[nicname] += 1
753
+ nicinfo = nicinfo.lower()
754
+ yield (nicname,
755
+ {'MAC Address {}'.format(idxsbyname[nicname]): nicinfo})
659
756
 
660
757
  def _get_eth_urls(self):
661
758
  ethurls = self._varsysinfo.get('EthernetInterfaces', {})
@@ -780,20 +877,24 @@ class OEMHandler(object):
780
877
 
781
878
  def update_firmware(self, filename, data=None, progress=None, bank=None):
782
879
  usd = self._do_web_request('/redfish/v1/UpdateService')
783
- if usd.get('HttpPushUriTargetsBusy', False):
784
- raise exc.TemporaryError('Cannot run multtiple updates to '
785
- 'same target concurrently')
786
- try:
787
- upurl = usd['HttpPushUri']
788
- except KeyError:
789
- raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
790
- if 'HttpPushUriTargetsBusy' in usd:
791
- self._do_web_request(
792
- '/redfish/v1/UpdateService',
793
- {'HttpPushUriTargetsBusy': True}, method='PATCH')
880
+ upurl = usd.get('MultipartHttpPushUri', None)
881
+ ismultipart = True
882
+ if not upurl:
883
+ ismultipart = False
884
+ if usd.get('HttpPushUriTargetsBusy', False):
885
+ raise exc.TemporaryError('Cannot run multtiple updates to '
886
+ 'same target concurrently')
887
+ try:
888
+ upurl = usd['HttpPushUri']
889
+ except KeyError:
890
+ raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
891
+ if 'HttpPushUriTargetsBusy' in usd:
892
+ self._do_web_request(
893
+ '/redfish/v1/UpdateService',
894
+ {'HttpPushUriTargetsBusy': True}, method='PATCH')
794
895
  try:
795
896
  uploadthread = webclient.FileUploader(
796
- self.webclient, upurl, filename, data, formwrap=False,
897
+ self.webclient, upurl, filename, data, formwrap=ismultipart,
797
898
  excepterror=False)
798
899
  uploadthread.start()
799
900
  wc = self.webclient
@@ -823,6 +924,7 @@ class OEMHandler(object):
823
924
  # sometimes we get an empty pgress when transitioning from the apply phase to
824
925
  # the validating phase; add a retry here so we don't exit the loop in this case
825
926
  retry = 3
927
+ pct = 0.0
826
928
  while not complete and retry > 0:
827
929
  pgress = self._do_web_request(monitorurl, cache=False)
828
930
  if not pgress:
@@ -837,7 +939,10 @@ class OEMHandler(object):
837
939
  'Suspended'):
838
940
  raise Exception(
839
941
  json.dumps(json.dumps(pgress['Messages'])))
840
- pct = float(pgress['PercentComplete'])
942
+ if 'PercentComplete' in pgress:
943
+ pct = float(pgress['PercentComplete'])
944
+ else:
945
+ print(repr(pgress))
841
946
  complete = state == 'Completed'
842
947
  progress({'phase': phase, 'progress': pct})
843
948
  if complete:
@@ -910,17 +1015,62 @@ class OEMHandler(object):
910
1015
  raise exc.UnsupportedFunctionality(
911
1016
  'Retrieving diagnostic data is not implemented for this platform')
912
1017
 
913
- def get_licenses(self):
914
- raise exc.UnsupportedFunctionality()
1018
+ def _get_license_collection_url(self, fishclient):
1019
+ overview = fishclient._do_web_request('/redfish/v1/')
1020
+ licsrv = overview.get('LicenseService', {}).get('@odata.id', None)
1021
+ if not licsrv:
1022
+ raise exc.UnsupportedFunctionality()
1023
+ lcs = fishclient._do_web_request(licsrv)
1024
+ licenses = lcs.get('Licenses', {}).get('@odata.id',None)
1025
+ if not licenses:
1026
+ raise exc.UnsupportedFunctionality()
1027
+ return licenses
915
1028
 
916
- def delete_license(self, name):
1029
+ def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
917
1030
  raise exc.UnsupportedFunctionality()
918
1031
 
919
- def save_licenses(self, directory):
920
- raise exc.UnsupportedFunctionality()
1032
+ def _get_licenses(self, fishclient):
1033
+ licenses = self._get_license_collection_url(fishclient)
1034
+ collection = fishclient._do_web_request(licenses)
1035
+ alllic = [x['@odata.id'] for x in collection.get('Members', [])]
1036
+ for license in alllic:
1037
+ licdet = fishclient._do_web_request(license)
1038
+ state = licdet.get('Status', {}).get('State')
1039
+ if state != 'Enabled':
1040
+ continue
1041
+ yield licdet
921
1042
 
922
- def apply_license(self, filename, progress=None, data=None):
923
- raise exc.UnsupportedFunctionality()
1043
+ def get_licenses(self, fishclient):
1044
+ for licdet in self._get_licenses(fishclient):
1045
+ name = licdet['Name']
1046
+ yield {'name': name, 'state': 'Active'}
1047
+
1048
+ def delete_license(self, name, fishclient):
1049
+ for licdet in self._get_licenses(fishclient):
1050
+ lname = licdet['Name']
1051
+ if name == lname:
1052
+ fishclient._do_web_request(licdet['@odata.id'], method='DELETE')
1053
+
1054
+ def save_licenses(self, directory, fishclient):
1055
+ for licdet in self._get_licenses(fishclient):
1056
+ dload = licdet.get('DownloadURI', None)
1057
+ if dload:
1058
+ filename = os.path.basename(dload)
1059
+ savefile = os.path.join(directory, filename)
1060
+ fd = webclient.FileDownloader(fishclient.wc, dload, savefile)
1061
+ fd.start()
1062
+ while fd.isAlive():
1063
+ fd.join(1)
1064
+ yield savefile
1065
+
1066
+ def apply_license(self, filename, fishclient, progress=None, data=None):
1067
+ licenses = self._get_license_collection_url(fishclient)
1068
+ if data is None:
1069
+ data = open(filename, 'rb')
1070
+ licdata = data.read()
1071
+ lic64 = base64.b64encode(licdata).decode()
1072
+ licinfo = {"LicenseString": lic64}
1073
+ fishclient._do_web_request(licenses, licinfo)
924
1074
 
925
1075
  def get_user_expiration(self, uid):
926
1076
  return None
@@ -15,15 +15,28 @@
15
15
  import pyghmi.redfish.oem.generic as generic
16
16
  from pyghmi.redfish.oem.lenovo import tsma
17
17
  from pyghmi.redfish.oem.lenovo import xcc
18
+ from pyghmi.redfish.oem.lenovo import xcc3
18
19
 
19
20
 
20
21
  def get_handler(sysinfo, sysurl, webclient, cache, cmd):
21
22
  leninf = sysinfo.get('Oem', {}).get('Lenovo', {})
23
+ mgrinfo = {}
24
+ if leninf:
25
+ mgrinf, status = webclient.grab_json_response_with_status('/redfish/v1/Managers/1')
26
+ if status != 200:
27
+ mgrinfo = {}
22
28
  if not leninf:
23
29
  bmcinfo = cmd.bmcinfo
24
30
  if 'Ami' in bmcinfo.get('Oem', {}):
25
31
  return tsma.TsmHandler(sysinfo, sysurl, webclient, cache)
26
- if 'FrontPanelUSB' in leninf or 'USBManagementPortAssignment' in leninf or sysinfo.get('SKU', '').startswith('7X58'):
32
+ elif 'xclarity controller' in mgrinf.get('Model', '').lower():
33
+ if mgrinf['Model'].endswith('3'):
34
+ return xcc3.OEMHandler(sysinfo, sysurl, webclient, cache,
35
+ gpool=cmd._gpool)
36
+ else:
37
+ return xcc.OEMHandler(sysinfo, sysurl, webclient, cache,
38
+ gpool=cmd._gpool)
39
+ elif 'FrontPanelUSB' in leninf or 'USBManagementPortAssignment' in leninf or sysinfo.get('SKU', '').startswith('7X58'):
27
40
  return xcc.OEMHandler(sysinfo, sysurl, webclient, cache,
28
41
  gpool=cmd._gpool)
29
42
  else:
@@ -149,6 +149,13 @@ class OEMHandler(generic.OEMHandler):
149
149
  self.fwc = None
150
150
  self.fwo = None
151
151
 
152
+ def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
153
+ immsettings = self.get_system_configuration(fetchimm=True, hideadvanced=hideadvanced)
154
+ for setting in list(immsettings):
155
+ if not setting.startswith('IMM.'):
156
+ del immsettings[setting]
157
+ return immsettings
158
+
152
159
  def get_system_configuration(self, hideadvanced=True, fishclient=None,
153
160
  fetchimm=False):
154
161
  if not self.fwc:
@@ -572,7 +579,7 @@ class OEMHandler(generic.OEMHandler):
572
579
  summary['badreadings'] = fallbackdata
573
580
  return summary
574
581
 
575
- def get_description(self):
582
+ def get_description(self, fishclient):
576
583
  description = self._do_web_request('/DeviceDescription.json')
577
584
  if description:
578
585
  description = description[0]
@@ -667,7 +674,7 @@ class OEMHandler(generic.OEMHandler):
667
674
  for diskent in adp.get('aimDisks', ()):
668
675
  yield self._get_disk_firmware_single(diskent)
669
676
 
670
- def get_firmware_inventory(self, components):
677
+ def get_firmware_inventory(self, components, fishclient):
671
678
  sysinf = self.wc.grab_json_response('/api/dataset/sys_info')
672
679
  for item in sysinf.get('items', {}):
673
680
  for firm in item.get('firmware', []):
@@ -1553,7 +1560,7 @@ class OEMHandler(generic.OEMHandler):
1553
1560
  progress({'phase': 'complete'})
1554
1561
  return savefile
1555
1562
 
1556
- def get_licenses(self):
1563
+ def get_licenses(self, fishclient):
1557
1564
  licdata = self.wc.grab_json_response('/api/providers/imm_fod')
1558
1565
  for lic in licdata.get('items', [{}])[0].get('keys', []):
1559
1566
  if lic['status'] == 0:
@@ -1564,7 +1571,7 @@ class OEMHandler(generic.OEMHandler):
1564
1571
  'state': 'Missing required license'
1565
1572
  }
1566
1573
 
1567
- def delete_license(self, name):
1574
+ def delete_license(self, name, fishclient):
1568
1575
  licdata = self.wc.grab_json_response('/api/providers/imm_fod')
1569
1576
  for lic in licdata.get('items', [{}])[0].get('keys', []):
1570
1577
  if lic.get('feature', None) == name:
@@ -1577,7 +1584,7 @@ class OEMHandler(generic.OEMHandler):
1577
1584
  )
1578
1585
  break
1579
1586
 
1580
- def save_licenses(self, directory):
1587
+ def save_licenses(self, directory, fishclient):
1581
1588
  licdata = self.wc.grab_json_response('/api/providers/imm_fod')
1582
1589
  for lic in licdata.get('items', [{}])[0].get('keys', []):
1583
1590
  licid = ','.join((str(lic['type']), str(lic['id'])))
@@ -1594,7 +1601,7 @@ class OEMHandler(generic.OEMHandler):
1594
1601
  self._refresh_token()
1595
1602
  yield savefile
1596
1603
 
1597
- def apply_license(self, filename, progress=None, data=None):
1604
+ def apply_license(self, filename, fishclient, progress=None, data=None):
1598
1605
  license_errors = {
1599
1606
  310: "License is for a different model of system",
1600
1607
  311: "License is for a different system serial number",
@@ -1618,7 +1625,7 @@ class OEMHandler(generic.OEMHandler):
1618
1625
  if rsp.get('return', 0) in license_errors:
1619
1626
  raise pygexc.InvalidParameterValue(
1620
1627
  license_errors[rsp['return']])
1621
- return self.get_licenses()
1628
+ return self.get_licenses(fishclient)
1622
1629
 
1623
1630
  def user_delete(self, uid):
1624
1631
  userinfo = self.wc.grab_json_response('/api/dataset/imm_users')
@@ -0,0 +1,137 @@
1
+ import pyghmi.redfish.oem.generic as generic
2
+ import pyghmi.exceptions as pygexc
3
+
4
+
5
+ class OEMHandler(generic.OEMHandler):
6
+
7
+ def get_description(self, fishclient):
8
+ bmcstgs = fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
9
+ heightu = bmcstgs.get('Attributes', {}).get('ServerConfigHeightU')
10
+ return {'height': heightu}
11
+
12
+
13
+ def get_system_configuration(self, hideadvanced=True, fishclient=None):
14
+ stgs = self._getsyscfg(fishclient)[0]
15
+ outstgs = {}
16
+ for stg in stgs:
17
+ outstgs[f'UEFI.{stg}'] = stgs[stg]
18
+ return outstgs
19
+
20
+ def set_system_configuration(self, changeset, fishclient):
21
+ bmchangeset = {}
22
+ vpdchangeset = {}
23
+ for stg in list(changeset):
24
+ if stg.startswith('BMC.'):
25
+ bmchangeset[stg.replace('BMC.', '')] = changeset[stg]
26
+ del changeset[stg]
27
+ if stg.startswith('UEFI.'):
28
+ changeset[stg.replace('UEFI.' '')] = changeset[stg]
29
+ del changeset[stg]
30
+ if stg.startswith('VPD.'):
31
+ vpdchangeset[stg.replace('VPD.', '')] = changeset[stg]
32
+ del changeset[stg]
33
+ if changeset:
34
+ super().set_system_configuration(changeset, fishclient)
35
+ if bmchangeset:
36
+ self._set_xcc3_settings(bmchangeset, fishclient)
37
+ if vpdchangeset:
38
+ self._set_xcc3_vpd(vpdchangeset, fishclient)
39
+
40
+ def _set_xcc3_vpd(self, changeset, fishclient):
41
+ newvpd = {'Attributes': changeset}
42
+ fishclient._do_web_request(
43
+ '/redfish/v1/Chassis/1/Oem/Lenovo/SysvpdSettings/Actions/LenovoSysVpdSettings.SetVpdSettings',
44
+ newvpd)
45
+
46
+
47
+ def _set_xcc3_settings(self, changeset, fishclient):
48
+ currsettings, reginfo = self._get_lnv_bmcstgs(fishclient)
49
+ rawsettings = fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings',
50
+ cache=False)
51
+ rawsettings = rawsettings.get('Attributes', {})
52
+ pendingsettings = {}
53
+ ret = self._set_redfish_settings(
54
+ changeset, fishclient, currsettings, rawsettings,
55
+ pendingsettings, self.lenovobmcattrdeps, reginfo,
56
+ '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
57
+ fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings', cache=False)
58
+ return ret
59
+
60
+ def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
61
+ cfgin = self._get_lnv_bmcstgs(fishclient)[0]
62
+ cfgout = {}
63
+ for stgname in cfgin:
64
+ cfgout[f'BMC.{stgname}'] = cfgin[stgname]
65
+ vpdin = self._get_lnv_vpd(fishclient)[0]
66
+ for stgname in vpdin:
67
+ cfgout[f'VPD.{stgname}'] = vpdin[stgname]
68
+ return cfgout
69
+
70
+ def _get_lnv_vpd(self, fishclient):
71
+ currsettings, reginfo = self._get_lnv_stgs(
72
+ fishclient, '/redfish/v1/Chassis/1/Oem/Lenovo/SysvpdSettings')
73
+ self.lenovobmcattrdeps = reginfo[3]
74
+ return currsettings, reginfo
75
+
76
+ def _get_lnv_bmcstgs(self, fishclient):
77
+ currsettings, reginfo = self._get_lnv_stgs(
78
+ fishclient, '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
79
+ self.lenovobmcattrdeps = reginfo[3]
80
+ return currsettings, reginfo
81
+
82
+ def _get_lnv_stgs(self, fishclient, url):
83
+ bmcstgs = fishclient._do_web_request(url)
84
+ bmcreg = bmcstgs.get('AttributeRegistry', None)
85
+ extrainfo = {}
86
+ valtodisplay = {}
87
+ currsettings = {}
88
+ reginfo = {}, {}, {}, {}
89
+ if bmcreg:
90
+ reginfo = self._get_attrib_registry(fishclient, bmcreg)
91
+ if reginfo:
92
+ extrainfo, valtodisplay, _, _ = reginfo
93
+ for setting in bmcstgs.get('Attributes', {}):
94
+ val = bmcstgs['Attributes'][setting]
95
+ currval = val
96
+ val = valtodisplay.get(setting, {}).get(val, val)
97
+ val = {'value': val}
98
+ val.update(**extrainfo.get(setting, {}))
99
+ currsettings[setting] = val
100
+ return currsettings, reginfo
101
+
102
+ def get_firmware_inventory(self, components, fishclient):
103
+ fwlist = fishclient._do_web_request(fishclient._fwinventory)
104
+ rawfwurls = [x['@odata.id'] for x in fwlist.get('Members', [])]
105
+ fwurls = []
106
+ for fwurl in rawfwurls:
107
+ if fwurl.startswith('/redfish/v1/UpdateService/FirmwareInventory/Bundle.'):
108
+ continue # skip Bundle information for now
109
+ fwurls.append(fwurl)
110
+ self._fwnamemap = {}
111
+ for res in fishclient._do_bulk_requests(fwurls):
112
+ redres = res[0]
113
+ if redres.get('Name', '').startswith('Firmware:'):
114
+ redres['Name'] = redres['Name'].replace('Firmware:', '')
115
+ if redres['Name'].startswith('Firmware-PSoC') and 'Drive_Backplane' in redres["@odata.id"]:
116
+ redres['Name'] = 'Drive Backplane'
117
+ if redres['Name'].startswith('DEVICE-'):
118
+ redres['Name'] = redres['Name'].replace('DEVICE-', '')
119
+ if redres['Name'].startswith('POWER-PSU'):
120
+ redres['Name'] = redres['Name'].replace('POWER-', '')
121
+ swid = redres.get('SoftwareId', '')
122
+ buildid = ''
123
+ version = redres.get('Version', None)
124
+ if swid.startswith('FPGA-') or swid.startswith('UEFI-') or swid.startswith('BMC-'):
125
+ buildid = swid.split('-')[1] + version.split('-')[0]
126
+ version = '-'.join(version.split('-')[1:])
127
+ if version:
128
+ redres['Version'] = version
129
+ cres = fishclient._extract_fwinfo(res)
130
+ if cres[0] is None:
131
+ continue
132
+ if buildid:
133
+ cres[1]['build'] = buildid
134
+ yield cres
135
+ raise pygexc.BypassGenericBehavior()
136
+
137
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyghmi
3
- Version: 1.5.70
3
+ Version: 1.5.72
4
4
  Summary: Python General Hardware Management Initiative (IPMI and others)
5
5
  Home-page: http://github.com/openstack/pyghmi/
6
6
  Author: Jarrod Johnson
@@ -11,7 +11,7 @@ pyghmi/cmd/pyghmiutil.py,sha256=hir7FFvwKDNxYGpOPCgIVSgHP4UsVKFIbVBgBWqkBxA,2917
11
11
  pyghmi/cmd/virshbmc.py,sha256=rNbRJrVnx5BmQQLVRV8JK3lW9YWUcP7Z8hCWfpfVLCM,5149
12
12
  pyghmi/ipmi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  pyghmi/ipmi/bmc.py,sha256=LJBF90msq8xFcZSUe3s3jVcW02Ib-0Fc5zWvQNtGmcQ,7283
14
- pyghmi/ipmi/command.py,sha256=1quCxG5K2jYr77JpYiGLwwOmt0xB2FPJ7T-axnMLTxU,90301
14
+ pyghmi/ipmi/command.py,sha256=DkqKeuicNL02JY2pQzZJwJLRvgH3Uakr5DKm0ElPFkY,90345
15
15
  pyghmi/ipmi/console.py,sha256=Jle7uJI3ZQS6cMwbEisFEvXjmu5MVqMs17BcAlygR_4,23369
16
16
  pyghmi/ipmi/events.py,sha256=zgUidJIARHomwxasgeYAzDO1AEMfEOzb6XVxzry22Us,22569
17
17
  pyghmi/ipmi/fru.py,sha256=sw5ZBMrEVSBDgOUPVU_ksehQMJvrl2v-r7rVyA9xoiE,14430
@@ -20,14 +20,14 @@ pyghmi/ipmi/oem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  pyghmi/ipmi/oem/generic.py,sha256=HQ-9qTYIBpZqB1K75jTOTSUsirrKAQcI8BhLx0eAJ1g,18518
21
21
  pyghmi/ipmi/oem/lookup.py,sha256=Ex00OEEolsdWCVhyP0QDGzOxHGEA7sKI8a8fW4kJPD8,3653
22
22
  pyghmi/ipmi/oem/lenovo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- pyghmi/ipmi/oem/lenovo/config.py,sha256=woFD20UwZn5JjM-dBXsNW498e9_F6Sg9Z4_W7Y2QSuA,26005
23
+ pyghmi/ipmi/oem/lenovo/config.py,sha256=jSA8_NACwzouLpAhsu591QQFaBYPEU7NHvhpEddLQpg,26105
24
24
  pyghmi/ipmi/oem/lenovo/cpu.py,sha256=POZMP9n2S1v6r8iNStkCOVEiQYs3ut3RqL_9x-kgOFw,1651
25
25
  pyghmi/ipmi/oem/lenovo/dimm.py,sha256=L8k1aBgtvxqyubDBNKdDkz80pDE8Sck1eMLcMz1GhFI,1875
26
26
  pyghmi/ipmi/oem/lenovo/drive.py,sha256=MmVgaosEwJXcwi1kKYGnY-dbrx4Zp55941qWMvprUMA,2055
27
27
  pyghmi/ipmi/oem/lenovo/energy.py,sha256=THttIqlwpnj7ljbBWTHjelDLmDaQiCuMvNqJy9Ec7j8,6355
28
28
  pyghmi/ipmi/oem/lenovo/firmware.py,sha256=KS9uUBjFUzvdMw_e-kpr5sYIvFUaeg0yqyo69T94IVc,3747
29
- pyghmi/ipmi/oem/lenovo/handler.py,sha256=deTRv4mmzV-27gmGLnF0pu_xHgnJzT3Vk2gE-f5VChg,56492
30
- pyghmi/ipmi/oem/lenovo/imm.py,sha256=C9kH7M3lOYW2z211Oz7KQZgiOAh6KjTjnyzZ6h_ZGeM,111156
29
+ pyghmi/ipmi/oem/lenovo/handler.py,sha256=8OBkpxpPiwRFnBBCbs7RI4HtrdPT9k-cpZTEbAuuiG4,56536
30
+ pyghmi/ipmi/oem/lenovo/imm.py,sha256=2LFdzkTvgn4VaaXTHVazv6TTAosEAyIs77FMB6_fIBI,111202
31
31
  pyghmi/ipmi/oem/lenovo/inventory.py,sha256=FLJJinw-ibdHtf3KmrTzhWXbQrpxq3TSycVf96Hg7cw,5911
32
32
  pyghmi/ipmi/oem/lenovo/nextscale.py,sha256=ojLh17M87GnKUl-3yCTJcIJca1mpcrhlc7rQmhpby3A,43407
33
33
  pyghmi/ipmi/oem/lenovo/pci.py,sha256=S7p-5Q2qu2YhlffN-LEmIvjfXim6OlfYL7Q6r6VZqJ4,2020
@@ -43,17 +43,18 @@ pyghmi/ipmi/private/simplesession.py,sha256=cNGaoT0uWIKDut6gUG9kAOX_b_qTzdB26R6I
43
43
  pyghmi/ipmi/private/spd.py,sha256=oEPSXm19X2eNXDiyW_6fVjBFqhuuMAtBI9quRJgclH4,27094
44
44
  pyghmi/ipmi/private/util.py,sha256=ayYodiSydlrrt0_pQppoRB1T6n-KNOiHZSfAlCMcpG0,3847
45
45
  pyghmi/redfish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
- pyghmi/redfish/command.py,sha256=iUjF9d_ss1fmIW-CyPSfXQBiVABNk-4HsDUnelfa6C8,57241
46
+ pyghmi/redfish/command.py,sha256=SEiaw74uQQTzGrRkWFRKRcGnVpHXd2Kvgch4Ty_7oks,57340
47
47
  pyghmi/redfish/oem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- pyghmi/redfish/oem/generic.py,sha256=1DQS9RFe7a6yWfFlcglnVLMJVaTPxdCKCPHF0ukXaOU,39736
48
+ pyghmi/redfish/oem/generic.py,sha256=lOj8FgJOMC5rLj4IHM0Bfls4NkRNVFHrGw__FHjFjEc,46367
49
49
  pyghmi/redfish/oem/lookup.py,sha256=pfJW5xSkUY61OirMeYy0b1SbjBFz6IDfN5ZOYog_Yq4,1530
50
50
  pyghmi/redfish/oem/dell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  pyghmi/redfish/oem/dell/idrac.py,sha256=pNnmqdV1sOP3ABw0xq0wF1QEO2L8onT7Osc_-sDO8EU,2146
52
52
  pyghmi/redfish/oem/dell/main.py,sha256=g8773SShUpbYxXB9zVx2pD5z1xP04wB_sXAxcAs6_xY,793
53
53
  pyghmi/redfish/oem/lenovo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- pyghmi/redfish/oem/lenovo/main.py,sha256=MAJGAoOX-l5hMUiI7MXRsORPf0tGKWXWC8V1rDgb-KE,1665
54
+ pyghmi/redfish/oem/lenovo/main.py,sha256=-50u7hTT8urunKTOult2MNMAqLU09sOv_cJZsViwGcU,2249
55
55
  pyghmi/redfish/oem/lenovo/tsma.py,sha256=puSj0fO5Dt5VpDoEMVTRY95CP9q18eXcAqq7TDK350E,34633
56
- pyghmi/redfish/oem/lenovo/xcc.py,sha256=oRLXiGk8gdQsz6qqP79bpC_KN0lQH_qG7XVH3N6k8KQ,82294
56
+ pyghmi/redfish/oem/lenovo/xcc.py,sha256=wsAo-69qSV1eamFLBDx-dS3dn67V05xUrWfK7r8f0_g,82705
57
+ pyghmi/redfish/oem/lenovo/xcc3.py,sha256=p0tDMXVm4Z7oheindI0RInth8xvCLBt8CqwS42T1cMQ,5843
57
58
  pyghmi/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
59
  pyghmi/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
60
  pyghmi/tests/unit/base.py,sha256=xWImA7zPRgfrEe2xAdRZ6w_dLwExGRBJ5CBybssUQGg,744
@@ -62,11 +63,11 @@ pyghmi/tests/unit/ipmi/test_sdr.py,sha256=vb3iLY0cnHJ2K_m4xgYUjEcbPd_ZYhYx-uBowB
62
63
  pyghmi/util/__init__.py,sha256=GZLBWJiun2Plb_VE9dDSh4_PQMCha3gA7QLUqx3oSYI,25
63
64
  pyghmi/util/parse.py,sha256=6VlyBCEcE8gy8PJWmEDdtCyWATaKwPaTswCdioPCWOE,2120
64
65
  pyghmi/util/webclient.py,sha256=jV091_s-HWNDVMKfMxB5XljqiwinQkfXJgHt1u6Umms,14526
65
- pyghmi-1.5.70.dist-info/AUTHORS,sha256=-0iHKtdQwAJfAGKcruCnvcQXrXuE_LgBZ3P15DJI1xY,2044
66
- pyghmi-1.5.70.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
67
- pyghmi-1.5.70.dist-info/METADATA,sha256=qfec80M9j57DKetia0gs7CzqMTJDcCzBW-rruYdN-7A,1119
68
- pyghmi-1.5.70.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
69
- pyghmi-1.5.70.dist-info/entry_points.txt,sha256=WkbeJkEZzG9MOILxkaEPSEQ109YP9euntH9kcxbysuk,169
70
- pyghmi-1.5.70.dist-info/pbr.json,sha256=E7DnB_ZOTXuWLFkKYyyr0Osn89sl1zimBHAsBojDA94,46
71
- pyghmi-1.5.70.dist-info/top_level.txt,sha256=aDtt6S9eVu6-tNdaUs4Pz9PbdUd69bziZZMhNvk9Ulc,7
72
- pyghmi-1.5.70.dist-info/RECORD,,
66
+ pyghmi-1.5.72.dist-info/AUTHORS,sha256=-0iHKtdQwAJfAGKcruCnvcQXrXuE_LgBZ3P15DJI1xY,2044
67
+ pyghmi-1.5.72.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
68
+ pyghmi-1.5.72.dist-info/METADATA,sha256=RHABrdEfRdrxJAbFBYVzLnYMfik-0KQmilz1mbfOq_I,1119
69
+ pyghmi-1.5.72.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
70
+ pyghmi-1.5.72.dist-info/entry_points.txt,sha256=WkbeJkEZzG9MOILxkaEPSEQ109YP9euntH9kcxbysuk,169
71
+ pyghmi-1.5.72.dist-info/pbr.json,sha256=xzV_2z-mjUTo-ASlE1utsOowAV3Aa33TPNq7HGCInsg,46
72
+ pyghmi-1.5.72.dist-info/top_level.txt,sha256=aDtt6S9eVu6-tNdaUs4Pz9PbdUd69bziZZMhNvk9Ulc,7
73
+ pyghmi-1.5.72.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ {"git_version": "b6776ce", "is_release": true}
@@ -1 +0,0 @@
1
- {"git_version": "3673666", "is_release": true}