Skip to content

Commit

Permalink
Update redfish module for compatibility with VirtualMedia resource lo…
Browse files Browse the repository at this point in the history
…cation (#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>
(cherry picked from commit 766c109)
  • Loading branch information
jixj5 authored and patchback[bot] committed Aug 24, 2022
1 parent d2b0a0d commit b6067e0
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -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).
55 changes: 42 additions & 13 deletions plugins/module_utils/redfish_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ def _get_extended_message(error):
def _init_session(self):
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):
response = self.get_request(self.root_uri + self.service_root)
if response['ret'] is False:
Expand Down Expand Up @@ -2162,11 +2172,15 @@ def get_virtualmedia(self, resource_uri):
result["entries"] = virtualmedia_results
return result

def get_multi_virtualmedia(self):
def get_multi_virtualmedia(self, resource_type='Manager'):
ret = True
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:
virtualmedia = self.get_virtualmedia(resource_uri)
Expand All @@ -2178,7 +2192,7 @@ def get_multi_virtualmedia(self):

@staticmethod
def _find_empty_virt_media_slot(resources, media_types,
media_match_strict=True):
media_match_strict=True, vendor=''):
for uri, data in resources.items():
# check MediaTypes
if 'MediaTypes' in data and media_types:
Expand All @@ -2187,8 +2201,12 @@ def _find_empty_virt_media_slot(resources, media_types,
else:
if media_match_strict:
continue
# if ejected, 'Inserted' should be False
if (not data.get('Inserted', 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 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 None, None

Expand Down Expand Up @@ -2262,7 +2280,7 @@ def virtual_media_insert_via_patch(self, options, param_map, uri, data, image_on
return response
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 = {
'Inserted': 'inserted',
'WriteProtected': 'write_protected',
Expand All @@ -2279,7 +2297,12 @@ def virtual_media_insert(self, options):
media_types = options.get('media_types')

# 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:
return response
data = response['data']
Expand All @@ -2288,7 +2311,7 @@ def virtual_media_insert(self, options):

# Some hardware (such as iLO 4) only supports the Image property on the PATCH operation
# 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

# Supermicro does also not support Inserted and WriteProtected
Expand All @@ -2315,12 +2338,13 @@ def virtual_media_insert(self, options):

# find an empty slot to insert the media
# try first with strict media_type matching
vendor = self._get_vendor()['Vendor']
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 found, try without strict media_type matching
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:
return {'ret': False,
'msg': "Unable to find an available VirtualMedia resource "
Expand Down Expand Up @@ -2378,14 +2402,19 @@ def virtual_media_eject_via_patch(self, uri, image_only=False):
return {'ret': True, 'changed': True,
'msg': "VirtualMedia ejected"}

def virtual_media_eject(self, options):
def virtual_media_eject(self, options, resource_type='Manager'):
image_url = options.get('image_url')
if not image_url:
return {'ret': False,
'msg': "image_url option required for VirtualMediaEject"}

# 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:
return response
data = response['data']
Expand All @@ -2395,7 +2424,7 @@ def virtual_media_eject(self, options):
# Some hardware (such as iLO 4) only supports the Image property on the PATCH operation
# Inserted is not writable
image_only = False
if data["FirmwareVersion"].startswith("iLO 4"):
if "FirmwareVersion" in data and data["FirmwareVersion"].startswith("iLO 4"):
image_only = True

if 'Supermicro' in data['Oem']:
Expand Down
35 changes: 32 additions & 3 deletions plugins/modules/remote_management/redfish/redfish_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,20 @@
username: operator
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
community.general.redfish_command:
category: Manager
Expand All @@ -519,6 +533,17 @@
- DVD
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
community.general.redfish_command:
category: Manager
Expand Down Expand Up @@ -593,7 +618,7 @@
CATEGORY_COMMANDS_ALL = {
"Systems": ["PowerOn", "PowerForceOff", "PowerForceRestart", "PowerGracefulRestart",
"PowerGracefulShutdown", "PowerReboot", "SetOneTimeBoot", "EnableContinuousBootOverride", "DisableBootOverride",
"IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink"],
"IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink", "VirtualMediaInsert", "VirtualMediaEject"],
"Chassis": ["IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink"],
"Accounts": ["AddUser", "EnableUser", "DeleteUser", "DisableUser",
"UpdateUserRole", "UpdateUserPassword", "UpdateUserName",
Expand Down Expand Up @@ -766,6 +791,10 @@ def main():
result = rf_utils.set_boot_override(boot_opts)
elif command.startswith('IndicatorLed'):
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":
result = rf_utils._find_chassis_resource()
Expand Down Expand Up @@ -814,9 +843,9 @@ def main():
elif command == 'ClearLogs':
result = rf_utils.clear_logs()
elif command == 'VirtualMediaInsert':
result = rf_utils.virtual_media_insert(virtual_media)
result = rf_utils.virtual_media_insert(virtual_media, category)
elif command == 'VirtualMediaEject':
result = rf_utils.virtual_media_eject(virtual_media)
result = rf_utils.virtual_media_eject(virtual_media, category)

elif category == "Update":
# execute only if we find UpdateService resources
Expand Down
19 changes: 17 additions & 2 deletions plugins/modules/remote_management/redfish/redfish_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@
ansible.builtin.debug:
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
community.general.redfish_info:
category: Systems
Expand Down Expand Up @@ -303,7 +316,7 @@
"Systems": ["GetSystemInventory", "GetPsuInventory", "GetCpuInventory",
"GetMemoryInventory", "GetNicInventory", "GetHealthReport",
"GetStorageControllerInventory", "GetDiskInventory", "GetVolumeInventory",
"GetBiosAttributes", "GetBootOrder", "GetBootOverride"],
"GetBiosAttributes", "GetBootOrder", "GetBootOverride", "GetVirtualMedia"],
"Chassis": ["GetFanInventory", "GetPsuInventory", "GetChassisPower",
"GetChassisThermals", "GetChassisInventory", "GetHealthReport"],
"Accounts": ["ListUsers"],
Expand Down Expand Up @@ -420,6 +433,8 @@ def main():
result["boot_override"] = rf_utils.get_multi_boot_override()
elif command == "GetHealthReport":
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":
# execute only if we find Chassis resource
Expand Down Expand Up @@ -485,7 +500,7 @@ def main():
if command == "GetManagerNicInventory":
result["manager_nics"] = rf_utils.get_multi_nic_inventory(category)
elif command == "GetVirtualMedia":
result["virtual_media"] = rf_utils.get_multi_virtualmedia()
result["virtual_media"] = rf_utils.get_multi_virtualmedia(category)
elif command == "GetLogs":
result["log"] = rf_utils.get_logs()
elif command == "GetNetworkProtocols":
Expand Down

0 comments on commit b6067e0

Please sign in to comment.