From 5b478635927e588ea4d80cef5b43ed7e1d01e37e Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 27 Aug 2024 09:32:21 -0400 Subject: [PATCH] Add generic redfish license handling Use redfish standard mechanism for generic and starting point for redfish OEM support. Change-Id: I6ae8939c5b8f3a15a9b941a5a81f60438e7aa005 --- pyghmi/redfish/command.py | 8 ++--- pyghmi/redfish/oem/generic.py | 59 +++++++++++++++++++++++++++----- pyghmi/redfish/oem/lenovo/xcc.py | 10 +++--- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/pyghmi/redfish/command.py b/pyghmi/redfish/command.py index aa8c0cb6..76043c00 100644 --- a/pyghmi/redfish/command.py +++ b/pyghmi/redfish/command.py @@ -1421,20 +1421,20 @@ class Command(object): return self.oem.get_diagnostic_data(savefile, progress, autosuffix) def get_licenses(self): - return self.oem.get_licenses() + return self.oem.get_licenses(self) def delete_license(self, name): - return self.oem.delete_license(name) + return self.oem.delete_license(name, self) def save_licenses(self, directory): if os.path.exists(directory) and not os.path.isdir(directory): raise exc.InvalidParameterValue( 'Not allowed to overwrite existing file: {0}'.format( directory)) - return self.oem.save_licenses(directory) + return self.oem.save_licenses(directory, self) def apply_license(self, filename, progress=None, data=None): - return self.oem.apply_license(filename, progress, data) + return self.oem.apply_license(filename, self, progress, data) if __name__ == '__main__': diff --git a/pyghmi/redfish/oem/generic.py b/pyghmi/redfish/oem/generic.py index 8b251e1a..57648f3e 100644 --- a/pyghmi/redfish/oem/generic.py +++ b/pyghmi/redfish/oem/generic.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import base64 from fnmatch import fnmatch import json import os @@ -982,17 +983,59 @@ class OEMHandler(object): raise exc.UnsupportedFunctionality( 'Retrieving diagnostic data is not implemented for this platform') - def get_licenses(self): - raise exc.UnsupportedFunctionality() + def _get_license_collection_url(self, fishclient): + overview = fishclient._do_web_request('/redfish/v1/') + licsrv = overview.get('LicenseService', {}).get('@odata.id', None) + if not licsrv: + raise exc.UnsupportedFunctionality() + lcs = fishclient._do_web_request(licsrv) + licenses = lcs.get('Licenses', {}).get('@odata.id',None) + if not licenses: + raise exc.UnsupportedFunctionality() + return licenses - def delete_license(self, name): - raise exc.UnsupportedFunctionality() + def _get_licenses(self, fishclient): + licenses = self._get_license_collection_url(fishclient) + collection = fishclient._do_web_request(licenses) + alllic = [x['@odata.id'] for x in collection.get('Members', [])] + for license in alllic: + licdet = fishclient._do_web_request(license) + state = licdet.get('Status', {}).get('State') + if state != 'Enabled': + continue + yield licdet - def save_licenses(self, directory): - raise exc.UnsupportedFunctionality() + def get_licenses(self, fishclient): + for licdet in self._get_licenses(fishclient): + name = licdet['Name'] + yield {'name': name, 'state': 'Active'} - def apply_license(self, filename, progress=None, data=None): - raise exc.UnsupportedFunctionality() + def delete_license(self, name, fishclient): + for licdet in self._get_licenses(fishclient): + lname = licdet['Name'] + if name == lname: + fishclient._do_web_request(licdet['@odata.id'], method='DELETE') + + def save_licenses(self, directory, fishclient): + for licdet in self._get_licenses(fishclient): + dload = licdet.get('DownloadURI', None) + if dload: + filename = os.path.basename(dload) + savefile = os.path.join(directory, filename) + fd = webclient.FileDownloader(fishclient.wc, dload, savefile) + fd.start() + while fd.isAlive(): + fd.join(1) + yield savefile + + def apply_license(self, filename, fishclient, progress=None, data=None): + licenses = self._get_license_collection_url(fishclient) + if data is None: + data = open(filename, 'rb') + licdata = data.read() + lic64 = base64.b64encode(licdata).decode() + licinfo = {"LicenseString": lic64} + fishclient._do_web_request(licenses, licinfo) def get_user_expiration(self, uid): return None diff --git a/pyghmi/redfish/oem/lenovo/xcc.py b/pyghmi/redfish/oem/lenovo/xcc.py index 2d883834..6dd7ac37 100644 --- a/pyghmi/redfish/oem/lenovo/xcc.py +++ b/pyghmi/redfish/oem/lenovo/xcc.py @@ -1553,7 +1553,7 @@ class OEMHandler(generic.OEMHandler): progress({'phase': 'complete'}) return savefile - def get_licenses(self): + def get_licenses(self, fishclient): licdata = self.wc.grab_json_response('/api/providers/imm_fod') for lic in licdata.get('items', [{}])[0].get('keys', []): if lic['status'] == 0: @@ -1564,7 +1564,7 @@ class OEMHandler(generic.OEMHandler): 'state': 'Missing required license' } - def delete_license(self, name): + def delete_license(self, name, fishclient): licdata = self.wc.grab_json_response('/api/providers/imm_fod') for lic in licdata.get('items', [{}])[0].get('keys', []): if lic.get('feature', None) == name: @@ -1577,7 +1577,7 @@ class OEMHandler(generic.OEMHandler): ) break - def save_licenses(self, directory): + def save_licenses(self, directory, fishclient): licdata = self.wc.grab_json_response('/api/providers/imm_fod') for lic in licdata.get('items', [{}])[0].get('keys', []): licid = ','.join((str(lic['type']), str(lic['id']))) @@ -1594,7 +1594,7 @@ class OEMHandler(generic.OEMHandler): self._refresh_token() yield savefile - def apply_license(self, filename, progress=None, data=None): + def apply_license(self, filename, fishclient, progress=None, data=None): license_errors = { 310: "License is for a different model of system", 311: "License is for a different system serial number", @@ -1618,7 +1618,7 @@ class OEMHandler(generic.OEMHandler): if rsp.get('return', 0) in license_errors: raise pygexc.InvalidParameterValue( license_errors[rsp['return']]) - return self.get_licenses() + return self.get_licenses(fishclient) def user_delete(self, uid): userinfo = self.wc.grab_json_response('/api/dataset/imm_users')