Skip to content

Commit

Permalink
Fix to handle Redfish Gen2 Firmware upgrade (#8444)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
(cherry picked from commit feb1ecb)
  • Loading branch information
cmadarsh authored and patchback[bot] committed Jul 8, 2024
1 parent 7111772 commit 5a25a7b
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 12 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/8444-fix-redfish-gen2-upgrade.yaml
Original file line number Diff line number Diff line change
@@ -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).
70 changes: 59 additions & 11 deletions plugins/module_utils/wdc_redfish_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import re
import time
import tarfile
import os

from ansible.module_utils.urls import fetch_file
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
Expand Down Expand Up @@ -79,19 +80,25 @@ def _find_updateservice_resource(self):
return response
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.
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")
if response['ret'] is False:
return None
pattern = r".*-[A,B]"
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):
"""Find & set WDC-specific update service URIs"""
Expand Down Expand Up @@ -180,15 +187,44 @@ def _get_bundle_version(self,
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.
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.
:return: Firmware version number contained in the bundle, and whether or not the bundle is multi-tenant.
Either value will be None if unable to determine.
:return: Firmware version number contained in the bundle, whether or not the bundle is multi-tenant
and bundle generation. Either value will be None if unable to determine.
:rtype: str or None, bool or None
"""
bundle_temp_filename = fetch_file(module=self.module,
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):
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)
pattern_pkg = r"oobm-(.+)\.pkg"
pattern_bin = r"(.*\.bin)"
Expand All @@ -205,8 +241,9 @@ def _get_bundle_version(self,
bin_file.seek(11)
byte_11 = bin_file.read(1)
is_multi_tenant = byte_11 == b'\x80'
gen = "G1"

return bundle_version, is_multi_tenant
return bundle_version, is_multi_tenant, gen

@staticmethod
def uri_is_http(uri):
Expand Down Expand Up @@ -267,15 +304,16 @@ def update_and_activate(self, update_opts):
# Check the FW version in the bundle file, and compare it to what is already on the IOMs

# Bundle version number
bundle_firmware_version, is_bundle_multi_tenant = self._get_bundle_version(bundle_uri)
if bundle_firmware_version is None or is_bundle_multi_tenant is None:
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 or bundle_gen is None:
return {
'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
is_enclosure_multi_tenant = self._is_enclosure_multi_tenant()
if is_enclosure_multi_tenant != is_bundle_multi_tenant:
return {
'ret': False,
Expand All @@ -285,6 +323,16 @@ def update_and_activate(self, update_opts):
)
}

# 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
firmware_inventory = self.get_firmware_inventory()
if not firmware_inventory["ret"]:
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/plugins/modules/test_wdc_redfish_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"


Expand Down

0 comments on commit 5a25a7b

Please sign in to comment.