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:
parent
57e1e2bd8e
commit
766c109d47
4 changed files with 93 additions and 18 deletions
|
@ -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).
|
|
@ -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,10 +2172,14 @@ 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 = []
|
||||||
|
|
||||||
|
# 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
|
resource_uris = self.manager_uris
|
||||||
|
|
||||||
for resource_uri in resource_uris:
|
for resource_uri in resource_uris:
|
||||||
|
@ -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']:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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":
|
||||||
|
|
Loading…
Reference in a new issue