1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

[PR #8444/feb1ecbf backport][stable-9] Fix to handle Redfish Gen2 Firmware upgrade (#8601)

Fix to handle Redfish Gen2 Firmware upgrade (#8444)

* Fix to handle Redfish Gen2 Firmware upgrade

* Fixed sanity checks and unit test cases

* Added change log gragment

* Updated change log fragment

* Updated review comments

---------

Co-authored-by: Adarsh Manjunath <adarsh.manjunath@wdc.com>
(cherry picked from commit feb1ecbfcd)

Co-authored-by: cmadarsh <53748644+cmadarsh@users.noreply.github.com>
This commit is contained in:
patchback[bot] 2024-07-08 22:25:30 +02:00 committed by GitHub
parent f6349578c6
commit b0af1e9c75
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 12 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- wdc_redfish_command - minor change to handle upgrade file for Redfish WD platforms (https://github.com/ansible-collections/community.general/pull/8444).

View file

@ -11,6 +11,7 @@ import datetime
import re import re
import time import time
import tarfile import tarfile
import os
from ansible.module_utils.urls import fetch_file from ansible.module_utils.urls import fetch_file
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
@ -79,19 +80,25 @@ class WdcRedfishUtils(RedfishUtils):
return response return response
return self._find_updateservice_additional_uris() return self._find_updateservice_additional_uris()
def _is_enclosure_multi_tenant(self): def _is_enclosure_multi_tenant_and_fetch_gen(self):
"""Determine if the enclosure is multi-tenant. """Determine if the enclosure is multi-tenant.
The serial number of a multi-tenant enclosure will end in "-A" or "-B". The serial number of a multi-tenant enclosure will end in "-A" or "-B".
Fetching enclsoure generation.
:return: True/False if the enclosure is multi-tenant or not; None if unable to determine. :return: True/False if the enclosure is multi-tenant or not and return enclosure generation;
None if unable to determine.
""" """
response = self.get_request(self.root_uri + self.service_root + "Chassis/Enclosure") response = self.get_request(self.root_uri + self.service_root + "Chassis/Enclosure")
if response['ret'] is False: if response['ret'] is False:
return None return None
pattern = r".*-[A,B]" pattern = r".*-[A,B]"
data = response['data'] data = response['data']
return re.match(pattern, data['SerialNumber']) is not None if 'EnclVersion' not in data:
enc_version = 'G1'
else:
enc_version = data['EnclVersion']
return re.match(pattern, data['SerialNumber']) is not None, enc_version
def _find_updateservice_additional_uris(self): def _find_updateservice_additional_uris(self):
"""Find & set WDC-specific update service URIs""" """Find & set WDC-specific update service URIs"""
@ -180,15 +187,44 @@ class WdcRedfishUtils(RedfishUtils):
To determine if the bundle is multi-tenant or not, it looks inside the .bin file within the tarfile, To determine if the bundle is multi-tenant or not, it looks inside the .bin file within the tarfile,
and checks the appropriate byte in the file. and checks the appropriate byte in the file.
If not tarfile, the bundle is checked for 2048th byte to determine whether it is Gen2 bundle.
Gen2 is always single tenant at this time.
:param str bundle_uri: HTTP URI of the firmware bundle. :param str bundle_uri: HTTP URI of the firmware bundle.
:return: Firmware version number contained in the bundle, and whether or not the bundle is multi-tenant. :return: Firmware version number contained in the bundle, whether or not the bundle is multi-tenant
Either value will be None if unable to determine. and bundle generation. Either value will be None if unable to determine.
:rtype: str or None, bool or None :rtype: str or None, bool or None
""" """
bundle_temp_filename = fetch_file(module=self.module, bundle_temp_filename = fetch_file(module=self.module,
url=bundle_uri) url=bundle_uri)
bundle_version = None
is_multi_tenant = None
gen = None
# If not tarfile, then if the file has "MMG2" or "DPG2" at 2048th byte
# then the bundle is for MM or DP G2
if not tarfile.is_tarfile(bundle_temp_filename): if not tarfile.is_tarfile(bundle_temp_filename):
return None, None cookie1 = None
with open(bundle_temp_filename, "rb") as bundle_file:
file_size = os.path.getsize(bundle_temp_filename)
if file_size >= 2052:
bundle_file.seek(2048)
cookie1 = bundle_file.read(4)
# It is anticipated that DP firmware bundle will be having the value "DPG2"
# for cookie1 in the header
if cookie1 and cookie1.decode("utf8") == "MMG2" or cookie1.decode("utf8") == "DPG2":
file_name, ext = os.path.splitext(str(bundle_uri.rsplit('/', 1)[1]))
# G2 bundle file name: Ultrastar-Data102_3000_SEP_1010-032_2.1.12
parsedFileName = file_name.split('_')
if len(parsedFileName) == 5:
bundle_version = parsedFileName[4]
# MM G2 is always single tanant
is_multi_tenant = False
gen = "G2"
return bundle_version, is_multi_tenant, gen
# Bundle is for MM or DP G1
tf = tarfile.open(bundle_temp_filename) tf = tarfile.open(bundle_temp_filename)
pattern_pkg = r"oobm-(.+)\.pkg" pattern_pkg = r"oobm-(.+)\.pkg"
pattern_bin = r"(.*\.bin)" pattern_bin = r"(.*\.bin)"
@ -205,8 +241,9 @@ class WdcRedfishUtils(RedfishUtils):
bin_file.seek(11) bin_file.seek(11)
byte_11 = bin_file.read(1) byte_11 = bin_file.read(1)
is_multi_tenant = byte_11 == b'\x80' is_multi_tenant = byte_11 == b'\x80'
gen = "G1"
return bundle_version, is_multi_tenant return bundle_version, is_multi_tenant, gen
@staticmethod @staticmethod
def uri_is_http(uri): def uri_is_http(uri):
@ -267,15 +304,16 @@ class WdcRedfishUtils(RedfishUtils):
# Check the FW version in the bundle file, and compare it to what is already on the IOMs # Check the FW version in the bundle file, and compare it to what is already on the IOMs
# Bundle version number # Bundle version number
bundle_firmware_version, is_bundle_multi_tenant = self._get_bundle_version(bundle_uri) bundle_firmware_version, is_bundle_multi_tenant, bundle_gen = self._get_bundle_version(bundle_uri)
if bundle_firmware_version is None or is_bundle_multi_tenant is None: if bundle_firmware_version is None or is_bundle_multi_tenant is None or bundle_gen is None:
return { return {
'ret': False, 'ret': False,
'msg': 'Unable to extract bundle version or multi-tenant status from update image tarfile' 'msg': 'Unable to extract bundle version or multi-tenant status or generation from update image file'
} }
is_enclosure_multi_tenant, enclosure_gen = self._is_enclosure_multi_tenant_and_fetch_gen()
# Verify that the bundle is correctly multi-tenant or not # Verify that the bundle is correctly multi-tenant or not
is_enclosure_multi_tenant = self._is_enclosure_multi_tenant()
if is_enclosure_multi_tenant != is_bundle_multi_tenant: if is_enclosure_multi_tenant != is_bundle_multi_tenant:
return { return {
'ret': False, 'ret': False,
@ -285,6 +323,16 @@ class WdcRedfishUtils(RedfishUtils):
) )
} }
# Verify that the bundle is compliant with the target enclosure
if enclosure_gen != bundle_gen:
return {
'ret': False,
'msg': 'Enclosure generation is {0} but bundle is of {1}'.format(
enclosure_gen,
bundle_gen,
)
}
# Version number installed on IOMs # Version number installed on IOMs
firmware_inventory = self.get_firmware_inventory() firmware_inventory = self.get_firmware_inventory()
if not firmware_inventory["ret"]: if not firmware_inventory["ret"]:

View file

@ -289,7 +289,7 @@ def mock_get_firmware_inventory_version_1_2_3(*args, **kwargs):
} }
ERROR_MESSAGE_UNABLE_TO_EXTRACT_BUNDLE_VERSION = "Unable to extract bundle version or multi-tenant status from update image tarfile" ERROR_MESSAGE_UNABLE_TO_EXTRACT_BUNDLE_VERSION = "Unable to extract bundle version or multi-tenant status or generation from update image file"
ACTION_WAS_SUCCESSFUL_MESSAGE = "Action was successful" ACTION_WAS_SUCCESSFUL_MESSAGE = "Action was successful"