Allow resources to use any field as 'name'

The 'name' field for some resources is called something different,
for example 'display_name' for volumes. There was a hack in our
find method to search for display_name as well.

This change adds a new class variable to a Resource to tell it
which attribute to use for searching by name. Volumes and snapshots
were switched to use 'display_name' and hypervisors were switched
to use 'hypervisor_hostname'.

Tests fixed and added.

Fixes bug 1034536

Change-Id: I1b4fb969d42c59d1ab8e3e275a563bbe158e9264
This commit is contained in:
Vishvananda Ishaya 2012-08-08 11:18:13 -07:00
parent 077cc0bf22
commit 576a64fbb5
6 changed files with 41 additions and 18 deletions

View File

@ -281,6 +281,7 @@ class Resource(object):
:param loaded: prevent lazy-loading if set to True :param loaded: prevent lazy-loading if set to True
""" """
HUMAN_ID = False HUMAN_ID = False
NAME_ATTR = 'name'
def __init__(self, manager, info, loaded=False): def __init__(self, manager, info, loaded=False):
self.manager = manager self.manager = manager
@ -303,8 +304,8 @@ class Resource(object):
"""Subclasses may override this provide a pretty ID which can be used """Subclasses may override this provide a pretty ID which can be used
for bash completion. for bash completion.
""" """
if 'name' in self.__dict__ and self.HUMAN_ID: if self.NAME_ATTR in self.__dict__ and self.HUMAN_ID:
return utils.slugify(self.name) return utils.slugify(getattr(self, self.NAME_ATTR))
return None return None
def _add_details(self, info): def _add_details(self, info):

View File

@ -180,15 +180,14 @@ def find_resource(manager, name_or_id):
# finally try to find entity by name # finally try to find entity by name
try: try:
return manager.find(name=name_or_id) resource = getattr(manager, 'resource_class', None)
name_attr = resource.NAME_ATTR if resource else 'name'
kwargs = {name_attr: name_or_id}
return manager.find(**kwargs)
except exceptions.NotFound: except exceptions.NotFound:
try: msg = "No %s with a name or ID of '%s' exists." % \
# Volumes does not have name, but display_name (manager.resource_class.__name__.lower(), name_or_id)
return manager.find(display_name=name_or_id) raise exceptions.CommandError(msg)
except exceptions.NotFound:
msg = "No %s with a name or ID of '%s' exists." % \
(manager.resource_class.__name__.lower(), name_or_id)
raise exceptions.CommandError(msg)
except exceptions.NoUniqueMatch: except exceptions.NoUniqueMatch:
msg = ("Multiple %s matches found for '%s', use an ID to be more" msg = ("Multiple %s matches found for '%s', use an ID to be more"
" specific." % (manager.resource_class.__name__.lower(), " specific." % (manager.resource_class.__name__.lower(),

View File

@ -23,11 +23,13 @@ from novaclient import base
class Hypervisor(base.Resource): class Hypervisor(base.Resource):
NAME_ATTR = 'hypervisor_hostname'
def __repr__(self): def __repr__(self):
return "<Hypervisor: %s>" % self.id return "<Hypervisor: %s>" % self.id
class HypervisorManager(base.Manager): class HypervisorManager(base.ManagerWithFind):
resource_class = Hypervisor resource_class = Hypervisor
def list(self, detailed=True): def list(self, detailed=True):

View File

@ -24,6 +24,8 @@ class Snapshot(base.Resource):
""" """
A Snapshot is a point-in-time snapshot of an openstack volume. A Snapshot is a point-in-time snapshot of an openstack volume.
""" """
NAME_ATTR = 'display_name'
def __repr__(self): def __repr__(self):
return "<Snapshot: %s>" % self.id return "<Snapshot: %s>" % self.id

View File

@ -24,6 +24,8 @@ class Volume(base.Resource):
""" """
A volume is an extra block level storage to the OpenStack instances. A volume is an extra block level storage to the OpenStack instances.
""" """
NAME_ATTR = 'display_name'
def __repr__(self): def __repr__(self):
return "<Volume: %s>" % self.id return "<Volume: %s>" % self.id

View File

@ -8,6 +8,7 @@ UUID = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0'
class FakeResource(object): class FakeResource(object):
NAME_ATTR = 'name'
def __init__(self, _id, properties): def __init__(self, _id, properties):
self.id = _id self.id = _id
@ -15,10 +16,6 @@ class FakeResource(object):
self.name = properties['name'] self.name = properties['name']
except KeyError: except KeyError:
pass pass
try:
self.display_name = properties['display_name']
except KeyError:
pass
class FakeManager(base.ManagerWithFind): class FakeManager(base.ManagerWithFind):
@ -28,7 +25,6 @@ class FakeManager(base.ManagerWithFind):
resources = [ resources = [
FakeResource('1234', {'name': 'entity_one'}), FakeResource('1234', {'name': 'entity_one'}),
FakeResource(UUID, {'name': 'entity_two'}), FakeResource(UUID, {'name': 'entity_two'}),
FakeResource('4242', {'display_name': 'entity_three'}),
FakeResource('5678', {'name': '9876'}) FakeResource('5678', {'name': '9876'})
] ]
@ -42,6 +38,26 @@ class FakeManager(base.ManagerWithFind):
return self.resources return self.resources
class FakeDisplayResource(object):
NAME_ATTR = 'display_name'
def __init__(self, _id, properties):
self.id = _id
try:
self.display_name = properties['display_name']
except KeyError:
pass
class FakeDisplayManager(FakeManager):
resource_class = FakeDisplayResource
resources = [
FakeDisplayResource('4242', {'display_name': 'entity_three'}),
]
class FindResourceTestCase(test_utils.TestCase): class FindResourceTestCase(test_utils.TestCase):
def setUp(self): def setUp(self):
@ -70,5 +86,6 @@ class FindResourceTestCase(test_utils.TestCase):
self.assertEqual(output, self.manager.get('1234')) self.assertEqual(output, self.manager.get('1234'))
def test_find_by_str_displayname(self): def test_find_by_str_displayname(self):
output = utils.find_resource(self.manager, 'entity_three') display_manager = FakeDisplayManager(None)
self.assertEqual(output, self.manager.get('4242')) output = utils.find_resource(display_manager, 'entity_three')
self.assertEqual(output, display_manager.get('4242'))