pyghmi 1.5.70__py3-none-any.whl → 1.5.72__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.
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}