summaryrefslogtreecommitdiff
path: root/neutronclient/v2_0
diff options
context:
space:
mode:
authorJustin Hammond <justin.hammond@rackspace.com>2013-11-26 23:30:47 +0000
committerJustin Hammond <justin.hammond@rackspace.com>2015-02-24 14:57:10 -0600
commit779b02e480d8bb3bb1147f3fe0e101d6f1e802d5 (patch)
tree88f32139b0df9d260d09056a308454c34619618c /neutronclient/v2_0
parentb9a7d52ecb346c4faf0a09184ac6bfc17509eab5 (diff)
downloadpython-neutronclient-779b02e480d8bb3bb1147f3fe0e101d6f1e802d5.tar.gz
Client command extension support
Adds extension support with emphasis on ease of extension creation. Extensions strongly conform to preexisting neutron commands (/neutron/v2_0/*). A sample extension has been included (/neutron/v2_0/contrib/_fox_sockets.py). As it is assumed that the sample extension will be packaged with the client, small changes were required to include it with the unit tests. It is also possible to install a module with a 'neutronclient.extension' entry- point defined. More information on this can be found in the stevedore docs under the section "Loading the Plugins". Extension discovery is modeled after nova's module discovery but deviates strongly beyond that. A conforming module, at a minimum: * Will have a class that subclasses NeutronClientExtension to provide the requisite version support, paths, and variable names for the client. Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocket * Will have at least one class that subclasses from the ClientExtension* classes to provide the new functionality to the client Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsList * ClientExtension* subclasses must have a shell_command class variable if the command is to be available to the CLI (shell.py) Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsList Provides client command extensions through new classes: NeutronClientExtension, and ClientExtension<Action>. The precedence of command loading are as follows: * hard coded commands are loaded first * contribued commands (those in /contrib) * external commands (installed in the environment) are loaded last Commands that have the same name will be overwritten by commands that are loaded later. To greatly change the execution of a command for your particular extension you only need to override the execute method. Currently this extension support is limited to top-level resources. Parent/ child relationships may be added if desired. Change-Id: I5b2fe530c90b5ce1243fc10341d6d434a1ecea7a Implements: blueprint extensible-neutronclient
Diffstat (limited to 'neutronclient/v2_0')
-rw-r--r--neutronclient/v2_0/client.py89
1 files changed, 89 insertions, 0 deletions
diff --git a/neutronclient/v2_0/client.py b/neutronclient/v2_0/client.py
index 9640572..0feac68 100644
--- a/neutronclient/v2_0/client.py
+++ b/neutronclient/v2_0/client.py
@@ -15,6 +15,8 @@
# under the License.
#
+import inspect
+import itertools
import logging
import time
@@ -24,6 +26,7 @@ import six.moves.urllib.parse as urlparse
from neutronclient import client
from neutronclient.common import constants
from neutronclient.common import exceptions
+from neutronclient.common import extension as client_extension
from neutronclient.common import serializer
from neutronclient.common import utils
from neutronclient.i18n import _
@@ -454,6 +457,36 @@ class Client(ClientBase):
}
@APIParamsCall
+ def list_ext(self, path, **_params):
+ """Client extension hook for lists.
+ """
+ return self.get(path, params=_params)
+
+ @APIParamsCall
+ def show_ext(self, path, id, **_params):
+ """Client extension hook for shows.
+ """
+ return self.get(path % id, params=_params)
+
+ @APIParamsCall
+ def create_ext(self, path, body=None):
+ """Client extension hook for creates.
+ """
+ return self.post(path, body=body)
+
+ @APIParamsCall
+ def update_ext(self, path, id, body=None):
+ """Client extension hook for updates.
+ """
+ return self.put(path % id, body=body)
+
+ @APIParamsCall
+ def delete_ext(self, path, id):
+ """Client extension hook for deletes.
+ """
+ return self.delete(path % id)
+
+ @APIParamsCall
def get_quotas_tenant(self, **_params):
"""Fetch tenant info in server's context for following quota operation.
"""
@@ -1523,3 +1556,59 @@ class Client(ClientBase):
def delete_packet_filter(self, packet_filter_id):
"""Delete the specified packet filter."""
return self.delete(self.packet_filter_path % packet_filter_id)
+
+ def __init__(self, **kwargs):
+ """Initialize a new client for the Neutron v2.0 API."""
+ super(Client, self).__init__(**kwargs)
+ self._register_extensions(self.version)
+
+ def extend_show(self, resource_plural, path):
+ 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 _fx(**_params):
+ return self.list_ext(path, **_params)
+ setattr(self, "list_%s" % resource_plural, _fx)
+
+ def extend_create(self, resource_singular, path):
+ 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 _fx(obj):
+ return self.delete_ext(path, obj)
+ setattr(self, "delete_%s" % resource_singular, _fx)
+
+ def extend_update(self, resource_singular, path):
+ def _fx(obj, body=None):
+ return self.update_ext(path, obj, body)
+ setattr(self, "update_%s" % resource_singular, _fx)
+
+ def _extend_client_with_module(self, module, version):
+ classes = inspect.getmembers(module, inspect.isclass)
+ for cls_name, cls in classes:
+ if hasattr(cls, 'versions'):
+ if version not in cls.versions:
+ continue
+ if issubclass(cls, client_extension.ClientExtensionList):
+ self.extend_list(cls.resource_plural, cls.object_path)
+ elif issubclass(cls, client_extension.ClientExtensionCreate):
+ self.extend_create(cls.resource, cls.object_path)
+ elif issubclass(cls, client_extension.ClientExtensionUpdate):
+ self.extend_update(cls.resource, cls.resource_path)
+ elif issubclass(cls, client_extension.ClientExtensionDelete):
+ self.extend_delete(cls.resource, cls.resource_path)
+ elif issubclass(cls, client_extension.ClientExtensionShow):
+ self.extend_show(cls.resource, cls.resource_path)
+ elif issubclass(cls, client_extension.NeutronClientExtension):
+ setattr(self, "%s_path" % cls.resource_plural,
+ cls.object_path)
+ setattr(self, "%s_path" % cls.resource, cls.resource_path)
+
+ def _register_extensions(self, version):
+ for name, module in itertools.chain(
+ client_extension._discover_via_entry_points()):
+ self._extend_client_with_module(module, version)