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

Update redfish module for compatibility with VirtualMedia resource location (#5124)

* Update redfish module for compatibility with VirtualMedia resource location from Manager to Systems

* Add changelogs fragments for PR 5124

* Update some issue according to the suggestions

* update changelogs fragment to list new features in the minor_changes catagory

Co-authored-by: Tami YY3 Pan <panyy3@lenovo.com>
This commit is contained in:
jixj5 2022-08-25 03:36:35 +08:00 committed by GitHub
parent 57e1e2bd8e
commit 766c109d47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 18 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- redfish - added new command GetVirtualMedia, VirtualMediaInsert and VirtualMediaEject to Systems category due to Redfish spec changes the virtualMedia resource location from Manager to System (https://github.com/ansible-collections/community.general/pull/5124).

View file

@ -202,6 +202,16 @@ class RedfishUtils(object):
def _init_session(self): def _init_session(self):
pass pass
def _get_vendor(self):
response = self.get_request(self.root_uri + self.service_root)
if response['ret'] is False:
return {'ret': False, 'Vendor': ''}
data = response['data']
if 'Vendor' in data:
return {'ret': True, 'Vendor': data["Vendor"]}
else:
return {'ret': True, 'Vendor': ''}
def _find_accountservice_resource(self): def _find_accountservice_resource(self):
response = self.get_request(self.root_uri + self.service_root) response = self.get_request(self.root_uri + self.service_root)
if response['ret'] is False: if response['ret'] is False:
@ -2162,11 +2172,15 @@ class RedfishUtils(object):
result["entries"] = virtualmedia_results result["entries"] = virtualmedia_results
return result return result
def get_multi_virtualmedia(self): def get_multi_virtualmedia(self, resource_type='Manager'):
ret = True ret = True
entries = [] entries = []
resource_uris = self.manager_uris # Given resource_type, use the proper URI
if resource_type == 'Systems':
resource_uris = self.systems_uris
elif resource_type == 'Manager':
resource_uris = self.manager_uris
for resource_uri in resource_uris: for resource_uri in resource_uris:
virtualmedia = self.get_virtualmedia(resource_uri) virtualmedia = self.get_virtualmedia(resource_uri)
@ -2178,7 +2192,7 @@ class RedfishUtils(object):
@staticmethod @staticmethod
def _find_empty_virt_media_slot(resources, media_types, def _find_empty_virt_media_slot(resources, media_types,
media_match_strict=True): media_match_strict=True, vendor=''):
for uri, data in resources.items(): for uri, data in resources.items():
# check MediaTypes # check MediaTypes
if 'MediaTypes' in data and media_types: if 'MediaTypes' in data and media_types:
@ -2187,8 +2201,12 @@ class RedfishUtils(object):
else: else:
if media_match_strict: if media_match_strict:
continue continue
# if ejected, 'Inserted' should be False # Base on current Lenovo server capability, filter out slot RDOC1/2 and Remote1/2/3/4 which are not supported to Insert/Eject.
if (not data.get('Inserted', False)): if vendor == 'Lenovo' and ('RDOC' in uri or 'Remote' in uri):
continue
# if ejected, 'Inserted' should be False and 'ImageName' cleared
if (not data.get('Inserted', False) and
not data.get('ImageName')):
return uri, data return uri, data
return None, None return None, None
@ -2262,7 +2280,7 @@ class RedfishUtils(object):
return response return response
return {'ret': True, 'changed': True, 'msg': "VirtualMedia inserted"} return {'ret': True, 'changed': True, 'msg': "VirtualMedia inserted"}
def virtual_media_insert(self, options): def virtual_media_insert(self, options, resource_type='Manager'):
param_map = { param_map = {
'Inserted': 'inserted', 'Inserted': 'inserted',
'WriteProtected': 'write_protected', 'WriteProtected': 'write_protected',
@ -2279,7 +2297,12 @@ class RedfishUtils(object):
media_types = options.get('media_types') media_types = options.get('media_types')
# locate and read the VirtualMedia resources # locate and read the VirtualMedia resources
response = self.get_request(self.root_uri + self.manager_uri) # Given resource_type, use the proper URI
if resource_type == 'Systems':
resource_uri = self.systems_uri
elif resource_type == 'Manager':
resource_uri = self.manager_uri
response = self.get_request(self.root_uri + resource_uri)
if response['ret'] is False: if response['ret'] is False:
return response return response
data = response['data'] data = response['data']
@ -2288,7 +2311,7 @@ class RedfishUtils(object):
# Some hardware (such as iLO 4) only supports the Image property on the PATCH operation # Some hardware (such as iLO 4) only supports the Image property on the PATCH operation
# Inserted and WriteProtected are not writable # Inserted and WriteProtected are not writable
if data["FirmwareVersion"].startswith("iLO 4"): if "FirmwareVersion" in data and data["FirmwareVersion"].startswith("iLO 4"):
image_only = True image_only = True
# Supermicro does also not support Inserted and WriteProtected # Supermicro does also not support Inserted and WriteProtected
@ -2315,12 +2338,13 @@ class RedfishUtils(object):
# find an empty slot to insert the media # find an empty slot to insert the media
# try first with strict media_type matching # try first with strict media_type matching
vendor = self._get_vendor()['Vendor']
uri, data = self._find_empty_virt_media_slot( uri, data = self._find_empty_virt_media_slot(
resources, media_types, media_match_strict=True) resources, media_types, media_match_strict=True, vendor=vendor)
if not uri: if not uri:
# if not found, try without strict media_type matching # if not found, try without strict media_type matching
uri, data = self._find_empty_virt_media_slot( uri, data = self._find_empty_virt_media_slot(
resources, media_types, media_match_strict=False) resources, media_types, media_match_strict=False, vendor=vendor)
if not uri: if not uri:
return {'ret': False, return {'ret': False,
'msg': "Unable to find an available VirtualMedia resource " 'msg': "Unable to find an available VirtualMedia resource "
@ -2378,14 +2402,19 @@ class RedfishUtils(object):
return {'ret': True, 'changed': True, return {'ret': True, 'changed': True,
'msg': "VirtualMedia ejected"} 'msg': "VirtualMedia ejected"}
def virtual_media_eject(self, options): def virtual_media_eject(self, options, resource_type='Manager'):
image_url = options.get('image_url') image_url = options.get('image_url')
if not image_url: if not image_url:
return {'ret': False, return {'ret': False,
'msg': "image_url option required for VirtualMediaEject"} 'msg': "image_url option required for VirtualMediaEject"}
# locate and read the VirtualMedia resources # locate and read the VirtualMedia resources
response = self.get_request(self.root_uri + self.manager_uri) # Given resource_type, use the proper URI
if resource_type == 'Systems':
resource_uri = self.systems_uri
elif resource_type == 'Manager':
resource_uri = self.manager_uri
response = self.get_request(self.root_uri + resource_uri)
if response['ret'] is False: if response['ret'] is False:
return response return response
data = response['data'] data = response['data']
@ -2395,7 +2424,7 @@ class RedfishUtils(object):
# Some hardware (such as iLO 4) only supports the Image property on the PATCH operation # Some hardware (such as iLO 4) only supports the Image property on the PATCH operation
# Inserted is not writable # Inserted is not writable
image_only = False image_only = False
if data["FirmwareVersion"].startswith("iLO 4"): if "FirmwareVersion" in data and data["FirmwareVersion"].startswith("iLO 4"):
image_only = True image_only = True
if 'Supermicro' in data['Oem']: if 'Supermicro' in data['Oem']:

View file

@ -505,6 +505,20 @@ EXAMPLES = '''
username: operator username: operator
password: supersecretpwd password: supersecretpwd
- name: Insert Virtual Media
community.general.redfish_command:
category: Systems
command: VirtualMediaInsert
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
virtual_media:
image_url: 'http://example.com/images/SomeLinux-current.iso'
media_types:
- CD
- DVD
resource_id: 1
- name: Insert Virtual Media - name: Insert Virtual Media
community.general.redfish_command: community.general.redfish_command:
category: Manager category: Manager
@ -519,6 +533,17 @@ EXAMPLES = '''
- DVD - DVD
resource_id: BMC resource_id: BMC
- name: Eject Virtual Media
community.general.redfish_command:
category: Systems
command: VirtualMediaEject
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
virtual_media:
image_url: 'http://example.com/images/SomeLinux-current.iso'
resource_id: 1
- name: Eject Virtual Media - name: Eject Virtual Media
community.general.redfish_command: community.general.redfish_command:
category: Manager category: Manager
@ -593,7 +618,7 @@ from ansible.module_utils.common.text.converters import to_native
CATEGORY_COMMANDS_ALL = { CATEGORY_COMMANDS_ALL = {
"Systems": ["PowerOn", "PowerForceOff", "PowerForceRestart", "PowerGracefulRestart", "Systems": ["PowerOn", "PowerForceOff", "PowerForceRestart", "PowerGracefulRestart",
"PowerGracefulShutdown", "PowerReboot", "SetOneTimeBoot", "EnableContinuousBootOverride", "DisableBootOverride", "PowerGracefulShutdown", "PowerReboot", "SetOneTimeBoot", "EnableContinuousBootOverride", "DisableBootOverride",
"IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink"], "IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink", "VirtualMediaInsert", "VirtualMediaEject"],
"Chassis": ["IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink"], "Chassis": ["IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink"],
"Accounts": ["AddUser", "EnableUser", "DeleteUser", "DisableUser", "Accounts": ["AddUser", "EnableUser", "DeleteUser", "DisableUser",
"UpdateUserRole", "UpdateUserPassword", "UpdateUserName", "UpdateUserRole", "UpdateUserPassword", "UpdateUserName",
@ -766,6 +791,10 @@ def main():
result = rf_utils.set_boot_override(boot_opts) result = rf_utils.set_boot_override(boot_opts)
elif command.startswith('IndicatorLed'): elif command.startswith('IndicatorLed'):
result = rf_utils.manage_system_indicator_led(command) result = rf_utils.manage_system_indicator_led(command)
elif command == 'VirtualMediaInsert':
result = rf_utils.virtual_media_insert(virtual_media, category)
elif command == 'VirtualMediaEject':
result = rf_utils.virtual_media_eject(virtual_media, category)
elif category == "Chassis": elif category == "Chassis":
result = rf_utils._find_chassis_resource() result = rf_utils._find_chassis_resource()
@ -814,9 +843,9 @@ def main():
elif command == 'ClearLogs': elif command == 'ClearLogs':
result = rf_utils.clear_logs() result = rf_utils.clear_logs()
elif command == 'VirtualMediaInsert': elif command == 'VirtualMediaInsert':
result = rf_utils.virtual_media_insert(virtual_media) result = rf_utils.virtual_media_insert(virtual_media, category)
elif command == 'VirtualMediaEject': elif command == 'VirtualMediaEject':
result = rf_utils.virtual_media_eject(virtual_media) result = rf_utils.virtual_media_eject(virtual_media, category)
elif category == "Update": elif category == "Update":
# execute only if we find UpdateService resources # execute only if we find UpdateService resources

View file

@ -118,6 +118,19 @@ EXAMPLES = '''
ansible.builtin.debug: ansible.builtin.debug:
msg: "{{ result.redfish_facts.virtual_media.entries | to_nice_json }}" msg: "{{ result.redfish_facts.virtual_media.entries | to_nice_json }}"
- name: Get Virtual Media information from Systems
community.general.redfish_info:
category: Systems
command: GetVirtualMedia
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
register: result
- name: Print fetched information
ansible.builtin.debug:
msg: "{{ result.redfish_facts.virtual_media.entries | to_nice_json }}"
- name: Get Volume Inventory - name: Get Volume Inventory
community.general.redfish_info: community.general.redfish_info:
category: Systems category: Systems
@ -303,7 +316,7 @@ CATEGORY_COMMANDS_ALL = {
"Systems": ["GetSystemInventory", "GetPsuInventory", "GetCpuInventory", "Systems": ["GetSystemInventory", "GetPsuInventory", "GetCpuInventory",
"GetMemoryInventory", "GetNicInventory", "GetHealthReport", "GetMemoryInventory", "GetNicInventory", "GetHealthReport",
"GetStorageControllerInventory", "GetDiskInventory", "GetVolumeInventory", "GetStorageControllerInventory", "GetDiskInventory", "GetVolumeInventory",
"GetBiosAttributes", "GetBootOrder", "GetBootOverride"], "GetBiosAttributes", "GetBootOrder", "GetBootOverride", "GetVirtualMedia"],
"Chassis": ["GetFanInventory", "GetPsuInventory", "GetChassisPower", "Chassis": ["GetFanInventory", "GetPsuInventory", "GetChassisPower",
"GetChassisThermals", "GetChassisInventory", "GetHealthReport"], "GetChassisThermals", "GetChassisInventory", "GetHealthReport"],
"Accounts": ["ListUsers"], "Accounts": ["ListUsers"],
@ -420,6 +433,8 @@ def main():
result["boot_override"] = rf_utils.get_multi_boot_override() result["boot_override"] = rf_utils.get_multi_boot_override()
elif command == "GetHealthReport": elif command == "GetHealthReport":
result["health_report"] = rf_utils.get_multi_system_health_report() result["health_report"] = rf_utils.get_multi_system_health_report()
elif command == "GetVirtualMedia":
result["virtual_media"] = rf_utils.get_multi_virtualmedia(category)
elif category == "Chassis": elif category == "Chassis":
# execute only if we find Chassis resource # execute only if we find Chassis resource
@ -485,7 +500,7 @@ def main():
if command == "GetManagerNicInventory": if command == "GetManagerNicInventory":
result["manager_nics"] = rf_utils.get_multi_nic_inventory(category) result["manager_nics"] = rf_utils.get_multi_nic_inventory(category)
elif command == "GetVirtualMedia": elif command == "GetVirtualMedia":
result["virtual_media"] = rf_utils.get_multi_virtualmedia() result["virtual_media"] = rf_utils.get_multi_virtualmedia(category)
elif command == "GetLogs": elif command == "GetLogs":
result["log"] = rf_utils.get_logs() result["log"] = rf_utils.get_logs()
elif command == "GetNetworkProtocols": elif command == "GetNetworkProtocols":