diff --git a/pyghmi/ipmi/command.py b/pyghmi/ipmi/command.py index 1d137a71..0c897c67 100644 --- a/pyghmi/ipmi/command.py +++ b/pyghmi/ipmi/command.py @@ -1790,14 +1790,14 @@ class Command(object): self.set_user_password(uid, mode) return True - def get_firmware(self): + def get_firmware(self, components=()): """Retrieve OEM Firmware information """ self.oem_init() mcinfo = self.xraw_command(netfn=6, command=1) bmcver = '{0}.{1}'.format( ord(mcinfo['data'][2]), hex(ord(mcinfo['data'][3]))[2:]) - return self._oem.get_oem_firmware(bmcver) + return self._oem.get_oem_firmware(bmcver, components) def get_capping_enabled(self): """Get PSU based power capping status diff --git a/pyghmi/ipmi/oem/generic.py b/pyghmi/ipmi/oem/generic.py index a3f047e2..cbdbde16 100644 --- a/pyghmi/ipmi/oem/generic.py +++ b/pyghmi/ipmi/oem/generic.py @@ -159,12 +159,18 @@ class OEMHandler(object): fru['oem_parser'] = None return fru - def get_oem_firmware(self, bmcver): + def get_oem_firmware(self, bmcver, components): """Get Firmware information. """ # Here the bmc version is passed into the OEM handler, to allow # the handler to enrich the data. For the generic case, just # provide the generic BMC version, which is all that is possible + # Additionally, components may be provided for an advisory guide + # on interesting firmware. The OEM library is permitted to return + # more than requested, and it is the responsibility of the calling + # code to know whether it cares or not. The main purpose of the + # components argument is to indicate when certain performance + # optimizations can be performed. yield ('BMC Version', {'version': bmcver}) def get_oem_capping_enabled(self): diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index f3b776db..bc28f900 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -595,13 +595,13 @@ class OEMHandler(generic.OEMHandler): self._hasimm = (rdata[1] & 1 == 1) or (rdata[1] & 16 == 16) return self._hasimm - def get_oem_firmware(self, bmcver): + def get_oem_firmware(self, bmcver, components): if self.has_tsm: command = firmware.get_categories()["firmware"] rsp = self.ipmicmd.xraw_command(**command["command"]) return command["parser"](rsp["data"]) elif self.has_imm: - return self.immhandler.get_firmware_inventory(bmcver) + return self.immhandler.get_firmware_inventory(bmcver, components) elif self.is_fpc: return nextscale.get_fpc_firmware(bmcver, self.ipmicmd, self._fpc_variant) diff --git a/pyghmi/ipmi/oem/lenovo/imm.py b/pyghmi/ipmi/oem/lenovo/imm.py index 190d14b1..dacea248 100644 --- a/pyghmi/ipmi/oem/lenovo/imm.py +++ b/pyghmi/ipmi/oem/lenovo/imm.py @@ -469,55 +469,63 @@ class IMMClient(object): self.weblogout() return hwmap - def get_firmware_inventory(self, bmcver): + def get_firmware_inventory(self, bmcver, components): # First we fetch the system firmware found in imm properties # then check for agentless, if agentless, get adapter info using # https, using the caller TLS verification scheme - rsp = self.ipmicmd.xraw_command(netfn=0x3a, command=0x50) - immverdata = self.parse_imm_buildinfo(rsp['data']) - bdata = { - 'version': bmcver, 'build': immverdata[0], 'date': immverdata[1]} - yield (self.bmcname, bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/dm/fw/imm2/backup_build_id', - 'version': '/v2/ibmc/dm/fw/imm2/backup_build_version', - 'date': '/v2/ibmc/dm/fw/imm2/backup_build_date'}) - if bdata: - yield ('{0} Backup'.format(self.bmcname), bdata) + components = set(components) + if not components or set(('imm', 'xcc', 'bmc', 'core')) & components: + rsp = self.ipmicmd.xraw_command(netfn=0x3a, command=0x50) + immverdata = self.parse_imm_buildinfo(rsp['data']) + bdata = { + 'version': bmcver, 'build': immverdata[0], + 'date': immverdata[1]} + yield (self.bmcname, bdata) bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/trusted_buildid', - }) - if bdata: - yield ('{0} Trusted Image'.format(self.bmcname), bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/bios/build_id', - 'version': '/v2/bios/build_version', - 'date': '/v2/bios/build_date'}) - if bdata: - yield ('UEFI', bdata) - else: - yield ('UEFI', {'version': 'unknown'}) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/dm/fw/bios/backup_build_id', - 'version': '/v2/ibmc/dm/fw/bios/backup_build_version'}) - if bdata: - yield ('UEFI Backup', bdata) - # Note that the next pending could be pending for either primary - # or backup, so can't promise where it will go - bdata = self.fetch_grouped_properties({ - 'build': '/v2/bios/pending_build_id'}) - if bdata: - yield ('UEFI Pending Update', bdata) - try: - fpga = self.ipmicmd.xraw_command(netfn=0x3a, command=0x6b, - data=(0,)) - fpga = '{0}.{1}.{2}'.format(*[ord(x) for x in fpga['data']]) - yield ('FPGA', {'version': fpga}) - except pygexc.IpmiException as ie: - if ie.ipmicode != 193: - raise - for firm in self.fetch_agentless_firmware(): - yield firm + 'build': '/v2/ibmc/dm/fw/imm2/backup_build_id', + 'version': '/v2/ibmc/dm/fw/imm2/backup_build_version', + 'date': '/v2/ibmc/dm/fw/imm2/backup_build_date'}) + if bdata: + yield ('{0} Backup'.format(self.bmcname), bdata) + bdata = self.fetch_grouped_properties({ + 'build': '/v2/ibmc/trusted_buildid', + }) + if bdata: + yield ('{0} Trusted Image'.format(self.bmcname), bdata) + if not components or set(('uefi', 'bios', 'core')) & components: + bdata = self.fetch_grouped_properties({ + 'build': '/v2/bios/build_id', + 'version': '/v2/bios/build_version', + 'date': '/v2/bios/build_date'}) + if bdata: + yield ('UEFI', bdata) + else: + yield ('UEFI', {'version': 'unknown'}) + bdata = self.fetch_grouped_properties({ + 'build': '/v2/ibmc/dm/fw/bios/backup_build_id', + 'version': '/v2/ibmc/dm/fw/bios/backup_build_version'}) + if bdata: + yield ('UEFI Backup', bdata) + # Note that the next pending could be pending for either primary + # or backup, so can't promise where it will go + bdata = self.fetch_grouped_properties({ + 'build': '/v2/bios/pending_build_id'}) + if bdata: + yield ('UEFI Pending Update', bdata) + if not components or set(('fpga', 'core')) & components: + try: + fpga = self.ipmicmd.xraw_command(netfn=0x3a, command=0x6b, + data=(0,)) + fpga = '{0}.{1}.{2}'.format(*[ord(x) for x in fpga['data']]) + yield ('FPGA', {'version': fpga}) + except pygexc.IpmiException as ie: + if ie.ipmicode != 193: + raise + if (not components or (components - set(( + 'core', 'uefi', 'bios', 'bmc', 'xcc', 'imm', 'fpga', + 'lxpm')))): + for firm in self.fetch_agentless_firmware(): + yield firm class XCCClient(IMMClient): @@ -883,85 +891,95 @@ class XCCClient(IMMClient): def keepalive(self): self._refresh_token_wc(self._keepalivesession) - def get_firmware_inventory(self, bmcver): + def get_firmware_inventory(self, bmcver, components): # First we fetch the system firmware found in imm properties # then check for agentless, if agentless, get adapter info using # https, using the caller TLS verification scheme - rsp = self.ipmicmd.xraw_command(netfn=0x3a, command=0x50) - immverdata = self.parse_imm_buildinfo(rsp['data']) - bdata = { - 'version': bmcver, 'build': immverdata[0], 'date': immverdata[1]} - yield (self.bmcname, bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/dm/fw/imm3/backup_pending_build_id', - 'version': '/v2/ibmc/dm/fw/imm3/backup_pending_build_version', - 'date': '/v2/ibmc/dm/fw/imm3/backup_pending_build_date'}) - if bdata: - yield ('{0} Backup'.format(self.bmcname), bdata) - else: + components = set(components) + if (not components or + set(('core', 'imm', 'bmc', 'xcc')) & components): + rsp = self.ipmicmd.xraw_command(netfn=0x3a, command=0x50) + immverdata = self.parse_imm_buildinfo(rsp['data']) + bdata = {'version': bmcver, + 'build': immverdata[0], + 'date': immverdata[1]} + yield (self.bmcname, bdata) bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/dm/fw/imm3/backup_build_id', - 'version': '/v2/ibmc/dm/fw/imm3/backup_build_version', - 'date': '/v2/ibmc/dm/fw/imm3/backup_build_date'}) + 'build': '/v2/ibmc/dm/fw/imm3/backup_pending_build_id', + 'version': '/v2/ibmc/dm/fw/imm3/backup_pending_build_version', + 'date': '/v2/ibmc/dm/fw/imm3/backup_pending_build_date'}) if bdata: yield ('{0} Backup'.format(self.bmcname), bdata) + else: + bdata = self.fetch_grouped_properties({ + 'build': '/v2/ibmc/dm/fw/imm3/backup_build_id', + 'version': '/v2/ibmc/dm/fw/imm3/backup_build_version', + 'date': '/v2/ibmc/dm/fw/imm3/backup_build_date'}) + if bdata: + yield ('{0} Backup'.format(self.bmcname), bdata) + bdata = self.fetch_grouped_properties({ + 'build': '/v2/ibmc/trusted_buildid', + }) + if bdata: bdata = self.fetch_grouped_properties({ 'build': '/v2/ibmc/trusted_buildid', }) - if bdata: + if bdata: + yield ('{0} Trusted Image'.format(self.bmcname), bdata) bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/trusted_buildid', + 'build': '/v2/ibmc/dm/fw/imm3/primary_pending_build_id', + 'version': '/v2/ibmc/dm/fw/imm3/primary_pending_build_version', + 'date': '/v2/ibmc/dm/fw/imm3/primary_pending_build_date'}) + if bdata: + yield ('{0} Pending Update'.format(self.bmcname), bdata) + if (not components or set(('core', 'uefi', 'bios')) & components): + bdata = self.fetch_grouped_properties({ + 'build': '/v2/bios/build_id', + 'version': '/v2/bios/build_version', + 'date': '/v2/bios/build_date'}) + if bdata: + yield ('UEFI', bdata) + # Note that the next pending could be pending for either primary + # or backup, so can't promise where it will go + bdata = self.fetch_grouped_properties({ + 'build': '/v2/bios/pending_build_id'}) + if bdata: + yield ('UEFI Pending Update', bdata) + if not components or set(('lxpm', 'core')) & components: + bdata = self.fetch_grouped_properties({ + 'build': '/v2/tdm/build_id', + 'version': '/v2/tdm/build_version', + 'date': '/v2/tdm/build_date'}) + if bdata: + yield ('LXPM', bdata) + bdata = self.fetch_grouped_properties({ + 'build': '/v2/drvwn/build_id', + 'version': '/v2/drvwn/build_version', + 'date': '/v2/drvwn/build_date', }) - if bdata: - yield ('{0} Trusted Image'.format(self.bmcname), bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/ibmc/dm/fw/imm3/primary_pending_build_id', - 'version': '/v2/ibmc/dm/fw/imm3/primary_pending_build_version', - 'date': '/v2/ibmc/dm/fw/imm3/primary_pending_build_date'}) - if bdata: - yield ('{0} Pending Update'.format(self.bmcname), bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/bios/build_id', - 'version': '/v2/bios/build_version', - 'date': '/v2/bios/build_date'}) - if bdata: - yield ('UEFI', bdata) - # Note that the next pending could be pending for either primary - # or backup, so can't promise where it will go - bdata = self.fetch_grouped_properties({ - 'build': '/v2/bios/pending_build_id'}) - if bdata: - yield ('UEFI Pending Update', bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/tdm/build_id', - 'version': '/v2/tdm/build_version', - 'date': '/v2/tdm/build_date'}) - if bdata: - yield ('LXPM', bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/drvwn/build_id', - 'version': '/v2/drvwn/build_version', - 'date': '/v2/drvwn/build_date', - }) - if bdata: - yield ('LXPM Windows Driver Bundle', bdata) - bdata = self.fetch_grouped_properties({ - 'build': '/v2/drvln/build_id', - 'version': '/v2/drvln/build_version', - 'date': '/v2/drvln/build_date', - }) - if bdata: - yield ('LXPM Linux Driver Bundle', bdata) - try: - fpga = self.ipmicmd.xraw_command(netfn=0x3a, command=0x6b, - data=(0,)) - fpga = '{0}.{1}.{2}'.format(*[ord(x) for x in fpga['data']]) - yield ('FPGA', {'version': fpga}) - except pygexc.IpmiException as ie: - if ie.ipmicode != 193: - raise - for firm in self.fetch_agentless_firmware(): - yield firm + if bdata: + yield ('LXPM Windows Driver Bundle', bdata) + bdata = self.fetch_grouped_properties({ + 'build': '/v2/drvln/build_id', + 'version': '/v2/drvln/build_version', + 'date': '/v2/drvln/build_date', + }) + if bdata: + yield ('LXPM Linux Driver Bundle', bdata) + if not components or set(('core', 'fpga')) in components: + try: + fpga = self.ipmicmd.xraw_command(netfn=0x3a, command=0x6b, + data=(0,)) + fpga = '{0}.{1}.{2}'.format(*[ord(x) for x in fpga['data']]) + yield ('FPGA', {'version': fpga}) + except pygexc.IpmiException as ie: + if ie.ipmicode != 193: + raise + if (not components or components - set(( + 'core', 'uefi', 'bios', 'xcc', 'bmc', 'imm', 'fpga', + 'lxpm'))): + for firm in self.fetch_agentless_firmware(): + yield firm def detach_remote_media(self): if self.webkeepalive: