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.
- {pyghmi-1.5.69 → pyghmi-1.5.71}/ChangeLog +20 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/PKG-INFO +1 -1
- {pyghmi-1.5.69 → pyghmi-1.5.71}/builddeb +1 -1
- {pyghmi-1.5.69 → pyghmi-1.5.71}/makesetup +1 -1
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/command.py +2 -2
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/config.py +3 -1
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/energy.py +18 -5
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/handler.py +2 -2
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/imm.py +2 -2
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/command.py +16 -5
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/generic.py +159 -41
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/xcc.py +12 -5
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/PKG-INFO +1 -1
- pyghmi-1.5.71/pyghmi.egg-info/pbr.json +1 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/setup.cfg +3 -3
- {pyghmi-1.5.69 → pyghmi-1.5.71}/setup.py.tmpl +1 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/test-requirements.txt +0 -5
- pyghmi-1.5.69/pyghmi.egg-info/pbr.json +0 -1
- {pyghmi-1.5.69 → pyghmi-1.5.71}/.coveragerc +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/.stestr.conf +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/AUTHORS +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/CONTRIBUTING.rst +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/LICENSE +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/MANIFEST.in +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/README +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/README.md +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/buildrpm +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/requirements.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/conf.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/contributor/index.rst +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/index.rst +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/install/index.rst +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/doc/source/reference/index.rst +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/playbooks/legacy/tempest-devstack-ironic-pxe_ipmitool-pyghmi-src/post.yaml +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/playbooks/legacy/tempest-devstack-ironic-pxe_ipmitool-pyghmi-src/run.yaml +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/py27-constraints.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/fakebmc.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/pyghmicons.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/pyghmiutil.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/cmd/virshbmc.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/constants.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/exceptions.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/bmc.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/console.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/events.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/fru.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/generic.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/cpu.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/dimm.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/drive.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/firmware.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/inventory.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/nextscale.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/pci.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/psu.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/raid_controller.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lenovo/raid_drive.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/oem/lookup.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/constants.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/localsession.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/serversession.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/session.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/simplesession.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/spd.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/private/util.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/ipmi/sdr.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/media.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/dell/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/dell/idrac.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/dell/main.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/main.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lenovo/tsma.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/redfish/oem/lookup.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/storage.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/base.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/ipmi/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/tests/unit/ipmi/test_sdr.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/util/__init__.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/util/parse.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/util/webclient.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi/version.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/SOURCES.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/dependency_links.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/entry_points.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/not-zip-safe +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/requires.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/pyghmi.egg-info/top_level.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/python-pyghmi.spec +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/python-pyghmi.spec.tmpl +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/requirements.txt +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/setup.py +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/tox.ini +0 -0
- {pyghmi-1.5.69 → pyghmi-1.5.71}/wheezy.patch +0 -0
- {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
|
|
@@ -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=
|
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
|
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.
|
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',
|
36
|
-
|
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('
|
71
|
-
|
72
|
-
|
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
|
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
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
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
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
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=
|
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
|
-
|
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
|
914
|
-
|
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
|
997
|
+
def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
|
917
998
|
raise exc.UnsupportedFunctionality()
|
918
999
|
|
919
|
-
def
|
920
|
-
|
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
|
923
|
-
|
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')
|
@@ -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
|
-
|
4
|
+
description_file =
|
5
5
|
README
|
6
6
|
author = Jarrod Johnson
|
7
|
-
|
8
|
-
|
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
|
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
|
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
|