1
0
Fork 0
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:
jixj5 2022-05-18 13:24:27 +08:00 committed by GitHub
parent 1a2fa802c0
commit 8db265f99b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 133 additions and 19 deletions

View file

@ -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).

View file

@ -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']))

View file

@ -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):