pyghmi 1.5.70__tar.gz → 1.5.72__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {pyghmi-1.5.70 → pyghmi-1.5.72}/ChangeLog +25 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/PKG-INFO +1 -1
- {pyghmi-1.5.70 → pyghmi-1.5.72}/builddeb +5 -2
- pyghmi-1.5.72/makesetup +14 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/command.py +2 -2
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/config.py +3 -1
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/handler.py +2 -2
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/imm.py +2 -2
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/command.py +19 -22
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/generic.py +227 -77
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/lenovo/main.py +14 -1
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/lenovo/xcc.py +14 -7
- pyghmi-1.5.72/pyghmi/redfish/oem/lenovo/xcc3.py +137 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/PKG-INFO +1 -1
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/SOURCES.txt +1 -0
- pyghmi-1.5.72/pyghmi.egg-info/pbr.json +1 -0
- pyghmi-1.5.70/makesetup +0 -10
- pyghmi-1.5.70/pyghmi.egg-info/pbr.json +0 -1
- {pyghmi-1.5.70 → pyghmi-1.5.72}/.coveragerc +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/.stestr.conf +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/AUTHORS +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/CONTRIBUTING.rst +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/LICENSE +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/MANIFEST.in +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/README +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/README.md +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/buildrpm +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/doc/requirements.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/doc/source/conf.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/doc/source/contributor/index.rst +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/doc/source/index.rst +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/doc/source/install/index.rst +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/doc/source/reference/index.rst +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/playbooks/legacy/tempest-devstack-ironic-pxe_ipmitool-pyghmi-src/post.yaml +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/playbooks/legacy/tempest-devstack-ironic-pxe_ipmitool-pyghmi-src/run.yaml +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/py27-constraints.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/cmd/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/cmd/fakebmc.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/cmd/pyghmicons.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/cmd/pyghmiutil.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/cmd/virshbmc.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/constants.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/exceptions.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/bmc.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/console.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/events.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/fru.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/generic.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/cpu.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/dimm.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/drive.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/energy.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/firmware.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/inventory.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/nextscale.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/pci.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/psu.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/raid_controller.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lenovo/raid_drive.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/oem/lookup.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/constants.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/localsession.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/serversession.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/session.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/simplesession.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/spd.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/private/util.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/ipmi/sdr.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/media.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/dell/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/dell/idrac.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/dell/main.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/lenovo/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/lenovo/tsma.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/redfish/oem/lookup.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/storage.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/tests/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/tests/unit/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/tests/unit/base.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/tests/unit/ipmi/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/tests/unit/ipmi/test_sdr.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/util/__init__.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/util/parse.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/util/webclient.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi/version.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/dependency_links.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/entry_points.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/not-zip-safe +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/requires.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/pyghmi.egg-info/top_level.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/python-pyghmi.spec +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/python-pyghmi.spec.tmpl +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/requirements.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/setup.cfg +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/setup.py +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/setup.py.tmpl +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/test-requirements.txt +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/tox.ini +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/wheezy.patch +0 -0
- {pyghmi-1.5.70 → pyghmi-1.5.72}/zuul.d/project.yaml +0 -0
@@ -1,6 +1,31 @@
|
|
1
1
|
CHANGES
|
2
2
|
=======
|
3
3
|
|
4
|
+
1.5.72
|
5
|
+
------
|
6
|
+
|
7
|
+
* Rework get description to enable it to work fer XCC3
|
8
|
+
* Modify build for snap versions
|
9
|
+
* Amend deb package build to avoid extranoeus content
|
10
|
+
* Use approved method to determine XCC vintage
|
11
|
+
* Implement fixup of firmware inventory
|
12
|
+
* Prefer XCC3 detection over XCC2
|
13
|
+
* Fix str concatenation on redfish spec violations
|
14
|
+
* Refactor redfish settings and leverage in XCC3
|
15
|
+
|
16
|
+
1.5.71
|
17
|
+
------
|
18
|
+
|
19
|
+
* Wire up redfish for getting extended BMC settings
|
20
|
+
* Add generic redfish license handling
|
21
|
+
* Extend MAC collection in redfish
|
22
|
+
* Normalize UUID format
|
23
|
+
* Add multipart update support to redfish updates
|
24
|
+
* Add BMC reset to redfish implementation
|
25
|
+
* Fix the extended bmc configuration
|
26
|
+
* Exposed advanced, extended BMC configuration
|
27
|
+
* Restore UEFI configuration to IMM systems
|
28
|
+
|
4
29
|
1.5.70
|
5
30
|
------
|
6
31
|
|
@@ -11,7 +11,10 @@ if grep wheezy /etc/os-release; then
|
|
11
11
|
export DSCARGS=""
|
12
12
|
fi
|
13
13
|
# If not PBR, use the setup.py.tmpl
|
14
|
-
|
14
|
+
sed -e 's/~/./' ./makesetup > ./makesetup.deb
|
15
|
+
chmod +x ./makesetup.deb
|
16
|
+
./makesetup.deb
|
17
|
+
#$PYEXEC -c 'import pbr' || ./makesetup
|
15
18
|
VERSION=`$PYEXEC setup.py --version`
|
16
19
|
$PYEXEC setup.py sdist
|
17
20
|
py2dsc $DSCARGS dist/pyghmi-$VERSION.tar.gz
|
@@ -21,4 +24,4 @@ dpkg-buildpackage -rfakeroot -uc -us -i
|
|
21
24
|
cd -
|
22
25
|
rm -rf $(find deb_dist -mindepth 1 -maxdepth 1 -type d)
|
23
26
|
rm $1/*pyghmi*
|
24
|
-
cp deb_dist
|
27
|
+
cp deb_dist/*.deb $1/
|
pyghmi-1.5.72/makesetup
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
cd `dirname $0`
|
3
|
+
VERSION=`git describe|cut -d- -f 1`
|
4
|
+
NUMCOMMITS=`git describe|cut -d- -f 2`
|
5
|
+
if [ "$NUMCOMMITS" != "$VERSION" ]; then
|
6
|
+
LASTNUM=$(echo $VERSION|rev|cut -d . -f 1|rev)
|
7
|
+
LASTNUM=$((LASTNUM+1))
|
8
|
+
FIRSTPART=$(echo $VERSION|rev|cut -d . -f 2- |rev)
|
9
|
+
VERSION=${FIRSTPART}.${LASTNUM}
|
10
|
+
VERSION=$VERSION~dev$NUMCOMMITS+`git describe|cut -d- -f 3`
|
11
|
+
fi
|
12
|
+
echo $VERSION > VERSION
|
13
|
+
sed -e "s/#VERSION#/$VERSION/" setup.py.tmpl > setup.py
|
14
|
+
|
@@ -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(
|
@@ -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]
|
@@ -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
|
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
|
-
|
350
|
-
|
351
|
-
|
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(
|
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(
|
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
|
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
|
-
|
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
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
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
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
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=
|
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
|
-
|
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
|
914
|
-
|
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
|
1029
|
+
def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
|
917
1030
|
raise exc.UnsupportedFunctionality()
|
918
1031
|
|
919
|
-
def
|
920
|
-
|
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
|
923
|
-
|
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
|