Merge "Support for child resource extensions"

This commit is contained in:
Jenkins
2015-09-08 23:07:50 +00:00
committed by Gerrit Code Review
2 changed files with 113 additions and 15 deletions

View File

@@ -14,6 +14,7 @@
# under the License.
#
import inspect
import sys
import mock
@@ -150,3 +151,74 @@ class CLITestV20ExtensionJSONAlternatePlurals(test_cli20.CLITestV20Base):
resources = 'ip_addresses'
cmd = self.IPAddressesList(test_cli20.MyApp(sys.stdout), None)
self._test_list_resources(resources, cmd, True)
class CLITestV20ExtensionJSONChildResource(test_cli20.CLITestV20Base):
class Child(extension.NeutronClientExtension):
parent_resource = 'parents'
child_resource = 'child'
resource = '%s_%s' % (parent_resource, child_resource)
resource_plural = '%sren' % resource
child_resource_plural = '%ren' % child_resource
object_path = '/%s/%%s/%s' % (parent_resource, child_resource_plural)
resource_path = '/%s/%%s/%s/%%s' % (parent_resource,
child_resource_plural)
versions = ['2.0']
class ChildrenList(extension.ClientExtensionList, Child):
shell_command = 'parent-child-list'
class ChildShow(extension.ClientExtensionShow, Child):
shell_command = 'parent-child-show'
class ChildUpdate(extension.ClientExtensionUpdate, Child):
shell_command = 'parent-child-update'
class ChildDelete(extension.ClientExtensionDelete, Child):
shell_command = 'parent-child-delete'
class ChildCreate(extension.ClientExtensionCreate, Child):
shell_command = 'parent-child-create'
def setUp(self):
# need to mock before super because extensions loaded on instantiation
self._mock_extension_loading()
super(CLITestV20ExtensionJSONChildResource, self).setUp()
def _create_patch(self, name, func=None):
patcher = mock.patch(name)
thing = patcher.start()
self.addCleanup(patcher.stop)
return thing
def _mock_extension_loading(self):
ext_pkg = 'neutronclient.common.extension'
contrib = self._create_patch(ext_pkg + '._discover_via_entry_points')
child = mock.MagicMock()
child.Child = self.Child
child.ChildrenList = self.ChildrenList
child.ChildShow = self.ChildShow
child.ChildUpdate = self.ChildUpdate
child.ChildDelete = self.ChildDelete
child.ChildCreate = self.ChildCreate
contrib.return_value = [("child", child)]
return contrib
def test_ext_cmd_loaded(self):
shell.NeutronShell('2.0')
ext_cmd = {'parent-child-list': self.ChildrenList,
'parent-child-show': self.ChildShow,
'parent-child-update': self.ChildUpdate,
'parent-child-delete': self.ChildDelete,
'parent-child-create': self.ChildCreate}
self.assertDictContainsSubset(ext_cmd, shell.COMMANDS['2.0'])
def test_client_methods_have_parent_id_arg(self):
methods = (self.client.list_parents_children,
self.client.show_parents_child,
self.client.update_parents_child,
self.client.delete_parents_child,
self.client.create_parents_child)
for method in methods:
argspec = inspect.getargspec(method)
self.assertIn("parent_id", argspec.args)

View File

@@ -1631,30 +1631,50 @@ class Client(ClientBase):
super(Client, self).__init__(**kwargs)
self._register_extensions(self.version)
def extend_show(self, resource_plural, path):
def extend_show(self, resource_plural, path, parent_resource):
def _fx(obj, **_params):
return self.show_ext(path, obj, **_params)
setattr(self, "show_%s" % resource_plural, _fx)
def extend_list(self, resource_plural, path):
def _parent_fx(parent_id, obj, **_params):
return self.show_ext(path % parent_id, obj, **_params)
fn = _fx if not parent_resource else _parent_fx
setattr(self, "show_%s" % resource_plural, fn)
def extend_list(self, resource_plural, path, parent_resource):
def _fx(**_params):
return self.list_ext(path, **_params)
setattr(self, "list_%s" % resource_plural, _fx)
def extend_create(self, resource_singular, path):
def _parent_fx(parent_id, **_params):
return self.list_ext(path % parent_id, **_params)
fn = _fx if not parent_resource else _parent_fx
setattr(self, "list_%s" % resource_plural, fn)
def extend_create(self, resource_singular, path, parent_resource):
def _fx(body=None):
return self.create_ext(path, body)
setattr(self, "create_%s" % resource_singular, _fx)
def extend_delete(self, resource_singular, path):
def _parent_fx(parent_id, body=None):
return self.create_ext(path % parent_id, body)
fn = _fx if not parent_resource else _parent_fx
setattr(self, "create_%s" % resource_singular, fn)
def extend_delete(self, resource_singular, path, parent_resource):
def _fx(obj):
return self.delete_ext(path, obj)
setattr(self, "delete_%s" % resource_singular, _fx)
def extend_update(self, resource_singular, path):
def _parent_fx(parent_id, obj):
return self.delete_ext(path % parent_id, obj)
fn = _fx if not parent_resource else _parent_fx
setattr(self, "delete_%s" % resource_singular, fn)
def extend_update(self, resource_singular, path, parent_resource):
def _fx(obj, body=None):
return self.update_ext(path, obj, body)
setattr(self, "update_%s" % resource_singular, _fx)
def _parent_fx(parent_id, obj, body=None):
return self.update_ext(path % parent_id, obj, body)
fn = _fx if not parent_resource else _parent_fx
setattr(self, "update_%s" % resource_singular, fn)
def _extend_client_with_module(self, module, version):
classes = inspect.getmembers(module, inspect.isclass)
@@ -1662,16 +1682,22 @@ class Client(ClientBase):
if hasattr(cls, 'versions'):
if version not in cls.versions:
continue
parent_resource = getattr(cls, 'parent_resource', None)
if issubclass(cls, client_extension.ClientExtensionList):
self.extend_list(cls.resource_plural, cls.object_path)
self.extend_list(cls.resource_plural, cls.object_path,
parent_resource)
elif issubclass(cls, client_extension.ClientExtensionCreate):
self.extend_create(cls.resource, cls.object_path)
self.extend_create(cls.resource, cls.object_path,
parent_resource)
elif issubclass(cls, client_extension.ClientExtensionUpdate):
self.extend_update(cls.resource, cls.resource_path)
self.extend_update(cls.resource, cls.resource_path,
parent_resource)
elif issubclass(cls, client_extension.ClientExtensionDelete):
self.extend_delete(cls.resource, cls.resource_path)
self.extend_delete(cls.resource, cls.resource_path,
parent_resource)
elif issubclass(cls, client_extension.ClientExtensionShow):
self.extend_show(cls.resource, cls.resource_path)
self.extend_show(cls.resource, cls.resource_path,
parent_resource)
elif issubclass(cls, client_extension.NeutronClientExtension):
setattr(self, "%s_path" % cls.resource_plural,
cls.object_path)