mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Update lenovoxcc module for compatibility with the virtualMedia resource location from Manager to System (#4682)
* Update lenovoxcc module for compatibility due to redfish spec changes the virtualMedia resource location from Managers to Systems * Add changelogs fragment for PR 4682 * Update changelogs/fragments/4682-compatibility-virtualmedia-resource-location.yaml Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Tami YY3 Pan <panyy3@lenovo.com> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
1a2fa802c0
commit
8db265f99b
3 changed files with 133 additions and 19 deletions
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- xcc_redfish_command - for compatibility due to Redfish spec changes the virtualMedia resource location changed from Manager to System (https://github.com/ansible-collections/community.general/pull/4682).
|
|
@ -305,6 +305,8 @@ class XCCRedfishUtils(RedfishUtils):
|
|||
continue
|
||||
if 'RDOC' in uri:
|
||||
continue
|
||||
if 'Remote' in uri:
|
||||
continue
|
||||
# if ejected, 'Inserted' should be False and 'ImageName' cleared
|
||||
if (not data.get('Inserted', False) and
|
||||
not data.get('ImageName')):
|
||||
|
@ -312,13 +314,19 @@ class XCCRedfishUtils(RedfishUtils):
|
|||
return None, None
|
||||
|
||||
def virtual_media_eject_one(self, image_url):
|
||||
# locate and read the VirtualMedia resources
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
# read the VirtualMedia resources from systems
|
||||
response = self.get_request(self.root_uri + self.systems_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'VirtualMedia' not in data:
|
||||
return {'ret': False, 'msg': "VirtualMedia resource not found"}
|
||||
# read the VirtualMedia resources from manager
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'VirtualMedia' not in data:
|
||||
return {'ret': False, 'msg': "VirtualMedia resource not found"}
|
||||
virt_media_uri = data["VirtualMedia"]["@odata.id"]
|
||||
response = self.get_request(self.root_uri + virt_media_uri)
|
||||
if response['ret'] is False:
|
||||
|
@ -379,13 +387,20 @@ class XCCRedfishUtils(RedfishUtils):
|
|||
return self.virtual_media_eject_one(image_url)
|
||||
|
||||
# eject all inserted media when no image_url specified
|
||||
# read all the VirtualMedia resources
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
# read the VirtualMedia resources from systems
|
||||
response = self.get_request(self.root_uri + self.systems_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'VirtualMedia' not in data:
|
||||
return {'ret': False, 'msg': "VirtualMedia resource not found"}
|
||||
# read the VirtualMedia resources from manager
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'VirtualMedia' not in data:
|
||||
return {'ret': False, 'msg': "VirtualMedia resource not found"}
|
||||
# read all the VirtualMedia resources
|
||||
virt_media_uri = data["VirtualMedia"]["@odata.id"]
|
||||
response = self.get_request(self.root_uri + virt_media_uri)
|
||||
if response['ret'] is False:
|
||||
|
@ -413,6 +428,95 @@ class XCCRedfishUtils(RedfishUtils):
|
|||
return {'ret': True, 'changed': True,
|
||||
'msg': "VirtualMedia %s ejected" % str(ejected_media_list)}
|
||||
|
||||
def virtual_media_insert(self, options):
|
||||
param_map = {
|
||||
'Inserted': 'inserted',
|
||||
'WriteProtected': 'write_protected',
|
||||
'UserName': 'username',
|
||||
'Password': 'password',
|
||||
'TransferProtocolType': 'transfer_protocol_type',
|
||||
'TransferMethod': 'transfer_method'
|
||||
}
|
||||
image_url = options.get('image_url')
|
||||
if not image_url:
|
||||
return {'ret': False,
|
||||
'msg': "image_url option required for VirtualMediaInsert"}
|
||||
media_types = options.get('media_types')
|
||||
|
||||
# read the VirtualMedia resources from systems
|
||||
response = self.get_request(self.root_uri + self.systems_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'VirtualMedia' not in data:
|
||||
# read the VirtualMedia resources from manager
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'VirtualMedia' not in data:
|
||||
return {'ret': False, 'msg': "VirtualMedia resource not found"}
|
||||
virt_media_uri = data["VirtualMedia"]["@odata.id"]
|
||||
response = self.get_request(self.root_uri + virt_media_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
virt_media_list = []
|
||||
for member in data[u'Members']:
|
||||
virt_media_list.append(member[u'@odata.id'])
|
||||
resources, headers = self._read_virt_media_resources(virt_media_list)
|
||||
|
||||
# see if image already inserted; if so, nothing to do
|
||||
if self._virt_media_image_inserted(resources, image_url):
|
||||
return {'ret': True, 'changed': False,
|
||||
'msg': "VirtualMedia '%s' already inserted" % image_url}
|
||||
|
||||
# find an empty slot to insert the media
|
||||
# try first with strict media_type matching
|
||||
uri, data = self._find_empty_virt_media_slot(
|
||||
resources, media_types, media_match_strict=True)
|
||||
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)
|
||||
if not uri:
|
||||
return {'ret': False,
|
||||
'msg': "Unable to find an available VirtualMedia resource "
|
||||
"%s" % ('supporting ' + str(media_types)
|
||||
if media_types else '')}
|
||||
|
||||
# confirm InsertMedia action found
|
||||
if ('Actions' not in data or
|
||||
'#VirtualMedia.InsertMedia' not in data['Actions']):
|
||||
# try to insert via PATCH if no InsertMedia action found
|
||||
h = headers[uri]
|
||||
if 'allow' in h:
|
||||
methods = [m.strip() for m in h.get('allow').split(',')]
|
||||
if 'PATCH' not in methods:
|
||||
# if Allow header present and PATCH missing, return error
|
||||
return {'ret': False,
|
||||
'msg': "%s action not found and PATCH not allowed"
|
||||
% '#VirtualMedia.InsertMedia'}
|
||||
return self.virtual_media_insert_via_patch(options, param_map,
|
||||
uri, data)
|
||||
|
||||
# get the action property
|
||||
action = data['Actions']['#VirtualMedia.InsertMedia']
|
||||
if 'target' not in action:
|
||||
return {'ret': False,
|
||||
'msg': "target URI missing from Action "
|
||||
"#VirtualMedia.InsertMedia"}
|
||||
action_uri = action['target']
|
||||
# get ActionInfo or AllowableValues
|
||||
ai = self._get_all_action_info_values(action)
|
||||
# construct payload
|
||||
payload = self._insert_virt_media_payload(options, param_map, data, ai)
|
||||
# POST to action
|
||||
response = self.post_request(self.root_uri + action_uri, payload)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
return {'ret': True, 'changed': True, 'msg': "VirtualMedia inserted"}
|
||||
|
||||
def raw_get_resource(self, resource_uri):
|
||||
if resource_uri is None:
|
||||
return {'ret': False, 'msg': "resource_uri is missing"}
|
||||
|
@ -640,7 +744,11 @@ def main():
|
|||
|
||||
# Organize by Categories / Commands
|
||||
if category == "Manager":
|
||||
# execute only if we find a Manager service resource
|
||||
# For virtual media resource locates on Systems service
|
||||
result = rf_utils._find_systems_resource()
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
# For virtual media resource locates on Managers service
|
||||
result = rf_utils._find_managers_resource()
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
|
|
|
@ -72,14 +72,16 @@ class TestXCCRedfishCommand(unittest.TestCase):
|
|||
'transfer_protocol_type': 'NFS'
|
||||
}
|
||||
})
|
||||
with patch.object(module.XCCRedfishUtils, '_find_managers_resource') as mock__find_managers_resource:
|
||||
mock__find_managers_resource.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
with patch.object(module.XCCRedfishUtils, '_find_systems_resource') as mock__find_systems_resource:
|
||||
mock__find_systems_resource.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
with patch.object(module.XCCRedfishUtils, '_find_managers_resource') as mock__find_managers_resource:
|
||||
mock__find_managers_resource.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
|
||||
with patch.object(module.XCCRedfishUtils, 'virtual_media_insert') as mock_virtual_media_insert:
|
||||
mock_virtual_media_insert.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
with patch.object(module.XCCRedfishUtils, 'virtual_media_insert') as mock_virtual_media_insert:
|
||||
mock_virtual_media_insert.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
|
||||
with self.assertRaises(AnsibleExitJson) as result:
|
||||
module.main()
|
||||
with self.assertRaises(AnsibleExitJson) as result:
|
||||
module.main()
|
||||
|
||||
def test_module_command_VirtualMediaEject_pass(self):
|
||||
set_module_args({
|
||||
|
@ -93,14 +95,16 @@ class TestXCCRedfishCommand(unittest.TestCase):
|
|||
'image_url': "nfs://10.245.52.18:/home/nfs/bootable-sr635-20210111-autorun.iso",
|
||||
}
|
||||
})
|
||||
with patch.object(module.XCCRedfishUtils, '_find_managers_resource') as mock__find_managers_resource:
|
||||
mock__find_managers_resource.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
with patch.object(module.XCCRedfishUtils, '_find_systems_resource') as mock__find_systems_resource:
|
||||
mock__find_systems_resource.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
with patch.object(module.XCCRedfishUtils, '_find_managers_resource') as mock__find_managers_resource:
|
||||
mock__find_managers_resource.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
|
||||
with patch.object(module.XCCRedfishUtils, 'virtual_media_eject') as mock_virtual_media_eject:
|
||||
mock_virtual_media_eject.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
with patch.object(module.XCCRedfishUtils, 'virtual_media_eject') as mock_virtual_media_eject:
|
||||
mock_virtual_media_eject.return_value = {'ret': True, 'changed': True, 'msg': 'success'}
|
||||
|
||||
with self.assertRaises(AnsibleExitJson) as result:
|
||||
module.main()
|
||||
with self.assertRaises(AnsibleExitJson) as result:
|
||||
module.main()
|
||||
|
||||
def test_module_command_VirtualMediaEject_fail_when_required_args_missing(self):
|
||||
with self.assertRaises(AnsibleFailJson):
|
||||
|
|
Loading…
Reference in a new issue