If no resource, don't call Resource.to_dict()
This adds a new method base.Manager._get_as_dict() which checks whether there is a resource first, before calling Resource.to_dict(). Code was modified to call this new method, instead of calling Resource.to_dict() directly. This fixes the AttributeError that occurs if, for example, one tries to get the list of driver passthru methods of the 'fake' driver (via 'ironic driver-get-vendor-passthru-methods fake'). There are no methods, and without this change, an AttributeError exception is raised. With this fix, an empty list is returned. Change-Id: Ib6b691cd39ede9c5902b4df29023fd974b367a7d Closes-Bug: #1626806
This commit is contained in:
parent
229824c2ca
commit
109b438527
@ -83,6 +83,20 @@ class Manager(object):
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def _get_as_dict(self, resource_id, fields=None):
|
||||
"""Retrieve a resource as a dictionary
|
||||
|
||||
:param resource_id: Identifier of the resource.
|
||||
:param fields: List of specific fields to be returned.
|
||||
:returns: a dictionary representing the resource; may be empty
|
||||
"""
|
||||
|
||||
resource = self._get(resource_id, fields=fields)
|
||||
if resource:
|
||||
return resource.to_dict()
|
||||
else:
|
||||
return {}
|
||||
|
||||
def _format_body_data(self, body, response_key):
|
||||
if response_key:
|
||||
try:
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import copy
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from ironicclient.common import base
|
||||
@ -121,6 +122,35 @@ class ManagerTestCase(testtools.TestCase):
|
||||
self.manager.create,
|
||||
**INVALID_ATTRIBUTE_TESTABLE_RESOURCE)
|
||||
|
||||
def test__get(self):
|
||||
resource_id = TESTABLE_RESOURCE['uuid']
|
||||
resource = self.manager._get(resource_id)
|
||||
expect = [
|
||||
('GET', '/v1/testableresources/%s' % resource_id,
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(resource_id, resource.uuid)
|
||||
self.assertEqual(TESTABLE_RESOURCE['attribute1'], resource.attribute1)
|
||||
|
||||
def test__get_as_dict(self):
|
||||
resource_id = TESTABLE_RESOURCE['uuid']
|
||||
resource = self.manager._get_as_dict(resource_id)
|
||||
expect = [
|
||||
('GET', '/v1/testableresources/%s' % resource_id,
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(TESTABLE_RESOURCE, resource)
|
||||
|
||||
@mock.patch.object(base.Manager, '_get', autospec=True)
|
||||
def test__get_as_dict_empty(self, mock_get):
|
||||
mock_get.return_value = None
|
||||
resource_id = TESTABLE_RESOURCE['uuid']
|
||||
resource = self.manager._get_as_dict(resource_id)
|
||||
mock_get.assert_called_once_with(mock.ANY, resource_id, fields=None)
|
||||
self.assertEqual({}, resource)
|
||||
|
||||
def test_get(self):
|
||||
resource = self.manager.get(TESTABLE_RESOURCE['uuid'])
|
||||
expect = [
|
||||
|
@ -41,7 +41,7 @@ class DriverManager(base.Manager):
|
||||
return self._delete(resource_id=driver_name)
|
||||
|
||||
def properties(self, driver_name):
|
||||
return self._get(resource_id='%s/properties' % driver_name).to_dict()
|
||||
return self._get_as_dict('%s/properties' % driver_name)
|
||||
|
||||
def raid_logical_disk_properties(self, driver_name):
|
||||
"""Returns the RAID logical disk properties for the driver.
|
||||
@ -92,5 +92,4 @@ class DriverManager(base.Manager):
|
||||
_('Unknown HTTP method: %s') % http_method)
|
||||
|
||||
def get_vendor_passthru_methods(self, driver_name):
|
||||
path = "%s/vendor_passthru/methods" % driver_name
|
||||
return self.get(path).to_dict()
|
||||
return self._get_as_dict("%s/vendor_passthru/methods" % driver_name)
|
||||
|
@ -334,10 +334,7 @@ class NodeManager(base.CreateManager):
|
||||
|
||||
def get_console(self, node_uuid):
|
||||
path = "%s/states/console" % node_uuid
|
||||
info = self.get(path)
|
||||
if not info:
|
||||
return {}
|
||||
return info.to_dict()
|
||||
return self._get_as_dict(path)
|
||||
|
||||
def set_console_mode(self, node_uuid, enabled):
|
||||
"""Set the console mode for the node.
|
||||
@ -358,15 +355,15 @@ class NodeManager(base.CreateManager):
|
||||
|
||||
def get_boot_device(self, node_uuid):
|
||||
path = "%s/management/boot_device" % node_uuid
|
||||
return self.get(path).to_dict()
|
||||
return self._get_as_dict(path)
|
||||
|
||||
def get_supported_boot_devices(self, node_uuid):
|
||||
path = "%s/management/boot_device/supported" % node_uuid
|
||||
return self.get(path).to_dict()
|
||||
return self._get_as_dict(path)
|
||||
|
||||
def get_vendor_passthru_methods(self, node_ident):
|
||||
path = "%s/vendor_passthru/methods" % node_ident
|
||||
return self.get(path).to_dict()
|
||||
return self._get_as_dict(path)
|
||||
|
||||
def wait_for_provision_state(self, node_ident, expected_state,
|
||||
timeout=0,
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
fixes:
|
||||
- For node resources that had no boot devices, no supported boot devices, or
|
||||
no passthru methods (and driver resources with no properties or no passthru
|
||||
methods), issuing a request to get that information (for example,
|
||||
'ironic driver-get-vendor-passthru-methods fake') would result in the
|
||||
error "'NoneType' has no attribute 'to_dict'". This is fixed; an empty
|
||||
list is now returned.
|
Loading…
Reference in New Issue
Block a user