pyghmi 1.5.69__tar.gz → 1.5.71__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. {pyghmi-1.5.69 → pyghmi-1.5.71}/ChangeLog +20 -0
  2. {pyghmi-1.5.69 → pyghmi-1.5.71}/PKG-INFO +1 -1
  3. {pyghmi-1.5.69 → pyghmi-1.5.71}/builddeb +1 -1
  4. {pyghmi-1.5.69 → pyghmi-1.5.71}/makesetup +1 -1
  5. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/command.py +2 -2
  6. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/config.py +3 -1
  7. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/energy.py +18 -5
  8. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/handler.py +2 -2
  9. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/imm.py +2 -2
  10. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/command.py +16 -5
  11. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/generic.py +159 -41
  12. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/xcc.py +12 -5
  13. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/PKG-INFO +1 -1
  14. pyghmi-1.5.71/pyghmi.egg-info/pbr.json +1 -0
  15. {pyghmi-1.5.69 → pyghmi-1.5.71}/setup.cfg +3 -3
  16. {pyghmi-1.5.69 → pyghmi-1.5.71}/setup.py.tmpl +1 -0
  17. {pyghmi-1.5.69 → pyghmi-1.5.71}/test-requirements.txt +0 -5
  18. pyghmi-1.5.69/pyghmi.egg-info/pbr.json +0 -1
  19. {pyghmi-1.5.69 → pyghmi-1.5.71}/.coveragerc +0 -0
  20. {pyghmi-1.5.69 → pyghmi-1.5.71}/.stestr.conf +0 -0
  21. {pyghmi-1.5.69 → pyghmi-1.5.71}/AUTHORS +0 -0
  22. {pyghmi-1.5.69 → pyghmi-1.5.71}/CONTRIBUTING.rst +0 -0
  23. {pyghmi-1.5.69 → pyghmi-1.5.71}/LICENSE +0 -0
  24. {pyghmi-1.5.69 → pyghmi-1.5.71}/MANIFEST.in +0 -0
  25. {pyghmi-1.5.69 → pyghmi-1.5.71}/README +0 -0
  26. {pyghmi-1.5.69 → pyghmi-1.5.71}/README.md +0 -0
  27. {pyghmi-1.5.69 → pyghmi-1.5.71}/buildrpm +0 -0
  28. {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/requirements.txt +0 -0
  29. {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/conf.py +0 -0
  30. {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/contributor/index.rst +0 -0
  31. {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/index.rst +0 -0
  32. {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/install/index.rst +0 -0
  33. {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/reference/index.rst +0 -0
  34. {pyghmi-1.5.69 → pyghmi-1.5.71}/playbooks/legacy/tempest-devstack-ironic-pxe_ipmitool-pyghmi-src/post.yaml +0 -0
  35. {pyghmi-1.5.69 → pyghmi-1.5.71}/playbooks/legacy/tempest-devstack-ironic-pxe_ipmitool-pyghmi-src/run.yaml +0 -0
  36. {pyghmi-1.5.69 → pyghmi-1.5.71}/py27-constraints.txt +0 -0
  37. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/__init__.py +0 -0
  38. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/__init__.py +0 -0
  39. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/fakebmc.py +0 -0
  40. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/pyghmicons.py +0 -0
  41. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/pyghmiutil.py +0 -0
  42. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/virshbmc.py +0 -0
  43. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/constants.py +0 -0
  44. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/exceptions.py +0 -0
  45. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/__init__.py +0 -0
  46. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/bmc.py +0 -0
  47. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/console.py +0 -0
  48. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/events.py +0 -0
  49. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/fru.py +0 -0
  50. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/__init__.py +0 -0
  51. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/generic.py +0 -0
  52. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/__init__.py +0 -0
  53. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/cpu.py +0 -0
  54. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/dimm.py +0 -0
  55. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/drive.py +0 -0
  56. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/firmware.py +0 -0
  57. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/inventory.py +0 -0
  58. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/nextscale.py +0 -0
  59. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/pci.py +0 -0
  60. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/psu.py +0 -0
  61. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/raid_controller.py +0 -0
  62. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/raid_drive.py +0 -0
  63. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lookup.py +0 -0
  64. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/__init__.py +0 -0
  65. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/constants.py +0 -0
  66. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/localsession.py +0 -0
  67. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/serversession.py +0 -0
  68. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/session.py +0 -0
  69. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/simplesession.py +0 -0
  70. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/spd.py +0 -0
  71. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/util.py +0 -0
  72. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/sdr.py +0 -0
  73. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/media.py +0 -0
  74. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/__init__.py +0 -0
  75. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/__init__.py +0 -0
  76. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/dell/__init__.py +0 -0
  77. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/dell/idrac.py +0 -0
  78. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/dell/main.py +0 -0
  79. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/__init__.py +0 -0
  80. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/main.py +0 -0
  81. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/tsma.py +0 -0
  82. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lookup.py +0 -0
  83. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/storage.py +0 -0
  84. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/__init__.py +0 -0
  85. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/__init__.py +0 -0
  86. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/base.py +0 -0
  87. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/ipmi/__init__.py +0 -0
  88. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/ipmi/test_sdr.py +0 -0
  89. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/util/__init__.py +0 -0
  90. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/util/parse.py +0 -0
  91. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/util/webclient.py +0 -0
  92. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/version.py +0 -0
  93. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/SOURCES.txt +0 -0
  94. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/dependency_links.txt +0 -0
  95. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/entry_points.txt +0 -0
  96. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/not-zip-safe +0 -0
  97. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/requires.txt +0 -0
  98. {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/top_level.txt +0 -0
  99. {pyghmi-1.5.69 → pyghmi-1.5.71}/python-pyghmi.spec +0 -0
  100. {pyghmi-1.5.69 → pyghmi-1.5.71}/python-pyghmi.spec.tmpl +0 -0
  101. {pyghmi-1.5.69 → pyghmi-1.5.71}/requirements.txt +0 -0
  102. {pyghmi-1.5.69 → pyghmi-1.5.71}/setup.py +0 -0
  103. {pyghmi-1.5.69 → pyghmi-1.5.71}/tox.ini +0 -0
  104. {pyghmi-1.5.69 → pyghmi-1.5.71}/wheezy.patch +0 -0
  105. {pyghmi-1.5.69 → pyghmi-1.5.71}/zuul.d/project.yaml +0 -0
@@ -1,6 +1,26 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ 1.5.71
5
+ ------
6
+
7
+ * Wire up redfish for getting extended BMC settings
8
+ * Add generic redfish license handling
9
+ * Extend MAC collection in redfish
10
+ * Normalize UUID format
11
+ * Add multipart update support to redfish updates
12
+ * Add BMC reset to redfish implementation
13
+ * Fix the extended bmc configuration
14
+ * Exposed advanced, extended BMC configuration
15
+ * Restore UEFI configuration to IMM systems
16
+
17
+ 1.5.70
18
+ ------
19
+
20
+ * Update for modern Debian/Ubuntu build
21
+ * Add FAPM meters for better quality power data
22
+ * Remove unused test-requirements
23
+
4
24
  1.5.69
5
25
  ------
6
26
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyghmi
3
- Version: 1.5.69
3
+ Version: 1.5.71
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
@@ -4,7 +4,7 @@ mkdir -p /tmp/pyghmi
4
4
  cp -a * .git /tmp/pyghmi
5
5
  cd /tmp/pyghmi
6
6
  export PYEXEC=python3
7
- export DSCARGS="--with-python2=True --with-python3=True"
7
+ export DSCARGS="--with-python2=False --with-python3=True"
8
8
  if grep wheezy /etc/os-release; then
9
9
  # also it's old, use python2 instead of python3
10
10
  export PYEXEC=python
@@ -3,7 +3,7 @@ cd `dirname $0`
3
3
  VERSION=`git describe|cut -d- -f 1`
4
4
  NUMCOMMITS=`git describe|cut -d- -f 2`
5
5
  if [ "$NUMCOMMITS" != "$VERSION" ]; then
6
- VERSION=$VERSION.dev$NUMCOMMITS.g`git describe|cut -d- -f 3`
6
+ VERSION=$VERSION.dev$NUMCOMMITS+g`git describe|cut -d- -f 3`
7
7
  fi
8
8
  echo $VERSION > VERSION
9
9
  sed -e "s/#VERSION#/$VERSION/" setup.py.tmpl > setup.py
@@ -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(
@@ -32,8 +32,8 @@ class EnergyManager(object):
32
32
  try:
33
33
  rsp = ipmicmd.xraw_command(netfn=0x3a, command=0x32, data=[4, 2, 0, 0, 0])
34
34
  if len(rsp['data']) >= 8:
35
- self.supportedmeters = ('DC Energy',) # 'GPU Power',
36
- # 'Node Power', 'Total Power')
35
+ self.supportedmeters = ('DC Energy', 'GPU Power',
36
+ 'Node Power', 'Total Power')
37
37
  self._mypowermeters = ('node power', 'total power', 'gpu power', 'riser 1 power', 'riser 2 power')
38
38
  self._usefapm = True
39
39
  return
@@ -67,9 +67,22 @@ class EnergyManager(object):
67
67
 
68
68
  def get_sensor(self, name, ipmicmd):
69
69
  if name.lower() not in self._mypowermeters:
70
- raise pygexc.UnsupportedFunctionality('Unrecogcized sensor')
71
- rsp = ipmicmd.xraw_command(netfn=0x3a, command=0x32, data=[4, 8, 0, 0, 0])
72
- npow, gpupow, r1pow, r2pow = struct.unpack('<HHHH', rsp['data'][6:10])
70
+ raise pygexc.UnsupportedFunctionality('Unrecognized sensor: {}'.format(name))
71
+ tries = 3
72
+ rsp = None
73
+ while tries:
74
+ tries -= 1
75
+ try:
76
+ rsp = ipmicmd.xraw_command(netfn=0x3a, command=0x32, data=[4, 8, 0, 0, 0])
77
+ break
78
+ except pygexc.IpmiException as ie:
79
+ if tries and ie.ipmicode == 0xc3:
80
+ ipmicmd.ipmi_session.pause(0.1)
81
+ continue
82
+ raise
83
+ if rsp is None:
84
+ raise pygexc.UnsupportedFunctionality('Unrecognized sensor: {}'.format(name))
85
+ npow, gpupow, r1pow, r2pow = struct.unpack('<HHHH', rsp['data'][6:14])
73
86
  if name.lower().startswith('node'):
74
87
  return npow, 'W'
75
88
  elif name.lower().startswith('gpu'):
@@ -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]
@@ -789,6 +789,9 @@ class Command(object):
789
789
  def get_health(self, verbose=True):
790
790
  return self.oem.get_health(self, verbose)
791
791
 
792
+ def get_extended_bmc_configuration(self, hideadvanced=True):
793
+ return self.oem.get_extended_bmc_configuration(self, hideadvanced=hideadvanced)
794
+
792
795
  def get_bmc_configuration(self):
793
796
  """Get miscellaneous BMC configuration
794
797
 
@@ -823,8 +826,16 @@ class Command(object):
823
826
  In many cases, this may render remote network access impracticle or
824
827
  impossible."
825
828
  """
829
+ bmcinfo = self._do_web_request(self._bmcurl)
830
+ rc = bmcinfo.get('Actions', {}).get('#Manager.ResetToDefaults', {})
831
+ actinf = rc.get('ResetType@Redfish.AllowableValues', [])
832
+ if 'ResetAll' in actinf:
833
+ acturl = actinf.get('target', None)
834
+ if acturl:
835
+ self._do_web_request(acturl, {'ResetType': 'ResetAll'})
836
+ return
826
837
  raise exc.UnsupportedFunctionality(
827
- 'Clear BMC configuration not supported in redfish yet')
838
+ 'Clear BMC configuration not supported on this platform')
828
839
 
829
840
  def get_system_configuration(self, hideadvanced=True):
830
841
  return self.oem.get_system_configuration(hideadvanced, self)
@@ -1413,20 +1424,20 @@ class Command(object):
1413
1424
  return self.oem.get_diagnostic_data(savefile, progress, autosuffix)
1414
1425
 
1415
1426
  def get_licenses(self):
1416
- return self.oem.get_licenses()
1427
+ return self.oem.get_licenses(self)
1417
1428
 
1418
1429
  def delete_license(self, name):
1419
- return self.oem.delete_license(name)
1430
+ return self.oem.delete_license(name, self)
1420
1431
 
1421
1432
  def save_licenses(self, directory):
1422
1433
  if os.path.exists(directory) and not os.path.isdir(directory):
1423
1434
  raise exc.InvalidParameterValue(
1424
1435
  'Not allowed to overwrite existing file: {0}'.format(
1425
1436
  directory))
1426
- return self.oem.save_licenses(directory)
1437
+ return self.oem.save_licenses(directory, self)
1427
1438
 
1428
1439
  def apply_license(self, filename, progress=None, data=None):
1429
- return self.oem.apply_license(filename, progress, data)
1440
+ return self.oem.apply_license(filename, self, progress, data)
1430
1441
 
1431
1442
 
1432
1443
  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,11 @@ class SensorReading(object):
43
44
  self.units = units
44
45
  self.unavailable = unavailable
45
46
 
47
+ def _normalize_mac(mac):
48
+ if ':' not in mac:
49
+ mac = ':'.join((mac[:2], mac[2:4], mac[4:6], mac[6:8], mac[8:10], mac[10:12]))
50
+ return mac.lower()
51
+
46
52
  _healthmap = {
47
53
  'Critical': const.Health.Critical,
48
54
  'Unknown': const.Health.Warning,
@@ -533,6 +539,12 @@ class OEMHandler(object):
533
539
  'Model': self._varsysinfo.get(
534
540
  'SKU', self._varsysinfo.get('PartNumber', '')),
535
541
  }
542
+ if sysinfo['UUID'] and '-' not in sysinfo['UUID']:
543
+ sysinfo['UUID'] = '-'.join((
544
+ sysinfo['UUID'][:8], sysinfo['UUID'][8:12],
545
+ sysinfo['UUID'][12:16], sysinfo['UUID'][16:20],
546
+ sysinfo['UUID'][20:]))
547
+ sysinfo['UUID'] = sysinfo['UUID'].lower()
536
548
  return sysinfo
537
549
  else:
538
550
  for invpair in self.get_inventory():
@@ -548,6 +560,12 @@ class OEMHandler(object):
548
560
  'Model': self._varsysinfo.get(
549
561
  'SKU', self._varsysinfo.get('PartNumber', '')),
550
562
  }
563
+ if sysinfo['UUID'] and '-' not in sysinfo['UUID']:
564
+ sysinfo['UUID'] = '-'.join((
565
+ sysinfo['UUID'][:8], sysinfo['UUID'][8:12],
566
+ sysinfo['UUID'][12:16], sysinfo['UUID'][16:20],
567
+ sysinfo['UUID'][20:]))
568
+ sysinfo['UUID'] = sysinfo['UUID'].lower()
551
569
  yield ('System', sysinfo)
552
570
  self._hwnamemap = {}
553
571
  cpumemurls = []
@@ -599,22 +617,39 @@ class OEMHandler(object):
599
617
  yield (dname, ddata)
600
618
 
601
619
  def _get_adp_inventory(self, onlyname=False, withids=False, urls=None):
620
+ foundmacs = False
621
+ macinfobyadpname = {}
622
+ if 'NetworkInterfaces' in self._varsysinfo:
623
+ nifurls = self._do_web_request(self._varsysinfo['NetworkInterfaces']['@odata.id'])
624
+ nifurls = nifurls.get('Members', [])
625
+ nifurls = [x['@odata.id'] for x in nifurls]
626
+ for nifurl in nifurls:
627
+ nifinfo = self._do_web_request(nifurl)
628
+
629
+ nadurl = nifinfo.get('Links', {}).get('NetworkAdapter', {}).get("@odata.id")
630
+ if nadurl:
631
+ nadinfo = self._do_web_request(nadurl)
632
+ if 'Name' not in nadinfo:
633
+ continue
634
+ nicname = nadinfo['Name']
635
+ yieldinf = {}
636
+ macidx = 1
637
+ for ctrlr in nadinfo.get('Controllers', []):
638
+ porturls = [x['@odata.id'] for x in ctrlr.get(
639
+ 'Links', {}).get('Ports', [])]
640
+ for porturl in porturls:
641
+ portinfo = self._do_web_request(porturl)
642
+ macs = [x for x in portinfo.get(
643
+ 'Ethernet', {}).get(
644
+ 'AssociatedMACAddresses', [])]
645
+ for mac in macs:
646
+ label = 'MAC Address {}'.format(macidx)
647
+ yieldinf[label] = _normalize_mac(mac)
648
+ macidx += 1
649
+ foundmacs = True
650
+ macinfobyadpname[nicname] = yieldinf
602
651
  if not urls:
603
652
  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
653
  for inf in self._do_bulk_requests(urls):
619
654
  adpinfo, url = inf
620
655
  aname = adpinfo.get('Name', 'Unknown')
@@ -636,6 +671,8 @@ class OEMHandler(object):
636
671
  yieldinf = {'Id': adpinfo.get('Id', aname)}
637
672
  else:
638
673
  yieldinf = {}
674
+ if aname in macinfobyadpname:
675
+ yieldinf.update(macinfobyadpname[aname])
639
676
  funurls = [x['@odata.id'] for x in functions]
640
677
  for fun in self._do_bulk_requests(funurls):
641
678
  funinfo, url = fun
@@ -648,14 +685,42 @@ class OEMHandler(object):
648
685
  yieldinf['PCI Subsystem Vendor ID'] = funinfo[
649
686
  'SubsystemVendorId'].replace('0x', '')
650
687
  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
688
+ if aname not in macinfobyadpname:
689
+ for nicinfo in funinfo.get('Links', {}).get(
690
+ 'EthernetInterfaces', []):
691
+ nicinfo = self._do_web_request(nicinfo['@odata.id'])
692
+ macaddr = nicinfo.get('MACAddress', None)
693
+ if macaddr:
694
+ macaddr = _normalize_mac(macaddr)
695
+ foundmacs = True
696
+ yieldinf['MAC Address {0}'.format(nicidx)] = macaddr
697
+ nicidx += 1
698
+ if aname in macinfobyadpname:
699
+ del macinfobyadpname[aname]
658
700
  yield aname, yieldinf
701
+ if macinfobyadpname:
702
+ for adp in macinfobyadpname:
703
+ yield adp, macinfobyadpname[adp]
704
+ if not foundmacs:
705
+ # No PCIe device inventory, but *maybe* ethernet inventory...
706
+ idxsbyname = {}
707
+ for nicinfo in self._get_eth_urls():
708
+ nicinfo = self._do_web_request(nicinfo)
709
+ nicname = nicinfo.get('Name', None)
710
+ nicinfo = nicinfo.get('MACAddress', nicinfo.get('PermanentAddress', None))
711
+ if nicinfo and ':' not in nicinfo:
712
+ nicinfo = ':'.join((
713
+ nicinfo[:2], nicinfo[2:4], nicinfo[4:6], nicinfo[6:8],
714
+ nicinfo[8:10], nicinfo[10:12]))
715
+ if not nicname:
716
+ nicname = 'NIC'
717
+ if nicinfo:
718
+ if nicname not in idxsbyname:
719
+ idxsbyname[nicname] = 0
720
+ idxsbyname[nicname] += 1
721
+ nicinfo = nicinfo.lower()
722
+ yield (nicname,
723
+ {'MAC Address {}'.format(idxsbyname[nicname]): nicinfo})
659
724
 
660
725
  def _get_eth_urls(self):
661
726
  ethurls = self._varsysinfo.get('EthernetInterfaces', {})
@@ -780,20 +845,24 @@ class OEMHandler(object):
780
845
 
781
846
  def update_firmware(self, filename, data=None, progress=None, bank=None):
782
847
  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')
848
+ upurl = usd.get('MultipartHttpPushUri', None)
849
+ ismultipart = True
850
+ if not upurl:
851
+ ismultipart = False
852
+ if usd.get('HttpPushUriTargetsBusy', False):
853
+ raise exc.TemporaryError('Cannot run multtiple updates to '
854
+ 'same target concurrently')
855
+ try:
856
+ upurl = usd['HttpPushUri']
857
+ except KeyError:
858
+ raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
859
+ if 'HttpPushUriTargetsBusy' in usd:
860
+ self._do_web_request(
861
+ '/redfish/v1/UpdateService',
862
+ {'HttpPushUriTargetsBusy': True}, method='PATCH')
794
863
  try:
795
864
  uploadthread = webclient.FileUploader(
796
- self.webclient, upurl, filename, data, formwrap=False,
865
+ self.webclient, upurl, filename, data, formwrap=ismultipart,
797
866
  excepterror=False)
798
867
  uploadthread.start()
799
868
  wc = self.webclient
@@ -823,6 +892,7 @@ class OEMHandler(object):
823
892
  # sometimes we get an empty pgress when transitioning from the apply phase to
824
893
  # the validating phase; add a retry here so we don't exit the loop in this case
825
894
  retry = 3
895
+ pct = 0.0
826
896
  while not complete and retry > 0:
827
897
  pgress = self._do_web_request(monitorurl, cache=False)
828
898
  if not pgress:
@@ -837,7 +907,10 @@ class OEMHandler(object):
837
907
  'Suspended'):
838
908
  raise Exception(
839
909
  json.dumps(json.dumps(pgress['Messages'])))
840
- pct = float(pgress['PercentComplete'])
910
+ if 'PercentComplete' in pgress:
911
+ pct = float(pgress['PercentComplete'])
912
+ else:
913
+ print(repr(pgress))
841
914
  complete = state == 'Completed'
842
915
  progress({'phase': phase, 'progress': pct})
843
916
  if complete:
@@ -910,17 +983,62 @@ class OEMHandler(object):
910
983
  raise exc.UnsupportedFunctionality(
911
984
  'Retrieving diagnostic data is not implemented for this platform')
912
985
 
913
- def get_licenses(self):
914
- raise exc.UnsupportedFunctionality()
986
+ def _get_license_collection_url(self, fishclient):
987
+ overview = fishclient._do_web_request('/redfish/v1/')
988
+ licsrv = overview.get('LicenseService', {}).get('@odata.id', None)
989
+ if not licsrv:
990
+ raise exc.UnsupportedFunctionality()
991
+ lcs = fishclient._do_web_request(licsrv)
992
+ licenses = lcs.get('Licenses', {}).get('@odata.id',None)
993
+ if not licenses:
994
+ raise exc.UnsupportedFunctionality()
995
+ return licenses
915
996
 
916
- def delete_license(self, name):
997
+ def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
917
998
  raise exc.UnsupportedFunctionality()
918
999
 
919
- def save_licenses(self, directory):
920
- raise exc.UnsupportedFunctionality()
1000
+ def _get_licenses(self, fishclient):
1001
+ licenses = self._get_license_collection_url(fishclient)
1002
+ collection = fishclient._do_web_request(licenses)
1003
+ alllic = [x['@odata.id'] for x in collection.get('Members', [])]
1004
+ for license in alllic:
1005
+ licdet = fishclient._do_web_request(license)
1006
+ state = licdet.get('Status', {}).get('State')
1007
+ if state != 'Enabled':
1008
+ continue
1009
+ yield licdet
921
1010
 
922
- def apply_license(self, filename, progress=None, data=None):
923
- raise exc.UnsupportedFunctionality()
1011
+ def get_licenses(self, fishclient):
1012
+ for licdet in self._get_licenses(fishclient):
1013
+ name = licdet['Name']
1014
+ yield {'name': name, 'state': 'Active'}
1015
+
1016
+ def delete_license(self, name, fishclient):
1017
+ for licdet in self._get_licenses(fishclient):
1018
+ lname = licdet['Name']
1019
+ if name == lname:
1020
+ fishclient._do_web_request(licdet['@odata.id'], method='DELETE')
1021
+
1022
+ def save_licenses(self, directory, fishclient):
1023
+ for licdet in self._get_licenses(fishclient):
1024
+ dload = licdet.get('DownloadURI', None)
1025
+ if dload:
1026
+ filename = os.path.basename(dload)
1027
+ savefile = os.path.join(directory, filename)
1028
+ fd = webclient.FileDownloader(fishclient.wc, dload, savefile)
1029
+ fd.start()
1030
+ while fd.isAlive():
1031
+ fd.join(1)
1032
+ yield savefile
1033
+
1034
+ def apply_license(self, filename, fishclient, progress=None, data=None):
1035
+ licenses = self._get_license_collection_url(fishclient)
1036
+ if data is None:
1037
+ data = open(filename, 'rb')
1038
+ licdata = data.read()
1039
+ lic64 = base64.b64encode(licdata).decode()
1040
+ licinfo = {"LicenseString": lic64}
1041
+ fishclient._do_web_request(licenses, licinfo)
924
1042
 
925
1043
  def get_user_expiration(self, uid):
926
1044
  return None
@@ -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:
@@ -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')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyghmi
3
- Version: 1.5.69
3
+ Version: 1.5.71
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
@@ -0,0 +1 @@
1
+ {"git_version": "a8a0363", "is_release": true}
@@ -1,11 +1,11 @@
1
1
  [metadata]
2
2
  name = pyghmi
3
3
  summary = Python General Hardware Management Initiative (IPMI and others)
4
- description-file =
4
+ description_file =
5
5
  README
6
6
  author = Jarrod Johnson
7
- author-email = jjohnson2@lenovo.com
8
- home-page = http://github.com/openstack/pyghmi/
7
+ author_email = jjohnson2@lenovo.com
8
+ home_page = http://github.com/openstack/pyghmi/
9
9
  classifier =
10
10
  Intended Audience :: Information Technology
11
11
  Intended Audience :: System Administrators
@@ -21,6 +21,7 @@ setuptools.setup(
21
21
  name='pyghmi',
22
22
  version='#VERSION#',
23
23
  description='Python General Hardware Management Initiative (IPMI, redfish, etc)',
24
+ long_description='Python General Hardware Management Initiative (IPMI, redfish, etc)',
24
25
  author='Jarrod Johnson',
25
26
  author_email='jjohnson2@lenovo.com',
26
27
  packages=['pyghmi', 'pyghmi.util', 'pyghmi.ipmi', 'pyghmi.cmd',
@@ -1,9 +1,4 @@
1
-
2
1
  coverage!=4.4,>=4.0 # Apache-2.0
3
- fixtures>=3.0.0
4
- python-subunit>=1.0.0
5
2
  stestr>=2.0.0,!=2.3.0,!=3.0.0 # Apache-2.0
6
- testscenarios>=0.4
7
- testtools>=2.2.0
8
3
  oslotest>=3.2.0,<4;python_version<'3.6' # Apache-2.0
9
4
  oslotest>=3.2.0;python_version>='3.6' # Apache-2.0
@@ -1 +0,0 @@
1
- {"git_version": "ed94d36", "is_release": true}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes