Merge "Support for child resource extensions"
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
@@ -150,3 +151,74 @@ class CLITestV20ExtensionJSONAlternatePlurals(test_cli20.CLITestV20Base):
|
|||||||
resources = 'ip_addresses'
|
resources = 'ip_addresses'
|
||||||
cmd = self.IPAddressesList(test_cli20.MyApp(sys.stdout), None)
|
cmd = self.IPAddressesList(test_cli20.MyApp(sys.stdout), None)
|
||||||
self._test_list_resources(resources, cmd, True)
|
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)
|
||||||
|
@@ -1631,30 +1631,50 @@ class Client(ClientBase):
|
|||||||
super(Client, self).__init__(**kwargs)
|
super(Client, self).__init__(**kwargs)
|
||||||
self._register_extensions(self.version)
|
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):
|
def _fx(obj, **_params):
|
||||||
return self.show_ext(path, 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):
|
def _fx(**_params):
|
||||||
return self.list_ext(path, **_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):
|
def _fx(body=None):
|
||||||
return self.create_ext(path, body)
|
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):
|
def _fx(obj):
|
||||||
return self.delete_ext(path, 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):
|
def _fx(obj, body=None):
|
||||||
return self.update_ext(path, obj, body)
|
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):
|
def _extend_client_with_module(self, module, version):
|
||||||
classes = inspect.getmembers(module, inspect.isclass)
|
classes = inspect.getmembers(module, inspect.isclass)
|
||||||
@@ -1662,16 +1682,22 @@ class Client(ClientBase):
|
|||||||
if hasattr(cls, 'versions'):
|
if hasattr(cls, 'versions'):
|
||||||
if version not in cls.versions:
|
if version not in cls.versions:
|
||||||
continue
|
continue
|
||||||
|
parent_resource = getattr(cls, 'parent_resource', None)
|
||||||
if issubclass(cls, client_extension.ClientExtensionList):
|
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):
|
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):
|
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):
|
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):
|
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):
|
elif issubclass(cls, client_extension.NeutronClientExtension):
|
||||||
setattr(self, "%s_path" % cls.resource_plural,
|
setattr(self, "%s_path" % cls.resource_plural,
|
||||||
cls.object_path)
|
cls.object_path)
|
||||||
|
Reference in New Issue
Block a user