summaryrefslogtreecommitdiff
path: root/quantumclient
diff options
context:
space:
mode:
Diffstat (limited to 'quantumclient')
-rw-r--r--quantumclient/client.py250
-rw-r--r--quantumclient/common/__init__.py8
-rw-r--r--quantumclient/common/clientmanager.py87
-rw-r--r--quantumclient/common/command.py41
-rw-r--r--quantumclient/common/constants.py43
-rw-r--r--quantumclient/common/exceptions.py153
-rw-r--r--quantumclient/common/serializer.py410
-rw-r--r--quantumclient/common/utils.py188
-rw-r--r--quantumclient/openstack/__init__.py0
-rw-r--r--quantumclient/openstack/common/__init__.py0
-rw-r--r--quantumclient/openstack/common/exception.py142
-rw-r--r--quantumclient/openstack/common/gettextutils.py33
-rw-r--r--quantumclient/openstack/common/jsonutils.py148
-rw-r--r--quantumclient/openstack/common/strutils.py133
-rw-r--r--quantumclient/openstack/common/timeutils.py164
-rw-r--r--quantumclient/quantum/client.py64
-rw-r--r--quantumclient/quantum/v2_0/__init__.py574
-rw-r--r--quantumclient/quantum/v2_0/agent.py65
-rw-r--r--quantumclient/quantum/v2_0/agentscheduler.py234
-rw-r--r--quantumclient/quantum/v2_0/extension.py44
-rw-r--r--quantumclient/quantum/v2_0/floatingip.py151
-rw-r--r--quantumclient/quantum/v2_0/lb/__init__.py16
-rw-r--r--quantumclient/quantum/v2_0/lb/healthmonitor.py174
-rw-r--r--quantumclient/quantum/v2_0/lb/member.py99
-rw-r--r--quantumclient/quantum/v2_0/lb/pool.py124
-rw-r--r--quantumclient/quantum/v2_0/lb/vip.py115
-rw-r--r--quantumclient/quantum/v2_0/network.py152
-rw-r--r--quantumclient/quantum/v2_0/nvp_qos_queue.py89
-rw-r--r--quantumclient/quantum/v2_0/nvpnetworkgateway.py159
-rw-r--r--quantumclient/quantum/v2_0/port.py170
-rw-r--r--quantumclient/quantum/v2_0/quota.py232
-rw-r--r--quantumclient/quantum/v2_0/router.py230
-rw-r--r--quantumclient/quantum/v2_0/securitygroup.py259
-rw-r--r--quantumclient/quantum/v2_0/subnet.py168
-rw-r--r--quantumclient/shell.py633
-rw-r--r--quantumclient/tests/unit/test_utils.py45
-rw-r--r--quantumclient/v2_0/client.py864
37 files changed, 19 insertions, 6442 deletions
diff --git a/quantumclient/client.py b/quantumclient/client.py
index a4669c4..b816bee 100644
--- a/quantumclient/client.py
+++ b/quantumclient/client.py
@@ -1,249 +1,3 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
+from neutronclient import client
-try:
- import json
-except ImportError:
- import simplejson as json
-import logging
-import os
-import urlparse
-# Python 2.5 compat fix
-if not hasattr(urlparse, 'parse_qsl'):
- import cgi
- urlparse.parse_qsl = cgi.parse_qsl
-
-import httplib2
-
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-
-_logger = logging.getLogger(__name__)
-
-if 'QUANTUMCLIENT_DEBUG' in os.environ and os.environ['QUANTUMCLIENT_DEBUG']:
- ch = logging.StreamHandler()
- _logger.setLevel(logging.DEBUG)
- _logger.addHandler(ch)
-
-
-class ServiceCatalog(object):
- """Helper methods for dealing with a Keystone Service Catalog."""
-
- def __init__(self, resource_dict):
- self.catalog = resource_dict
-
- def get_token(self):
- """Fetch token details fron service catalog."""
- token = {'id': self.catalog['access']['token']['id'],
- 'expires': self.catalog['access']['token']['expires'], }
- try:
- token['user_id'] = self.catalog['access']['user']['id']
- token['tenant_id'] = (
- self.catalog['access']['token']['tenant']['id'])
- except Exception:
- # just leave the tenant and user out if it doesn't exist
- pass
- return token
-
- def url_for(self, attr=None, filter_value=None,
- service_type='network', endpoint_type='publicURL'):
- """Fetch the URL from the Quantum service for
- a particular endpoint type. If none given, return
- publicURL.
- """
-
- catalog = self.catalog['access'].get('serviceCatalog', [])
- matching_endpoints = []
- for service in catalog:
- if service['type'] != service_type:
- continue
-
- endpoints = service['endpoints']
- for endpoint in endpoints:
- if not filter_value or endpoint.get(attr) == filter_value:
- matching_endpoints.append(endpoint)
-
- if not matching_endpoints:
- raise exceptions.EndpointNotFound()
- elif len(matching_endpoints) > 1:
- raise exceptions.AmbiguousEndpoints(message=matching_endpoints)
- else:
- if endpoint_type not in matching_endpoints[0]:
- raise exceptions.EndpointTypeNotFound(message=endpoint_type)
-
- return matching_endpoints[0][endpoint_type]
-
-
-class HTTPClient(httplib2.Http):
- """Handles the REST calls and responses, include authn."""
-
- USER_AGENT = 'python-quantumclient'
-
- def __init__(self, username=None, tenant_name=None,
- password=None, auth_url=None,
- token=None, region_name=None, timeout=None,
- endpoint_url=None, insecure=False,
- endpoint_type='publicURL',
- auth_strategy='keystone', **kwargs):
- super(HTTPClient, self).__init__(timeout=timeout)
- self.username = username
- self.tenant_name = tenant_name
- self.password = password
- self.auth_url = auth_url.rstrip('/') if auth_url else None
- self.endpoint_type = endpoint_type
- self.region_name = region_name
- self.auth_token = token
- self.content_type = 'application/json'
- self.endpoint_url = endpoint_url
- self.auth_strategy = auth_strategy
- # httplib2 overrides
- self.force_exception_to_status_code = True
- self.disable_ssl_certificate_validation = insecure
-
- def _cs_request(self, *args, **kwargs):
- kargs = {}
- kargs.setdefault('headers', kwargs.get('headers', {}))
- kargs['headers']['User-Agent'] = self.USER_AGENT
-
- if 'content_type' in kwargs:
- kargs['headers']['Content-Type'] = kwargs['content_type']
- kargs['headers']['Accept'] = kwargs['content_type']
- else:
- kargs['headers']['Content-Type'] = self.content_type
- kargs['headers']['Accept'] = self.content_type
-
- if 'body' in kwargs:
- kargs['body'] = kwargs['body']
- args = utils.safe_encode_list(args)
- kargs = utils.safe_encode_dict(kargs)
- utils.http_log_req(_logger, args, kargs)
- resp, body = self.request(*args, **kargs)
- utils.http_log_resp(_logger, resp, body)
- status_code = self.get_status_code(resp)
- if status_code == 401:
- raise exceptions.Unauthorized(message=body)
- elif status_code == 403:
- raise exceptions.Forbidden(message=body)
- return resp, body
-
- def authenticate_and_fetch_endpoint_url(self):
- if not self.auth_token:
- self.authenticate()
- elif not self.endpoint_url:
- self.endpoint_url = self._get_endpoint_url()
-
- def do_request(self, url, method, **kwargs):
- self.authenticate_and_fetch_endpoint_url()
- # Perform the request once. If we get a 401 back then it
- # might be because the auth token expired, so try to
- # re-authenticate and try again. If it still fails, bail.
- try:
- kwargs.setdefault('headers', {})
- kwargs['headers']['X-Auth-Token'] = self.auth_token
- resp, body = self._cs_request(self.endpoint_url + url, method,
- **kwargs)
- return resp, body
- except exceptions.Unauthorized:
- self.authenticate()
- kwargs.setdefault('headers', {})
- kwargs['headers']['X-Auth-Token'] = self.auth_token
- resp, body = self._cs_request(
- self.endpoint_url + url, method, **kwargs)
- return resp, body
-
- def _extract_service_catalog(self, body):
- """Set the client's service catalog from the response data."""
- self.service_catalog = ServiceCatalog(body)
- try:
- sc = self.service_catalog.get_token()
- self.auth_token = sc['id']
- self.auth_tenant_id = sc.get('tenant_id')
- self.auth_user_id = sc.get('user_id')
- except KeyError:
- raise exceptions.Unauthorized()
- self.endpoint_url = self.service_catalog.url_for(
- attr='region', filter_value=self.region_name,
- endpoint_type=self.endpoint_type)
-
- def authenticate(self):
- if self.auth_strategy != 'keystone':
- raise exceptions.Unauthorized(message='unknown auth strategy')
- body = {'auth': {'passwordCredentials':
- {'username': self.username,
- 'password': self.password, },
- 'tenantName': self.tenant_name, }, }
-
- token_url = self.auth_url + "/tokens"
-
- # Make sure we follow redirects when trying to reach Keystone
- tmp_follow_all_redirects = self.follow_all_redirects
- self.follow_all_redirects = True
- try:
- resp, body = self._cs_request(token_url, "POST",
- body=json.dumps(body),
- content_type="application/json")
- finally:
- self.follow_all_redirects = tmp_follow_all_redirects
- status_code = self.get_status_code(resp)
- if status_code != 200:
- raise exceptions.Unauthorized(message=body)
- if body:
- try:
- body = json.loads(body)
- except ValueError:
- pass
- else:
- body = None
- self._extract_service_catalog(body)
-
- def _get_endpoint_url(self):
- url = self.auth_url + '/tokens/%s/endpoints' % self.auth_token
- try:
- resp, body = self._cs_request(url, "GET")
- except exceptions.Unauthorized:
- # rollback to authenticate() to handle case when quantum client
- # is initialized just before the token is expired
- self.authenticate()
- return self.endpoint_url
-
- body = json.loads(body)
- for endpoint in body.get('endpoints', []):
- if (endpoint['type'] == 'network' and
- endpoint.get('region') == self.region_name):
- if self.endpoint_type not in endpoint:
- raise exceptions.EndpointTypeNotFound(
- message=self.endpoint_type)
- return endpoint[self.endpoint_type]
-
- raise exceptions.EndpointNotFound()
-
- def get_auth_info(self):
- return {'auth_token': self.auth_token,
- 'auth_tenant_id': self.auth_tenant_id,
- 'auth_user_id': self.auth_user_id,
- 'endpoint_url': self.endpoint_url}
-
- def get_status_code(self, response):
- """Returns the integer status code from the response.
-
- Either a Webob.Response (used in testing) or httplib.Response
- is returned.
- """
- if hasattr(response, 'status_int'):
- return response.status_int
- else:
- return response.status
+HTTPClient = client.HTTPClient
diff --git a/quantumclient/common/__init__.py b/quantumclient/common/__init__.py
index 1415c50..7e695ff 100644
--- a/quantumclient/common/__init__.py
+++ b/quantumclient/common/__init__.py
@@ -14,11 +14,3 @@
# License for the specific language governing permissions and limitations
# under the License.
# @author: Somik Behera, Nicira Networks, Inc.
-
-import gettext
-
-t = gettext.translation('quantumclient', fallback=True)
-
-
-def _(msg):
- return t.ugettext(msg)
diff --git a/quantumclient/common/clientmanager.py b/quantumclient/common/clientmanager.py
deleted file mode 100644
index 4d219e4..0000000
--- a/quantumclient/common/clientmanager.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-"""Manage access to the clients, including authenticating when needed.
-"""
-
-import logging
-
-from quantumclient import client
-from quantumclient.quantum import client as quantum_client
-
-
-LOG = logging.getLogger(__name__)
-
-
-class ClientCache(object):
- """Descriptor class for caching created client handles.
- """
-
- def __init__(self, factory):
- self.factory = factory
- self._handle = None
-
- def __get__(self, instance, owner):
- # Tell the ClientManager to login to keystone
- if self._handle is None:
- self._handle = self.factory(instance)
- return self._handle
-
-
-class ClientManager(object):
- """Manages access to API clients, including authentication.
- """
- quantum = ClientCache(quantum_client.make_client)
-
- def __init__(self, token=None, url=None,
- auth_url=None,
- endpoint_type=None,
- tenant_name=None, tenant_id=None,
- username=None, password=None,
- region_name=None,
- api_version=None,
- auth_strategy=None,
- insecure=False
- ):
- self._token = token
- self._url = url
- self._auth_url = auth_url
- self._endpoint_type = endpoint_type
- self._tenant_name = tenant_name
- self._tenant_id = tenant_id
- self._username = username
- self._password = password
- self._region_name = region_name
- self._api_version = api_version
- self._service_catalog = None
- self._auth_strategy = auth_strategy
- self._insecure = insecure
- return
-
- def initialize(self):
- if not self._url:
- httpclient = client.HTTPClient(username=self._username,
- tenant_name=self._tenant_name,
- password=self._password,
- region_name=self._region_name,
- auth_url=self._auth_url,
- endpoint_type=self._endpoint_type,
- insecure=self._insecure)
- httpclient.authenticate()
- # Populate other password flow attributes
- self._token = httpclient.auth_token
- self._url = httpclient.endpoint_url
diff --git a/quantumclient/common/command.py b/quantumclient/common/command.py
deleted file mode 100644
index 7191436..0000000
--- a/quantumclient/common/command.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-"""
-OpenStack base command
-"""
-
-from cliff import command
-
-
-class OpenStackCommand(command.Command):
- """Base class for OpenStack commands
- """
-
- api = None
-
- def run(self, parsed_args):
- if not self.api:
- return
- else:
- return super(OpenStackCommand, self).run(parsed_args)
-
- def get_data(self, parsed_args):
- pass
-
- def take_action(self, parsed_args):
- return self.get_data(parsed_args)
diff --git a/quantumclient/common/constants.py b/quantumclient/common/constants.py
deleted file mode 100644
index a8e8276..0000000
--- a/quantumclient/common/constants.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2012 OpenStack, LLC.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-EXT_NS = '_extension_ns'
-XML_NS_V20 = 'http://openstack.org/quantum/api/v2.0'
-XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
-XSI_ATTR = "xsi:nil"
-XSI_NIL_ATTR = "xmlns:xsi"
-TYPE_XMLNS = "xmlns:quantum"
-TYPE_ATTR = "quantum:type"
-VIRTUAL_ROOT_KEY = "_v_root"
-ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
-ATOM_XMLNS = "xmlns:atom"
-ATOM_LINK_NOTATION = "{%s}link" % ATOM_NAMESPACE
-
-TYPE_BOOL = "bool"
-TYPE_INT = "int"
-TYPE_LONG = "long"
-TYPE_FLOAT = "float"
-TYPE_LIST = "list"
-TYPE_DICT = "dict"
-
-PLURALS = {'networks': 'network',
- 'ports': 'port',
- 'subnets': 'subnet',
- 'dns_nameservers': 'dns_nameserver',
- 'host_routes': 'host_route',
- 'allocation_pools': 'allocation_pool',
- 'fixed_ips': 'fixed_ip',
- 'extensions': 'extension'}
diff --git a/quantumclient/common/exceptions.py b/quantumclient/common/exceptions.py
index ee33ef7..ab22951 100644
--- a/quantumclient/common/exceptions.py
+++ b/quantumclient/common/exceptions.py
@@ -15,155 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from quantumclient.common import _
+from neutronclient.common.exceptions import * # noqa
-"""
-Quantum base exception handling.
-"""
-
-
-class QuantumException(Exception):
- """Base Quantum Exception
-
- Taken from nova.exception.NovaException
- To correctly use this class, inherit from it and define
- a 'message' property. That message will get printf'd
- with the keyword arguments provided to the constructor.
-
- """
- message = _("An unknown exception occurred.")
-
- def __init__(self, **kwargs):
- try:
- self._error_string = self.message % kwargs
-
- except Exception:
- # at least get the core message out if something happened
- self._error_string = self.message
-
- def __str__(self):
- return self._error_string
-
-
-class NotFound(QuantumException):
- pass
-
-
-class QuantumClientException(QuantumException):
-
- def __init__(self, **kwargs):
- message = kwargs.get('message')
- self.status_code = kwargs.get('status_code', 0)
- if message:
- self.message = message
- super(QuantumClientException, self).__init__(**kwargs)
-
-
-# NOTE: on the client side, we use different exception types in order
-# to allow client library users to handle server exceptions in try...except
-# blocks. The actual error message is the one generated on the server side
-class NetworkNotFoundClient(QuantumClientException):
- pass
-
-
-class PortNotFoundClient(QuantumClientException):
- pass
-
-
-class MalformedResponseBody(QuantumException):
- message = _("Malformed response body: %(reason)s")
-
-
-class StateInvalidClient(QuantumClientException):
- pass
-
-
-class NetworkInUseClient(QuantumClientException):
- pass
-
-
-class PortInUseClient(QuantumClientException):
- pass
-
-
-class AlreadyAttachedClient(QuantumClientException):
- pass
-
-
-class Unauthorized(QuantumClientException):
- message = _("Unauthorized: bad credentials.")
-
-
-class Forbidden(QuantumClientException):
- message = _("Forbidden: your credentials don't give you access to this "
- "resource.")
-
-
-class EndpointNotFound(QuantumClientException):
- """Could not find Service or Region in Service Catalog."""
- message = _("Could not find Service or Region in Service Catalog.")
-
-
-class EndpointTypeNotFound(QuantumClientException):
- """Could not find endpoint type in Service Catalog."""
-
- def __str__(self):
- msg = "Could not find endpoint type %s in Service Catalog."
- return msg % repr(self.message)
-
-
-class AmbiguousEndpoints(QuantumClientException):
- """Found more than one matching endpoint in Service Catalog."""
-
- def __str__(self):
- return "AmbiguousEndpoints: %s" % repr(self.message)
-
-
-class QuantumCLIError(QuantumClientException):
- """Exception raised when command line parsing fails."""
- pass
-
-
-class RequestURITooLong(QuantumClientException):
- """Raised when a request fails with HTTP error 414."""
-
- def __init__(self, **kwargs):
- self.excess = kwargs.get('excess', 0)
- super(RequestURITooLong, self).__init__(**kwargs)
-
-
-class ConnectionFailed(QuantumClientException):
- message = _("Connection to quantum failed: %(reason)s")
-
-
-class BadInputError(Exception):
- """Error resulting from a client sending bad input to a server."""
- pass
-
-
-class Error(Exception):
- def __init__(self, message=None):
- super(Error, self).__init__(message)
-
-
-class MalformedRequestBody(QuantumException):
- message = _("Malformed request body: %(reason)s")
-
-
-class Invalid(Error):
- pass
-
-
-class InvalidContentType(Invalid):
- message = _("Invalid content type %(content_type)s.")
-
-
-class UnsupportedVersion(Exception):
- """Indicates that the user is trying to use an unsupported
- version of the API
- """
- pass
-
-
-class CommandError(Exception):
- pass
+QuantumException = NeutronException
diff --git a/quantumclient/common/serializer.py b/quantumclient/common/serializer.py
deleted file mode 100644
index 9c595e4..0000000
--- a/quantumclient/common/serializer.py
+++ /dev/null
@@ -1,410 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-###
-### Codes from quantum wsgi
-###
-
-import logging
-
-from xml.etree import ElementTree as etree
-from xml.parsers import expat
-
-from quantumclient.common import constants
-from quantumclient.common import exceptions as exception
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.openstack.common import jsonutils
-
-LOG = logging.getLogger(__name__)
-
-
-class ActionDispatcher(object):
- """Maps method name to local methods through action name."""
-
- def dispatch(self, *args, **kwargs):
- """Find and call local method."""
- action = kwargs.pop('action', 'default')
- action_method = getattr(self, str(action), self.default)
- return action_method(*args, **kwargs)
-
- def default(self, data):
- raise NotImplementedError()
-
-
-class DictSerializer(ActionDispatcher):
- """Default request body serialization."""
-
- def serialize(self, data, action='default'):
- return self.dispatch(data, action=action)
-
- def default(self, data):
- return ""
-
-
-class JSONDictSerializer(DictSerializer):
- """Default JSON request body serialization."""
-
- def default(self, data):
- def sanitizer(obj):
- return unicode(obj)
- return jsonutils.dumps(data, default=sanitizer)
-
-
-class XMLDictSerializer(DictSerializer):
-
- def __init__(self, metadata=None, xmlns=None):
- """XMLDictSerializer constructor.
-
- :param metadata: information needed to deserialize xml into
- a dictionary.
- :param xmlns: XML namespace to include with serialized xml
- """
- super(XMLDictSerializer, self).__init__()
- self.metadata = metadata or {}
- if not xmlns:
- xmlns = self.metadata.get('xmlns')
- if not xmlns:
- xmlns = constants.XML_NS_V20
- self.xmlns = xmlns
-
- def default(self, data):
- """Default serializer of XMLDictSerializer.
-
- :param data: expect data to contain a single key as XML root, or
- contain another '*_links' key as atom links. Other
- case will use 'VIRTUAL_ROOT_KEY' as XML root.
- """
- try:
- links = None
- has_atom = False
- if data is None:
- root_key = constants.VIRTUAL_ROOT_KEY
- root_value = None
- else:
- link_keys = [k for k in data.iterkeys() or []
- if k.endswith('_links')]
- if link_keys:
- links = data.pop(link_keys[0], None)
- has_atom = True
- root_key = (len(data) == 1 and
- data.keys()[0] or constants.VIRTUAL_ROOT_KEY)
- root_value = data.get(root_key, data)
- doc = etree.Element("_temp_root")
- used_prefixes = []
- self._to_xml_node(doc, self.metadata, root_key,
- root_value, used_prefixes)
- if links:
- self._create_link_nodes(list(doc)[0], links)
- return self.to_xml_string(list(doc)[0], used_prefixes, has_atom)
- except AttributeError as e:
- LOG.exception(str(e))
- return ''
-
- def __call__(self, data):
- # Provides a migration path to a cleaner WSGI layer, this
- # "default" stuff and extreme extensibility isn't being used
- # like originally intended
- return self.default(data)
-
- def to_xml_string(self, node, used_prefixes, has_atom=False):
- self._add_xmlns(node, used_prefixes, has_atom)
- return etree.tostring(node, encoding='UTF-8')
-
- #NOTE (ameade): the has_atom should be removed after all of the
- # xml serializers and view builders have been updated to the current
- # spec that required all responses include the xmlns:atom, the has_atom
- # flag is to prevent current tests from breaking
- def _add_xmlns(self, node, used_prefixes, has_atom=False):
- node.set('xmlns', self.xmlns)
- node.set(constants.TYPE_XMLNS, self.xmlns)
- if has_atom:
- node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
- node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
- ext_ns = self.metadata.get(constants.EXT_NS, {})
- for prefix in used_prefixes:
- if prefix in ext_ns:
- node.set('xmlns:' + prefix, ext_ns[prefix])
-
- def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
- """Recursive method to convert data members to XML nodes."""
- result = etree.SubElement(parent, nodename)
- if ":" in nodename:
- used_prefixes.append(nodename.split(":", 1)[0])
- #TODO(bcwaldon): accomplish this without a type-check
- if isinstance(data, list):
- if not data:
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_LIST)
- return result
- singular = metadata.get('plurals', {}).get(nodename, None)
- if singular is None:
- if nodename.endswith('s'):
- singular = nodename[:-1]
- else:
- singular = 'item'
- for item in data:
- self._to_xml_node(result, metadata, singular, item,
- used_prefixes)
- #TODO(bcwaldon): accomplish this without a type-check
- elif isinstance(data, dict):
- if not data:
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_DICT)
- return result
- attrs = metadata.get('attributes', {}).get(nodename, {})
- for k, v in data.items():
- if k in attrs:
- result.set(k, str(v))
- else:
- self._to_xml_node(result, metadata, k, v,
- used_prefixes)
- elif data is None:
- result.set(constants.XSI_ATTR, 'true')
- else:
- if isinstance(data, bool):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_BOOL)
- elif isinstance(data, int):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_INT)
- elif isinstance(data, long):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_LONG)
- elif isinstance(data, float):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_FLOAT)
- LOG.debug(_("Data %(data)s type is %(type)s"),
- {'data': data,
- 'type': type(data)})
- if isinstance(data, str):
- result.text = unicode(data, 'utf-8')
- else:
- result.text = unicode(data)
- return result
-
- def _create_link_nodes(self, xml_doc, links):
- for link in links:
- link_node = etree.SubElement(xml_doc, 'atom:link')
- link_node.set('rel', link['rel'])
- link_node.set('href', link['href'])
-
-
-class TextDeserializer(ActionDispatcher):
- """Default request body deserialization."""
-
- def deserialize(self, datastring, action='default'):
- return self.dispatch(datastring, action=action)
-
- def default(self, datastring):
- return {}
-
-
-class JSONDeserializer(TextDeserializer):
-
- def _from_json(self, datastring):
- try:
- return jsonutils.loads(datastring)
- except ValueError:
- msg = _("Cannot understand JSON")
- raise exception.MalformedRequestBody(reason=msg)
-
- def default(self, datastring):
- return {'body': self._from_json(datastring)}
-
-
-class XMLDeserializer(TextDeserializer):
-
- def __init__(self, metadata=None):
- """XMLDeserializer constructor.
-
- :param metadata: information needed to deserialize xml into
- a dictionary.
- """
- super(XMLDeserializer, self).__init__()
- self.metadata = metadata or {}
- xmlns = self.metadata.get('xmlns')
- if not xmlns:
- xmlns = constants.XML_NS_V20
- self.xmlns = xmlns
-
- def _get_key(self, tag):
- tags = tag.split("}", 1)
- if len(tags) == 2:
- ns = tags[0][1:]
- bare_tag = tags[1]
- ext_ns = self.metadata.get(constants.EXT_NS, {})
- if ns == self.xmlns:
- return bare_tag
- for prefix, _ns in ext_ns.items():
- if ns == _ns:
- return prefix + ":" + bare_tag
- else:
- return tag
-
- def _get_links(self, root_tag, node):
- link_nodes = node.findall(constants.ATOM_LINK_NOTATION)
- root_tag = self._get_key(node.tag)
- link_key = "%s_links" % root_tag
- link_list = []
- for link in link_nodes:
- link_list.append({'rel': link.get('rel'),
- 'href': link.get('href')})
- # Remove link node in order to avoid link node being
- # processed as an item in _from_xml_node
- node.remove(link)
- return link_list and {link_key: link_list} or {}
-
- def _from_xml(self, datastring):
- if datastring is None:
- return None
- plurals = set(self.metadata.get('plurals', {}))
- try:
- node = etree.fromstring(datastring)
- root_tag = self._get_key(node.tag)
- links = self._get_links(root_tag, node)
- result = self._from_xml_node(node, plurals)
- # There is no case where root_tag = constants.VIRTUAL_ROOT_KEY
- # and links is not None because of the way data are serialized
- if root_tag == constants.VIRTUAL_ROOT_KEY:
- return result
- return dict({root_tag: result}, **links)
- except Exception as e:
- parseError = False
- # Python2.7
- if (hasattr(etree, 'ParseError') and
- isinstance(e, getattr(etree, 'ParseError'))):
- parseError = True
- # Python2.6
- elif isinstance(e, expat.ExpatError):
- parseError = True
- if parseError:
- msg = _("Cannot understand XML")
- raise exception.MalformedRequestBody(reason=msg)
- else:
- raise
-
- def _from_xml_node(self, node, listnames):
- """Convert a minidom node to a simple Python type.
-
- :param listnames: list of XML node names whose subnodes should
- be considered list items.
-
- """
- attrNil = node.get(str(etree.QName(constants.XSI_NAMESPACE, "nil")))
- attrType = node.get(str(etree.QName(
- self.metadata.get('xmlns'), "type")))
- if (attrNil and attrNil.lower() == 'true'):
- return None
- elif not len(node) and not node.text:
- if (attrType and attrType == constants.TYPE_DICT):
- return {}
- elif (attrType and attrType == constants.TYPE_LIST):
- return []
- else:
- return ''
- elif (len(node) == 0 and node.text):
- converters = {constants.TYPE_BOOL:
- lambda x: x.lower() == 'true',
- constants.TYPE_INT:
- lambda x: int(x),
- constants.TYPE_LONG:
- lambda x: long(x),
- constants.TYPE_FLOAT:
- lambda x: float(x)}
- if attrType and attrType in converters:
- return converters[attrType](node.text)
- else:
- return node.text
- elif self._get_key(node.tag) in listnames:
- return [self._from_xml_node(n, listnames) for n in node]
- else:
- result = dict()
- for attr in node.keys():
- if (attr == 'xmlns' or
- attr.startswith('xmlns:') or
- attr == constants.XSI_ATTR or
- attr == constants.TYPE_ATTR):
- continue
- result[self._get_key(attr)] = node.get(attr)
- children = list(node)
- for child in children:
- result[self._get_key(child.tag)] = self._from_xml_node(
- child, listnames)
- return result
-
- def default(self, datastring):
- return {'body': self._from_xml(datastring)}
-
- def __call__(self, datastring):
- # Adding a migration path to allow us to remove unncessary classes
- return self.default(datastring)
-
-
-# NOTE(maru): this class is duplicated from quantum.wsgi
-class Serializer(object):
- """Serializes and deserializes dictionaries to certain MIME types."""
-
- def __init__(self, metadata=None, default_xmlns=None):
- """Create a serializer based on the given WSGI environment.
-
- 'metadata' is an optional dict mapping MIME types to information
- needed to serialize a dictionary to that type.
-
- """
- self.metadata = metadata or {}
- self.default_xmlns = default_xmlns
-
- def _get_serialize_handler(self, content_type):
- handlers = {
- 'application/json': JSONDictSerializer(),
- 'application/xml': XMLDictSerializer(self.metadata),
- }
-
- try:
- return handlers[content_type]
- except Exception:
- raise exception.InvalidContentType(content_type=content_type)
-
- def serialize(self, data, content_type):
- """Serialize a dictionary into the specified content type."""
- return self._get_serialize_handler(content_type).serialize(data)
-
- def deserialize(self, datastring, content_type):
- """Deserialize a string to a dictionary.
-
- The string must be in the format of a supported MIME type.
-
- """
- return self.get_deserialize_handler(content_type).deserialize(
- datastring)
-
- def get_deserialize_handler(self, content_type):
- handlers = {
- 'application/json': JSONDeserializer(),
- 'application/xml': XMLDeserializer(self.metadata),
- }
-
- try:
- return handlers[content_type]
- except Exception:
- raise exception.InvalidContentType(content_type=content_type)
diff --git a/quantumclient/common/utils.py b/quantumclient/common/utils.py
index 192b46f..01a0442 100644
--- a/quantumclient/common/utils.py
+++ b/quantumclient/common/utils.py
@@ -1,6 +1,7 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011, Nicira Networks, Inc.
+# Copyright 2011 Nicira Networks, Inc
+# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -13,188 +14,5 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-#
-# Borrowed from nova code base, more utilities will be added/borrowed as and
-# when needed.
-# @author: Somik Behera, Nicira Networks, Inc.
-
-"""Utilities and helper functions."""
-
-import datetime
-import json
-import logging
-import os
-import sys
-
-from quantumclient.common import exceptions
-from quantumclient.openstack.common import strutils
-
-
-def env(*vars, **kwargs):
- """Returns the first environment variable set.
-
- if none are non-empty, defaults to '' or keyword arg default.
- """
- for v in vars:
- value = os.environ.get(v)
- if value:
- return value
- return kwargs.get('default', '')
-
-
-def to_primitive(value):
- if isinstance(value, list) or isinstance(value, tuple):
- o = []
- for v in value:
- o.append(to_primitive(v))
- return o
- elif isinstance(value, dict):
- o = {}
- for k, v in value.iteritems():
- o[k] = to_primitive(v)
- return o
- elif isinstance(value, datetime.datetime):
- return str(value)
- elif hasattr(value, 'iteritems'):
- return to_primitive(dict(value.iteritems()))
- elif hasattr(value, '__iter__'):
- return to_primitive(list(value))
- else:
- return value
-
-
-def dumps(value, indent=None):
- try:
- return json.dumps(value, indent=indent)
- except TypeError:
- pass
- return json.dumps(to_primitive(value))
-
-
-def loads(s):
- return json.loads(s)
-
-
-def import_class(import_str):
- """Returns a class from a string including module and class.
-
- :param import_str: a string representation of the class name
- :rtype: the requested class
- """
- mod_str, _sep, class_str = import_str.rpartition('.')
- __import__(mod_str)
- return getattr(sys.modules[mod_str], class_str)
-
-
-def get_client_class(api_name, version, version_map):
- """Returns the client class for the requested API version
-
- :param api_name: the name of the API, e.g. 'compute', 'image', etc
- :param version: the requested API version
- :param version_map: a dict of client classes keyed by version
- :rtype: a client class for the requested API version
- """
- try:
- client_path = version_map[str(version)]
- except (KeyError, ValueError):
- msg = "Invalid %s client version '%s'. must be one of: %s" % (
- (api_name, version, ', '.join(version_map.keys())))
- raise exceptions.UnsupportedVersion(msg)
-
- return import_class(client_path)
-
-
-def get_item_properties(item, fields, mixed_case_fields=[], formatters={}):
- """Return a tuple containing the item properties.
-
- :param item: a single item resource (e.g. Server, Tenant, etc)
- :param fields: tuple of strings with the desired field names
- :param mixed_case_fields: tuple of field names to preserve case
- :param formatters: dictionary mapping field names to callables
- to format the values
- """
- row = []
-
- for field in fields:
- if field in formatters:
- row.append(formatters[field](item))
- else:
- if field in mixed_case_fields:
- field_name = field.replace(' ', '_')
- else:
- field_name = field.lower().replace(' ', '_')
- if not hasattr(item, field_name) and isinstance(item, dict):
- data = item[field_name]
- else:
- data = getattr(item, field_name, '')
- if data is None:
- data = ''
- row.append(data)
- return tuple(row)
-
-
-def str2bool(strbool):
- if strbool is None:
- return None
- else:
- return strbool.lower() == 'true'
-
-
-def str2dict(strdict):
- '''Convert key1=value1,key2=value2,... string into dictionary.
-
- :param strdict: key1=value1,key2=value2
- '''
- _info = {}
- for kv_str in strdict.split(","):
- k, v = kv_str.split("=", 1)
- _info.update({k: v})
- return _info
-
-
-def http_log_req(_logger, args, kwargs):
- if not _logger.isEnabledFor(logging.DEBUG):
- return
-
- string_parts = ['curl -i']
- for element in args:
- if element in ('GET', 'POST', 'DELETE', 'PUT'):
- string_parts.append(' -X %s' % element)
- else:
- string_parts.append(' %s' % element)
-
- for element in kwargs['headers']:
- header = ' -H "%s: %s"' % (element, kwargs['headers'][element])
- string_parts.append(header)
-
- if 'body' in kwargs and kwargs['body']:
- string_parts.append(" -d '%s'" % (kwargs['body']))
- string_parts = safe_encode_list(string_parts)
- _logger.debug("\nREQ: %s\n" % "".join(string_parts))
-
-
-def http_log_resp(_logger, resp, body):
- if not _logger.isEnabledFor(logging.DEBUG):
- return
- _logger.debug("RESP:%s %s\n", resp, body)
-
-
-def _safe_encode_without_obj(data):
- if isinstance(data, basestring):
- return strutils.safe_encode(data)
- return data
-
-
-def safe_encode_list(data):
- return map(_safe_encode_without_obj, data)
-
-
-def safe_encode_dict(data):
- def _encode_item((k, v)):
- if isinstance(v, list):
- return (k, safe_encode_list(v))
- elif isinstance(v, dict):
- return (k, safe_encode_dict(v))
- return (k, _safe_encode_without_obj(v))
- return dict(map(_encode_item, data.items()))
+from neutronclient.common.utils import * # noqa
diff --git a/quantumclient/openstack/__init__.py b/quantumclient/openstack/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/quantumclient/openstack/__init__.py
+++ /dev/null
diff --git a/quantumclient/openstack/common/__init__.py b/quantumclient/openstack/common/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/quantumclient/openstack/common/__init__.py
+++ /dev/null
diff --git a/quantumclient/openstack/common/exception.py b/quantumclient/openstack/common/exception.py
deleted file mode 100644
index d7dddf3..0000000
--- a/quantumclient/openstack/common/exception.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack Foundation.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Exceptions common to OpenStack projects
-"""
-
-import logging
-
-from quantumclient.openstack.common.gettextutils import _
-
-_FATAL_EXCEPTION_FORMAT_ERRORS = False
-
-
-class Error(Exception):
- def __init__(self, message=None):
- super(Error, self).__init__(message)
-
-
-class ApiError(Error):
- def __init__(self, message='Unknown', code='Unknown'):
- self.message = message
- self.code = code
- super(ApiError, self).__init__('%s: %s' % (code, message))
-
-
-class NotFound(Error):
- pass
-
-
-class UnknownScheme(Error):
-
- msg = "Unknown scheme '%s' found in URI"
-
- def __init__(self, scheme):
- msg = self.__class__.msg % scheme
- super(UnknownScheme, self).__init__(msg)
-
-
-class BadStoreUri(Error):
-
- msg = "The Store URI %s was malformed. Reason: %s"
-
- def __init__(self, uri, reason):
- msg = self.__class__.msg % (uri, reason)
- super(BadStoreUri, self).__init__(msg)
-
-
-class Duplicate(Error):
- pass
-
-
-class NotAuthorized(Error):
- pass
-
-
-class NotEmpty(Error):
- pass
-
-
-class Invalid(Error):
- pass
-
-
-class BadInputError(Exception):
- """Error resulting from a client sending bad input to a server"""
- pass
-
-
-class MissingArgumentError(Error):
- pass
-
-
-class DatabaseMigrationError(Error):
- pass
-
-
-class ClientConnectionError(Exception):
- """Error resulting from a client connecting to a server"""
- pass
-
-
-def wrap_exception(f):
- def _wrap(*args, **kw):
- try:
- return f(*args, **kw)
- except Exception, e:
- if not isinstance(e, Error):
- #exc_type, exc_value, exc_traceback = sys.exc_info()
- logging.exception(_('Uncaught exception'))
- #logging.error(traceback.extract_stack(exc_traceback))
- raise Error(str(e))
- raise
- _wrap.func_name = f.func_name
- return _wrap
-
-
-class OpenstackException(Exception):
- """
- Base Exception
-
- To correctly use this class, inherit from it and define
- a 'message' property. That message will get printf'd
- with the keyword arguments provided to the constructor.
- """
- message = "An unknown exception occurred"
-
- def __init__(self, **kwargs):
- try:
- self._error_string = self.message % kwargs
-
- except Exception as e:
- if _FATAL_EXCEPTION_FORMAT_ERRORS:
- raise e
- else:
- # at least get the core message out if something happened
- self._error_string = self.message
-
- def __str__(self):
- return self._error_string
-
-
-class MalformedRequestBody(OpenstackException):
- message = "Malformed message body: %(reason)s"
-
-
-class InvalidContentType(OpenstackException):
- message = "Invalid content type %(content_type)s"
diff --git a/quantumclient/openstack/common/gettextutils.py b/quantumclient/openstack/common/gettextutils.py
deleted file mode 100644
index 490f194..0000000
--- a/quantumclient/openstack/common/gettextutils.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 Red Hat, Inc.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-gettext for openstack-common modules.
-
-Usual usage in an openstack.common module:
-
- from quantumclient.openstack.common.gettextutils import _
-"""
-
-import gettext
-
-
-t = gettext.translation('openstack-common', 'locale', fallback=True)
-
-
-def _(msg):
- return t.ugettext(msg)
diff --git a/quantumclient/openstack/common/jsonutils.py b/quantumclient/openstack/common/jsonutils.py
deleted file mode 100644
index ad76e06..0000000
--- a/quantumclient/openstack/common/jsonutils.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# Copyright 2011 Justin Santa Barbara
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-'''
-JSON related utilities.
-
-This module provides a few things:
-
- 1) A handy function for getting an object down to something that can be
- JSON serialized. See to_primitive().
-
- 2) Wrappers around loads() and dumps(). The dumps() wrapper will
- automatically use to_primitive() for you if needed.
-
- 3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson
- is available.
-'''
-
-
-import datetime
-import inspect
-import itertools
-import json
-import xmlrpclib
-
-from quantumclient.openstack.common import timeutils
-
-
-def to_primitive(value, convert_instances=False, level=0):
- """Convert a complex object into primitives.
-
- Handy for JSON serialization. We can optionally handle instances,
- but since this is a recursive function, we could have cyclical
- data structures.
-
- To handle cyclical data structures we could track the actual objects
- visited in a set, but not all objects are hashable. Instead we just
- track the depth of the object inspections and don't go too deep.
-
- Therefore, convert_instances=True is lossy ... be aware.
-
- """
- nasty = [inspect.ismodule, inspect.isclass, inspect.ismethod,
- inspect.isfunction, inspect.isgeneratorfunction,
- inspect.isgenerator, inspect.istraceback, inspect.isframe,
- inspect.iscode, inspect.isbuiltin, inspect.isroutine,
- inspect.isabstract]
- for test in nasty:
- if test(value):
- return unicode(value)
-
- # value of itertools.count doesn't get caught by inspects
- # above and results in infinite loop when list(value) is called.
- if type(value) == itertools.count:
- return unicode(value)
-
- # FIXME(vish): Workaround for LP bug 852095. Without this workaround,
- # tests that raise an exception in a mocked method that
- # has a @wrap_exception with a notifier will fail. If
- # we up the dependency to 0.5.4 (when it is released) we
- # can remove this workaround.
- if getattr(value, '__module__', None) == 'mox':
- return 'mock'
-
- if level > 3:
- return '?'
-
- # The try block may not be necessary after the class check above,
- # but just in case ...
- try:
- # It's not clear why xmlrpclib created their own DateTime type, but
- # for our purposes, make it a datetime type which is explicitly
- # handled
- if isinstance(value, xmlrpclib.DateTime):
- value = datetime.datetime(*tuple(value.timetuple())[:6])
-
- if isinstance(value, (list, tuple)):
- o = []
- for v in value:
- o.append(to_primitive(v, convert_instances=convert_instances,
- level=level))
- return o
- elif isinstance(value, dict):
- o = {}
- for k, v in value.iteritems():
- o[k] = to_primitive(v, convert_instances=convert_instances,
- level=level)
- return o
- elif isinstance(value, datetime.datetime):
- return timeutils.strtime(value)
- elif hasattr(value, 'iteritems'):
- return to_primitive(dict(value.iteritems()),
- convert_instances=convert_instances,
- level=level + 1)
- elif hasattr(value, '__iter__'):
- return to_primitive(list(value),
- convert_instances=convert_instances,
- level=level)
- elif convert_instances and hasattr(value, '__dict__'):
- # Likely an instance of something. Watch for cycles.
- # Ignore class member vars.
- return to_primitive(value.__dict__,
- convert_instances=convert_instances,
- level=level + 1)
- else:
- return value
- except TypeError:
- # Class objects are tricky since they may define something like
- # __iter__ defined but it isn't callable as list().
- return unicode(value)
-
-
-def dumps(value, default=to_primitive, **kwargs):
- return json.dumps(value, default=default, **kwargs)
-
-
-def loads(s):
- return json.loads(s)
-
-
-def load(s):
- return json.load(s)
-
-
-try:
- import anyjson
-except ImportError:
- pass
-else:
- anyjson._modules.append((__name__, 'dumps', TypeError,
- 'loads', ValueError, 'load'))
- anyjson.force_implementation(__name__)
diff --git a/quantumclient/openstack/common/strutils.py b/quantumclient/openstack/common/strutils.py
deleted file mode 100644
index ecf3cfd..0000000
--- a/quantumclient/openstack/common/strutils.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack Foundation.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-System-level utilities and helper functions.
-"""
-
-import logging
-import sys
-
-LOG = logging.getLogger(__name__)
-
-
-def int_from_bool_as_string(subject):
- """
- Interpret a string as a boolean and return either 1 or 0.
-
- Any string value in:
-
- ('True', 'true', 'On', 'on', '1')
-
- is interpreted as a boolean True.
-
- Useful for JSON-decoded stuff and config file parsing
- """
- return bool_from_string(subject) and 1 or 0
-
-
-def bool_from_string(subject):
- """
- Interpret a string as a boolean.
-
- Any string value in:
-
- ('True', 'true', 'On', 'on', 'Yes', 'yes', '1')
-
- is interpreted as a boolean True.
-
- Useful for JSON-decoded stuff and config file parsing
- """
- if isinstance(subject, bool):
- return subject
- if isinstance(subject, basestring):
- if subject.strip().lower() in ('true', 'on', 'yes', '1'):
- return True
- return False
-
-
-def safe_decode(text, incoming=None, errors='strict'):
- """
- Decodes incoming str using `incoming` if they're
- not already unicode.
-
- :param incoming: Text's current encoding
- :param errors: Errors handling policy. See here for valid
- values http://docs.python.org/2/library/codecs.html
- :returns: text or a unicode `incoming` encoded
- representation of it.
- :raises TypeError: If text is not an isntance of basestring
- """
- if not isinstance(text, basestring):
- raise TypeError("%s can't be decoded" % type(text))
-
- if isinstance(text, unicode):
- return text
-
- if not incoming:
- incoming = (sys.stdin.encoding or
- sys.getdefaultencoding())
-
- try:
- return text.decode(incoming, errors)
- except UnicodeDecodeError:
- # Note(flaper87) If we get here, it means that
- # sys.stdin.encoding / sys.getdefaultencoding
- # didn't return a suitable encoding to decode
- # text. This happens mostly when global LANG
- # var is not set correctly and there's no
- # default encoding. In this case, most likely
- # python will use ASCII or ANSI encoders as
- # default encodings but they won't be capable
- # of decoding non-ASCII characters.
- #
- # Also, UTF-8 is being used since it's an ASCII
- # extension.
- return text.decode('utf-8', errors)
-
-
-def safe_encode(text, incoming=None,
- encoding='utf-8', errors='strict'):
- """
- Encodes incoming str/unicode using `encoding`. If
- incoming is not specified, text is expected to
- be encoded with current python's default encoding.
- (`sys.getdefaultencoding`)
-
- :param incoming: Text's current encoding
- :param encoding: Expected encoding for text (Default UTF-8)
- :param errors: Errors handling policy. See here for valid
- values http://docs.python.org/2/library/codecs.html
- :returns: text or a bytestring `encoding` encoded
- representation of it.
- :raises TypeError: If text is not an isntance of basestring
- """
- if not isinstance(text, basestring):
- raise TypeError("%s can't be encoded" % type(text))
-
- if not incoming:
- incoming = (sys.stdin.encoding or
- sys.getdefaultencoding())
-
- if isinstance(text, unicode):
- return text.encode(encoding, errors)
- elif text and encoding != incoming:
- # Decode text before encoding it with `encoding`
- text = safe_decode(text, incoming, errors)
- return text.encode(encoding, errors)
-
- return text
diff --git a/quantumclient/openstack/common/timeutils.py b/quantumclient/openstack/common/timeutils.py
deleted file mode 100644
index 0f34608..0000000
--- a/quantumclient/openstack/common/timeutils.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Time related utilities and helper functions.
-"""
-
-import calendar
-import datetime
-
-import iso8601
-
-
-TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
-PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
-
-
-def isotime(at=None):
- """Stringify time in ISO 8601 format"""
- if not at:
- at = utcnow()
- str = at.strftime(TIME_FORMAT)
- tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC'
- str += ('Z' if tz == 'UTC' else tz)
- return str
-
-
-def parse_isotime(timestr):
- """Parse time from ISO 8601 format"""
- try:
- return iso8601.parse_date(timestr)
- except iso8601.ParseError as e:
- raise ValueError(e.message)
- except TypeError as e:
- raise ValueError(e.message)
-
-
-def strtime(at=None, fmt=PERFECT_TIME_FORMAT):
- """Returns formatted utcnow."""
- if not at:
- at = utcnow()
- return at.strftime(fmt)
-
-
-def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT):
- """Turn a formatted time back into a datetime."""
- return datetime.datetime.strptime(timestr, fmt)
-
-
-def normalize_time(timestamp):
- """Normalize time in arbitrary timezone to UTC naive object"""
- offset = timestamp.utcoffset()
- if offset is None:
- return timestamp
- return timestamp.replace(tzinfo=None) - offset
-
-
-def is_older_than(before, seconds):
- """Return True if before is older than seconds."""
- if isinstance(before, basestring):
- before = parse_strtime(before).replace(tzinfo=None)
- return utcnow() - before > datetime.timedelta(seconds=seconds)
-
-
-def is_newer_than(after, seconds):
- """Return True if after is newer than seconds."""
- if isinstance(after, basestring):
- after = parse_strtime(after).replace(tzinfo=None)
- return after - utcnow() > datetime.timedelta(seconds=seconds)
-
-
-def utcnow_ts():
- """Timestamp version of our utcnow function."""
- return calendar.timegm(utcnow().timetuple())
-
-
-def utcnow():
- """Overridable version of utils.utcnow."""
- if utcnow.override_time:
- try:
- return utcnow.override_time.pop(0)
- except AttributeError:
- return utcnow.override_time
- return datetime.datetime.utcnow()
-
-
-utcnow.override_time = None
-
-
-def set_time_override(override_time=datetime.datetime.utcnow()):
- """
- Override utils.utcnow to return a constant time or a list thereof,
- one at a time.
- """
- utcnow.override_time = override_time
-
-
-def advance_time_delta(timedelta):
- """Advance overridden time using a datetime.timedelta."""
- assert(not utcnow.override_time is None)
- try:
- for dt in utcnow.override_time:
- dt += timedelta
- except TypeError:
- utcnow.override_time += timedelta
-
-
-def advance_time_seconds(seconds):
- """Advance overridden time by seconds."""
- advance_time_delta(datetime.timedelta(0, seconds))
-
-
-def clear_time_override():
- """Remove the overridden time."""
- utcnow.override_time = None
-
-
-def marshall_now(now=None):
- """Make an rpc-safe datetime with microseconds.
-
- Note: tzinfo is stripped, but not required for relative times."""
- if not now:
- now = utcnow()
- return dict(day=now.day, month=now.month, year=now.year, hour=now.hour,
- minute=now.minute, second=now.second,
- microsecond=now.microsecond)
-
-
-def unmarshall_time(tyme):
- """Unmarshall a datetime dict."""
- return datetime.datetime(day=tyme['day'],
- month=tyme['month'],
- year=tyme['year'],
- hour=tyme['hour'],
- minute=tyme['minute'],
- second=tyme['second'],
- microsecond=tyme['microsecond'])
-
-
-def delta_seconds(before, after):
- """
- Compute the difference in seconds between two date, time, or
- datetime objects (as a float, to microsecond resolution).
- """
- delta = after - before
- try:
- return delta.total_seconds()
- except AttributeError:
- return ((delta.days * 24 * 3600) + delta.seconds +
- float(delta.microseconds) / (10 ** 6))
diff --git a/quantumclient/quantum/client.py b/quantumclient/quantum/client.py
deleted file mode 100644
index 1661a63..0000000
--- a/quantumclient/quantum/client.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-
-
-API_NAME = 'network'
-API_VERSIONS = {
- '2.0': 'quantumclient.v2_0.client.Client',
-}
-
-
-def make_client(instance):
- """Returns an quantum client.
- """
- quantum_client = utils.get_client_class(
- API_NAME,
- instance._api_version[API_NAME],
- API_VERSIONS,
- )
- instance.initialize()
- url = instance._url
- url = url.rstrip("/")
- if '2.0' == instance._api_version[API_NAME]:
- client = quantum_client(username=instance._username,
- tenant_name=instance._tenant_name,
- password=instance._password,
- region_name=instance._region_name,
- auth_url=instance._auth_url,
- endpoint_url=url,
- token=instance._token,
- auth_strategy=instance._auth_strategy,
- insecure=instance._insecure)
- return client
- else:
- raise exceptions.UnsupportedVersion("API version %s is not supported" %
- instance._api_version[API_NAME])
-
-
-def Client(api_version, *args, **kwargs):
- """Return an quantum client.
- @param api_version: only 2.0 is supported now
- """
- quantum_client = utils.get_client_class(
- API_NAME,
- api_version,
- API_VERSIONS,
- )
- return quantum_client(*args, **kwargs)
diff --git a/quantumclient/quantum/v2_0/__init__.py b/quantumclient/quantum/v2_0/__init__.py
index 1be1d29..38e43ab 100644
--- a/quantumclient/quantum/v2_0/__init__.py
+++ b/quantumclient/quantum/v2_0/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2012 OpenStack LLC.
+# Copyright 2013 OpenStack Foundation.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -15,574 +15,6 @@
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-import argparse
-import logging
-import re
+from neutronclient.neutron.v2_0 import NeutronCommand
-from cliff.formatters import table
-from cliff import lister
-from cliff import show
-
-from quantumclient.common import command
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-from quantumclient.openstack.common.gettextutils import _
-
-HEX_ELEM = '[0-9A-Fa-f]'
-UUID_PATTERN = '-'.join([HEX_ELEM + '{8}', HEX_ELEM + '{4}',
- HEX_ELEM + '{4}', HEX_ELEM + '{4}',
- HEX_ELEM + '{12}'])
-
-
-def find_resourceid_by_name_or_id(client, resource, name_or_id):
- obj_lister = getattr(client, "list_%ss" % resource)
- # perform search by id only if we are passing a valid UUID
- match = re.match(UUID_PATTERN, name_or_id)
- collection = resource + "s"
- if match:
- data = obj_lister(id=name_or_id, fields='id')
- if data and data[collection]:
- return data[collection][0]['id']
- return _find_resourceid_by_name(client, resource, name_or_id)
-
-
-def _find_resourceid_by_name(client, resource, name):
- obj_lister = getattr(client, "list_%ss" % resource)
- data = obj_lister(name=name, fields='id')
- collection = resource + "s"
- info = data[collection]
- if len(info) > 1:
- msg = (_("Multiple %(resource)s matches found for name '%(name)s',"
- " use an ID to be more specific.") %
- {'resource': resource, 'name': name})
- raise exceptions.QuantumClientException(
- message=msg)
- elif len(info) == 0:
- not_found_message = (_("Unable to find %(resource)s with name "
- "'%(name)s'") %
- {'resource': resource, 'name': name})
- # 404 is used to simulate server side behavior
- raise exceptions.QuantumClientException(
- message=not_found_message, status_code=404)
- else:
- return info[0]['id']
-
-
-def add_show_list_common_argument(parser):
- parser.add_argument(
- '-D', '--show-details',
- help='show detailed info',
- action='store_true',
- default=False, )
- parser.add_argument(
- '--show_details',
- action='store_true',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--fields',
- help=argparse.SUPPRESS,
- action='append',
- default=[])
- parser.add_argument(
- '-F', '--field',
- dest='fields', metavar='FIELD',
- help='specify the field(s) to be returned by server,'
- ' can be repeated',
- action='append',
- default=[])
-
-
-def add_pagination_argument(parser):
- parser.add_argument(
- '-P', '--page-size',
- dest='page_size', metavar='SIZE', type=int,
- help=("specify retrieve unit of each request, then split one request "
- "to several requests"),
- default=None)
-
-
-def add_sorting_argument(parser):
- parser.add_argument(
- '--sort-key',
- dest='sort_key', metavar='FIELD',
- action='append',
- help=("sort list by specified fields (This option can be repeated), "
- "The number of sort_dir and sort_key should match each other, "
- "more sort_dir specified will be omitted, less will be filled "
- "with asc as default direction "),
- default=[])
- parser.add_argument(
- '--sort-dir',
- dest='sort_dir', metavar='{asc,desc}',
- help=("sort list in specified directions "
- "(This option can be repeated)"),
- action='append',
- default=[],
- choices=['asc', 'desc'])
-
-
-def is_number(s):
- try:
- float(s) # for int, long and float
- except ValueError:
- try:
- complex(s) # for complex
- except ValueError:
- return False
-
- return True
-
-
-def parse_args_to_dict(values_specs):
- '''It is used to analyze the extra command options to command.
-
- Besides known options and arguments, our commands also support user to
- put more options to the end of command line. For example,
- list_nets -- --tag x y --key1 value1, where '-- --tag x y --key1 value1'
- is extra options to our list_nets. This feature can support V2.0 API's
- fields selection and filters. For example, to list networks which has name
- 'test4', we can have list_nets -- --name=test4.
-
- value spec is: --key type=int|bool|... value. Type is one of Python
- built-in types. By default, type is string. The key without value is
- a bool option. Key with two values will be a list option.
-
- '''
- # -- is a pseudo argument
- values_specs_copy = values_specs[:]
- if values_specs_copy and values_specs_copy[0] == '--':
- del values_specs_copy[0]
- _options = {}
- current_arg = None
- _values_specs = []
- _value_number = 0
- _list_flag = False
- current_item = None
- for _item in values_specs_copy:
- if _item.startswith('--'):
- if current_arg is not None:
- if _value_number > 1 or _list_flag:
- current_arg.update({'nargs': '+'})
- elif _value_number == 0:
- current_arg.update({'action': 'store_true'})
- _temp = _item
- if "=" in _item:
- _item = _item.split('=')[0]
- if _item in _options:
- raise exceptions.CommandError(
- "duplicated options %s" % ' '.join(values_specs))
- else:
- _options.update({_item: {}})
- current_arg = _options[_item]
- _item = _temp
- elif _item.startswith('type='):
- if current_arg is None:
- raise exceptions.CommandError(
- "invalid values_specs %s" % ' '.join(values_specs))
- if 'type' not in current_arg:
- _type_str = _item.split('=', 2)[1]
- current_arg.update({'type': eval(_type_str)})
- if _type_str == 'bool':
- current_arg.update({'type': utils.str2bool})
- elif _type_str == 'dict':
- current_arg.update({'type': utils.str2dict})
- continue
- elif _item == 'list=true':
- _list_flag = True
- continue
- if not _item.startswith('--'):
- if (not current_item or '=' in current_item or
- _item.startswith('-') and not is_number(_item)):
- raise exceptions.CommandError(
- "Invalid values_specs %s" % ' '.join(values_specs))
- _value_number += 1
- elif _item.startswith('--'):
- current_item = _item
- if '=' in current_item:
- _value_number = 1
- else:
- _value_number = 0
- _list_flag = False
- _values_specs.append(_item)
- if current_arg is not None:
- if _value_number > 1 or _list_flag:
- current_arg.update({'nargs': '+'})
- elif _value_number == 0:
- current_arg.update({'action': 'store_true'})
- _args = None
- if _values_specs:
- _parser = argparse.ArgumentParser(add_help=False)
- for opt, optspec in _options.iteritems():
- _parser.add_argument(opt, **optspec)
- _args = _parser.parse_args(_values_specs)
- result_dict = {}
- if _args:
- for opt in _options.iterkeys():
- _opt = opt.split('--', 2)[1]
- _opt = _opt.replace('-', '_')
- _value = getattr(_args, _opt)
- if _value is not None:
- result_dict.update({_opt: _value})
- return result_dict
-
-
-def _merge_args(qCmd, parsed_args, _extra_values, value_specs):
- """Merge arguments from _extra_values into parsed_args.
-
- If an argument value are provided in both and it is a list,
- the values in _extra_values will be merged into parsed_args.
-
- @param parsed_args: the parsed args from known options
- @param _extra_values: the other parsed arguments in unknown parts
- @param values_specs: the unparsed unknown parts
- """
- temp_values = _extra_values.copy()
- for key, value in temp_values.iteritems():
- if hasattr(parsed_args, key):
- arg_value = getattr(parsed_args, key)
- if arg_value is not None and value is not None:
- if isinstance(arg_value, list):
- if value and isinstance(value, list):
- if type(arg_value[0]) == type(value[0]):
- arg_value.extend(value)
- _extra_values.pop(key)
-
-
-def update_dict(obj, dict, attributes):
- for attribute in attributes:
- if hasattr(obj, attribute) and getattr(obj, attribute):
- dict[attribute] = getattr(obj, attribute)
-
-
-class TableFormater(table.TableFormatter):
- """This class is used to keep consistency with prettytable 0.6.
-
- https://bugs.launchpad.net/python-quantumclient/+bug/1165962
- """
- def emit_list(self, column_names, data, stdout, parsed_args):
- if column_names:
- super(TableFormater, self).emit_list(column_names, data, stdout,
- parsed_args)
- else:
- stdout.write('\n')
-
-
-class QuantumCommand(command.OpenStackCommand):
- api = 'network'
- log = logging.getLogger(__name__ + '.QuantumCommand')
- values_specs = []
- json_indent = None
-
- def __init__(self, app, app_args):
- super(QuantumCommand, self).__init__(app, app_args)
- if hasattr(self, 'formatters'):
- self.formatters['table'] = TableFormater()
-
- def get_client(self):
- return self.app.client_manager.quantum
-
- def get_parser(self, prog_name):
- parser = super(QuantumCommand, self).get_parser(prog_name)
- parser.add_argument(
- '--request-format',
- help=_('the xml or json request format'),
- default='json',
- choices=['json', 'xml', ], )
- parser.add_argument(
- '--request_format',
- choices=['json', 'xml', ],
- help=argparse.SUPPRESS)
-
- return parser
-
- def format_output_data(self, data):
- # Modify data to make it more readable
- if self.resource in data:
- for k, v in data[self.resource].iteritems():
- if isinstance(v, list):
- value = '\n'.join(utils.dumps(
- i, indent=self.json_indent) if isinstance(i, dict)
- else str(i) for i in v)
- data[self.resource][k] = value
- elif isinstance(v, dict):
- value = utils.dumps(v, indent=self.json_indent)
- data[self.resource][k] = value
- elif v is None:
- data[self.resource][k] = ''
-
- def add_known_arguments(self, parser):
- pass
-
- def args2body(self, parsed_args):
- return {}
-
-
-class CreateCommand(QuantumCommand, show.ShowOne):
- """Create a resource for a given tenant
-
- """
-
- api = 'network'
- resource = None
- log = None
-
- def get_parser(self, prog_name):
- parser = super(CreateCommand, self).get_parser(prog_name)
- parser.add_argument(
- '--tenant-id', metavar='TENANT_ID',
- help=_('the owner tenant ID'), )
- parser.add_argument(
- '--tenant_id',
- help=argparse.SUPPRESS)
- self.add_known_arguments(parser)
- return parser
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = parse_args_to_dict(self.values_specs)
- _merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- body = self.args2body(parsed_args)
- body[self.resource].update(_extra_values)
- obj_creator = getattr(quantum_client,
- "create_%s" % self.resource)
- data = obj_creator(body)
- self.format_output_data(data)
- # {u'network': {u'id': u'e9424a76-6db4-4c93-97b6-ec311cd51f19'}}
- info = self.resource in data and data[self.resource] or None
- if info:
- print >>self.app.stdout, _('Created a new %s:') % self.resource
- else:
- info = {'': ''}
- return zip(*sorted(info.iteritems()))
-
-
-class UpdateCommand(QuantumCommand):
- """Update resource's information
- """
-
- api = 'network'
- resource = None
- log = None
-
- def get_parser(self, prog_name):
- parser = super(UpdateCommand, self).get_parser(prog_name)
- parser.add_argument(
- 'id', metavar=self.resource.upper(),
- help='ID or name of %s to update' % self.resource)
- self.add_known_arguments(parser)
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = parse_args_to_dict(self.values_specs)
- _merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- body = self.args2body(parsed_args)
- if self.resource in body:
- body[self.resource].update(_extra_values)
- else:
- body[self.resource] = _extra_values
- if not body[self.resource]:
- raise exceptions.CommandError(
- "Must specify new values to update %s" % self.resource)
- _id = find_resourceid_by_name_or_id(quantum_client,
- self.resource,
- parsed_args.id)
- obj_updator = getattr(quantum_client,
- "update_%s" % self.resource)
- obj_updator(_id, body)
- print >>self.app.stdout, (
- _('Updated %(resource)s: %(id)s') %
- {'id': parsed_args.id, 'resource': self.resource})
- return
-
-
-class DeleteCommand(QuantumCommand):
- """Delete a given resource
-
- """
-
- api = 'network'
- resource = None
- log = None
- allow_names = True
-
- def get_parser(self, prog_name):
- parser = super(DeleteCommand, self).get_parser(prog_name)
- if self.allow_names:
- help_str = 'ID or name of %s to delete'
- else:
- help_str = 'ID of %s to delete'
- parser.add_argument(
- 'id', metavar=self.resource.upper(),
- help=help_str % self.resource)
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- obj_deleter = getattr(quantum_client,
- "delete_%s" % self.resource)
- if self.allow_names:
- _id = find_resourceid_by_name_or_id(quantum_client, self.resource,
- parsed_args.id)
- else:
- _id = parsed_args.id
- obj_deleter(_id)
- print >>self.app.stdout, (_('Deleted %(resource)s: %(id)s')
- % {'id': parsed_args.id,
- 'resource': self.resource})
- return
-
-
-class ListCommand(QuantumCommand, lister.Lister):
- """List resources that belong to a given tenant
-
- """
-
- api = 'network'
- resource = None
- log = None
- _formatters = {}
- list_columns = []
- unknown_parts_flag = True
- pagination_support = False
- sorting_support = False
-
- def get_parser(self, prog_name):
- parser = super(ListCommand, self).get_parser(prog_name)
- add_show_list_common_argument(parser)
- if self.pagination_support:
- add_pagination_argument(parser)
- if self.sorting_support:
- add_sorting_argument(parser)
- return parser
-
- def args2search_opts(self, parsed_args):
- search_opts = {}
- fields = parsed_args.fields
- if parsed_args.fields:
- search_opts.update({'fields': fields})
- if parsed_args.show_details:
- search_opts.update({'verbose': 'True'})
- return search_opts
-
- def call_server(self, quantum_client, search_opts, parsed_args):
- obj_lister = getattr(quantum_client,
- "list_%ss" % self.resource)
- data = obj_lister(**search_opts)
- return data
-
- def retrieve_list(self, parsed_args):
- """Retrieve a list of resources from Quantum server"""
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = parse_args_to_dict(self.values_specs)
- _merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- search_opts = self.args2search_opts(parsed_args)
- search_opts.update(_extra_values)
- if self.pagination_support:
- page_size = parsed_args.page_size
- if page_size:
- search_opts.update({'limit': page_size})
- if self.sorting_support:
- keys = parsed_args.sort_key
- if keys:
- search_opts.update({'sort_key': keys})
- dirs = parsed_args.sort_dir
- len_diff = len(keys) - len(dirs)
- if len_diff > 0:
- dirs += ['asc'] * len_diff
- elif len_diff < 0:
- dirs = dirs[:len(keys)]
- if dirs:
- search_opts.update({'sort_dir': dirs})
- data = self.call_server(quantum_client, search_opts, parsed_args)
- collection = self.resource + "s"
- return data.get(collection, [])
-
- def extend_list(self, data, parsed_args):
- """Update a retrieved list.
-
- This method provides a way to modify a original list returned from
- the quantum server. For example, you can add subnet cidr information
- to a list network.
- """
- pass
-
- def setup_columns(self, info, parsed_args):
- _columns = len(info) > 0 and sorted(info[0].keys()) or []
- if not _columns:
- # clean the parsed_args.columns so that cliff will not break
- parsed_args.columns = []
- elif parsed_args.columns:
- _columns = [x for x in parsed_args.columns if x in _columns]
- elif self.list_columns:
- # if no -c(s) by user and list_columns, we use columns in
- # both list_columns and returned resource.
- # Also Keep their order the same as in list_columns
- _columns = [x for x in self.list_columns if x in _columns]
- return (_columns, (utils.get_item_properties(
- s, _columns, formatters=self._formatters, )
- for s in info), )
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- data = self.retrieve_list(parsed_args)
- self.extend_list(data, parsed_args)
- return self.setup_columns(data, parsed_args)
-
-
-class ShowCommand(QuantumCommand, show.ShowOne):
- """Show information of a given resource
-
- """
-
- api = 'network'
- resource = None
- log = None
- allow_names = True
-
- def get_parser(self, prog_name):
- parser = super(ShowCommand, self).get_parser(prog_name)
- add_show_list_common_argument(parser)
- if self.allow_names:
- help_str = 'ID or name of %s to look up'
- else:
- help_str = 'ID of %s to look up'
- parser.add_argument(
- 'id', metavar=self.resource.upper(),
- help=help_str % self.resource)
- return parser
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
-
- params = {}
- if parsed_args.show_details:
- params = {'verbose': 'True'}
- if parsed_args.fields:
- params = {'fields': parsed_args.fields}
- if self.allow_names:
- _id = find_resourceid_by_name_or_id(quantum_client, self.resource,
- parsed_args.id)
- else:
- _id = parsed_args.id
-
- obj_shower = getattr(quantum_client, "show_%s" % self.resource)
- data = obj_shower(_id, **params)
- self.format_output_data(data)
- resource = data[self.resource]
- if self.resource in data:
- return zip(*sorted(resource.iteritems()))
- else:
- return None
+QuantumCommand = NeutronCommand
diff --git a/quantumclient/quantum/v2_0/agent.py b/quantumclient/quantum/v2_0/agent.py
deleted file mode 100644
index 67bf87e..0000000
--- a/quantumclient/quantum/v2_0/agent.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.quantum import v2_0 as quantumV20
-
-
-def _format_timestamp(component):
- try:
- return component['heartbeat_timestamp'].split(".", 2)[0]
- except Exception:
- return ''
-
-
-class ListAgent(quantumV20.ListCommand):
- """List agents."""
-
- resource = 'agent'
- log = logging.getLogger(__name__ + '.ListAgent')
- list_columns = ['id', 'agent_type', 'host', 'alive', 'admin_state_up']
- _formatters = {'heartbeat_timestamp': _format_timestamp}
-
- def extend_list(self, data, parsed_args):
- for agent in data:
- agent['alive'] = ":-)" if agent['alive'] else 'xxx'
-
-
-class ShowAgent(quantumV20.ShowCommand):
- """Show information of a given agent."""
-
- resource = 'agent'
- log = logging.getLogger(__name__ + '.ShowAgent')
- allow_names = False
- json_indent = 5
-
-
-class DeleteAgent(quantumV20.DeleteCommand):
- """Delete a given agent."""
-
- log = logging.getLogger(__name__ + '.DeleteAgent')
- resource = 'agent'
- allow_names = False
-
-
-class UpdateAgent(quantumV20.UpdateCommand):
- """Update a given agent."""
-
- log = logging.getLogger(__name__ + '.UpdateAgent')
- resource = 'agent'
- allow_names = False
diff --git a/quantumclient/quantum/v2_0/agentscheduler.py b/quantumclient/quantum/v2_0/agentscheduler.py
deleted file mode 100644
index 8e41376..0000000
--- a/quantumclient/quantum/v2_0/agentscheduler.py
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.quantum import v2_0 as quantumV20
-from quantumclient.quantum.v2_0 import network
-from quantumclient.quantum.v2_0 import router
-PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
-
-
-class AddNetworkToDhcpAgent(quantumV20.QuantumCommand):
- """Add a network to a DHCP agent."""
-
- log = logging.getLogger(__name__ + '.AddNetworkToDhcpAgent')
-
- def get_parser(self, prog_name):
- parser = super(AddNetworkToDhcpAgent, self).get_parser(prog_name)
- parser.add_argument(
- 'dhcp_agent',
- help='ID of the DHCP agent')
- parser.add_argument(
- 'network',
- help='network to add')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _net_id = quantumV20.find_resourceid_by_name_or_id(
- quantum_client, 'network', parsed_args.network)
- quantum_client.add_network_to_dhcp_agent(parsed_args.dhcp_agent,
- {'network_id': _net_id})
- print >>self.app.stdout, (
- _('Added network %s to DHCP agent') % parsed_args.network)
-
-
-class RemoveNetworkFromDhcpAgent(quantumV20.QuantumCommand):
- """Remove a network from a DHCP agent."""
- log = logging.getLogger(__name__ + '.RemoveNetworkFromDhcpAgent')
-
- def get_parser(self, prog_name):
- parser = super(RemoveNetworkFromDhcpAgent, self).get_parser(prog_name)
- parser.add_argument(
- 'dhcp_agent',
- help='ID of the DHCP agent')
- parser.add_argument(
- 'network',
- help='network to remove')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _net_id = quantumV20.find_resourceid_by_name_or_id(
- quantum_client, 'network', parsed_args.network)
- quantum_client.remove_network_from_dhcp_agent(
- parsed_args.dhcp_agent, _net_id)
- print >>self.app.stdout, (
- _('Removed network %s to DHCP agent') % parsed_args.network)
-
-
-class ListNetworksOnDhcpAgent(network.ListNetwork):
- """List the networks on a DHCP agent."""
-
- log = logging.getLogger(__name__ + '.ListNetworksOnDhcpAgent')
- unknown_parts_flag = False
-
- def get_parser(self, prog_name):
- parser = super(ListNetworksOnDhcpAgent,
- self).get_parser(prog_name)
- parser.add_argument(
- 'dhcp_agent',
- help='ID of the DHCP agent')
- return parser
-
- def call_server(self, quantum_client, search_opts, parsed_args):
- data = quantum_client.list_networks_on_dhcp_agent(
- parsed_args.dhcp_agent, **search_opts)
- return data
-
-
-class ListDhcpAgentsHostingNetwork(quantumV20.ListCommand):
- """List DHCP agents hosting a network."""
-
- resource = 'agent'
- _formatters = {}
- log = logging.getLogger(__name__ + '.ListDhcpAgentsHostingNetwork')
- list_columns = ['id', 'host', 'admin_state_up', 'alive']
- unknown_parts_flag = False
-
- def get_parser(self, prog_name):
- parser = super(ListDhcpAgentsHostingNetwork,
- self).get_parser(prog_name)
- parser.add_argument(
- 'network',
- help='network to query')
- return parser
-
- def extend_list(self, data, parsed_args):
- for agent in data:
- agent['alive'] = ":-)" if agent['alive'] else 'xxx'
-
- def call_server(self, quantum_client, search_opts, parsed_args):
- _id = quantumV20.find_resourceid_by_name_or_id(quantum_client,
- 'network',
- parsed_args.network)
- search_opts['network'] = _id
- data = quantum_client.list_dhcp_agent_hosting_networks(**search_opts)
- return data
-
-
-class AddRouterToL3Agent(quantumV20.QuantumCommand):
- """Add a router to a L3 agent."""
-
- log = logging.getLogger(__name__ + '.AddRouterToL3Agent')
-
- def get_parser(self, prog_name):
- parser = super(AddRouterToL3Agent, self).get_parser(prog_name)
- parser.add_argument(
- 'l3_agent',
- help='ID of the L3 agent')
- parser.add_argument(
- 'router',
- help='router to add')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _id = quantumV20.find_resourceid_by_name_or_id(
- quantum_client, 'router', parsed_args.router)
- quantum_client.add_router_to_l3_agent(parsed_args.l3_agent,
- {'router_id': _id})
- print >>self.app.stdout, (
- _('Added router %s to L3 agent') % parsed_args.router)
-
-
-class RemoveRouterFromL3Agent(quantumV20.QuantumCommand):
- """Remove a router from a L3 agent."""
-
- log = logging.getLogger(__name__ + '.RemoveRouterFromL3Agent')
-
- def get_parser(self, prog_name):
- parser = super(RemoveRouterFromL3Agent, self).get_parser(prog_name)
- parser.add_argument(
- 'l3_agent',
- help='ID of the L3 agent')
- parser.add_argument(
- 'router',
- help='router to remove')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _id = quantumV20.find_resourceid_by_name_or_id(
- quantum_client, 'router', parsed_args.router)
- quantum_client.remove_router_from_l3_agent(
- parsed_args.l3_agent, _id)
- print >>self.app.stdout, (
- _('Removed Router %s to L3 agent') % parsed_args.router)
-
-
-class ListRoutersOnL3Agent(quantumV20.ListCommand):
- """List the routers on a L3 agent."""
-
- log = logging.getLogger(__name__ + '.ListRoutersOnL3Agent')
- _formatters = {'external_gateway_info':
- router._format_external_gateway_info}
- list_columns = ['id', 'name', 'external_gateway_info']
- resource = 'router'
- unknown_parts_flag = False
-
- def get_parser(self, prog_name):
- parser = super(ListRoutersOnL3Agent,
- self).get_parser(prog_name)
- parser.add_argument(
- 'l3_agent',
- help='ID of the L3 agent to query')
- return parser
-
- def call_server(self, quantum_client, search_opts, parsed_args):
- data = quantum_client.list_routers_on_l3_agent(
- parsed_args.l3_agent, **search_opts)
- return data
-
-
-class ListL3AgentsHostingRouter(quantumV20.ListCommand):
- """List L3 agents hosting a router."""
-
- resource = 'agent'
- _formatters = {}
- log = logging.getLogger(__name__ + '.ListL3AgentsHostingRouter')
- list_columns = ['id', 'host', 'admin_state_up', 'alive', 'default']
- unknown_parts_flag = False
-
- def get_parser(self, prog_name):
- parser = super(ListL3AgentsHostingRouter,
- self).get_parser(prog_name)
- parser.add_argument('router',
- help='router to query')
- return parser
-
- def extend_list(self, data, parsed_args):
- for agent in data:
- agent['alive'] = ":-)" if agent['alive'] else 'xxx'
-
- def call_server(self, quantum_client, search_opts, parsed_args):
- _id = quantumV20.find_resourceid_by_name_or_id(quantum_client,
- 'router',
- parsed_args.router)
- search_opts['router'] = _id
- data = quantum_client.list_l3_agent_hosting_routers(**search_opts)
- return data
diff --git a/quantumclient/quantum/v2_0/extension.py b/quantumclient/quantum/v2_0/extension.py
deleted file mode 100644
index 1ebea6f..0000000
--- a/quantumclient/quantum/v2_0/extension.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.quantum import v2_0 as cmd_base
-
-
-class ListExt(cmd_base.ListCommand):
- """List all extensions."""
-
- resource = 'extension'
- log = logging.getLogger(__name__ + '.ListExt')
- list_columns = ['alias', 'name']
-
-
-class ShowExt(cmd_base.ShowCommand):
- """Show information of a given resource."""
-
- resource = "extension"
- log = logging.getLogger(__name__ + '.ShowExt')
- allow_names = False
-
- def get_parser(self, prog_name):
- parser = super(cmd_base.ShowCommand, self).get_parser(prog_name)
- cmd_base.add_show_list_common_argument(parser)
- parser.add_argument(
- 'id', metavar='EXT-ALIAS',
- help='the extension alias')
- return parser
diff --git a/quantumclient/quantum/v2_0/floatingip.py b/quantumclient/quantum/v2_0/floatingip.py
deleted file mode 100644
index 1d82444..0000000
--- a/quantumclient/quantum/v2_0/floatingip.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import argparse
-import logging
-
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListFloatingIP(quantumv20.ListCommand):
- """List floating ips that belong to a given tenant."""
-
- resource = 'floatingip'
- log = logging.getLogger(__name__ + '.ListFloatingIP')
- list_columns = ['id', 'fixed_ip_address', 'floating_ip_address',
- 'port_id']
- pagination_support = True
- sorting_support = True
-
-
-class ShowFloatingIP(quantumv20.ShowCommand):
- """Show information of a given floating ip."""
-
- resource = 'floatingip'
- log = logging.getLogger(__name__ + '.ShowFloatingIP')
- allow_names = False
-
-
-class CreateFloatingIP(quantumv20.CreateCommand):
- """Create a floating ip for a given tenant."""
-
- resource = 'floatingip'
- log = logging.getLogger(__name__ + '.CreateFloatingIP')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'floating_network_id', metavar='FLOATING_NETWORK',
- help='Network name or id to allocate floating IP from')
- parser.add_argument(
- '--port-id',
- help='ID of the port to be associated with the floatingip')
- parser.add_argument(
- '--port_id',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--fixed-ip-address',
- help=('IP address on the port (only required if port has multiple'
- 'IPs)'))
- parser.add_argument(
- '--fixed_ip_address',
- help=argparse.SUPPRESS)
-
- def args2body(self, parsed_args):
- _network_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'network', parsed_args.floating_network_id)
- body = {self.resource: {'floating_network_id': _network_id}}
- if parsed_args.port_id:
- body[self.resource].update({'port_id': parsed_args.port_id})
- if parsed_args.tenant_id:
- body[self.resource].update({'tenant_id': parsed_args.tenant_id})
- if parsed_args.fixed_ip_address:
- body[self.resource].update({'fixed_ip_address':
- parsed_args.fixed_ip_address})
- return body
-
-
-class DeleteFloatingIP(quantumv20.DeleteCommand):
- """Delete a given floating ip."""
-
- log = logging.getLogger(__name__ + '.DeleteFloatingIP')
- resource = 'floatingip'
- allow_names = False
-
-
-class AssociateFloatingIP(quantumv20.QuantumCommand):
- """Create a mapping between a floating ip and a fixed ip."""
-
- api = 'network'
- log = logging.getLogger(__name__ + '.AssociateFloatingIP')
- resource = 'floatingip'
-
- def get_parser(self, prog_name):
- parser = super(AssociateFloatingIP, self).get_parser(prog_name)
- parser.add_argument(
- 'floatingip_id', metavar='FLOATINGIP_ID',
- help='ID of the floating IP to associate')
- parser.add_argument(
- 'port_id', metavar='PORT',
- help='ID or name of the port to be associated with the floatingip')
- parser.add_argument(
- '--fixed-ip-address',
- help=('IP address on the port (only required if port has multiple'
- 'IPs)'))
- parser.add_argument(
- '--fixed_ip_address',
- help=argparse.SUPPRESS)
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- update_dict = {}
- if parsed_args.port_id:
- update_dict['port_id'] = parsed_args.port_id
- if parsed_args.fixed_ip_address:
- update_dict['fixed_ip_address'] = parsed_args.fixed_ip_address
- quantum_client.update_floatingip(parsed_args.floatingip_id,
- {'floatingip': update_dict})
- print >>self.app.stdout, (
- _('Associated floatingip %s') % parsed_args.floatingip_id)
-
-
-class DisassociateFloatingIP(quantumv20.QuantumCommand):
- """Remove a mapping from a floating ip to a fixed ip.
- """
-
- api = 'network'
- log = logging.getLogger(__name__ + '.DisassociateFloatingIP')
- resource = 'floatingip'
-
- def get_parser(self, prog_name):
- parser = super(DisassociateFloatingIP, self).get_parser(prog_name)
- parser.add_argument(
- 'floatingip_id', metavar='FLOATINGIP_ID',
- help='ID of the floating IP to associate')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- quantum_client.update_floatingip(parsed_args.floatingip_id,
- {'floatingip': {'port_id': None}})
- print >>self.app.stdout, (
- _('Disassociated floatingip %s') % parsed_args.floatingip_id)
diff --git a/quantumclient/quantum/v2_0/lb/__init__.py b/quantumclient/quantum/v2_0/lb/__init__.py
deleted file mode 100644
index 1668497..0000000
--- a/quantumclient/quantum/v2_0/lb/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
diff --git a/quantumclient/quantum/v2_0/lb/healthmonitor.py b/quantumclient/quantum/v2_0/lb/healthmonitor.py
deleted file mode 100644
index f0a828b..0000000
--- a/quantumclient/quantum/v2_0/lb/healthmonitor.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright 2013 Mirantis Inc.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# @author: Ilya Shakhat, Mirantis Inc.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListHealthMonitor(quantumv20.ListCommand):
- """List healthmonitors that belong to a given tenant."""
-
- resource = 'health_monitor'
- log = logging.getLogger(__name__ + '.ListHealthMonitor')
- list_columns = ['id', 'type', 'admin_state_up', 'status']
- pagination_support = True
- sorting_support = True
-
-
-class ShowHealthMonitor(quantumv20.ShowCommand):
- """Show information of a given healthmonitor."""
-
- resource = 'health_monitor'
- log = logging.getLogger(__name__ + '.ShowHealthMonitor')
-
-
-class CreateHealthMonitor(quantumv20.CreateCommand):
- """Create a healthmonitor."""
-
- resource = 'health_monitor'
- log = logging.getLogger(__name__ + '.CreateHealthMonitor')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='set admin state up to false')
- parser.add_argument(
- '--expected-codes',
- help='the list of HTTP status codes expected in '
- 'response from the member to declare it healthy. This '
- 'attribute can contain one value, '
- 'or a list of values separated by comma, '
- 'or a range of values (e.g. "200-299"). If this attribute '
- 'is not specified, it defaults to "200". ')
- parser.add_argument(
- '--http-method',
- help='the HTTP method used for requests by the monitor of type '
- 'HTTP.')
- parser.add_argument(
- '--url-path',
- help='the HTTP path used in the HTTP request used by the monitor'
- ' to test a member health. This must be a string '
- 'beginning with a / (forward slash)')
- parser.add_argument(
- '--delay',
- required=True,
- help='the minimum time in seconds between regular connections '
- 'of the member.')
- parser.add_argument(
- '--max-retries',
- required=True,
- help='number of permissible connection failures before changing '
- 'the member status to INACTIVE.')
- parser.add_argument(
- '--timeout',
- required=True,
- help='maximum number of seconds for a monitor to wait for a '
- 'connection to be established before it times out. The '
- 'value must be less than the delay value.')
- parser.add_argument(
- '--type',
- required=True,
- help='one of predefined health monitor types, e.g. RoundRobin')
-
- def args2body(self, parsed_args):
- body = {
- self.resource: {
- 'admin_state_up': parsed_args.admin_state,
- 'delay': parsed_args.delay,
- 'max_retries': parsed_args.max_retries,
- 'timeout': parsed_args.timeout,
- 'type': parsed_args.type,
- },
- }
- quantumv20.update_dict(parsed_args, body[self.resource],
- ['expected_codes', 'http_method', 'url_path',
- 'tenant_id'])
- return body
-
-
-class UpdateHealthMonitor(quantumv20.UpdateCommand):
- """Update a given healthmonitor."""
-
- resource = 'health_monitor'
- log = logging.getLogger(__name__ + '.UpdateHealthMonitor')
-
-
-class DeleteHealthMonitor(quantumv20.DeleteCommand):
- """Delete a given healthmonitor."""
-
- resource = 'health_monitor'
- log = logging.getLogger(__name__ + '.DeleteHealthMonitor')
-
-
-class AssociateHealthMonitor(quantumv20.QuantumCommand):
- """Create a mapping between a health monitor and a pool."""
-
- log = logging.getLogger(__name__ + '.AssociateHealthMonitor')
- resource = 'health_monitor'
-
- def get_parser(self, prog_name):
- parser = super(AssociateHealthMonitor, self).get_parser(prog_name)
- parser.add_argument(
- 'health_monitor_id',
- help='Health monitor to associate')
- parser.add_argument(
- 'pool_id',
- help='ID of the pool to be associated with the health monitor')
- return parser
-
- def run(self, parsed_args):
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- body = {'health_monitor': {'id': parsed_args.health_monitor_id}}
- pool_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, 'pool', parsed_args.pool_id)
- quantum_client.associate_health_monitor(pool_id, body)
- print >>self.app.stdout, (_('Associated health monitor '
- '%s') % parsed_args.health_monitor_id)
-
-
-class DisassociateHealthMonitor(quantumv20.QuantumCommand):
- """Remove a mapping from a health monitor to a pool."""
-
- log = logging.getLogger(__name__ + '.DisassociateHealthMonitor')
- resource = 'health_monitor'
-
- def get_parser(self, prog_name):
- parser = super(DisassociateHealthMonitor, self).get_parser(prog_name)
- parser.add_argument(
- 'health_monitor_id',
- help='Health monitor to associate')
- parser.add_argument(
- 'pool_id',
- help='ID of the pool to be associated with the health monitor')
- return parser
-
- def run(self, parsed_args):
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- pool_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, 'pool', parsed_args.pool_id)
- quantum_client.disassociate_health_monitor(pool_id,
- parsed_args
- .health_monitor_id)
- print >>self.app.stdout, (_('Disassociated health monitor '
- '%s') % parsed_args.health_monitor_id)
diff --git a/quantumclient/quantum/v2_0/lb/member.py b/quantumclient/quantum/v2_0/lb/member.py
deleted file mode 100644
index 05fb430..0000000
--- a/quantumclient/quantum/v2_0/lb/member.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright 2013 Mirantis Inc.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# @author: Ilya Shakhat, Mirantis Inc.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListMember(quantumv20.ListCommand):
- """List members that belong to a given tenant."""
-
- resource = 'member'
- log = logging.getLogger(__name__ + '.ListMember')
- list_columns = [
- 'id', 'address', 'protocol_port', 'admin_state_up', 'status'
- ]
- pagination_support = True
- sorting_support = True
-
-
-class ShowMember(quantumv20.ShowCommand):
- """Show information of a given member."""
-
- resource = 'member'
- log = logging.getLogger(__name__ + '.ShowMember')
-
-
-class CreateMember(quantumv20.CreateCommand):
- """Create a member."""
-
- resource = 'member'
- log = logging.getLogger(__name__ + '.CreateMember')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'pool_id', metavar='pool',
- help='Pool id or name this vip belongs to')
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='set admin state up to false')
- parser.add_argument(
- '--weight',
- help='weight of pool member in the pool')
- parser.add_argument(
- '--address',
- required=True,
- help='IP address of the pool member on the pool network. ')
- parser.add_argument(
- '--protocol-port',
- required=True,
- help='port on which the pool member listens for requests or '
- 'connections. ')
-
- def args2body(self, parsed_args):
- _pool_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'pool', parsed_args.pool_id)
- body = {
- self.resource: {
- 'pool_id': _pool_id,
- 'admin_state_up': parsed_args.admin_state,
- },
- }
- quantumv20.update_dict(
- parsed_args,
- body[self.resource],
- ['address', 'protocol_port', 'weight', 'tenant_id']
- )
- return body
-
-
-class UpdateMember(quantumv20.UpdateCommand):
- """Update a given member."""
-
- resource = 'member'
- log = logging.getLogger(__name__ + '.UpdateMember')
-
-
-class DeleteMember(quantumv20.DeleteCommand):
- """Delete a given member."""
-
- resource = 'member'
- log = logging.getLogger(__name__ + '.DeleteMember')
diff --git a/quantumclient/quantum/v2_0/lb/pool.py b/quantumclient/quantum/v2_0/lb/pool.py
deleted file mode 100644
index 869cf7a..0000000
--- a/quantumclient/quantum/v2_0/lb/pool.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright 2013 Mirantis Inc.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# @author: Ilya Shakhat, Mirantis Inc.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListPool(quantumv20.ListCommand):
- """List pools that belong to a given tenant."""
-
- resource = 'pool'
- log = logging.getLogger(__name__ + '.ListPool')
- list_columns = ['id', 'name', 'lb_method', 'protocol',
- 'admin_state_up', 'status']
- pagination_support = True
- sorting_support = True
-
-
-class ShowPool(quantumv20.ShowCommand):
- """Show information of a given pool."""
-
- resource = 'pool'
- log = logging.getLogger(__name__ + '.ShowPool')
-
-
-class CreatePool(quantumv20.CreateCommand):
- """Create a pool."""
-
- resource = 'pool'
- log = logging.getLogger(__name__ + '.CreatePool')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='set admin state up to false')
- parser.add_argument(
- '--description',
- help='description of the pool')
- parser.add_argument(
- '--lb-method',
- required=True,
- help='the algorithm used to distribute load between the members '
- 'of the pool')
- parser.add_argument(
- '--name',
- required=True,
- help='the name of the pool')
- parser.add_argument(
- '--protocol',
- required=True,
- help='protocol for balancing')
- parser.add_argument(
- '--subnet-id',
- required=True,
- help='the subnet on which the members of the pool will be located')
-
- def args2body(self, parsed_args):
- _subnet_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'subnet', parsed_args.subnet_id)
- body = {
- self.resource: {
- 'admin_state_up': parsed_args.admin_state,
- 'subnet_id': _subnet_id,
- },
- }
- quantumv20.update_dict(parsed_args, body[self.resource],
- ['description', 'lb_method', 'name',
- 'protocol', 'tenant_id'])
- return body
-
-
-class UpdatePool(quantumv20.UpdateCommand):
- """Update a given pool."""
-
- resource = 'pool'
- log = logging.getLogger(__name__ + '.UpdatePool')
-
-
-class DeletePool(quantumv20.DeleteCommand):
- """Delete a given pool."""
-
- resource = 'pool'
- log = logging.getLogger(__name__ + '.DeletePool')
-
-
-class RetrievePoolStats(quantumv20.ShowCommand):
- """Retrieve stats for a given pool."""
-
- resource = 'pool'
- log = logging.getLogger(__name__ + '.RetrievePoolStats')
-
- def get_data(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- params = {}
- if parsed_args.fields:
- params = {'fields': parsed_args.fields}
-
- data = quantum_client.retrieve_pool_stats(parsed_args.id, **params)
- self.format_output_data(data)
- stats = data['stats']
- if 'stats' in data:
- return zip(*sorted(stats.iteritems()))
- else:
- return None
diff --git a/quantumclient/quantum/v2_0/lb/vip.py b/quantumclient/quantum/v2_0/lb/vip.py
deleted file mode 100644
index ced5b20..0000000
--- a/quantumclient/quantum/v2_0/lb/vip.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright 2013 Mirantis Inc.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# @author: Ilya Shakhat, Mirantis Inc.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListVip(quantumv20.ListCommand):
- """List vips that belong to a given tenant."""
-
- resource = 'vip'
- log = logging.getLogger(__name__ + '.ListVip')
- list_columns = ['id', 'name', 'algorithm', 'address', 'protocol',
- 'admin_state_up', 'status']
- pagination_support = True
- sorting_support = True
-
-
-class ShowVip(quantumv20.ShowCommand):
- """Show information of a given vip."""
-
- resource = 'vip'
- log = logging.getLogger(__name__ + '.ShowVip')
-
-
-class CreateVip(quantumv20.CreateCommand):
- """Create a vip."""
-
- resource = 'vip'
- log = logging.getLogger(__name__ + '.CreateVip')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'pool_id', metavar='pool',
- help='Pool id or name this vip belongs to')
- parser.add_argument(
- '--address',
- help='IP address of the vip')
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='set admin state up to false')
- parser.add_argument(
- '--connection-limit',
- help='the maximum number of connections per second allowed for '
- 'the vip')
- parser.add_argument(
- '--description',
- help='description of the vip')
- parser.add_argument(
- '--name',
- required=True,
- help='name of the vip')
- parser.add_argument(
- '--protocol-port',
- required=True,
- help='TCP port on which to listen for client traffic that is '
- 'associated with the vip address')
- parser.add_argument(
- '--protocol',
- required=True,
- help='protocol for balancing')
- parser.add_argument(
- '--subnet-id',
- required=True,
- help='the subnet on which to allocate the vip address')
-
- def args2body(self, parsed_args):
- _pool_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'pool', parsed_args.pool_id)
- _subnet_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'subnet', parsed_args.subnet_id)
- body = {
- self.resource: {
- 'pool_id': _pool_id,
- 'admin_state_up': parsed_args.admin_state,
- 'subnet_id': _subnet_id,
- },
- }
- quantumv20.update_dict(parsed_args, body[self.resource],
- ['address', 'connection_limit', 'description',
- 'name', 'protocol_port', 'protocol',
- 'tenant_id'])
- return body
-
-
-class UpdateVip(quantumv20.UpdateCommand):
- """Update a given vip."""
-
- resource = 'vip'
- log = logging.getLogger(__name__ + '.UpdateVip')
-
-
-class DeleteVip(quantumv20.DeleteCommand):
- """Delete a given vip."""
-
- resource = 'vip'
- log = logging.getLogger(__name__ + '.DeleteVip')
diff --git a/quantumclient/quantum/v2_0/network.py b/quantumclient/quantum/v2_0/network.py
deleted file mode 100644
index 31e621f..0000000
--- a/quantumclient/quantum/v2_0/network.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import argparse
-import logging
-
-from quantumclient.common import exceptions
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-def _format_subnets(network):
- try:
- return '\n'.join([' '.join([s['id'], s.get('cidr', '')])
- for s in network['subnets']])
- except Exception:
- return ''
-
-
-class ListNetwork(quantumv20.ListCommand):
- """List networks that belong to a given tenant."""
-
- # Length of a query filter on subnet id
- # id=<uuid>& (with len(uuid)=36)
- subnet_id_filter_len = 40
- resource = 'network'
- log = logging.getLogger(__name__ + '.ListNetwork')
- _formatters = {'subnets': _format_subnets, }
- list_columns = ['id', 'name', 'subnets']
- pagination_support = True
- sorting_support = True
-
- def extend_list(self, data, parsed_args):
- """Add subnet information to a network list."""
- quantum_client = self.get_client()
- search_opts = {'fields': ['id', 'cidr']}
- if self.pagination_support:
- page_size = parsed_args.page_size
- if page_size:
- search_opts.update({'limit': page_size})
- subnet_ids = []
- for n in data:
- if 'subnets' in n:
- subnet_ids.extend(n['subnets'])
-
- def _get_subnet_list(sub_ids):
- search_opts['id'] = sub_ids
- return quantum_client.list_subnets(
- **search_opts).get('subnets', [])
-
- try:
- subnets = _get_subnet_list(subnet_ids)
- except exceptions.RequestURITooLong as uri_len_exc:
- # The URI is too long because of too many subnet_id filters
- # Use the excess attribute of the exception to know how many
- # subnet_id filters can be inserted into a single request
- subnet_count = len(subnet_ids)
- max_size = ((self.subnet_id_filter_len * subnet_count) -
- uri_len_exc.excess)
- chunk_size = max_size / self.subnet_id_filter_len
- subnets = []
- for i in xrange(0, subnet_count, chunk_size):
- subnets.extend(
- _get_subnet_list(subnet_ids[i: i + chunk_size]))
-
- subnet_dict = dict([(s['id'], s) for s in subnets])
- for n in data:
- if 'subnets' in n:
- n['subnets'] = [(subnet_dict.get(s) or {"id": s})
- for s in n['subnets']]
-
-
-class ListExternalNetwork(ListNetwork):
- """List external networks that belong to a given tenant."""
-
- log = logging.getLogger(__name__ + '.ListExternalNetwork')
- pagination_support = True
- sorting_support = True
-
- def retrieve_list(self, parsed_args):
- external = '--router:external=True'
- if external not in self.values_specs:
- self.values_specs.append('--router:external=True')
- return super(ListExternalNetwork, self).retrieve_list(parsed_args)
-
-
-class ShowNetwork(quantumv20.ShowCommand):
- """Show information of a given network."""
-
- resource = 'network'
- log = logging.getLogger(__name__ + '.ShowNetwork')
-
-
-class CreateNetwork(quantumv20.CreateCommand):
- """Create a network for a given tenant."""
-
- resource = 'network'
- log = logging.getLogger(__name__ + '.CreateNetwork')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='Set Admin State Up to false')
- parser.add_argument(
- '--admin_state_down',
- dest='admin_state', action='store_false',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--shared',
- action='store_true',
- help='Set the network as shared')
- parser.add_argument(
- 'name', metavar='NAME',
- help='Name of network to create')
-
- def args2body(self, parsed_args):
- body = {'network': {
- 'name': parsed_args.name,
- 'admin_state_up': parsed_args.admin_state}, }
- if parsed_args.tenant_id:
- body['network'].update({'tenant_id': parsed_args.tenant_id})
- if parsed_args.shared:
- body['network'].update({'shared': parsed_args.shared})
- return body
-
-
-class DeleteNetwork(quantumv20.DeleteCommand):
- """Delete a given network."""
-
- log = logging.getLogger(__name__ + '.DeleteNetwork')
- resource = 'network'
-
-
-class UpdateNetwork(quantumv20.UpdateCommand):
- """Update network's information."""
-
- log = logging.getLogger(__name__ + '.UpdateNetwork')
- resource = 'network'
diff --git a/quantumclient/quantum/v2_0/nvp_qos_queue.py b/quantumclient/quantum/v2_0/nvp_qos_queue.py
deleted file mode 100644
index 386b887..0000000
--- a/quantumclient/quantum/v2_0/nvp_qos_queue.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2013 Nicira Inc.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import logging
-
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListQoSQueue(quantumv20.ListCommand):
- """List queues that belong to a given tenant."""
-
- resource = 'qos_queue'
- log = logging.getLogger(__name__ + '.ListQoSQueue')
- list_columns = ['id', 'name', 'min', 'max',
- 'qos_marking', 'dscp', 'default']
-
-
-class ShowQoSQueue(quantumv20.ShowCommand):
- """Show information of a given queue."""
-
- resource = 'qos_queue'
- log = logging.getLogger(__name__ + '.ShowQoSQueue')
- allow_names = True
-
-
-class CreateQoSQueue(quantumv20.CreateCommand):
- """Create a queue."""
-
- resource = 'qos_queue'
- log = logging.getLogger(__name__ + '.CreateQoSQueue')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'name', metavar='NAME',
- help='Name of queue')
- parser.add_argument(
- '--min',
- help='min-rate'),
- parser.add_argument(
- '--max',
- help='max-rate'),
- parser.add_argument(
- '--qos-marking',
- help='qos marking untrusted/trusted'),
- parser.add_argument(
- '--default',
- default=False,
- help=('If true all ports created with be the size of this queue'
- ' if queue is not specified')),
- parser.add_argument(
- '--dscp',
- help='Differentiated Services Code Point'),
-
- def args2body(self, parsed_args):
- params = {'name': parsed_args.name,
- 'default': parsed_args.default}
- if parsed_args.min:
- params['min'] = parsed_args.min
- if parsed_args.max:
- params['max'] = parsed_args.max
- if parsed_args.qos_marking:
- params['qos_marking'] = parsed_args.qos_marking
- if parsed_args.dscp:
- params['dscp'] = parsed_args.dscp
- if parsed_args.tenant_id:
- params['tenant_id'] = parsed_args.tenant_id
- return {'qos_queue': params}
-
-
-class DeleteQoSQueue(quantumv20.DeleteCommand):
- """Delete a given queue."""
-
- log = logging.getLogger(__name__ + '.DeleteQoSQueue')
- resource = 'qos_queue'
- allow_names = True
diff --git a/quantumclient/quantum/v2_0/nvpnetworkgateway.py b/quantumclient/quantum/v2_0/nvpnetworkgateway.py
deleted file mode 100644
index 1823b6f..0000000
--- a/quantumclient/quantum/v2_0/nvpnetworkgateway.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import logging
-
-from quantumclient.common import utils
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.quantum import v2_0 as quantumv20
-
-RESOURCE = 'network_gateway'
-
-
-class ListNetworkGateway(quantumv20.ListCommand):
- """List network gateways for a given tenant."""
-
- resource = RESOURCE
- log = logging.getLogger(__name__ + '.ListNetworkGateway')
- list_columns = ['id', 'name']
-
-
-class ShowNetworkGateway(quantumv20.ShowCommand):
- """Show information of a given network gateway."""
-
- resource = RESOURCE
- log = logging.getLogger(__name__ + '.ShowNetworkGateway')
-
-
-class CreateNetworkGateway(quantumv20.CreateCommand):
- """Create a network gateway."""
-
- resource = RESOURCE
- log = logging.getLogger(__name__ + '.CreateNetworkGateway')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'name', metavar='NAME',
- help='Name of network gateway to create')
- parser.add_argument(
- '--device',
- action='append',
- help='device info for this gateway '
- 'device_id=<device identifier>,'
- 'interface_name=<name_or_identifier> '
- 'It can be repeated for multiple devices for HA gateways')
-
- def args2body(self, parsed_args):
- body = {self.resource: {
- 'name': parsed_args.name}}
- devices = []
- if parsed_args.device:
- for device in parsed_args.device:
- devices.append(utils.str2dict(device))
- if devices:
- body[self.resource].update({'devices': devices})
- if parsed_args.tenant_id:
- body[self.resource].update({'tenant_id': parsed_args.tenant_id})
- return body
-
-
-class DeleteNetworkGateway(quantumv20.DeleteCommand):
- """Delete a given network gateway."""
-
- resource = RESOURCE
- log = logging.getLogger(__name__ + '.DeleteNetworkGateway')
-
-
-class UpdateNetworkGateway(quantumv20.UpdateCommand):
- """Update the name for a network gateway."""
-
- resource = RESOURCE
- log = logging.getLogger(__name__ + '.UpdateNetworkGateway')
-
-
-class NetworkGatewayInterfaceCommand(quantumv20.QuantumCommand):
- """Base class for connecting/disconnecting networks to/from a gateway."""
-
- resource = RESOURCE
-
- def get_parser(self, prog_name):
- parser = super(NetworkGatewayInterfaceCommand,
- self).get_parser(prog_name)
- parser.add_argument(
- 'net_gateway_id', metavar='NET-GATEWAY-ID',
- help='ID of the network gateway')
- parser.add_argument(
- 'network_id', metavar='NETWORK-ID',
- help='ID of the internal network to connect on the gateway')
- parser.add_argument(
- '--segmentation-type',
- help=('L2 segmentation strategy on the external side of '
- 'the gateway (e.g.: VLAN, FLAT)'))
- parser.add_argument(
- '--segmentation-id',
- help=('Identifier for the L2 segment on the external side '
- 'of the gateway'))
- return parser
-
- def retrieve_ids(self, client, args):
- gateway_id = quantumv20.find_resourceid_by_name_or_id(
- client, self.resource, args.net_gateway_id)
- network_id = quantumv20.find_resourceid_by_name_or_id(
- client, 'network', args.network_id)
- return (gateway_id, network_id)
-
-
-class ConnectNetworkGateway(NetworkGatewayInterfaceCommand):
- """Add an internal network interface to a router."""
-
- log = logging.getLogger(__name__ + '.ConnectNetworkGateway')
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- (gateway_id, network_id) = self.retrieve_ids(quantum_client,
- parsed_args)
- quantum_client.connect_network_gateway(
- gateway_id, {'network_id': network_id,
- 'segmentation_type': parsed_args.segmentation_type,
- 'segmentation_id': parsed_args.segmentation_id})
- # TODO(Salvatore-Orlando): Do output formatting as
- # any other command
- print >>self.app.stdout, (
- _('Connected network to gateway %s') % gateway_id)
-
-
-class DisconnectNetworkGateway(NetworkGatewayInterfaceCommand):
- """Remove a network from a network gateway."""
-
- log = logging.getLogger(__name__ + '.DisconnectNetworkGateway')
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- (gateway_id, network_id) = self.retrieve_ids(quantum_client,
- parsed_args)
- quantum_client.disconnect_network_gateway(
- gateway_id, {'network_id': network_id,
- 'segmentation_type': parsed_args.segmentation_type,
- 'segmentation_id': parsed_args.segmentation_id})
- # TODO(Salvatore-Orlando): Do output formatting as
- # any other command
- print >>self.app.stdout, (
- _('Disconnected network from gateway %s') % gateway_id)
diff --git a/quantumclient/quantum/v2_0/port.py b/quantumclient/quantum/v2_0/port.py
index 0d6af60..55b39e9 100644
--- a/quantumclient/quantum/v2_0/port.py
+++ b/quantumclient/quantum/v2_0/port.py
@@ -1,4 +1,4 @@
-# Copyright 2012 OpenStack LLC.
+# Copyright 2013 OpenStack Foundation.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -15,170 +15,4 @@
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-import argparse
-import logging
-
-from quantumclient.common import utils
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-def _format_fixed_ips(port):
- try:
- return '\n'.join([utils.dumps(ip) for ip in port['fixed_ips']])
- except Exception:
- return ''
-
-
-class ListPort(quantumv20.ListCommand):
- """List ports that belong to a given tenant."""
-
- resource = 'port'
- log = logging.getLogger(__name__ + '.ListPort')
- _formatters = {'fixed_ips': _format_fixed_ips, }
- list_columns = ['id', 'name', 'mac_address', 'fixed_ips']
- pagination_support = True
- sorting_support = True
-
-
-class ListRouterPort(quantumv20.ListCommand):
- """List ports that belong to a given tenant, with specified router."""
-
- resource = 'port'
- log = logging.getLogger(__name__ + '.ListRouterPort')
- _formatters = {'fixed_ips': _format_fixed_ips, }
- list_columns = ['id', 'name', 'mac_address', 'fixed_ips']
- pagination_support = True
- sorting_support = True
-
- def get_parser(self, prog_name):
- parser = super(ListRouterPort, self).get_parser(prog_name)
- parser.add_argument(
- 'id', metavar='router',
- help='ID or name of router to look up')
- return parser
-
- def get_data(self, parsed_args):
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, 'router', parsed_args.id)
- self.values_specs.append('--device_id=%s' % _id)
- return super(ListRouterPort, self).get_data(parsed_args)
-
-
-class ShowPort(quantumv20.ShowCommand):
- """Show information of a given port."""
-
- resource = 'port'
- log = logging.getLogger(__name__ + '.ShowPort')
-
-
-class CreatePort(quantumv20.CreateCommand):
- """Create a port for a given tenant."""
-
- resource = 'port'
- log = logging.getLogger(__name__ + '.CreatePort')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--name',
- help='name of this port')
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='set admin state up to false')
- parser.add_argument(
- '--admin_state_down',
- dest='admin_state', action='store_false',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--mac-address',
- help='mac address of this port')
- parser.add_argument(
- '--mac_address',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--device-id',
- help='device id of this port')
- parser.add_argument(
- '--device_id',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--fixed-ip', metavar='ip_address=IP_ADDR',
- action='append',
- help='desired IP for this port: '
- 'subnet_id=<name_or_id>,ip_address=<ip>, '
- '(This option can be repeated.)')
- parser.add_argument(
- '--fixed_ip',
- action='append',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--security-group', metavar='SECURITY_GROUP',
- default=[], action='append', dest='security_groups',
- help='security group associated with the port '
- '(This option can be repeated)')
- parser.add_argument(
- 'network_id', metavar='NETWORK',
- help='Network id or name this port belongs to')
-
- def args2body(self, parsed_args):
- _network_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'network', parsed_args.network_id)
- body = {'port': {'admin_state_up': parsed_args.admin_state,
- 'network_id': _network_id, }, }
- if parsed_args.mac_address:
- body['port'].update({'mac_address': parsed_args.mac_address})
- if parsed_args.device_id:
- body['port'].update({'device_id': parsed_args.device_id})
- if parsed_args.tenant_id:
- body['port'].update({'tenant_id': parsed_args.tenant_id})
- if parsed_args.name:
- body['port'].update({'name': parsed_args.name})
- ips = []
- if parsed_args.fixed_ip:
- for ip_spec in parsed_args.fixed_ip:
- ip_dict = utils.str2dict(ip_spec)
- if 'subnet_id' in ip_dict:
- subnet_name_id = ip_dict['subnet_id']
- _subnet_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'subnet', subnet_name_id)
- ip_dict['subnet_id'] = _subnet_id
- ips.append(ip_dict)
- if ips:
- body['port'].update({'fixed_ips': ips})
-
- _sgids = []
- for sg in parsed_args.security_groups:
- _sgids.append(quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'security_group', sg))
- if _sgids:
- body['port']['security_groups'] = _sgids
-
- return body
-
-
-class DeletePort(quantumv20.DeleteCommand):
- """Delete a given port."""
-
- resource = 'port'
- log = logging.getLogger(__name__ + '.DeletePort')
-
-
-class UpdatePort(quantumv20.UpdateCommand):
- """Update port's information."""
-
- resource = 'port'
- log = logging.getLogger(__name__ + '.UpdatePort')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--no-security-groups',
- action='store_true',
- help='remove security groups from port')
-
- def args2body(self, parsed_args):
- body = {'port': {}}
- if parsed_args.no_security_groups:
- body['port'].update({'security_groups': None})
- return body
+from neutronclient.neutron.v2_0.port import _format_fixed_ips # noqa
diff --git a/quantumclient/quantum/v2_0/quota.py b/quantumclient/quantum/v2_0/quota.py
deleted file mode 100644
index 1c15192..0000000
--- a/quantumclient/quantum/v2_0/quota.py
+++ /dev/null
@@ -1,232 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import argparse
-import logging
-
-from cliff import lister
-from cliff import show
-
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-def get_tenant_id(tenant_id, client):
- return (tenant_id if tenant_id else
- client.get_quotas_tenant()['tenant']['tenant_id'])
-
-
-class DeleteQuota(quantumv20.QuantumCommand):
- """Delete defined quotas of a given tenant."""
-
- api = 'network'
- resource = 'quota'
- log = logging.getLogger(__name__ + '.DeleteQuota')
-
- def get_parser(self, prog_name):
- parser = super(DeleteQuota, self).get_parser(prog_name)
- parser.add_argument(
- '--tenant-id', metavar='tenant-id',
- help='the owner tenant ID')
- parser.add_argument(
- '--tenant_id',
- help=argparse.SUPPRESS)
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- tenant_id = get_tenant_id(parsed_args.tenant_id,
- quantum_client)
- obj_deleter = getattr(quantum_client,
- "delete_%s" % self.resource)
- obj_deleter(tenant_id)
- print >>self.app.stdout, (_('Deleted %(resource)s: %(tenant_id)s')
- % {'tenant_id': tenant_id,
- 'resource': self.resource})
- return
-
-
-class ListQuota(quantumv20.QuantumCommand, lister.Lister):
- """List defined quotas of all tenants."""
-
- api = 'network'
- resource = 'quota'
- log = logging.getLogger(__name__ + '.ListQuota')
-
- def get_parser(self, prog_name):
- parser = super(ListQuota, self).get_parser(prog_name)
- return parser
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- quantum_client = self.get_client()
- search_opts = {}
- self.log.debug('search options: %s', search_opts)
- quantum_client.format = parsed_args.request_format
- obj_lister = getattr(quantum_client,
- "list_%ss" % self.resource)
- data = obj_lister(**search_opts)
- info = []
- collection = self.resource + "s"
- if collection in data:
- info = data[collection]
- _columns = len(info) > 0 and sorted(info[0].keys()) or []
- return (_columns, (utils.get_item_properties(s, _columns)
- for s in info))
-
-
-class ShowQuota(quantumv20.QuantumCommand, show.ShowOne):
- """Show quotas of a given tenant
-
- """
- api = 'network'
- resource = "quota"
- log = logging.getLogger(__name__ + '.ShowQuota')
-
- def get_parser(self, prog_name):
- parser = super(ShowQuota, self).get_parser(prog_name)
- parser.add_argument(
- '--tenant-id', metavar='tenant-id',
- help='the owner tenant ID')
- parser.add_argument(
- '--tenant_id',
- help=argparse.SUPPRESS)
- return parser
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- tenant_id = get_tenant_id(parsed_args.tenant_id,
- quantum_client)
- params = {}
- obj_shower = getattr(quantum_client,
- "show_%s" % self.resource)
- data = obj_shower(tenant_id, **params)
- if self.resource in data:
- for k, v in data[self.resource].iteritems():
- if isinstance(v, list):
- value = ""
- for _item in v:
- if value:
- value += "\n"
- if isinstance(_item, dict):
- value += utils.dumps(_item)
- else:
- value += str(_item)
- data[self.resource][k] = value
- elif v is None:
- data[self.resource][k] = ''
- return zip(*sorted(data[self.resource].iteritems()))
- else:
- return None
-
-
-class UpdateQuota(quantumv20.QuantumCommand, show.ShowOne):
- """Define tenant's quotas not to use defaults."""
-
- resource = 'quota'
- log = logging.getLogger(__name__ + '.UpdateQuota')
-
- def get_parser(self, prog_name):
- parser = super(UpdateQuota, self).get_parser(prog_name)
- parser.add_argument(
- '--tenant-id', metavar='tenant-id',
- help='the owner tenant ID')
- parser.add_argument(
- '--tenant_id',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--network', metavar='networks',
- help='the limit of networks')
- parser.add_argument(
- '--subnet', metavar='subnets',
- help='the limit of subnets')
- parser.add_argument(
- '--port', metavar='ports',
- help='the limit of ports')
- parser.add_argument(
- '--router', metavar='routers',
- help='the limit of routers')
- parser.add_argument(
- '--floatingip', metavar='floatingips',
- help='the limit of floating IPs')
- parser.add_argument(
- '--security-group', metavar='security_groups',
- help='the limit of security groups')
- parser.add_argument(
- '--security-group-rule', metavar='security_group_rules',
- help='the limit of security groups rules')
- return parser
-
- def _validate_int(self, name, value):
- try:
- return_value = int(value)
- except Exception:
- message = (_('quota limit for %(name)s must be an integer') %
- {'name': name})
- raise exceptions.QuantumClientException(message=message)
- return return_value
-
- def args2body(self, parsed_args):
- quota = {}
- for resource in ('network', 'subnet', 'port', 'router', 'floatingip',
- 'security_group', 'security_group_rule'):
- if getattr(parsed_args, resource):
- quota[resource] = self._validate_int(
- resource,
- getattr(parsed_args, resource))
- return {self.resource: quota}
-
- def get_data(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = quantumv20.parse_args_to_dict(self.values_specs)
- quantumv20._merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- body = self.args2body(parsed_args)
- if self.resource in body:
- body[self.resource].update(_extra_values)
- else:
- body[self.resource] = _extra_values
- obj_updator = getattr(quantum_client,
- "update_%s" % self.resource)
- tenant_id = get_tenant_id(parsed_args.tenant_id,
- quantum_client)
- data = obj_updator(tenant_id, body)
- if self.resource in data:
- for k, v in data[self.resource].iteritems():
- if isinstance(v, list):
- value = ""
- for _item in v:
- if value:
- value += "\n"
- if isinstance(_item, dict):
- value += utils.dumps(_item)
- else:
- value += str(_item)
- data[self.resource][k] = value
- elif v is None:
- data[self.resource][k] = ''
- return zip(*sorted(data[self.resource].iteritems()))
- else:
- return None
diff --git a/quantumclient/quantum/v2_0/router.py b/quantumclient/quantum/v2_0/router.py
deleted file mode 100644
index c5b1570..0000000
--- a/quantumclient/quantum/v2_0/router.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import argparse
-import logging
-
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-def _format_external_gateway_info(router):
- try:
- return utils.dumps(router['external_gateway_info'])
- except Exception:
- return ''
-
-
-class ListRouter(quantumv20.ListCommand):
- """List routers that belong to a given tenant."""
-
- resource = 'router'
- log = logging.getLogger(__name__ + '.ListRouter')
- _formatters = {'external_gateway_info': _format_external_gateway_info, }
- list_columns = ['id', 'name', 'external_gateway_info']
- pagination_support = True
- sorting_support = True
-
-
-class ShowRouter(quantumv20.ShowCommand):
- """Show information of a given router."""
-
- resource = 'router'
- log = logging.getLogger(__name__ + '.ShowRouter')
-
-
-class CreateRouter(quantumv20.CreateCommand):
- """Create a router for a given tenant."""
-
- resource = 'router'
- log = logging.getLogger(__name__ + '.CreateRouter')
- _formatters = {'external_gateway_info': _format_external_gateway_info, }
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--admin-state-down',
- dest='admin_state', action='store_false',
- help='Set Admin State Up to false')
- parser.add_argument(
- '--admin_state_down',
- dest='admin_state', action='store_false',
- help=argparse.SUPPRESS)
- parser.add_argument(
- 'name', metavar='NAME',
- help='Name of router to create')
-
- def args2body(self, parsed_args):
- body = {'router': {
- 'name': parsed_args.name,
- 'admin_state_up': parsed_args.admin_state, }, }
- if parsed_args.tenant_id:
- body['router'].update({'tenant_id': parsed_args.tenant_id})
- return body
-
-
-class DeleteRouter(quantumv20.DeleteCommand):
- """Delete a given router."""
-
- log = logging.getLogger(__name__ + '.DeleteRouter')
- resource = 'router'
-
-
-class UpdateRouter(quantumv20.UpdateCommand):
- """Update router's information."""
-
- log = logging.getLogger(__name__ + '.UpdateRouter')
- resource = 'router'
-
-
-class RouterInterfaceCommand(quantumv20.QuantumCommand):
- """Based class to Add/Remove router interface."""
-
- api = 'network'
- resource = 'router'
-
- def call_api(self, quantum_client, router_id, body):
- raise NotImplementedError()
-
- def success_message(self, router_id, portinfo):
- raise NotImplementedError()
-
- def get_parser(self, prog_name):
- parser = super(RouterInterfaceCommand, self).get_parser(prog_name)
- parser.add_argument(
- 'router_id', metavar='router-id',
- help='ID of the router')
- parser.add_argument(
- 'interface', metavar='INTERFACE',
- help='The format is "SUBNET|subnet=SUBNET|port=PORT". '
- 'Either a subnet or port must be specified. '
- 'Both ID and name are accepted as SUBNET or PORT. '
- 'Note that "subnet=" can be omitted when specifying subnet.')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
-
- if '=' in parsed_args.interface:
- resource, value = parsed_args.interface.split('=', 1)
- if resource not in ['subnet', 'port']:
- exceptions.CommandError('You must specify either subnet or '
- 'port for INTERFACE parameter.')
- else:
- resource = 'subnet'
- value = parsed_args.interface
-
- _router_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, self.resource, parsed_args.router_id)
-
- _interface_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, resource, value)
- body = {'%s_id' % resource: _interface_id}
-
- portinfo = self.call_api(quantum_client, _router_id, body)
- print >>self.app.stdout, self.success_message(parsed_args.router_id,
- portinfo)
-
-
-class AddInterfaceRouter(RouterInterfaceCommand):
- """Add an internal network interface to a router."""
-
- log = logging.getLogger(__name__ + '.AddInterfaceRouter')
-
- def call_api(self, quantum_client, router_id, body):
- return quantum_client.add_interface_router(router_id, body)
-
- def success_message(self, router_id, portinfo):
- return (_('Added interface %(port)s to router %(router)s.') %
- {'router': router_id, 'port': portinfo['port_id']})
-
-
-class RemoveInterfaceRouter(RouterInterfaceCommand):
- """Remove an internal network interface from a router."""
-
- log = logging.getLogger(__name__ + '.RemoveInterfaceRouter')
-
- def call_api(self, quantum_client, router_id, body):
- return quantum_client.remove_interface_router(router_id, body)
-
- def success_message(self, router_id, portinfo):
- # portinfo is not used since it is None for router-interface-delete.
- return _('Removed interface from router %s.') % router_id
-
-
-class SetGatewayRouter(quantumv20.QuantumCommand):
- """Set the external network gateway for a router."""
-
- log = logging.getLogger(__name__ + '.SetGatewayRouter')
- api = 'network'
- resource = 'router'
-
- def get_parser(self, prog_name):
- parser = super(SetGatewayRouter, self).get_parser(prog_name)
- parser.add_argument(
- 'router_id', metavar='router-id',
- help='ID of the router')
- parser.add_argument(
- 'external_network_id', metavar='external-network-id',
- help='ID of the external network for the gateway')
- parser.add_argument(
- '--disable-snat', action='store_false', dest='enable_snat',
- help='Disable Source NAT on the router gateway')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _router_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, self.resource, parsed_args.router_id)
- _ext_net_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, 'network', parsed_args.external_network_id)
- quantum_client.add_gateway_router(
- _router_id,
- {'network_id': _ext_net_id,
- 'enable_snat': parsed_args.enable_snat})
- print >>self.app.stdout, (
- _('Set gateway for router %s') % parsed_args.router_id)
-
-
-class RemoveGatewayRouter(quantumv20.QuantumCommand):
- """Remove an external network gateway from a router."""
-
- log = logging.getLogger(__name__ + '.RemoveGatewayRouter')
- api = 'network'
- resource = 'router'
-
- def get_parser(self, prog_name):
- parser = super(RemoveGatewayRouter, self).get_parser(prog_name)
- parser.add_argument(
- 'router_id', metavar='router-id',
- help='ID of the router')
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _router_id = quantumv20.find_resourceid_by_name_or_id(
- quantum_client, self.resource, parsed_args.router_id)
- quantum_client.remove_gateway_router(_router_id)
- print >>self.app.stdout, (
- _('Removed gateway from router %s') % parsed_args.router_id)
diff --git a/quantumclient/quantum/v2_0/securitygroup.py b/quantumclient/quantum/v2_0/securitygroup.py
deleted file mode 100644
index 5fa899c..0000000
--- a/quantumclient/quantum/v2_0/securitygroup.py
+++ /dev/null
@@ -1,259 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import argparse
-import logging
-
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-class ListSecurityGroup(quantumv20.ListCommand):
- """List security groups that belong to a given tenant."""
-
- resource = 'security_group'
- log = logging.getLogger(__name__ + '.ListSecurityGroup')
- list_columns = ['id', 'name', 'description']
- pagination_support = True
- sorting_support = True
-
-
-class ShowSecurityGroup(quantumv20.ShowCommand):
- """Show information of a given security group."""
-
- resource = 'security_group'
- log = logging.getLogger(__name__ + '.ShowSecurityGroup')
- allow_names = True
-
-
-class CreateSecurityGroup(quantumv20.CreateCommand):
- """Create a security group."""
-
- resource = 'security_group'
- log = logging.getLogger(__name__ + '.CreateSecurityGroup')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'name', metavar='NAME',
- help='Name of security group')
- parser.add_argument(
- '--description',
- help='description of security group')
-
- def args2body(self, parsed_args):
- body = {'security_group': {
- 'name': parsed_args.name}}
- if parsed_args.description:
- body['security_group'].update(
- {'description': parsed_args.description})
- if parsed_args.tenant_id:
- body['security_group'].update({'tenant_id': parsed_args.tenant_id})
- return body
-
-
-class DeleteSecurityGroup(quantumv20.DeleteCommand):
- """Delete a given security group."""
-
- log = logging.getLogger(__name__ + '.DeleteSecurityGroup')
- resource = 'security_group'
- allow_names = True
-
-
-class UpdateSecurityGroup(quantumv20.UpdateCommand):
- """Update a given security group."""
-
- log = logging.getLogger(__name__ + '.UpdateSecurityGroup')
- resource = 'security_group'
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--name',
- help='Name of security group')
- parser.add_argument(
- '--description',
- help='description of security group')
-
- def args2body(self, parsed_args):
- body = {'security_group': {}}
- if parsed_args.name:
- body['security_group'].update(
- {'name': parsed_args.name})
- if parsed_args.description:
- body['security_group'].update(
- {'description': parsed_args.description})
- return body
-
-
-class ListSecurityGroupRule(quantumv20.ListCommand):
- """List security group rules that belong to a given tenant."""
-
- resource = 'security_group_rule'
- log = logging.getLogger(__name__ + '.ListSecurityGroupRule')
- list_columns = ['id', 'security_group_id', 'direction', 'protocol',
- 'remote_ip_prefix', 'remote_group_id']
- replace_rules = {'security_group_id': 'security_group',
- 'remote_group_id': 'remote_group'}
- pagination_support = True
- sorting_support = True
-
- def get_parser(self, prog_name):
- parser = super(ListSecurityGroupRule, self).get_parser(prog_name)
- parser.add_argument(
- '--no-nameconv', action='store_true',
- help='Do not convert security group ID to its name')
- return parser
-
- @staticmethod
- def replace_columns(cols, rules, reverse=False):
- if reverse:
- rules = dict((rules[k], k) for k in rules.keys())
- return [rules.get(col, col) for col in cols]
-
- def retrieve_list(self, parsed_args):
- parsed_args.fields = self.replace_columns(parsed_args.fields,
- self.replace_rules,
- reverse=True)
- return super(ListSecurityGroupRule, self).retrieve_list(parsed_args)
-
- def extend_list(self, data, parsed_args):
- if parsed_args.no_nameconv:
- return
- quantum_client = self.get_client()
- search_opts = {'fields': ['id', 'name']}
- if self.pagination_support:
- page_size = parsed_args.page_size
- if page_size:
- search_opts.update({'limit': page_size})
- sec_group_ids = set()
- for rule in data:
- for key in self.replace_rules:
- sec_group_ids.add(rule[key])
- search_opts.update({"id": sec_group_ids})
- secgroups = quantum_client.list_security_groups(**search_opts)
- secgroups = secgroups.get('security_groups', [])
- sg_dict = dict([(sg['id'], sg['name'])
- for sg in secgroups if sg['name']])
- for rule in data:
- for key in self.replace_rules:
- rule[key] = sg_dict.get(rule[key], rule[key])
-
- def setup_columns(self, info, parsed_args):
- parsed_args.columns = self.replace_columns(parsed_args.columns,
- self.replace_rules,
- reverse=True)
- # NOTE(amotoki): 2nd element of the tuple returned by setup_columns()
- # is a generator, so if you need to create a look using the generator
- # object, you need to recreate a generator to show a list expectedly.
- info = super(ListSecurityGroupRule, self).setup_columns(info,
- parsed_args)
- cols = info[0]
- if not parsed_args.no_nameconv:
- cols = self.replace_columns(info[0], self.replace_rules)
- parsed_args.columns = cols
- return (cols, info[1])
-
-
-class ShowSecurityGroupRule(quantumv20.ShowCommand):
- """Show information of a given security group rule."""
-
- resource = 'security_group_rule'
- log = logging.getLogger(__name__ + '.ShowSecurityGroupRule')
- allow_names = False
-
-
-class CreateSecurityGroupRule(quantumv20.CreateCommand):
- """Create a security group rule."""
-
- resource = 'security_group_rule'
- log = logging.getLogger(__name__ + '.CreateSecurityGroupRule')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- 'security_group_id', metavar='SECURITY_GROUP',
- help='Security group name or id to add rule.')
- parser.add_argument(
- '--direction',
- default='ingress', choices=['ingress', 'egress'],
- help='direction of traffic: ingress/egress')
- parser.add_argument(
- '--ethertype',
- default='IPv4',
- help='IPv4/IPv6')
- parser.add_argument(
- '--protocol',
- help='protocol of packet')
- parser.add_argument(
- '--port-range-min',
- help='starting port range')
- parser.add_argument(
- '--port_range_min',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--port-range-max',
- help='ending port range')
- parser.add_argument(
- '--port_range_max',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--remote-ip-prefix',
- help='cidr to match on')
- parser.add_argument(
- '--remote_ip_prefix',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--remote-group-id', metavar='REMOTE_GROUP',
- help='remote security group name or id to apply rule')
- parser.add_argument(
- '--remote_group_id',
- help=argparse.SUPPRESS)
-
- def args2body(self, parsed_args):
- _security_group_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'security_group', parsed_args.security_group_id)
- body = {'security_group_rule': {
- 'security_group_id': _security_group_id,
- 'direction': parsed_args.direction,
- 'ethertype': parsed_args.ethertype}}
- if parsed_args.protocol:
- body['security_group_rule'].update(
- {'protocol': parsed_args.protocol})
- if parsed_args.port_range_min:
- body['security_group_rule'].update(
- {'port_range_min': parsed_args.port_range_min})
- if parsed_args.port_range_max:
- body['security_group_rule'].update(
- {'port_range_max': parsed_args.port_range_max})
- if parsed_args.remote_ip_prefix:
- body['security_group_rule'].update(
- {'remote_ip_prefix': parsed_args.remote_ip_prefix})
- if parsed_args.remote_group_id:
- _remote_group_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'security_group',
- parsed_args.remote_group_id)
- body['security_group_rule'].update(
- {'remote_group_id': _remote_group_id})
- if parsed_args.tenant_id:
- body['security_group_rule'].update(
- {'tenant_id': parsed_args.tenant_id})
- return body
-
-
-class DeleteSecurityGroupRule(quantumv20.DeleteCommand):
- """Delete a given security group rule."""
-
- log = logging.getLogger(__name__ + '.DeleteSecurityGroupRule')
- resource = 'security_group_rule'
- allow_names = False
diff --git a/quantumclient/quantum/v2_0/subnet.py b/quantumclient/quantum/v2_0/subnet.py
deleted file mode 100644
index e79cdc0..0000000
--- a/quantumclient/quantum/v2_0/subnet.py
+++ /dev/null
@@ -1,168 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import argparse
-import logging
-
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-from quantumclient.quantum import v2_0 as quantumv20
-
-
-def _format_allocation_pools(subnet):
- try:
- return '\n'.join([utils.dumps(pool) for pool in
- subnet['allocation_pools']])
- except Exception:
- return ''
-
-
-def _format_dns_nameservers(subnet):
- try:
- return '\n'.join([utils.dumps(server) for server in
- subnet['dns_nameservers']])
- except Exception:
- return ''
-
-
-def _format_host_routes(subnet):
- try:
- return '\n'.join([utils.dumps(route) for route in
- subnet['host_routes']])
- except Exception:
- return ''
-
-
-class ListSubnet(quantumv20.ListCommand):
- """List networks that belong to a given tenant."""
-
- resource = 'subnet'
- log = logging.getLogger(__name__ + '.ListSubnet')
- _formatters = {'allocation_pools': _format_allocation_pools,
- 'dns_nameservers': _format_dns_nameservers,
- 'host_routes': _format_host_routes, }
- list_columns = ['id', 'name', 'cidr', 'allocation_pools']
- pagination_support = True
- sorting_support = True
-
-
-class ShowSubnet(quantumv20.ShowCommand):
- """Show information of a given subnet."""
-
- resource = 'subnet'
- log = logging.getLogger(__name__ + '.ShowSubnet')
-
-
-class CreateSubnet(quantumv20.CreateCommand):
- """Create a subnet for a given tenant."""
-
- resource = 'subnet'
- log = logging.getLogger(__name__ + '.CreateSubnet')
-
- def add_known_arguments(self, parser):
- parser.add_argument(
- '--name',
- help='name of this subnet')
- parser.add_argument(
- '--ip-version',
- type=int,
- default=4, choices=[4, 6],
- help='IP version with default 4')
- parser.add_argument(
- '--ip_version',
- type=int,
- choices=[4, 6],
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--gateway', metavar='GATEWAY_IP',
- help='gateway ip of this subnet')
- parser.add_argument(
- '--no-gateway',
- action='store_true',
- help='No distribution of gateway')
- parser.add_argument(
- '--allocation-pool', metavar='start=IP_ADDR,end=IP_ADDR',
- action='append', dest='allocation_pools', type=utils.str2dict,
- help='Allocation pool IP addresses for this subnet '
- '(This option can be repeated)')
- parser.add_argument(
- '--allocation_pool',
- action='append', dest='allocation_pools', type=utils.str2dict,
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--host-route', metavar='destination=CIDR,nexthop=IP_ADDR',
- action='append', dest='host_routes', type=utils.str2dict,
- help='Additional route (This option can be repeated)')
- parser.add_argument(
- '--dns-nameserver', metavar='DNS_NAMESERVER',
- action='append', dest='dns_nameservers',
- help='DNS name server for this subnet '
- '(This option can be repeated)')
- parser.add_argument(
- '--disable-dhcp',
- action='store_true',
- help='Disable DHCP for this subnet')
- parser.add_argument(
- 'network_id', metavar='NETWORK',
- help='network id or name this subnet belongs to')
- parser.add_argument(
- 'cidr', metavar='CIDR',
- help='cidr of subnet to create')
-
- def args2body(self, parsed_args):
- _network_id = quantumv20.find_resourceid_by_name_or_id(
- self.get_client(), 'network', parsed_args.network_id)
- body = {'subnet': {'cidr': parsed_args.cidr,
- 'network_id': _network_id,
- 'ip_version': parsed_args.ip_version, }, }
-
- if parsed_args.gateway and parsed_args.no_gateway:
- raise exceptions.CommandError("--gateway option and "
- "--no-gateway option can "
- "not be used same time")
- if parsed_args.no_gateway:
- body['subnet'].update({'gateway_ip': None})
- if parsed_args.gateway:
- body['subnet'].update({'gateway_ip': parsed_args.gateway})
- if parsed_args.tenant_id:
- body['subnet'].update({'tenant_id': parsed_args.tenant_id})
- if parsed_args.name:
- body['subnet'].update({'name': parsed_args.name})
- if parsed_args.disable_dhcp:
- body['subnet'].update({'enable_dhcp': False})
- if parsed_args.allocation_pools:
- body['subnet']['allocation_pools'] = parsed_args.allocation_pools
- if parsed_args.host_routes:
- body['subnet']['host_routes'] = parsed_args.host_routes
- if parsed_args.dns_nameservers:
- body['subnet']['dns_nameservers'] = parsed_args.dns_nameservers
-
- return body
-
-
-class DeleteSubnet(quantumv20.DeleteCommand):
- """Delete a given subnet."""
-
- resource = 'subnet'
- log = logging.getLogger(__name__ + '.DeleteSubnet')
-
-
-class UpdateSubnet(quantumv20.UpdateCommand):
- """Update subnet's information."""
-
- resource = 'subnet'
- log = logging.getLogger(__name__ + '.UpdateSubnet')
diff --git a/quantumclient/shell.py b/quantumclient/shell.py
index 29c56f0..ce7647d 100644
--- a/quantumclient/shell.py
+++ b/quantumclient/shell.py
@@ -19,637 +19,14 @@
Command-line interface to the Quantum APIs
"""
-import argparse
-import logging
-import os
import sys
-from cliff import app
-from cliff import commandmanager
-
-from quantumclient.common import clientmanager
-from quantumclient.common import exceptions as exc
-from quantumclient.common import utils
-from quantumclient.openstack.common import strutils
-from quantumclient.version import __version__
-
-
-VERSION = '2.0'
-QUANTUM_API_VERSION = '2.0'
-
-
-def run_command(cmd, cmd_parser, sub_argv):
- _argv = sub_argv
- index = -1
- values_specs = []
- if '--' in sub_argv:
- index = sub_argv.index('--')
- _argv = sub_argv[:index]
- values_specs = sub_argv[index:]
- known_args, _values_specs = cmd_parser.parse_known_args(_argv)
- cmd.values_specs = (index == -1 and _values_specs or values_specs)
- return cmd.run(known_args)
-
-
-def env(*_vars, **kwargs):
- """Search for the first defined of possibly many env vars
-
- Returns the first environment variable defined in vars, or
- returns the default defined in kwargs.
-
- """
- for v in _vars:
- value = os.environ.get(v, None)
- if value:
- return value
- return kwargs.get('default', '')
-
-
-COMMAND_V2 = {
- 'net-list': utils.import_class(
- 'quantumclient.quantum.v2_0.network.ListNetwork'),
- 'net-external-list': utils.import_class(
- 'quantumclient.quantum.v2_0.network.ListExternalNetwork'),
- 'net-show': utils.import_class(
- 'quantumclient.quantum.v2_0.network.ShowNetwork'),
- 'net-create': utils.import_class(
- 'quantumclient.quantum.v2_0.network.CreateNetwork'),
- 'net-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.network.DeleteNetwork'),
- 'net-update': utils.import_class(
- 'quantumclient.quantum.v2_0.network.UpdateNetwork'),
- 'subnet-list': utils.import_class(
- 'quantumclient.quantum.v2_0.subnet.ListSubnet'),
- 'subnet-show': utils.import_class(
- 'quantumclient.quantum.v2_0.subnet.ShowSubnet'),
- 'subnet-create': utils.import_class(
- 'quantumclient.quantum.v2_0.subnet.CreateSubnet'),
- 'subnet-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.subnet.DeleteSubnet'),
- 'subnet-update': utils.import_class(
- 'quantumclient.quantum.v2_0.subnet.UpdateSubnet'),
- 'port-list': utils.import_class(
- 'quantumclient.quantum.v2_0.port.ListPort'),
- 'port-show': utils.import_class(
- 'quantumclient.quantum.v2_0.port.ShowPort'),
- 'port-create': utils.import_class(
- 'quantumclient.quantum.v2_0.port.CreatePort'),
- 'port-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.port.DeletePort'),
- 'port-update': utils.import_class(
- 'quantumclient.quantum.v2_0.port.UpdatePort'),
- 'quota-list': utils.import_class(
- 'quantumclient.quantum.v2_0.quota.ListQuota'),
- 'quota-show': utils.import_class(
- 'quantumclient.quantum.v2_0.quota.ShowQuota'),
- 'quota-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.quota.DeleteQuota'),
- 'quota-update': utils.import_class(
- 'quantumclient.quantum.v2_0.quota.UpdateQuota'),
- 'ext-list': utils.import_class(
- 'quantumclient.quantum.v2_0.extension.ListExt'),
- 'ext-show': utils.import_class(
- 'quantumclient.quantum.v2_0.extension.ShowExt'),
- 'router-list': utils.import_class(
- 'quantumclient.quantum.v2_0.router.ListRouter'),
- 'router-port-list': utils.import_class(
- 'quantumclient.quantum.v2_0.port.ListRouterPort'),
- 'router-show': utils.import_class(
- 'quantumclient.quantum.v2_0.router.ShowRouter'),
- 'router-create': utils.import_class(
- 'quantumclient.quantum.v2_0.router.CreateRouter'),
- 'router-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.router.DeleteRouter'),
- 'router-update': utils.import_class(
- 'quantumclient.quantum.v2_0.router.UpdateRouter'),
- 'router-interface-add': utils.import_class(
- 'quantumclient.quantum.v2_0.router.AddInterfaceRouter'),
- 'router-interface-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.router.RemoveInterfaceRouter'),
- 'router-gateway-set': utils.import_class(
- 'quantumclient.quantum.v2_0.router.SetGatewayRouter'),
- 'router-gateway-clear': utils.import_class(
- 'quantumclient.quantum.v2_0.router.RemoveGatewayRouter'),
- 'floatingip-list': utils.import_class(
- 'quantumclient.quantum.v2_0.floatingip.ListFloatingIP'),
- 'floatingip-show': utils.import_class(
- 'quantumclient.quantum.v2_0.floatingip.ShowFloatingIP'),
- 'floatingip-create': utils.import_class(
- 'quantumclient.quantum.v2_0.floatingip.CreateFloatingIP'),
- 'floatingip-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.floatingip.DeleteFloatingIP'),
- 'floatingip-associate': utils.import_class(
- 'quantumclient.quantum.v2_0.floatingip.AssociateFloatingIP'),
- 'floatingip-disassociate': utils.import_class(
- 'quantumclient.quantum.v2_0.floatingip.DisassociateFloatingIP'),
- 'security-group-list': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.ListSecurityGroup'),
- 'security-group-show': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.ShowSecurityGroup'),
- 'security-group-create': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.CreateSecurityGroup'),
- 'security-group-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.DeleteSecurityGroup'),
- 'security-group-update': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.UpdateSecurityGroup'),
- 'security-group-rule-list': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.ListSecurityGroupRule'),
- 'security-group-rule-show': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.ShowSecurityGroupRule'),
- 'security-group-rule-create': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.CreateSecurityGroupRule'),
- 'security-group-rule-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.securitygroup.DeleteSecurityGroupRule'),
- 'lb-vip-list': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.vip.ListVip'),
- 'lb-vip-show': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.vip.ShowVip'),
- 'lb-vip-create': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.vip.CreateVip'),
- 'lb-vip-update': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.vip.UpdateVip'),
- 'lb-vip-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.vip.DeleteVip'),
- 'lb-pool-list': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.pool.ListPool'),
- 'lb-pool-show': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.pool.ShowPool'),
- 'lb-pool-create': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.pool.CreatePool'),
- 'lb-pool-update': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.pool.UpdatePool'),
- 'lb-pool-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.pool.DeletePool'),
- 'lb-pool-stats': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.pool.RetrievePoolStats'),
- 'lb-member-list': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.member.ListMember'),
- 'lb-member-show': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.member.ShowMember'),
- 'lb-member-create': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.member.CreateMember'),
- 'lb-member-update': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.member.UpdateMember'),
- 'lb-member-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.member.DeleteMember'),
- 'lb-healthmonitor-list': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor.ListHealthMonitor'),
- 'lb-healthmonitor-show': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor.ShowHealthMonitor'),
- 'lb-healthmonitor-create': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor.CreateHealthMonitor'),
- 'lb-healthmonitor-update': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor.UpdateHealthMonitor'),
- 'lb-healthmonitor-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor.DeleteHealthMonitor'),
- 'lb-healthmonitor-associate': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor.AssociateHealthMonitor'),
- 'lb-healthmonitor-disassociate': utils.import_class(
- 'quantumclient.quantum.v2_0.lb.healthmonitor'
- '.DisassociateHealthMonitor'),
- 'queue-create': utils.import_class(
- 'quantumclient.quantum.v2_0.nvp_qos_queue.CreateQoSQueue'),
- 'queue-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.nvp_qos_queue.DeleteQoSQueue'),
- 'queue-show': utils.import_class(
- 'quantumclient.quantum.v2_0.nvp_qos_queue.ShowQoSQueue'),
- 'queue-list': utils.import_class(
- 'quantumclient.quantum.v2_0.nvp_qos_queue.ListQoSQueue'),
- 'agent-list': utils.import_class(
- 'quantumclient.quantum.v2_0.agent.ListAgent'),
- 'agent-show': utils.import_class(
- 'quantumclient.quantum.v2_0.agent.ShowAgent'),
- 'agent-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.agent.DeleteAgent'),
- 'agent-update': utils.import_class(
- 'quantumclient.quantum.v2_0.agent.UpdateAgent'),
- 'net-gateway-create': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.CreateNetworkGateway'),
- 'net-gateway-update': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.UpdateNetworkGateway'),
- 'net-gateway-delete': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.DeleteNetworkGateway'),
- 'net-gateway-show': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.ShowNetworkGateway'),
- 'net-gateway-list': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.ListNetworkGateway'),
- 'net-gateway-connect': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.ConnectNetworkGateway'),
- 'net-gateway-disconnect': utils.import_class(
- 'quantumclient.quantum.v2_0.nvpnetworkgateway.'
- 'DisconnectNetworkGateway'),
- 'dhcp-agent-network-add': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.AddNetworkToDhcpAgent'),
- 'dhcp-agent-network-remove': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.'
- 'RemoveNetworkFromDhcpAgent'),
- 'net-list-on-dhcp-agent': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.'
- 'ListNetworksOnDhcpAgent'),
- 'dhcp-agent-list-hosting-net': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.'
- 'ListDhcpAgentsHostingNetwork'),
- 'l3-agent-router-add': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.AddRouterToL3Agent'),
- 'l3-agent-router-remove': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.RemoveRouterFromL3Agent'),
- 'router-list-on-l3-agent': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.ListRoutersOnL3Agent'),
- 'l3-agent-list-hosting-router': utils.import_class(
- 'quantumclient.quantum.v2_0.agentscheduler.ListL3AgentsHostingRouter'),
-}
-
-COMMANDS = {'2.0': COMMAND_V2}
-
-
-class HelpAction(argparse.Action):
- """Provide a custom action so the -h and --help options
- to the main app will print a list of the commands.
-
- The commands are determined by checking the CommandManager
- instance, passed in as the "default" value for the action.
- """
- def __call__(self, parser, namespace, values, option_string=None):
- outputs = []
- max_len = 0
- app = self.default
- parser.print_help(app.stdout)
- app.stdout.write('\nCommands for API v%s:\n' % app.api_version)
- command_manager = app.command_manager
- for name, ep in sorted(command_manager):
- factory = ep.load()
- cmd = factory(self, None)
- one_liner = cmd.get_description().split('\n')[0]
- outputs.append((name, one_liner))
- max_len = max(len(name), max_len)
- for (name, one_liner) in outputs:
- app.stdout.write(' %s %s\n' % (name.ljust(max_len), one_liner))
- sys.exit(0)
-
-
-class QuantumShell(app.App):
-
- CONSOLE_MESSAGE_FORMAT = '%(message)s'
- DEBUG_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s'
- log = logging.getLogger(__name__)
-
- def __init__(self, apiversion):
- super(QuantumShell, self).__init__(
- description=__doc__.strip(),
- version=VERSION,
- command_manager=commandmanager.CommandManager('quantum.cli'), )
- self.commands = COMMANDS
- for k, v in self.commands[apiversion].items():
- self.command_manager.add_command(k, v)
-
- # This is instantiated in initialize_app() only when using
- # password flow auth
- self.auth_client = None
- self.api_version = apiversion
-
- def build_option_parser(self, description, version):
- """Return an argparse option parser for this application.
-
- Subclasses may override this method to extend
- the parser with more global options.
-
- :param description: full description of the application
- :paramtype description: str
- :param version: version number for the application
- :paramtype version: str
- """
- parser = argparse.ArgumentParser(
- description=description,
- add_help=False, )
- parser.add_argument(
- '--version',
- action='version',
- version=__version__, )
- parser.add_argument(
- '-v', '--verbose',
- action='count',
- dest='verbose_level',
- default=self.DEFAULT_VERBOSE_LEVEL,
- help='Increase verbosity of output. Can be repeated.', )
- parser.add_argument(
- '-q', '--quiet',
- action='store_const',
- dest='verbose_level',
- const=0,
- help='suppress output except warnings and errors', )
- parser.add_argument(
- '-h', '--help',
- action=HelpAction,
- nargs=0,
- default=self, # tricky
- help="show this help message and exit", )
- parser.add_argument(
- '--debug',
- default=False,
- action='store_true',
- help='show tracebacks on errors', )
- # Global arguments
- parser.add_argument(
- '--os-auth-strategy', metavar='<auth-strategy>',
- default=env('OS_AUTH_STRATEGY', default='keystone'),
- help='Authentication strategy (Env: OS_AUTH_STRATEGY'
- ', default keystone). For now, any other value will'
- ' disable the authentication')
- parser.add_argument(
- '--os_auth_strategy',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--os-auth-url', metavar='<auth-url>',
- default=env('OS_AUTH_URL'),
- help='Authentication URL (Env: OS_AUTH_URL)')
- parser.add_argument(
- '--os_auth_url',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--os-tenant-name', metavar='<auth-tenant-name>',
- default=env('OS_TENANT_NAME'),
- help='Authentication tenant name (Env: OS_TENANT_NAME)')
- parser.add_argument(
- '--os_tenant_name',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--os-username', metavar='<auth-username>',
- default=utils.env('OS_USERNAME'),
- help='Authentication username (Env: OS_USERNAME)')
- parser.add_argument(
- '--os_username',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--os-password', metavar='<auth-password>',
- default=utils.env('OS_PASSWORD'),
- help='Authentication password (Env: OS_PASSWORD)')
- parser.add_argument(
- '--os_password',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--os-region-name', metavar='<auth-region-name>',
- default=env('OS_REGION_NAME'),
- help='Authentication region name (Env: OS_REGION_NAME)')
- parser.add_argument(
- '--os_region_name',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--os-token', metavar='<token>',
- default=env('OS_TOKEN'),
- help='Defaults to env[OS_TOKEN]')
- parser.add_argument(
- '--os_token',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--endpoint-type', metavar='<endpoint-type>',
- default=env('OS_ENDPOINT_TYPE', default='publicURL'),
- help='Defaults to env[OS_ENDPOINT_TYPE] or publicURL.')
-
- parser.add_argument(
- '--os-url', metavar='<url>',
- default=env('OS_URL'),
- help='Defaults to env[OS_URL]')
- parser.add_argument(
- '--os_url',
- help=argparse.SUPPRESS)
-
- parser.add_argument(
- '--insecure',
- action='store_true',
- default=env('QUANTUMCLIENT_INSECURE', default=False),
- help="Explicitly allow quantumclient to perform \"insecure\" "
- "SSL (https) requests. The server's certificate will "
- "not be verified against any certificate authorities. "
- "This option should be used with caution.")
-
- return parser
-
- def _bash_completion(self):
- """Prints all of the commands and options for bash-completion."""
- commands = set()
- options = set()
- for option, _action in self.parser._option_string_actions.items():
- options.add(option)
- for command_name, command in self.command_manager:
- commands.add(command_name)
- cmd_factory = command.load()
- cmd = cmd_factory(self, None)
- cmd_parser = cmd.get_parser('')
- for option, _action in cmd_parser._option_string_actions.items():
- options.add(option)
- print ' '.join(commands | options)
-
- def run(self, argv):
- """Equivalent to the main program for the application.
-
- :param argv: input arguments and options
- :paramtype argv: list of str
- """
- try:
- index = 0
- command_pos = -1
- help_pos = -1
- help_command_pos = -1
- for arg in argv:
- if arg == 'bash-completion':
- self._bash_completion()
- return 0
- if arg in self.commands[self.api_version]:
- if command_pos == -1:
- command_pos = index
- elif arg in ('-h', '--help'):
- if help_pos == -1:
- help_pos = index
- elif arg == 'help':
- if help_command_pos == -1:
- help_command_pos = index
- index = index + 1
- if command_pos > -1 and help_pos > command_pos:
- argv = ['help', argv[command_pos]]
- if help_command_pos > -1 and command_pos == -1:
- argv[help_command_pos] = '--help'
- self.options, remainder = self.parser.parse_known_args(argv)
- self.configure_logging()
- self.interactive_mode = not remainder
- self.initialize_app(remainder)
- except Exception as err:
- if self.options.debug:
- self.log.exception(unicode(err))
- raise
- else:
- self.log.error(unicode(err))
- return 1
- result = 1
- if self.interactive_mode:
- _argv = [sys.argv[0]]
- sys.argv = _argv
- result = self.interact()
- else:
- result = self.run_subcommand(remainder)
- return result
-
- def run_subcommand(self, argv):
- subcommand = self.command_manager.find_command(argv)
- cmd_factory, cmd_name, sub_argv = subcommand
- cmd = cmd_factory(self, self.options)
- err = None
- result = 1
- try:
- self.prepare_to_run_command(cmd)
- full_name = (cmd_name
- if self.interactive_mode
- else ' '.join([self.NAME, cmd_name])
- )
- cmd_parser = cmd.get_parser(full_name)
- return run_command(cmd, cmd_parser, sub_argv)
- except Exception as err:
- if self.options.debug:
- self.log.exception(unicode(err))
- else:
- self.log.error(unicode(err))
- try:
- self.clean_up(cmd, result, err)
- except Exception as err2:
- if self.options.debug:
- self.log.exception(unicode(err2))
- else:
- self.log.error('Could not clean up: %s', unicode(err2))
- if self.options.debug:
- raise
- else:
- try:
- self.clean_up(cmd, result, None)
- except Exception as err3:
- if self.options.debug:
- self.log.exception(unicode(err3))
- else:
- self.log.error('Could not clean up: %s', unicode(err3))
- return result
-
- def authenticate_user(self):
- """Make sure the user has provided all of the authentication
- info we need.
- """
- if self.options.os_auth_strategy == 'keystone':
- if self.options.os_token or self.options.os_url:
- # Token flow auth takes priority
- if not self.options.os_token:
- raise exc.CommandError(
- "You must provide a token via"
- " either --os-token or env[OS_TOKEN]")
-
- if not self.options.os_url:
- raise exc.CommandError(
- "You must provide a service URL via"
- " either --os-url or env[OS_URL]")
-
- else:
- # Validate password flow auth
- if not self.options.os_username:
- raise exc.CommandError(
- "You must provide a username via"
- " either --os-username or env[OS_USERNAME]")
-
- if not self.options.os_password:
- raise exc.CommandError(
- "You must provide a password via"
- " either --os-password or env[OS_PASSWORD]")
-
- if not (self.options.os_tenant_name):
- raise exc.CommandError(
- "You must provide a tenant_name via"
- " either --os-tenant-name or via env[OS_TENANT_NAME]")
-
- if not self.options.os_auth_url:
- raise exc.CommandError(
- "You must provide an auth url via"
- " either --os-auth-url or via env[OS_AUTH_URL]")
- else: # not keystone
- if not self.options.os_url:
- raise exc.CommandError(
- "You must provide a service URL via"
- " either --os-url or env[OS_URL]")
-
- self.client_manager = clientmanager.ClientManager(
- token=self.options.os_token,
- url=self.options.os_url,
- auth_url=self.options.os_auth_url,
- tenant_name=self.options.os_tenant_name,
- username=self.options.os_username,
- password=self.options.os_password,
- region_name=self.options.os_region_name,
- api_version=self.api_version,
- auth_strategy=self.options.os_auth_strategy,
- endpoint_type=self.options.endpoint_type,
- insecure=self.options.insecure, )
- return
-
- def initialize_app(self, argv):
- """Global app init bits:
-
- * set up API versions
- * validate authentication info
- """
-
- super(QuantumShell, self).initialize_app(argv)
-
- self.api_version = {'network': self.api_version}
-
- # If the user is not asking for help, make sure they
- # have given us auth.
- cmd_name = None
- if argv:
- cmd_info = self.command_manager.find_command(argv)
- cmd_factory, cmd_name, sub_argv = cmd_info
- if self.interactive_mode or cmd_name != 'help':
- self.authenticate_user()
-
- def clean_up(self, cmd, result, err):
- self.log.debug('clean_up %s', cmd.__class__.__name__)
- if err:
- self.log.debug('got an error: %s', unicode(err))
-
- def configure_logging(self):
- """Create logging handlers for any log output.
- """
- root_logger = logging.getLogger('')
-
- # Set up logging to a file
- root_logger.setLevel(logging.DEBUG)
-
- # Send higher-level messages to the console via stderr
- console = logging.StreamHandler(self.stderr)
- console_level = {0: logging.WARNING,
- 1: logging.INFO,
- 2: logging.DEBUG,
- }.get(self.options.verbose_level, logging.DEBUG)
- console.setLevel(console_level)
- if logging.DEBUG == console_level:
- formatter = logging.Formatter(self.DEBUG_MESSAGE_FORMAT)
- else:
- formatter = logging.Formatter(self.CONSOLE_MESSAGE_FORMAT)
- console.setFormatter(formatter)
- root_logger.addHandler(console)
- return
+from neutronclient import shell
def main(argv=sys.argv[1:]):
- try:
- return QuantumShell(QUANTUM_API_VERSION).run(map(strutils.safe_decode,
- argv))
- except exc.QuantumClientException:
- return 1
- except Exception as e:
- print unicode(e)
- return 1
-
+ shell.main(argv)
-if __name__ == "__main__":
- sys.exit(main(sys.argv[1:]))
+env = shell.env
+QuantumShell = shell.NeutronShell
+QUANTUM_API_VERSION = shell.NEUTRON_API_VERSION
diff --git a/quantumclient/tests/unit/test_utils.py b/quantumclient/tests/unit/test_utils.py
deleted file mode 100644
index 69ecf6d..0000000
--- a/quantumclient/tests/unit/test_utils.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-import testtools
-
-from quantumclient.common import utils
-
-
-class UtilsTest(testtools.TestCase):
- def test_safe_encode_list(self):
- o = object()
- unicode_text = u'\u7f51\u7edc'
- l = ['abc', unicode_text, unicode_text.encode('utf-8'), o]
- expected = ['abc', unicode_text.encode('utf-8'),
- unicode_text.encode('utf-8'), o]
- self.assertEqual(utils.safe_encode_list(l), expected)
-
- def test_safe_encode_dict(self):
- o = object()
- unicode_text = u'\u7f51\u7edc'
- d = {'test1': unicode_text,
- 'test2': [unicode_text, o],
- 'test3': o,
- 'test4': {'test5': unicode_text},
- 'test6': unicode_text.encode('utf-8')}
- expected = {'test1': unicode_text.encode('utf-8'),
- 'test2': [unicode_text.encode('utf-8'), o],
- 'test3': o,
- 'test4': {'test5': unicode_text.encode('utf-8')},
- 'test6': unicode_text.encode('utf-8')}
- self.assertEqual(utils.safe_encode_dict(d), expected)
diff --git a/quantumclient/v2_0/client.py b/quantumclient/v2_0/client.py
index 93539df..08a455b 100644
--- a/quantumclient/v2_0/client.py
+++ b/quantumclient/v2_0/client.py
@@ -15,866 +15,6 @@
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-import httplib
-import logging
-import time
-import urllib
-import urlparse
+from neutronclient.v2_0 import client
-from quantumclient import client
-from quantumclient.common import _
-from quantumclient.common import constants
-from quantumclient.common import exceptions
-from quantumclient.common import serializer
-from quantumclient.common import utils
-
-
-_logger = logging.getLogger(__name__)
-
-
-def exception_handler_v20(status_code, error_content):
- """Exception handler for API v2.0 client
-
- This routine generates the appropriate
- Quantum exception according to the contents of the
- response body
-
- :param status_code: HTTP error status code
- :param error_content: deserialized body of error response
- """
-
- quantum_errors = {
- 'NetworkNotFound': exceptions.NetworkNotFoundClient,
- 'NetworkInUse': exceptions.NetworkInUseClient,
- 'PortNotFound': exceptions.PortNotFoundClient,
- 'RequestedStateInvalid': exceptions.StateInvalidClient,
- 'PortInUse': exceptions.PortInUseClient,
- 'AlreadyAttached': exceptions.AlreadyAttachedClient, }
-
- error_dict = None
- if isinstance(error_content, dict):
- error_dict = error_content.get('QuantumError')
- # Find real error type
- bad_quantum_error_flag = False
- if error_dict:
- # If QuantumError key is found, it will definitely contain
- # a 'message' and 'type' keys?
- try:
- error_type = error_dict['type']
- error_message = (error_dict['message'] + "\n" +
- error_dict['detail'])
- except Exception:
- bad_quantum_error_flag = True
- if not bad_quantum_error_flag:
- ex = None
- try:
- # raise the appropriate error!
- ex = quantum_errors[error_type](message=error_message)
- ex.args = ([dict(status_code=status_code,
- message=error_message)], )
- except Exception:
- pass
- if ex:
- raise ex
- else:
- raise exceptions.QuantumClientException(status_code=status_code,
- message=error_dict)
- else:
- message = None
- if isinstance(error_content, dict):
- message = error_content.get('message', None)
- if message:
- raise exceptions.QuantumClientException(status_code=status_code,
- message=message)
-
- # If we end up here the exception was not a quantum error
- msg = "%s-%s" % (status_code, error_content)
- raise exceptions.QuantumClientException(status_code=status_code,
- message=msg)
-
-
-class APIParamsCall(object):
- """A Decorator to add support for format and tenant overriding
- and filters
- """
- def __init__(self, function):
- self.function = function
-
- def __get__(self, instance, owner):
- def with_params(*args, **kwargs):
- _format = instance.format
- if 'format' in kwargs:
- instance.format = kwargs['format']
- ret = self.function(instance, *args, **kwargs)
- instance.format = _format
- return ret
- return with_params
-
-
-class Client(object):
- """Client for the OpenStack Quantum v2.0 API.
-
- :param string username: Username for authentication. (optional)
- :param string password: Password for authentication. (optional)
- :param string token: Token for authentication. (optional)
- :param string tenant_name: Tenant name. (optional)
- :param string auth_url: Keystone service endpoint for authorization.
- :param string endpoint_type: Network service endpoint type to pull from the
- keystone catalog (e.g. 'publicURL',
- 'internalURL', or 'adminURL') (optional)
- :param string region_name: Name of a region to select when choosing an
- endpoint from the service catalog.
- :param string endpoint_url: A user-supplied endpoint URL for the quantum
- service. Lazy-authentication is possible for API
- service calls if endpoint is set at
- instantiation.(optional)
- :param integer timeout: Allows customization of the timeout for client
- http requests. (optional)
- :param insecure: ssl certificate validation. (optional)
-
- Example::
-
- from quantumclient.v2_0 import client
- quantum = client.Client(username=USER,
- password=PASS,
- tenant_name=TENANT_NAME,
- auth_url=KEYSTONE_URL)
-
- nets = quantum.list_networks()
- ...
-
- """
-
- networks_path = "/networks"
- network_path = "/networks/%s"
- ports_path = "/ports"
- port_path = "/ports/%s"
- subnets_path = "/subnets"
- subnet_path = "/subnets/%s"
- quotas_path = "/quotas"
- quota_path = "/quotas/%s"
- extensions_path = "/extensions"
- extension_path = "/extensions/%s"
- routers_path = "/routers"
- router_path = "/routers/%s"
- floatingips_path = "/floatingips"
- floatingip_path = "/floatingips/%s"
- security_groups_path = "/security-groups"
- security_group_path = "/security-groups/%s"
- security_group_rules_path = "/security-group-rules"
- security_group_rule_path = "/security-group-rules/%s"
- vips_path = "/lb/vips"
- vip_path = "/lb/vips/%s"
- pools_path = "/lb/pools"
- pool_path = "/lb/pools/%s"
- pool_path_stats = "/lb/pools/%s/stats"
- members_path = "/lb/members"
- member_path = "/lb/members/%s"
- health_monitors_path = "/lb/health_monitors"
- health_monitor_path = "/lb/health_monitors/%s"
- associate_pool_health_monitors_path = "/lb/pools/%s/health_monitors"
- disassociate_pool_health_monitors_path = (
- "/lb/pools/%(pool)s/health_monitors/%(health_monitor)s")
- qos_queues_path = "/qos-queues"
- qos_queue_path = "/qos-queues/%s"
- agents_path = "/agents"
- agent_path = "/agents/%s"
- network_gateways_path = "/network-gateways"
- network_gateway_path = "/network-gateways/%s"
-
- DHCP_NETS = '/dhcp-networks'
- DHCP_AGENTS = '/dhcp-agents'
- L3_ROUTERS = '/l3-routers'
- L3_AGENTS = '/l3-agents'
- # API has no way to report plurals, so we have to hard code them
- EXTED_PLURALS = {'routers': 'router',
- 'floatingips': 'floatingip',
- 'service_types': 'service_type',
- 'service_definitions': 'service_definition',
- 'security_groups': 'security_group',
- 'security_group_rules': 'security_group_rule',
- 'vips': 'vip',
- 'pools': 'pool',
- 'members': 'member',
- 'health_monitors': 'health_monitor',
- 'quotas': 'quota',
- }
- # 8192 Is the default max URI len for eventlet.wsgi.server
- MAX_URI_LEN = 8192
-
- def get_attr_metadata(self):
- if self.format == 'json':
- return {}
- old_request_format = self.format
- self.format = 'json'
- exts = self.list_extensions()['extensions']
- self.format = old_request_format
- ns = dict([(ext['alias'], ext['namespace']) for ext in exts])
- self.EXTED_PLURALS.update(constants.PLURALS)
- return {'plurals': self.EXTED_PLURALS,
- 'xmlns': constants.XML_NS_V20,
- constants.EXT_NS: ns}
-
- @APIParamsCall
- def get_quotas_tenant(self, **_params):
- """Fetch tenant info in server's context for
- following quota operation.
- """
- return self.get(self.quota_path % 'tenant', params=_params)
-
- @APIParamsCall
- def list_quotas(self, **_params):
- """Fetch all tenants' quotas."""
- return self.get(self.quotas_path, params=_params)
-
- @APIParamsCall
- def show_quota(self, tenant_id, **_params):
- """Fetch information of a certain tenant's quotas."""
- return self.get(self.quota_path % (tenant_id), params=_params)
-
- @APIParamsCall
- def update_quota(self, tenant_id, body=None):
- """Update a tenant's quotas."""
- return self.put(self.quota_path % (tenant_id), body=body)
-
- @APIParamsCall
- def delete_quota(self, tenant_id):
- """Delete the specified tenant's quota values."""
- return self.delete(self.quota_path % (tenant_id))
-
- @APIParamsCall
- def list_extensions(self, **_params):
- """Fetch a list of all exts on server side."""
- return self.get(self.extensions_path, params=_params)
-
- @APIParamsCall
- def show_extension(self, ext_alias, **_params):
- """Fetch a list of all exts on server side."""
- return self.get(self.extension_path % ext_alias, params=_params)
-
- @APIParamsCall
- def list_ports(self, retrieve_all=True, **_params):
- """Fetches a list of all networks for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('ports', self.ports_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_port(self, port, **_params):
- """Fetches information of a certain network."""
- return self.get(self.port_path % (port), params=_params)
-
- @APIParamsCall
- def create_port(self, body=None):
- """Creates a new port."""
- return self.post(self.ports_path, body=body)
-
- @APIParamsCall
- def update_port(self, port, body=None):
- """Updates a port."""
- return self.put(self.port_path % (port), body=body)
-
- @APIParamsCall
- def delete_port(self, port):
- """Deletes the specified port."""
- return self.delete(self.port_path % (port))
-
- @APIParamsCall
- def list_networks(self, retrieve_all=True, **_params):
- """Fetches a list of all networks for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('networks', self.networks_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_network(self, network, **_params):
- """Fetches information of a certain network."""
- return self.get(self.network_path % (network), params=_params)
-
- @APIParamsCall
- def create_network(self, body=None):
- """Creates a new network."""
- return self.post(self.networks_path, body=body)
-
- @APIParamsCall
- def update_network(self, network, body=None):
- """Updates a network."""
- return self.put(self.network_path % (network), body=body)
-
- @APIParamsCall
- def delete_network(self, network):
- """Deletes the specified network."""
- return self.delete(self.network_path % (network))
-
- @APIParamsCall
- def list_subnets(self, retrieve_all=True, **_params):
- """Fetches a list of all networks for a tenant."""
- return self.list('subnets', self.subnets_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_subnet(self, subnet, **_params):
- """Fetches information of a certain subnet."""
- return self.get(self.subnet_path % (subnet), params=_params)
-
- @APIParamsCall
- def create_subnet(self, body=None):
- """Creates a new subnet."""
- return self.post(self.subnets_path, body=body)
-
- @APIParamsCall
- def update_subnet(self, subnet, body=None):
- """Updates a subnet."""
- return self.put(self.subnet_path % (subnet), body=body)
-
- @APIParamsCall
- def delete_subnet(self, subnet):
- """Deletes the specified subnet."""
- return self.delete(self.subnet_path % (subnet))
-
- @APIParamsCall
- def list_routers(self, retrieve_all=True, **_params):
- """Fetches a list of all routers for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('routers', self.routers_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_router(self, router, **_params):
- """Fetches information of a certain router."""
- return self.get(self.router_path % (router), params=_params)
-
- @APIParamsCall
- def create_router(self, body=None):
- """Creates a new router."""
- return self.post(self.routers_path, body=body)
-
- @APIParamsCall
- def update_router(self, router, body=None):
- """Updates a router."""
- return self.put(self.router_path % (router), body=body)
-
- @APIParamsCall
- def delete_router(self, router):
- """Deletes the specified router."""
- return self.delete(self.router_path % (router))
-
- @APIParamsCall
- def add_interface_router(self, router, body=None):
- """Adds an internal network interface to the specified router."""
- return self.put((self.router_path % router) + "/add_router_interface",
- body=body)
-
- @APIParamsCall
- def remove_interface_router(self, router, body=None):
- """Removes an internal network interface from the specified router."""
- return self.put((self.router_path % router) +
- "/remove_router_interface", body=body)
-
- @APIParamsCall
- def add_gateway_router(self, router, body=None):
- """Adds an external network gateway to the specified router."""
- return self.put((self.router_path % router),
- body={'router': {'external_gateway_info': body}})
-
- @APIParamsCall
- def remove_gateway_router(self, router):
- """Removes an external network gateway from the specified router."""
- return self.put((self.router_path % router),
- body={'router': {'external_gateway_info': {}}})
-
- @APIParamsCall
- def list_floatingips(self, retrieve_all=True, **_params):
- """Fetches a list of all floatingips for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('floatingips', self.floatingips_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_floatingip(self, floatingip, **_params):
- """Fetches information of a certain floatingip."""
- return self.get(self.floatingip_path % (floatingip), params=_params)
-
- @APIParamsCall
- def create_floatingip(self, body=None):
- """Creates a new floatingip."""
- return self.post(self.floatingips_path, body=body)
-
- @APIParamsCall
- def update_floatingip(self, floatingip, body=None):
- """Updates a floatingip."""
- return self.put(self.floatingip_path % (floatingip), body=body)
-
- @APIParamsCall
- def delete_floatingip(self, floatingip):
- """Deletes the specified floatingip."""
- return self.delete(self.floatingip_path % (floatingip))
-
- @APIParamsCall
- def create_security_group(self, body=None):
- """Creates a new security group."""
- return self.post(self.security_groups_path, body=body)
-
- @APIParamsCall
- def update_security_group(self, security_group, body=None):
- """Updates a security group."""
- return self.put(self.security_group_path %
- security_group, body=body)
-
- @APIParamsCall
- def list_security_groups(self, retrieve_all=True, **_params):
- """Fetches a list of all security groups for a tenant."""
- return self.list('security_groups', self.security_groups_path,
- retrieve_all, **_params)
-
- @APIParamsCall
- def show_security_group(self, security_group, **_params):
- """Fetches information of a certain security group."""
- return self.get(self.security_group_path % (security_group),
- params=_params)
-
- @APIParamsCall
- def delete_security_group(self, security_group):
- """Deletes the specified security group."""
- return self.delete(self.security_group_path % (security_group))
-
- @APIParamsCall
- def create_security_group_rule(self, body=None):
- """Creates a new security group rule."""
- return self.post(self.security_group_rules_path, body=body)
-
- @APIParamsCall
- def delete_security_group_rule(self, security_group_rule):
- """Deletes the specified security group rule."""
- return self.delete(self.security_group_rule_path %
- (security_group_rule))
-
- @APIParamsCall
- def list_security_group_rules(self, retrieve_all=True, **_params):
- """Fetches a list of all security group rules for a tenant."""
- return self.list('security_group_rules',
- self.security_group_rules_path,
- retrieve_all, **_params)
-
- @APIParamsCall
- def show_security_group_rule(self, security_group_rule, **_params):
- """Fetches information of a certain security group rule."""
- return self.get(self.security_group_rule_path % (security_group_rule),
- params=_params)
-
- @APIParamsCall
- def list_vips(self, retrieve_all=True, **_params):
- """Fetches a list of all load balancer vips for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('vips', self.vips_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_vip(self, vip, **_params):
- """Fetches information of a certain load balancer vip."""
- return self.get(self.vip_path % (vip), params=_params)
-
- @APIParamsCall
- def create_vip(self, body=None):
- """Creates a new load balancer vip."""
- return self.post(self.vips_path, body=body)
-
- @APIParamsCall
- def update_vip(self, vip, body=None):
- """Updates a load balancer vip."""
- return self.put(self.vip_path % (vip), body=body)
-
- @APIParamsCall
- def delete_vip(self, vip):
- """Deletes the specified load balancer vip."""
- return self.delete(self.vip_path % (vip))
-
- @APIParamsCall
- def list_pools(self, retrieve_all=True, **_params):
- """Fetches a list of all load balancer pools for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('pools', self.pools_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_pool(self, pool, **_params):
- """Fetches information of a certain load balancer pool."""
- return self.get(self.pool_path % (pool), params=_params)
-
- @APIParamsCall
- def create_pool(self, body=None):
- """Creates a new load balancer pool."""
- return self.post(self.pools_path, body=body)
-
- @APIParamsCall
- def update_pool(self, pool, body=None):
- """Updates a load balancer pool."""
- return self.put(self.pool_path % (pool), body=body)
-
- @APIParamsCall
- def delete_pool(self, pool):
- """Deletes the specified load balancer pool."""
- return self.delete(self.pool_path % (pool))
-
- @APIParamsCall
- def retrieve_pool_stats(self, pool, **_params):
- """Retrieves stats for a certain load balancer pool."""
- return self.get(self.pool_path_stats % (pool), params=_params)
-
- @APIParamsCall
- def list_members(self, retrieve_all=True, **_params):
- """Fetches a list of all load balancer members for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('members', self.members_path, retrieve_all,
- **_params)
-
- @APIParamsCall
- def show_member(self, member, **_params):
- """Fetches information of a certain load balancer member."""
- return self.get(self.member_path % (member), params=_params)
-
- @APIParamsCall
- def create_member(self, body=None):
- """Creates a new load balancer member."""
- return self.post(self.members_path, body=body)
-
- @APIParamsCall
- def update_member(self, member, body=None):
- """Updates a load balancer member."""
- return self.put(self.member_path % (member), body=body)
-
- @APIParamsCall
- def delete_member(self, member):
- """Deletes the specified load balancer member."""
- return self.delete(self.member_path % (member))
-
- @APIParamsCall
- def list_health_monitors(self, retrieve_all=True, **_params):
- """Fetches a list of all load balancer health monitors for a tenant."""
- # Pass filters in "params" argument to do_request
- return self.list('health_monitors', self.health_monitors_path,
- retrieve_all, **_params)
-
- @APIParamsCall
- def show_health_monitor(self, health_monitor, **_params):
- """Fetches information of a certain load balancer health monitor."""
- return self.get(self.health_monitor_path % (health_monitor),
- params=_params)
-
- @APIParamsCall
- def create_health_monitor(self, body=None):
- """Creates a new load balancer health monitor."""
- return self.post(self.health_monitors_path, body=body)
-
- @APIParamsCall
- def update_health_monitor(self, health_monitor, body=None):
- """Updates a load balancer health monitor."""
- return self.put(self.health_monitor_path % (health_monitor), body=body)
-
- @APIParamsCall
- def delete_health_monitor(self, health_monitor):
- """Deletes the specified load balancer health monitor."""
- return self.delete(self.health_monitor_path % (health_monitor))
-
- @APIParamsCall
- def associate_health_monitor(self, pool, body):
- """Associate specified load balancer health monitor and pool."""
- return self.post(self.associate_pool_health_monitors_path % (pool),
- body=body)
-
- @APIParamsCall
- def disassociate_health_monitor(self, pool, health_monitor):
- """Disassociate specified load balancer health monitor and pool."""
- path = (self.disassociate_pool_health_monitors_path %
- {'pool': pool, 'health_monitor': health_monitor})
- return self.delete(path)
-
- @APIParamsCall
- def create_qos_queue(self, body=None):
- """Creates a new queue."""
- return self.post(self.qos_queues_path, body=body)
-
- @APIParamsCall
- def list_qos_queues(self, **_params):
- """Fetches a list of all queues for a tenant."""
- return self.get(self.qos_queues_path, params=_params)
-
- @APIParamsCall
- def show_qos_queue(self, queue, **_params):
- """Fetches information of a certain queue."""
- return self.get(self.qos_queue_path % (queue),
- params=_params)
-
- @APIParamsCall
- def delete_qos_queue(self, queue):
- """Deletes the specified queue."""
- return self.delete(self.qos_queue_path % (queue))
-
- @APIParamsCall
- def list_agents(self, **_params):
- """Fetches agents."""
- # Pass filters in "params" argument to do_request
- return self.get(self.agents_path, params=_params)
-
- @APIParamsCall
- def show_agent(self, agent, **_params):
- """Fetches information of a certain agent."""
- return self.get(self.agent_path % (agent), params=_params)
-
- @APIParamsCall
- def update_agent(self, agent, body=None):
- """Updates an agent."""
- return self.put(self.agent_path % (agent), body=body)
-
- @APIParamsCall
- def delete_agent(self, agent):
- """Deletes the specified agent."""
- return self.delete(self.agent_path % (agent))
-
- @APIParamsCall
- def list_network_gateways(self, **_params):
- """Retrieve network gateways."""
- return self.get(self.network_gateways_path, params=_params)
-
- @APIParamsCall
- def show_network_gateway(self, gateway_id, **_params):
- """Fetch a network gateway."""
- return self.get(self.network_gateway_path % gateway_id, params=_params)
-
- @APIParamsCall
- def create_network_gateway(self, body=None):
- """Create a new network gateway."""
- return self.post(self.network_gateways_path, body=body)
-
- @APIParamsCall
- def update_network_gateway(self, gateway_id, body=None):
- """Update a network gateway."""
- return self.put(self.network_gateway_path % gateway_id, body=body)
-
- @APIParamsCall
- def delete_network_gateway(self, gateway_id):
- """Delete the specified network gateway."""
- return self.delete(self.network_gateway_path % gateway_id)
-
- @APIParamsCall
- def connect_network_gateway(self, gateway_id, body=None):
- """Connect a network gateway to the specified network."""
- base_uri = self.network_gateway_path % gateway_id
- return self.put("%s/connect_network" % base_uri, body=body)
-
- @APIParamsCall
- def disconnect_network_gateway(self, gateway_id, body=None):
- """Disconnect a network from the specified gateway."""
- base_uri = self.network_gateway_path % gateway_id
- return self.put("%s/disconnect_network" % base_uri, body=body)
-
- @APIParamsCall
- def list_dhcp_agent_hosting_networks(self, network, **_params):
- """Fetches a list of dhcp agents hosting a network."""
- return self.get((self.network_path + self.DHCP_AGENTS) % network,
- params=_params)
-
- @APIParamsCall
- def list_networks_on_dhcp_agent(self, dhcp_agent, **_params):
- """Fetches a list of dhcp agents hosting a network."""
- return self.get((self.agent_path + self.DHCP_NETS) % dhcp_agent,
- params=_params)
-
- @APIParamsCall
- def add_network_to_dhcp_agent(self, dhcp_agent, body=None):
- """Adds a network to dhcp agent."""
- return self.post((self.agent_path + self.DHCP_NETS) % dhcp_agent,
- body=body)
-
- @APIParamsCall
- def remove_network_from_dhcp_agent(self, dhcp_agent, network_id):
- """Remove a network from dhcp agent."""
- return self.delete((self.agent_path + self.DHCP_NETS + "/%s") % (
- dhcp_agent, network_id))
-
- @APIParamsCall
- def list_l3_agent_hosting_routers(self, router, **_params):
- """Fetches a list of L3 agents hosting a router."""
- return self.get((self.router_path + self.L3_AGENTS) % router,
- params=_params)
-
- @APIParamsCall
- def list_routers_on_l3_agent(self, l3_agent, **_params):
- """Fetches a list of L3 agents hosting a router."""
- return self.get((self.agent_path + self.L3_ROUTERS) % l3_agent,
- params=_params)
-
- @APIParamsCall
- def add_router_to_l3_agent(self, l3_agent, body):
- """Adds a router to L3 agent."""
- return self.post((self.agent_path + self.L3_ROUTERS) % l3_agent,
- body=body)
-
- @APIParamsCall
- def remove_router_from_l3_agent(self, l3_agent, router_id):
- """Remove a router from l3 agent."""
- return self.delete((self.agent_path + self.L3_ROUTERS + "/%s") % (
- l3_agent, router_id))
-
- def __init__(self, **kwargs):
- """Initialize a new client for the Quantum v2.0 API."""
- super(Client, self).__init__()
- self.httpclient = client.HTTPClient(**kwargs)
- self.version = '2.0'
- self.format = 'json'
- self.action_prefix = "/v%s" % (self.version)
- self.retries = 0
- self.retry_interval = 1
-
- def _handle_fault_response(self, status_code, response_body):
- # Create exception with HTTP status code and message
- _logger.debug("Error message: %s", response_body)
- # Add deserialized error message to exception arguments
- try:
- des_error_body = self.deserialize(response_body, status_code)
- except Exception:
- # If unable to deserialized body it is probably not a
- # Quantum error
- des_error_body = {'message': response_body}
- # Raise the appropriate exception
- exception_handler_v20(status_code, des_error_body)
-
- def _check_uri_length(self, action):
- uri_len = len(self.httpclient.endpoint_url) + len(action)
- if uri_len > self.MAX_URI_LEN:
- raise exceptions.RequestURITooLong(
- excess=uri_len - self.MAX_URI_LEN)
-
- def do_request(self, method, action, body=None, headers=None, params=None):
- # Add format and tenant_id
- action += ".%s" % self.format
- action = self.action_prefix + action
- if type(params) is dict and params:
- params = utils.safe_encode_dict(params)
- action += '?' + urllib.urlencode(params, doseq=1)
- # Ensure client always has correct uri - do not guesstimate anything
- self.httpclient.authenticate_and_fetch_endpoint_url()
- self._check_uri_length(action)
-
- if body:
- body = self.serialize(body)
- self.httpclient.content_type = self.content_type()
- resp, replybody = self.httpclient.do_request(action, method, body=body)
- status_code = self.get_status_code(resp)
- if status_code in (httplib.OK,
- httplib.CREATED,
- httplib.ACCEPTED,
- httplib.NO_CONTENT):
- return self.deserialize(replybody, status_code)
- else:
- self._handle_fault_response(status_code, replybody)
-
- def get_auth_info(self):
- return self.httpclient.get_auth_info()
-
- def get_status_code(self, response):
- """Returns the integer status code from the response.
-
- Either a Webob.Response (used in testing) or httplib.Response
- is returned.
- """
- if hasattr(response, 'status_int'):
- return response.status_int
- else:
- return response.status
-
- def serialize(self, data):
- """Serializes a dictionary into either xml or json.
-
- A dictionary with a single key can be passed and
- it can contain any structure.
- """
- if data is None:
- return None
- elif type(data) is dict:
- return serializer.Serializer(
- self.get_attr_metadata()).serialize(data, self.content_type())
- else:
- raise Exception("unable to serialize object of type = '%s'" %
- type(data))
-
- def deserialize(self, data, status_code):
- """Deserializes an xml or json string into a dictionary."""
- if status_code == 204:
- return data
- return serializer.Serializer(self.get_attr_metadata()).deserialize(
- data, self.content_type())['body']
-
- def content_type(self, _format=None):
- """Returns the mime-type for either 'xml' or 'json'.
-
- Defaults to the currently set format.
- """
- _format = _format or self.format
- return "application/%s" % (_format)
-
- def retry_request(self, method, action, body=None,
- headers=None, params=None):
- """Call do_request with the default retry configuration.
-
- Only idempotent requests should retry failed connection attempts.
- :raises: ConnectionFailed if the maximum # of retries is exceeded
- """
- max_attempts = self.retries + 1
- for i in xrange(max_attempts):
- try:
- return self.do_request(method, action, body=body,
- headers=headers, params=params)
- except exceptions.ConnectionFailed:
- # Exception has already been logged by do_request()
- if i < self.retries:
- _logger.debug(_('Retrying connection to quantum service'))
- time.sleep(self.retry_interval)
-
- raise exceptions.ConnectionFailed(reason=_("Maximum attempts reached"))
-
- def delete(self, action, body=None, headers=None, params=None):
- return self.retry_request("DELETE", action, body=body,
- headers=headers, params=params)
-
- def get(self, action, body=None, headers=None, params=None):
- return self.retry_request("GET", action, body=body,
- headers=headers, params=params)
-
- def post(self, action, body=None, headers=None, params=None):
- # Do not retry POST requests to avoid the orphan objects problem.
- return self.do_request("POST", action, body=body,
- headers=headers, params=params)
-
- def put(self, action, body=None, headers=None, params=None):
- return self.retry_request("PUT", action, body=body,
- headers=headers, params=params)
-
- def list(self, collection, path, retrieve_all=True, **params):
- if retrieve_all:
- res = []
- for r in self._pagination(collection, path, **params):
- res.extend(r[collection])
- return {collection: res}
- else:
- return self._pagination(collection, path, **params)
-
- def _pagination(self, collection, path, **params):
- if params.get('page_reverse', False):
- linkrel = 'previous'
- else:
- linkrel = 'next'
- next = True
- while next:
- res = self.get(path, params=params)
- yield res
- next = False
- try:
- for link in res['%s_links' % collection]:
- if link['rel'] == linkrel:
- query_str = urlparse.urlparse(link['href']).query
- params = urlparse.parse_qs(query_str)
- next = True
- break
- except KeyError:
- break
+Client = client.Client