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:
Ruby Loo 2016-09-29 10:49:49 -04:00
parent 229824c2ca
commit 109b438527
5 changed files with 58 additions and 10 deletions

View File

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

View File

@ -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 = [

View File

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

View File

@ -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,

View File

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