diff --git a/pyghmi/ipmi/command.py b/pyghmi/ipmi/command.py index 4e2b7bc3..48c5c93a 100644 --- a/pyghmi/ipmi/command.py +++ b/pyghmi/ipmi/command.py @@ -431,6 +431,10 @@ class Command(object): rsp['data'] = buffer(rsp['data']) return rsp + def get_diagnostic_data(self, savefile, progress=None): + self.oem_init() + return self._oem.get_diagnostic_data(savefile) + def get_description(self): """Get physical attributes for the system, e.g. for GUI use diff --git a/pyghmi/ipmi/oem/generic.py b/pyghmi/ipmi/oem/generic.py index 17270697..7fec0901 100644 --- a/pyghmi/ipmi/oem/generic.py +++ b/pyghmi/ipmi/oem/generic.py @@ -85,6 +85,18 @@ class OEMHandler(object): """ return () + def get_diagnostic_data(self, savefile, progress=None): + """Download diagnostic data about target to a file + + This should be a payload that the vendor's support team can use + to do diagnostics. + :param savefile: File object or filename to save to + :param progress: Callback to be informed about progress + :return: + """ + raise exc.UnsupportedFunctionality( + 'Do not know how to get diagnostic data for this platform') + def get_sensor_data(self): """Get OEM sensor data diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index ca5736bf..86a9c938 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -607,6 +607,10 @@ class OEMHandler(generic.OEMHandler): self._fpc_variant) return super(OEMHandler, self).get_oem_firmware(bmcver) + def get_diagnostic_data(self, savefile, progress): + if self.has_xcc: + return self.immhandler.get_diagnostic_data(savefile, progress) + def get_oem_capping_enabled(self): if self.has_tsm: rsp = self.ipmicmd.xraw_command(netfn=0x3a, command=0x1b, diff --git a/pyghmi/ipmi/oem/lenovo/imm.py b/pyghmi/ipmi/oem/lenovo/imm.py index ba5b1077..bdcb8cbd 100644 --- a/pyghmi/ipmi/oem/lenovo/imm.py +++ b/pyghmi/ipmi/oem/lenovo/imm.py @@ -738,6 +738,33 @@ class XCCClient(IMMClient): self._parse_storage_cfgspec(pool) return True + def get_diagnostic_data(self, savefile, progress=None): + self.wc.grab_json_response('/api/providers/ffdc', + {'Generate_FFDC': 1}) + percent = 0 + while percent != 100: + ipmisession.Session.pause(3) + result = self.wc.grab_json_response('/api/providers/ffdc', + {'Generate_FFDC_status': 1}) + self._refresh_token() + if progress: + progress({'phase': 'generate', 'progress': float(percent)}) + percent = result['progress'] + while 'FileName' not in result: + result = self.wc.grab_json_response('/api/providers/ffdc', + {'Generate_FFDC_status': 1}) + url = '/ffdc/{0}'.format(result['FileName']) + fd = webclient.FileDownloader(self.wc, url, savefile) + fd.start() + while fd.isAlive(): + fd.join(1) + if progress and self.wc.get_download_progress(): + progress({'phase': 'download', + 'progress': 100 * self.wc.get_download_progress()}) + self._refresh_token() + if progress: + progress({'phase': 'complete'}) + def _parse_array_spec(self, arrayspec): controller = None if arrayspec.disks: diff --git a/pyghmi/util/webclient.py b/pyghmi/util/webclient.py index a741b01d..e9829e19 100644 --- a/pyghmi/util/webclient.py +++ b/pyghmi/util/webclient.py @@ -59,6 +59,17 @@ class FileUploader(threading.Thread): self.formname, otherfields=self.otherfields) +class FileDownloader(threading.Thread): + + def __init__(self, webclient, url, savefile): + self.wc = webclient + self.url = url + self.savefile = savefile + super(FileDownloader, self).__init__() + + def run(self): + self.wc.download(self.url, self.savefile) + def get_upload_form(filename, data, formname, otherfields): if not formname: formname = filename @@ -154,6 +165,28 @@ class SecureHTTPConnection(httplib.HTTPConnection, object): rsp.read() return {} + def download(self, url, file): + """Download a file to filename or file object + + """ + if isinstance(file, str) or isinstance(file, unicode): + file = open(file, 'wb') + webclient = self.dupe() + webclient.request('GET', url) + rsp = webclient.getresponse() + self._currdl = rsp + self._dlfile = file + for chunk in iter(lambda: rsp.read(16384), ''): + file.write(chunk) + self._currdl = None + file.close() + + def get_download_progress(self): + if not self._currdl: + return None + return float(self._dlfile.tell()) / float( + self._currdl.getheader('content-length')) + def upload(self, url, filename, data=None, formname=None, otherfields=()): """Upload a file to the url