diff --git a/README.rst b/README.rst index 20b7a89..9ab0b8e 100644 --- a/README.rst +++ b/README.rst @@ -1 +1,2 @@ -This is the client API library for Quantum. +This package provides a compatibility layer for code that was built to require +the old Quantum API Client. New code should use the neutronclient module. diff --git a/doc/source/index.rst b/doc/source/index.rst index f68f1e1..1405b9c 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -61,3 +61,8 @@ Release Notes * made the publicURL the default endpoint instead of adminURL * add ability to update security group name (requires 2013.2-Havana or later) * add flake8 and pbr support for testing and building + +2.2.4 +----- +* add compatibility layer to proxy neutronclient +* removes all quantumclient code diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index cff7a3d..0000000 --- a/openstack-common.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] - -# The list of modules to copy from openstack-common -modules=exception,gettextutils,jsonutils,strutils,timeutils - -# The base module to hold the copy of openstack.common -base=quantumclient diff --git a/quantum_test.sh b/quantum_test.sh deleted file mode 100755 index b42299b..0000000 --- a/quantum_test.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -set -x -function die() { - local exitcode=$? - set +o xtrace - echo $@ - exit $exitcode -} - -noauth_tenant_id=me -if [ $1 == 'noauth' ]; then - NOAUTH="--tenant_id $noauth_tenant_id" -else - NOAUTH= -fi - -FORMAT=" --request-format xml" - -# test the CRUD of network -network=mynet1 -quantum net-create $FORMAT $NOAUTH $network || die "fail to create network $network" -temp=`quantum net-list $FORMAT -- --name $network --fields id | wc -l` -echo $temp -if [ $temp -ne 5 ]; then - die "networks with name $network is not unique or found" -fi -network_id=`quantum net-list -- --name $network --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2` -echo "ID of network with name $network is $network_id" - -quantum net-show $FORMAT $network || die "fail to show network $network" -quantum net-show $FORMAT $network_id || die "fail to show network $network_id" - -quantum net-update $FORMAT $network --admin_state_up False || die "fail to update network $network" -quantum net-update $FORMAT $network_id --admin_state_up True || die "fail to update network $network_id" - -quantum net-list $FORMAT -c id -- --id fakeid || die "fail to list networks with column selection on empty list" - -# test the CRUD of subnet -subnet=mysubnet1 -cidr=10.0.1.3/24 -quantum subnet-create $FORMAT $NOAUTH $network $cidr --name $subnet || die "fail to create subnet $subnet" -tempsubnet=`quantum subnet-list $FORMAT -- --name $subnet --fields id | wc -l` -echo $tempsubnet -if [ $tempsubnet -ne 5 ]; then - die "subnets with name $subnet is not unique or found" -fi -subnet_id=`quantum subnet-list $FORMAT -- --name $subnet --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2` -echo "ID of subnet with name $subnet is $subnet_id" -quantum subnet-show $FORMAT $subnet || die "fail to show subnet $subnet" -quantum subnet-show $FORMAT $subnet_id || die "fail to show subnet $subnet_id" - -quantum subnet-update $FORMAT $subnet --dns_namesevers host1 || die "fail to update subnet $subnet" -quantum subnet-update $FORMAT $subnet_id --dns_namesevers host2 || die "fail to update subnet $subnet_id" - -# test the crud of ports -port=myport1 -quantum port-create $FORMAT $NOAUTH $network --name $port || die "fail to create port $port" -tempport=`quantum port-list $FORMAT -- --name $port --fields id | wc -l` -echo $tempport -if [ $tempport -ne 5 ]; then - die "ports with name $port is not unique or found" -fi -port_id=`quantum port-list $FORMAT -- --name $port --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2` -echo "ID of port with name $port is $port_id" -quantum port-show $FORMAT $port || die "fail to show port $port" -quantum port-show $FORMAT $port_id || die "fail to show port $port_id" - -quantum port-update $FORMAT $port --device_id deviceid1 || die "fail to update port $port" -quantum port-update $FORMAT $port_id --device_id deviceid2 || die "fail to update port $port_id" - -# test quota commands RUD -DEFAULT_NETWORKS=10 -DEFAULT_PORTS=50 -tenant_id=tenant_a -tenant_id_b=tenant_b -quantum quota-update $FORMAT --tenant_id $tenant_id --network 30 || die "fail to update quota for tenant $tenant_id" -quantum quota-update $FORMAT --tenant_id $tenant_id_b --network 20 || die "fail to update quota for tenant $tenant_id" -networks=`quantum quota-list $FORMAT -c network -c tenant_id | grep $tenant_id | awk '{print $2}'` -if [ $networks -ne 30 ]; then - die "networks quota should be 30" -fi -networks=`quantum quota-list $FORMAT -c network -c tenant_id | grep $tenant_id_b | awk '{print $2}'` -if [ $networks -ne 20 ]; then - die "networks quota should be 20" -fi -networks=`quantum quota-show $FORMAT --tenant_id $tenant_id | grep network | awk -F'|' '{print $3}'` -if [ $networks -ne 30 ]; then - die "networks quota should be 30" -fi -quantum quota-delete $FORMAT --tenant_id $tenant_id || die "fail to delete quota for tenant $tenant_id" -networks=`quantum quota-show $FORMAT --tenant_id $tenant_id | grep network | awk -F'|' '{print $3}'` -if [ $networks -ne $DEFAULT_NETWORKS ]; then - die "networks quota should be $DEFAULT_NETWORKS" -fi -# update self -if [ "t$NOAUTH" = "t" ]; then - # with auth - quantum quota-update $FORMAT --port 99 || die "fail to update quota for self" - ports=`quantum quota-show $FORMAT | grep port | awk -F'|' '{print $3}'` - if [ $ports -ne 99 ]; then - die "ports quota should be 99" - fi - - ports=`quantum quota-list $FORMAT -c port | grep 99 | awk '{print $2}'` - if [ $ports -ne 99 ]; then - die "ports quota should be 99" - fi - quantum quota-delete $FORMAT || die "fail to delete quota for tenant self" - ports=`quantum quota-show $FORMAT | grep port | awk -F'|' '{print $3}'` - if [ $ports -ne $DEFAULT_PORTS ]; then - die "ports quota should be $DEFAULT_PORTS" - fi -else - # without auth - quantum quota-update $FORMAT --port 100 - if [ $? -eq 0 ]; then - die "without valid context on server, quota update command should fail." - fi - quantum quota-show $FORMAT - if [ $? -eq 0 ]; then - die "without valid context on server, quota show command should fail." - fi - quantum quota-delete $FORMAT - if [ $? -eq 0 ]; then - die "without valid context on server, quota delete command should fail." - fi - quantum quota-list $FORMAT || die "fail to update quota for self" -fi 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 diff --git a/quantumclient/openstack/common/__init__.py b/quantumclient/openstack/common/__init__.py deleted file mode 100644 index e69de29..0000000 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=& (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=,' - 'interface_name= ' - '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=,ip_address=, ' - '(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='', - 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='', - 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='', - 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='', - 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='', - 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='', - 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='', - default=env('OS_TOKEN'), - help='Defaults to env[OS_TOKEN]') - parser.add_argument( - '--os_token', - help=argparse.SUPPRESS) - - parser.add_argument( - '--endpoint-type', metavar='', - default=env('OS_ENDPOINT_TYPE', default='publicURL'), - help='Defaults to env[OS_ENDPOINT_TYPE] or publicURL.') - - parser.add_argument( - '--os-url', metavar='', - 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 diff --git a/requirements.txt b/requirements.txt index 1eabc6f..12e8b5a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,2 @@ -d2to1>=0.2.10,<0.3 -pbr>=0.5.16,<0.6 -argparse -cliff>=1.4 -httplib2 -iso8601 -prettytable>=0.6,<0.8 -pyparsing>=1.5.6,<2.0 -simplejson +pbr>=0.5.21,<1.0 +python-neutronclient>=2.3.0,<3 diff --git a/setup.py b/setup.py index 80b6834..e5dcfc2 100644 --- a/setup.py +++ b/setup.py @@ -19,5 +19,5 @@ import setuptools setuptools.setup( - setup_requires=['d2to1>=0.2.10,<0.3', 'pbr>=0.5.10,<0.6'], - d2to1=True) + setup_requires=['pbr>=0.5.21,<1.0'], + pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt index 34b353c..6523547 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,15 +1,9 @@ -# Install bounded pep8/pyflakes first, then let flake8 install -pep8==1.4.5 -pyflakes==0.7.2 -flake8==2.0 -hacking>=0.5.3,<0.6 +hacking>=0.5.6,<0.8 -cliff-tablib>=1.0 -coverage +coverage>=3.6 discover -fixtures>=0.3.12 -mox +fixtures>=0.3.14 python-subunit sphinx>=1.1.2 -testrepository>=0.0.13 -testtools>=0.9.22 +testrepository>=0.0.17 +testtools>=0.9.32 diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py deleted file mode 100644 index 1668497..0000000 --- a/tests/unit/__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/tests/unit/lb/__init__.py b/tests/unit/lb/__init__.py deleted file mode 100644 index 1668497..0000000 --- a/tests/unit/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/tests/unit/lb/test_cli20_healthmonitor.py b/tests/unit/lb/test_cli20_healthmonitor.py deleted file mode 100644 index 0b87ff9..0000000 --- a/tests/unit/lb/test_cli20_healthmonitor.py +++ /dev/null @@ -1,219 +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 sys - -import mox - -from quantumclient.quantum.v2_0.lb import healthmonitor -from tests.unit import test_cli20 - - -class CLITestV20LbHealthmonitorJSON(test_cli20.CLITestV20Base): - def test_create_healthmonitor_with_mandatory_params(self): - """lb-healthmonitor-create with mandatory params only.""" - resource = 'health_monitor' - cmd = healthmonitor.CreateHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - admin_state_up = False - delay = '60' - max_retries = '2' - timeout = '10' - type = 'tcp' - tenant_id = 'my-tenant' - my_id = 'my-id' - args = ['--admin-state-down', - '--delay', delay, - '--max-retries', max_retries, - '--timeout', timeout, - '--type', type, - '--tenant-id', tenant_id] - position_names = ['admin_state_up', 'delay', 'max_retries', 'timeout', - 'type', 'tenant_id'] - position_values = [admin_state_up, delay, max_retries, timeout, type, - tenant_id] - self._test_create_resource(resource, cmd, '', my_id, args, - position_names, position_values) - - def test_create_healthmonitor_with_all_params(self): - """lb-healthmonitor-create with all params set.""" - resource = 'health_monitor' - cmd = healthmonitor.CreateHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - admin_state_up = False - delay = '60' - expected_codes = '200-202,204' - http_method = 'HEAD' - max_retries = '2' - timeout = '10' - type = 'tcp' - tenant_id = 'my-tenant' - url_path = '/health' - my_id = 'my-id' - args = ['--admin-state-down', - '--delay', delay, - '--expected-codes', expected_codes, - '--http-method', http_method, - '--max-retries', max_retries, - '--timeout', timeout, - '--type', type, - '--tenant-id', tenant_id, - '--url-path', url_path] - position_names = ['admin_state_up', 'delay', - 'expected_codes', 'http_method', - 'max_retries', 'timeout', - 'type', 'tenant_id', 'url_path'] - position_values = [admin_state_up, delay, - expected_codes, http_method, - max_retries, timeout, - type, tenant_id, url_path] - self._test_create_resource(resource, cmd, '', my_id, args, - position_names, position_values) - - def test_list_healthmonitors(self): - """lb-healthmonitor-list.""" - resources = "health_monitors" - cmd = healthmonitor.ListHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - self._test_list_resources(resources, cmd, True) - - def test_list_healthmonitors_pagination(self): - """lb-healthmonitor-list.""" - resources = "health_monitors" - cmd = healthmonitor.ListHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_healthmonitors_sort(self): - """lb-healthmonitor-list --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "health_monitors" - cmd = healthmonitor.ListHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_healthmonitors_limit(self): - """lb-healthmonitor-list -P.""" - resources = "health_monitors" - cmd = healthmonitor.ListHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_show_healthmonitor_id(self): - """lb-healthmonitor-show test_id.""" - resource = 'health_monitor' - cmd = healthmonitor.ShowHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args, ['id']) - - def test_show_healthmonitor_id_name(self): - """lb-healthmonitor-show.""" - resource = 'health_monitor' - cmd = healthmonitor.ShowHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_update_health_monitor(self): - """lb-healthmonitor-update myid --name myname --tags a b.""" - resource = 'health_monitor' - cmd = healthmonitor.UpdateHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--timeout', '5'], - {'timeout': '5', }) - - def test_delete_healthmonitor(self): - """lb-healthmonitor-delete my-id.""" - resource = 'health_monitor' - cmd = healthmonitor.DeleteHealthMonitor(test_cli20.MyApp(sys.stdout), - None) - my_id = 'my-id' - args = [my_id] - self._test_delete_resource(resource, cmd, my_id, args) - - def test_associate_healthmonitor(self): - cmd = healthmonitor.AssociateHealthMonitor( - test_cli20.MyApp(sys.stdout), - None) - resource = 'health_monitor' - health_monitor_id = 'hm-id' - pool_id = 'p_id' - args = [health_monitor_id, pool_id] - - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - - body = {resource: {'id': health_monitor_id}} - result = {resource: {'id': health_monitor_id}, } - result_str = self.client.serialize(result) - - path = getattr(self.client, - "associate_pool_health_monitors_path") % pool_id - return_tup = (test_cli20.MyResp(200), result_str) - self.client.httpclient.request( - test_cli20.end_url(path), 'POST', - body=test_cli20.MyComparator(body, self.client), - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(return_tup) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser('test_' + resource) - parsed_args = cmd_parser.parse_args(args) - cmd.run(parsed_args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def test_disassociate_healthmonitor(self): - cmd = healthmonitor.DisassociateHealthMonitor( - test_cli20.MyApp(sys.stdout), - None) - resource = 'health_monitor' - health_monitor_id = 'hm-id' - pool_id = 'p_id' - args = [health_monitor_id, pool_id] - - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - - path = (getattr(self.client, - "disassociate_pool_health_monitors_path") % - {'pool': pool_id, 'health_monitor': health_monitor_id}) - return_tup = (test_cli20.MyResp(204), None) - self.client.httpclient.request( - test_cli20.end_url(path), 'DELETE', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(return_tup) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser('test_' + resource) - parsed_args = cmd_parser.parse_args(args) - cmd.run(parsed_args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - - -class CLITestV20LbHealthmonitorXML(CLITestV20LbHealthmonitorJSON): - format = 'xml' diff --git a/tests/unit/lb/test_cli20_member.py b/tests/unit/lb/test_cli20_member.py deleted file mode 100644 index 9b75367..0000000 --- a/tests/unit/lb/test_cli20_member.py +++ /dev/null @@ -1,134 +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 sys - -from quantumclient.quantum.v2_0.lb import member -from tests.unit import test_cli20 - - -class CLITestV20LbMemberJSON(test_cli20.CLITestV20Base): - def setUp(self): - super(CLITestV20LbMemberJSON, self).setUp(plurals={'tags': 'tag'}) - - def test_create_member(self): - """lb-member-create with mandatory params only.""" - resource = 'member' - cmd = member.CreateMember(test_cli20.MyApp(sys.stdout), None) - address = '10.0.0.1' - port = '8080' - tenant_id = 'my-tenant' - my_id = 'my-id' - pool_id = 'pool-id' - args = ['--address', address, '--protocol-port', port, - '--tenant-id', tenant_id, pool_id] - position_names = ['address', 'protocol_port', 'tenant_id', 'pool_id', - 'admin_state_up'] - position_values = [address, port, tenant_id, pool_id, True] - self._test_create_resource(resource, cmd, None, my_id, args, - position_names, position_values, - admin_state_up=None) - - def test_create_member_all_params(self): - """lb-member-create with all available params.""" - resource = 'member' - cmd = member.CreateMember(test_cli20.MyApp(sys.stdout), None) - address = '10.0.0.1' - admin_state_up = False - port = '8080' - weight = '1' - tenant_id = 'my-tenant' - my_id = 'my-id' - pool_id = 'pool-id' - args = ['--address', address, '--admin-state-down', - '--protocol-port', port, '--weight', weight, - '--tenant-id', tenant_id, pool_id] - position_names = [ - 'address', 'admin_state_up', 'protocol_port', 'weight', - 'tenant_id', 'pool_id' - ] - position_values = [address, admin_state_up, port, weight, - tenant_id, pool_id] - self._test_create_resource(resource, cmd, None, my_id, args, - position_names, position_values, - admin_state_up=None) - - def test_list_members(self): - """lb-member-list.""" - resources = "members" - cmd = member.ListMember(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_members_pagination(self): - """lb-member-list.""" - resources = "members" - cmd = member.ListMember(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_members_sort(self): - """lb-member-list --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "members" - cmd = member.ListMember(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_members_limit(self): - """lb-member-list -P.""" - resources = "members" - cmd = member.ListMember(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_show_member_id(self): - """lb-member-show test_id.""" - resource = 'member' - cmd = member.ShowMember(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args, ['id']) - - def test_show_member_id_name(self): - """lb-member-show.""" - resource = 'member' - cmd = member.ShowMember(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_update_member(self): - """lb-member-update myid --name myname --tags a b.""" - resource = 'member' - cmd = member.UpdateMember(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--tags', 'a', 'b'], - {'name': 'myname', 'tags': ['a', 'b'], }) - - def test_delete_member(self): - """lb-member-delete my-id.""" - resource = 'member' - cmd = member.DeleteMember(test_cli20.MyApp(sys.stdout), None) - my_id = 'my-id' - args = [my_id] - self._test_delete_resource(resource, cmd, my_id, args) - - -class CLITestV20LbMemberXML(CLITestV20LbMemberJSON): - format = 'xml' diff --git a/tests/unit/lb/test_cli20_pool.py b/tests/unit/lb/test_cli20_pool.py deleted file mode 100644 index 709c3d1..0000000 --- a/tests/unit/lb/test_cli20_pool.py +++ /dev/null @@ -1,171 +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 sys - -import mox - -from quantumclient.quantum.v2_0.lb import pool -from tests.unit import test_cli20 - - -class CLITestV20LbPoolJSON(test_cli20.CLITestV20Base): - - def test_create_pool_with_mandatory_params(self): - """lb-pool-create with mandatory params only.""" - resource = 'pool' - cmd = pool.CreatePool(test_cli20.MyApp(sys.stdout), None) - name = 'my-name' - lb_method = 'round-robin' - protocol = 'http' - subnet_id = 'subnet-id' - tenant_id = 'my-tenant' - my_id = 'my-id' - args = ['--lb-method', lb_method, - '--name', name, - '--protocol', protocol, - '--subnet-id', subnet_id, - '--tenant-id', tenant_id] - position_names = ['admin_state_up', 'lb_method', 'name', - 'protocol', 'subnet_id', 'tenant_id'] - position_values = [True, lb_method, name, - protocol, subnet_id, tenant_id] - self._test_create_resource(resource, cmd, name, my_id, args, - position_names, position_values) - - def test_create_pool_with_all_params(self): - """lb-pool-create with all params set.""" - resource = 'pool' - cmd = pool.CreatePool(test_cli20.MyApp(sys.stdout), None) - name = 'my-name' - description = 'my-desc' - lb_method = 'round-robin' - protocol = 'http' - subnet_id = 'subnet-id' - tenant_id = 'my-tenant' - my_id = 'my-id' - args = ['--admin-state-down', - '--description', description, - '--lb-method', lb_method, - '--name', name, - '--protocol', protocol, - '--subnet-id', subnet_id, - '--tenant-id', tenant_id] - position_names = ['admin_state_up', 'description', 'lb_method', 'name', - 'protocol', 'subnet_id', 'tenant_id'] - position_values = [False, description, lb_method, name, - protocol, subnet_id, tenant_id] - self._test_create_resource(resource, cmd, name, my_id, args, - position_names, position_values) - - def test_list_pools(self): - """lb-pool-list.""" - resources = "pools" - cmd = pool.ListPool(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_pools_pagination(self): - """lb-pool-list.""" - resources = "pools" - cmd = pool.ListPool(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_pools_sort(self): - """lb-pool-list --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "pools" - cmd = pool.ListPool(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_pools_limit(self): - """lb-pool-list -P.""" - resources = "pools" - cmd = pool.ListPool(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_show_pool_id(self): - """lb-pool-show test_id.""" - resource = 'pool' - cmd = pool.ShowPool(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args, ['id']) - - def test_show_pool_id_name(self): - """lb-pool-show.""" - resource = 'pool' - cmd = pool.ShowPool(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_update_pool(self): - """lb-pool-update myid --name newname --tags a b.""" - resource = 'pool' - cmd = pool.UpdatePool(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'newname'], - {'name': 'newname', }) - - def test_delete_pool(self): - """lb-pool-delete my-id.""" - resource = 'pool' - cmd = pool.DeletePool(test_cli20.MyApp(sys.stdout), None) - my_id = 'my-id' - args = [my_id] - self._test_delete_resource(resource, cmd, my_id, args) - - def test_retrieve_pool_stats(self): - """lb-pool-stats test_id.""" - resource = 'pool' - cmd = pool.RetrievePoolStats(test_cli20.MyApp(sys.stdout), None) - my_id = self.test_id - fields = ['bytes_in', 'bytes_out'] - args = ['--fields', 'bytes_in', '--fields', 'bytes_out', my_id] - - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - query = "&".join(["fields=%s" % field for field in fields]) - expected_res = {'stats': {'bytes_in': '1234', 'bytes_out': '4321'}} - resstr = self.client.serialize(expected_res) - path = getattr(self.client, "pool_path_stats") - return_tup = (test_cli20.MyResp(200), resstr) - self.client.httpclient.request( - test_cli20.end_url(path % my_id, query), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(return_tup) - self.mox.ReplayAll() - - cmd_parser = cmd.get_parser("test_" + resource) - parsed_args = cmd_parser.parse_args(args) - cmd.run(parsed_args) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertTrue('bytes_in' in _str) - self.assertTrue('bytes_out' in _str) - - -class CLITestV20LbPoolXML(CLITestV20LbPoolJSON): - format = 'xml' diff --git a/tests/unit/lb/test_cli20_vip.py b/tests/unit/lb/test_cli20_vip.py deleted file mode 100644 index 4358cfb..0000000 --- a/tests/unit/lb/test_cli20_vip.py +++ /dev/null @@ -1,214 +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 sys - -from quantumclient.quantum.v2_0.lb import vip -from tests.unit import test_cli20 - - -class CLITestV20LbVipJSON(test_cli20.CLITestV20Base): - def setUp(self): - super(CLITestV20LbVipJSON, self).setUp(plurals={'tags': 'tag'}) - - def test_create_vip_with_mandatory_params(self): - """lb-vip-create with all mandatory params.""" - resource = 'vip' - cmd = vip.CreateVip(test_cli20.MyApp(sys.stdout), None) - pool_id = 'my-pool-id' - name = 'my-name' - subnet_id = 'subnet-id' - protocol_port = '1000' - protocol = 'tcp' - tenant_id = 'my-tenant' - my_id = 'my-id' - args = ['--name', name, - '--protocol-port', protocol_port, - '--protocol', protocol, - '--subnet-id', subnet_id, - '--tenant-id', tenant_id, - pool_id] - position_names = ['pool_id', 'name', 'protocol_port', 'protocol', - 'subnet_id', 'tenant_id'] - position_values = [pool_id, name, protocol_port, protocol, - subnet_id, tenant_id] - self._test_create_resource(resource, cmd, name, my_id, args, - position_names, position_values, - admin_state_up=True) - - def test_create_vip_with_all_params(self): - """lb-vip-create with all params.""" - resource = 'vip' - cmd = vip.CreateVip(test_cli20.MyApp(sys.stdout), None) - pool_id = 'my-pool-id' - name = 'my-name' - description = 'my-desc' - address = '10.0.0.2' - admin_state = False - connection_limit = '1000' - subnet_id = 'subnet-id' - protocol_port = '80' - protocol = 'tcp' - tenant_id = 'my-tenant' - my_id = 'my-id' - args = ['--name', name, - '--description', description, - '--address', address, - '--admin-state-down', - '--connection-limit', connection_limit, - '--protocol-port', protocol_port, - '--protocol', protocol, - '--subnet-id', subnet_id, - '--tenant-id', tenant_id, - pool_id] - position_names = ['pool_id', 'name', 'description', 'address', - 'admin_state_up', 'connection_limit', - 'protocol_port', 'protocol', 'subnet_id', - 'tenant_id'] - position_values = [pool_id, name, description, address, - admin_state, connection_limit, protocol_port, - protocol, subnet_id, - tenant_id] - self._test_create_resource(resource, cmd, name, my_id, args, - position_names, position_values) - - def test_create_vip_with_session_persistence_params(self): - """lb-vip-create with mandatory and session-persistence params.""" - resource = 'vip' - cmd = vip.CreateVip(test_cli20.MyApp(sys.stdout), None) - pool_id = 'my-pool-id' - name = 'my-name' - subnet_id = 'subnet-id' - protocol_port = '1000' - protocol = 'tcp' - tenant_id = 'my-tenant' - my_id = 'my-id' - args = ['--name', name, - '--protocol-port', protocol_port, - '--protocol', protocol, - '--subnet-id', subnet_id, - '--tenant-id', tenant_id, - pool_id, - '--session-persistence', 'type=dict', - 'type=cookie,cookie_name=pie', - '--optional-param', 'any'] - position_names = ['pool_id', 'name', 'protocol_port', 'protocol', - 'subnet_id', 'tenant_id', 'optional_param'] - position_values = [pool_id, name, protocol_port, protocol, - subnet_id, tenant_id, 'any'] - extra_body = { - 'session_persistence': { - 'type': 'cookie', - 'cookie_name': 'pie', - }, - } - self._test_create_resource(resource, cmd, name, my_id, args, - position_names, position_values, - admin_state_up=True, extra_body=extra_body) - - def test_list_vips(self): - """lb-vip-list.""" - resources = "vips" - cmd = vip.ListVip(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_vips_pagination(self): - """lb-vip-list.""" - resources = "vips" - cmd = vip.ListVip(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_vips_sort(self): - """lb-vip-list --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "vips" - cmd = vip.ListVip(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_vips_limit(self): - """lb-vip-list -P.""" - resources = "vips" - cmd = vip.ListVip(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_show_vip_id(self): - """lb-vip-show test_id.""" - resource = 'vip' - cmd = vip.ShowVip(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args, ['id']) - - def test_show_vip_id_name(self): - """lb-vip-show.""" - resource = 'vip' - cmd = vip.ShowVip(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_update_vip(self): - """lb-vip-update myid --name myname --tags a b.""" - resource = 'vip' - cmd = vip.UpdateVip(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--tags', 'a', 'b'], - {'name': 'myname', 'tags': ['a', 'b'], }) - - def test_update_vip_with_session_persistence(self): - resource = 'vip' - cmd = vip.UpdateVip(test_cli20.MyApp(sys.stdout), None) - body = { - 'session_persistence': { - 'type': 'source', - }, - } - args = ['myid', '--session-persistence', 'type=dict', - 'type=source'] - self._test_update_resource(resource, cmd, 'myid', args, body) - - def test_update_vip_with_session_persistence_and_name(self): - resource = 'vip' - cmd = vip.UpdateVip(test_cli20.MyApp(sys.stdout), None) - body = { - 'name': 'newname', - 'session_persistence': { - 'type': 'cookie', - 'cookie_name': 'pie', - }, - } - args = ['myid', '--name', 'newname', - '--session-persistence', 'type=dict', - 'type=cookie,cookie_name=pie'] - self._test_update_resource(resource, cmd, 'myid', args, body) - - def test_delete_vip(self): - """lb-vip-delete my-id.""" - resource = 'vip' - cmd = vip.DeleteVip(test_cli20.MyApp(sys.stdout), None) - my_id = 'my-id' - args = [my_id] - self._test_delete_resource(resource, cmd, my_id, args) - - -class CLITestV20LbVipXML(CLITestV20LbVipJSON): - format = 'xml' diff --git a/tests/unit/test_auth.py b/tests/unit/test_auth.py deleted file mode 100644 index 06cc2de..0000000 --- a/tests/unit/test_auth.py +++ /dev/null @@ -1,320 +0,0 @@ -# Copyright 2012 NEC Corporation -# 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 copy -import httplib2 -import json -import uuid - -import mox -import testtools - -from quantumclient import client -from quantumclient.common import exceptions - - -USERNAME = 'testuser' -TENANT_NAME = 'testtenant' -PASSWORD = 'password' -AUTH_URL = 'authurl' -ENDPOINT_URL = 'localurl' -TOKEN = 'tokentoken' -REGION = 'RegionTest' - -KS_TOKEN_RESULT = { - 'access': { - 'token': {'id': TOKEN, - 'expires': '2012-08-11T07:49:01Z', - 'tenant': {'id': str(uuid.uuid1())}}, - 'user': {'id': str(uuid.uuid1())}, - 'serviceCatalog': [ - {'endpoints_links': [], - 'endpoints': [{'adminURL': ENDPOINT_URL, - 'internalURL': ENDPOINT_URL, - 'publicURL': ENDPOINT_URL, - 'region': REGION}], - 'type': 'network', - 'name': 'Quantum Service'} - ] - } -} - -ENDPOINTS_RESULT = { - 'endpoints': [{ - 'type': 'network', - 'name': 'Quantum Service', - 'region': REGION, - 'adminURL': ENDPOINT_URL, - 'internalURL': ENDPOINT_URL, - 'publicURL': ENDPOINT_URL - }] -} - - -class CLITestAuthKeystone(testtools.TestCase): - - def setUp(self): - """Prepare the test environment.""" - super(CLITestAuthKeystone, self).setUp() - self.mox = mox.Mox() - self.client = client.HTTPClient(username=USERNAME, - tenant_name=TENANT_NAME, - password=PASSWORD, - auth_url=AUTH_URL, - region_name=REGION) - self.addCleanup(self.mox.VerifyAll) - self.addCleanup(self.mox.UnsetStubs) - - def test_get_token(self): - self.mox.StubOutWithMock(self.client, "request") - - res200 = self.mox.CreateMock(httplib2.Response) - res200.status = 200 - - self.client.request( - AUTH_URL + '/tokens', 'POST', - body=mox.IsA(str), headers=mox.IsA(dict) - ).AndReturn((res200, json.dumps(KS_TOKEN_RESULT))) - self.client.request( - mox.StrContains(ENDPOINT_URL + '/resource'), 'GET', - headers=mox.ContainsKeyValue('X-Auth-Token', TOKEN) - ).AndReturn((res200, '')) - self.mox.ReplayAll() - - self.client.do_request('/resource', 'GET') - self.assertEqual(self.client.endpoint_url, ENDPOINT_URL) - self.assertEqual(self.client.auth_token, TOKEN) - - def test_refresh_token(self): - self.mox.StubOutWithMock(self.client, "request") - - self.client.auth_token = TOKEN - self.client.endpoint_url = ENDPOINT_URL - - res200 = self.mox.CreateMock(httplib2.Response) - res200.status = 200 - res401 = self.mox.CreateMock(httplib2.Response) - res401.status = 401 - - # If a token is expired, quantum server retruns 401 - self.client.request( - mox.StrContains(ENDPOINT_URL + '/resource'), 'GET', - headers=mox.ContainsKeyValue('X-Auth-Token', TOKEN) - ).AndReturn((res401, '')) - self.client.request( - AUTH_URL + '/tokens', 'POST', - body=mox.IsA(str), headers=mox.IsA(dict) - ).AndReturn((res200, json.dumps(KS_TOKEN_RESULT))) - self.client.request( - mox.StrContains(ENDPOINT_URL + '/resource'), 'GET', - headers=mox.ContainsKeyValue('X-Auth-Token', TOKEN) - ).AndReturn((res200, '')) - self.mox.ReplayAll() - self.client.do_request('/resource', 'GET') - - def test_get_endpoint_url(self): - self.mox.StubOutWithMock(self.client, "request") - - self.client.auth_token = TOKEN - - res200 = self.mox.CreateMock(httplib2.Response) - res200.status = 200 - - self.client.request( - mox.StrContains(AUTH_URL + '/tokens/%s/endpoints' % TOKEN), 'GET', - headers=mox.IsA(dict) - ).AndReturn((res200, json.dumps(ENDPOINTS_RESULT))) - self.client.request( - mox.StrContains(ENDPOINT_URL + '/resource'), 'GET', - headers=mox.ContainsKeyValue('X-Auth-Token', TOKEN) - ).AndReturn((res200, '')) - self.mox.ReplayAll() - self.client.do_request('/resource', 'GET') - - def test_get_endpoint_url_other(self): - self.client = client.HTTPClient( - username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, - auth_url=AUTH_URL, region_name=REGION, endpoint_type='otherURL') - self.mox.StubOutWithMock(self.client, "request") - - self.client.auth_token = TOKEN - - res200 = self.mox.CreateMock(httplib2.Response) - res200.status = 200 - - self.client.request( - mox.StrContains(AUTH_URL + '/tokens/%s/endpoints' % TOKEN), 'GET', - headers=mox.IsA(dict) - ).AndReturn((res200, json.dumps(ENDPOINTS_RESULT))) - self.mox.ReplayAll() - self.assertRaises(exceptions.EndpointTypeNotFound, - self.client.do_request, - '/resource', - 'GET') - - def test_get_endpoint_url_failed(self): - self.mox.StubOutWithMock(self.client, "request") - - self.client.auth_token = TOKEN - - res200 = self.mox.CreateMock(httplib2.Response) - res200.status = 200 - res401 = self.mox.CreateMock(httplib2.Response) - res401.status = 401 - - self.client.request( - mox.StrContains(AUTH_URL + '/tokens/%s/endpoints' % TOKEN), 'GET', - headers=mox.IsA(dict) - ).AndReturn((res401, '')) - self.client.request( - AUTH_URL + '/tokens', 'POST', - body=mox.IsA(str), headers=mox.IsA(dict) - ).AndReturn((res200, json.dumps(KS_TOKEN_RESULT))) - self.client.request( - mox.StrContains(ENDPOINT_URL + '/resource'), 'GET', - headers=mox.ContainsKeyValue('X-Auth-Token', TOKEN) - ).AndReturn((res200, '')) - self.mox.ReplayAll() - self.client.do_request('/resource', 'GET') - - def test_url_for(self): - resources = copy.deepcopy(KS_TOKEN_RESULT) - - endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0] - endpoints['publicURL'] = 'public' - endpoints['internalURL'] = 'internal' - endpoints['adminURL'] = 'admin' - catalog = client.ServiceCatalog(resources) - - # endpoint_type not specified - url = catalog.url_for(attr='region', - filter_value=REGION) - self.assertEqual('public', url) - - # endpoint type specified (3 cases) - url = catalog.url_for(attr='region', - filter_value=REGION, - endpoint_type='adminURL') - self.assertEqual('admin', url) - - url = catalog.url_for(attr='region', - filter_value=REGION, - endpoint_type='publicURL') - self.assertEqual('public', url) - - url = catalog.url_for(attr='region', - filter_value=REGION, - endpoint_type='internalURL') - self.assertEqual('internal', url) - - # endpoint_type requested does not exist. - self.assertRaises(exceptions.EndpointTypeNotFound, - catalog.url_for, - attr='region', - filter_value=REGION, - endpoint_type='privateURL') - - # Test scenario with url_for when the service catalog only has publicURL. - def test_url_for_only_public_url(self): - resources = copy.deepcopy(KS_TOKEN_RESULT) - catalog = client.ServiceCatalog(resources) - - # Remove endpoints from the catalog. - endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0] - del endpoints['internalURL'] - del endpoints['adminURL'] - endpoints['publicURL'] = 'public' - - # Use publicURL when specified explicitly. - url = catalog.url_for(attr='region', - filter_value=REGION, - endpoint_type='publicURL') - self.assertEqual('public', url) - - # Use publicURL when specified explicitly. - url = catalog.url_for(attr='region', - filter_value=REGION) - self.assertEqual('public', url) - - # Test scenario with url_for when the service catalog only has adminURL. - def test_url_for_only_admin_url(self): - resources = copy.deepcopy(KS_TOKEN_RESULT) - catalog = client.ServiceCatalog(resources) - endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0] - del endpoints['internalURL'] - del endpoints['publicURL'] - endpoints['adminURL'] = 'admin' - - # Use publicURL when specified explicitly. - url = catalog.url_for(attr='region', - filter_value=REGION, - endpoint_type='adminURL') - self.assertEqual('admin', url) - - # But not when nothing is specified. - self.assertRaises(exceptions.EndpointTypeNotFound, - catalog.url_for, - attr='region', - filter_value=REGION) - - def test_endpoint_type(self): - resources = copy.deepcopy(KS_TOKEN_RESULT) - endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0] - endpoints['internalURL'] = 'internal' - endpoints['adminURL'] = 'admin' - endpoints['publicURL'] = 'public' - - # Test default behavior is to choose public. - self.client = client.HTTPClient( - username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, - auth_url=AUTH_URL, region_name=REGION) - - self.client._extract_service_catalog(resources) - self.assertEqual(self.client.endpoint_url, 'public') - - # Test admin url - self.client = client.HTTPClient( - username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, - auth_url=AUTH_URL, region_name=REGION, endpoint_type='adminURL') - - self.client._extract_service_catalog(resources) - self.assertEqual(self.client.endpoint_url, 'admin') - - # Test public url - self.client = client.HTTPClient( - username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, - auth_url=AUTH_URL, region_name=REGION, endpoint_type='publicURL') - - self.client._extract_service_catalog(resources) - self.assertEqual(self.client.endpoint_url, 'public') - - # Test internal url - self.client = client.HTTPClient( - username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, - auth_url=AUTH_URL, region_name=REGION, endpoint_type='internalURL') - - self.client._extract_service_catalog(resources) - self.assertEqual(self.client.endpoint_url, 'internal') - - # Test url that isn't found in the service catalog - self.client = client.HTTPClient( - username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, - auth_url=AUTH_URL, region_name=REGION, endpoint_type='privateURL') - - self.assertRaises(exceptions.EndpointTypeNotFound, - self.client._extract_service_catalog, - resources) diff --git a/tests/unit/test_casual_args.py b/tests/unit/test_casual_args.py deleted file mode 100644 index fcfff93..0000000 --- a/tests/unit/test_casual_args.py +++ /dev/null @@ -1,99 +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 testtools - -from quantumclient.common import exceptions -from quantumclient.quantum import v2_0 as quantumV20 - - -class CLITestArgs(testtools.TestCase): - - def test_empty(self): - _mydict = quantumV20.parse_args_to_dict([]) - self.assertEqual({}, _mydict) - - def test_default_bool(self): - _specs = ['--my_bool', '--arg1', 'value1'] - _mydict = quantumV20.parse_args_to_dict(_specs) - self.assertTrue(_mydict['my_bool']) - - def test_bool_true(self): - _specs = ['--my-bool', 'type=bool', 'true', '--arg1', 'value1'] - _mydict = quantumV20.parse_args_to_dict(_specs) - self.assertTrue(_mydict['my_bool']) - - def test_bool_false(self): - _specs = ['--my_bool', 'type=bool', 'false', '--arg1', 'value1'] - _mydict = quantumV20.parse_args_to_dict(_specs) - self.assertFalse(_mydict['my_bool']) - - def test_nargs(self): - _specs = ['--tag', 'x', 'y', '--arg1', 'value1'] - _mydict = quantumV20.parse_args_to_dict(_specs) - self.assertTrue('x' in _mydict['tag']) - self.assertTrue('y' in _mydict['tag']) - - def test_badarg(self): - _specs = ['--tag=t', 'x', 'y', '--arg1', 'value1'] - self.assertRaises(exceptions.CommandError, - quantumV20.parse_args_to_dict, _specs) - - def test_badarg_with_minus(self): - _specs = ['--arg1', 'value1', '-D'] - self.assertRaises(exceptions.CommandError, - quantumV20.parse_args_to_dict, _specs) - - def test_goodarg_with_minus_number(self): - _specs = ['--arg1', 'value1', '-1', '-1.0'] - _mydict = quantumV20.parse_args_to_dict(_specs) - self.assertEqual(['value1', '-1', '-1.0'], - _mydict['arg1']) - - def test_badarg_duplicate(self): - _specs = ['--tag=t', '--arg1', 'value1', '--arg1', 'value1'] - self.assertRaises(exceptions.CommandError, - quantumV20.parse_args_to_dict, _specs) - - def test_badarg_early_type_specification(self): - _specs = ['type=dict', 'key=value'] - self.assertRaises(exceptions.CommandError, - quantumV20.parse_args_to_dict, _specs) - - def test_arg(self): - _specs = ['--tag=t', '--arg1', 'value1'] - self.assertEqual('value1', - quantumV20.parse_args_to_dict(_specs)['arg1']) - - def test_dict_arg(self): - _specs = ['--tag=t', '--arg1', 'type=dict', 'key1=value1,key2=value2'] - arg1 = quantumV20.parse_args_to_dict(_specs)['arg1'] - self.assertEqual('value1', arg1['key1']) - self.assertEqual('value2', arg1['key2']) - - def test_dict_arg_with_attribute_named_type(self): - _specs = ['--tag=t', '--arg1', 'type=dict', 'type=value1,key2=value2'] - arg1 = quantumV20.parse_args_to_dict(_specs)['arg1'] - self.assertEqual('value1', arg1['type']) - self.assertEqual('value2', arg1['key2']) - - def test_list_of_dict_arg(self): - _specs = ['--tag=t', '--arg1', 'type=dict', - 'list=true', 'key1=value1,key2=value2'] - arg1 = quantumV20.parse_args_to_dict(_specs)['arg1'] - self.assertEqual('value1', arg1[0]['key1']) - self.assertEqual('value2', arg1[0]['key2']) diff --git a/tests/unit/test_cli20.py b/tests/unit/test_cli20.py deleted file mode 100644 index c89cdfa..0000000 --- a/tests/unit/test_cli20.py +++ /dev/null @@ -1,504 +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 urllib - -import fixtures -import mox -import testtools - -from quantumclient.common import constants -from quantumclient import shell -from quantumclient.v2_0 import client - - -API_VERSION = "2.0" -FORMAT = 'json' -TOKEN = 'testtoken' -ENDURL = 'localurl' - - -class FakeStdout: - - def __init__(self): - self.content = [] - - def write(self, text): - self.content.append(text) - - def make_string(self): - result = '' - for line in self.content: - result = result + line - return result - - -class MyResp(object): - def __init__(self, status): - self.status = status - - -class MyApp(object): - def __init__(self, _stdout): - self.stdout = _stdout - - -def end_url(path, query=None, format=FORMAT): - _url_str = ENDURL + "/v" + API_VERSION + path + "." + format - return query and _url_str + "?" + query or _url_str - - -class MyUrlComparator(mox.Comparator): - def __init__(self, lhs, client): - self.lhs = lhs - self.client = client - - def equals(self, rhs): - return str(self) == rhs - - def __str__(self): - if self.client and self.client.format != FORMAT: - lhs_parts = self.lhs.split("?", 1) - if len(lhs_parts) == 2: - lhs = ("%s.%s?%s" % (lhs_parts[0][:-4], - self.client.format, - lhs_parts[1])) - else: - lhs = ("%s.%s" % (lhs_parts[0][:-4], - self.client.format)) - return lhs - return self.lhs - - def __repr__(self): - return str(self) - - -class MyComparator(mox.Comparator): - def __init__(self, lhs, client): - self.lhs = lhs - self.client = client - - def _com_dict(self, lhs, rhs): - if len(lhs) != len(rhs): - return False - for key, value in lhs.iteritems(): - if key not in rhs: - return False - rhs_value = rhs[key] - if not self._com(value, rhs_value): - return False - return True - - def _com_list(self, lhs, rhs): - if len(lhs) != len(rhs): - return False - for lhs_value in lhs: - if lhs_value not in rhs: - return False - return True - - def _com(self, lhs, rhs): - if lhs is None: - return rhs is None - if isinstance(lhs, dict): - if not isinstance(rhs, dict): - return False - return self._com_dict(lhs, rhs) - if isinstance(lhs, list): - if not isinstance(rhs, list): - return False - return self._com_list(lhs, rhs) - if isinstance(lhs, tuple): - if not isinstance(rhs, tuple): - return False - return self._com_list(lhs, rhs) - return lhs == rhs - - def equals(self, rhs): - if self.client: - rhs = self.client.deserialize(rhs, 200) - return self._com(self.lhs, rhs) - - def __repr__(self): - if self.client: - return self.client.serialize(self.lhs) - return str(self.lhs) - - -class CLITestV20Base(testtools.TestCase): - - format = 'json' - test_id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' - id_field = 'id' - - def _find_resourceid(self, client, resource, name_or_id): - return name_or_id - - def _get_attr_metadata(self): - return self.metadata - client.Client.EXTED_PLURALS.update(constants.PLURALS) - client.Client.EXTED_PLURALS.update({'tags': 'tag'}) - return {'plurals': client.Client.EXTED_PLURALS, - 'xmlns': constants.XML_NS_V20, - constants.EXT_NS: {'prefix': 'http://xxxx.yy.com'}} - - def setUp(self, plurals={}): - """Prepare the test environment.""" - super(CLITestV20Base, self).setUp() - client.Client.EXTED_PLURALS.update(constants.PLURALS) - client.Client.EXTED_PLURALS.update(plurals) - self.metadata = {'plurals': client.Client.EXTED_PLURALS, - 'xmlns': constants.XML_NS_V20, - constants.EXT_NS: {'prefix': - 'http://xxxx.yy.com'}} - self.mox = mox.Mox() - self.endurl = ENDURL - self.fake_stdout = FakeStdout() - self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.fake_stdout)) - self.useFixture(fixtures.MonkeyPatch( - 'quantumclient.quantum.v2_0.find_resourceid_by_name_or_id', - self._find_resourceid)) - self.useFixture(fixtures.MonkeyPatch( - 'quantumclient.v2_0.client.Client.get_attr_metadata', - self._get_attr_metadata)) - self.client = client.Client(token=TOKEN, endpoint_url=self.endurl) - - def _test_create_resource(self, resource, cmd, - name, myid, args, - position_names, position_values, tenant_id=None, - tags=None, admin_state_up=True, shared=False, - extra_body=None, **kwargs): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - non_admin_status_resources = ['subnet', 'floatingip', 'security_group', - 'security_group_rule', 'qos_queue', - 'network_gateway'] - if (resource in non_admin_status_resources): - body = {resource: {}, } - else: - body = {resource: {'admin_state_up': admin_state_up, }, } - if tenant_id: - body[resource].update({'tenant_id': tenant_id}) - if tags: - body[resource].update({'tags': tags}) - if shared: - body[resource].update({'shared': shared}) - if extra_body: - body[resource].update(extra_body) - body[resource].update(kwargs) - - for i in xrange(len(position_names)): - body[resource].update({position_names[i]: position_values[i]}) - ress = {resource: - {self.id_field: myid}, } - if name: - ress[resource].update({'name': name}) - self.client.format = self.format - resstr = self.client.serialize(ress) - # url method body - path = getattr(self.client, resource + "s_path") - self.client.httpclient.request( - end_url(path, format=self.format), 'POST', - body=MyComparator(body, self.client), - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr)) - args.extend(['--request-format', self.format]) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser('create_' + resource) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertTrue(myid in _str) - if name: - self.assertTrue(name in _str) - - def _test_list_columns(self, cmd, resources_collection, - resources_out, args=['-f', 'json']): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - self.client.format = self.format - resstr = self.client.serialize(resources_out) - - path = getattr(self.client, resources_collection + "_path") - self.client.httpclient.request( - end_url(path, format=self.format), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr)) - args.extend(['--request-format', self.format]) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources_collection) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def _test_list_resources(self, resources, cmd, detail=False, tags=[], - fields_1=[], fields_2=[], page_size=None, - sort_key=[], sort_dir=[], response_contents=None): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - if response_contents is None: - contents = [{self.id_field: 'myid1', }, - {self.id_field: 'myid2', }, ] - else: - contents = response_contents - reses = {resources: contents} - self.client.format = self.format - resstr = self.client.serialize(reses) - # url method body - query = "" - args = detail and ['-D', ] or [] - args.extend(['--request-format', self.format]) - if fields_1: - for field in fields_1: - args.append('--fields') - args.append(field) - - if tags: - args.append('--') - args.append("--tag") - for tag in tags: - args.append(tag) - if isinstance(tag, unicode): - tag = urllib.quote(tag.encode('utf-8')) - if query: - query += "&tag=" + tag - else: - query = "tag=" + tag - if (not tags) and fields_2: - args.append('--') - if fields_2: - args.append("--fields") - for field in fields_2: - args.append(field) - if detail: - query = query and query + '&verbose=True' or 'verbose=True' - fields_1.extend(fields_2) - for field in fields_1: - if query: - query += "&fields=" + field - else: - query = "fields=" + field - if page_size: - args.append("--page-size") - args.append(str(page_size)) - if query: - query += "&limit=%s" % page_size - else: - query = "limit=%s" % page_size - if sort_key: - for key in sort_key: - args.append('--sort-key') - args.append(key) - if query: - query += '&' - query += 'sort_key=%s' % key - if sort_dir: - len_diff = len(sort_key) - len(sort_dir) - if len_diff > 0: - sort_dir += ['asc'] * len_diff - elif len_diff < 0: - sort_dir = sort_dir[:len(sort_key)] - for dir in sort_dir: - args.append('--sort-dir') - args.append(dir) - if query: - query += '&' - query += 'sort_dir=%s' % dir - path = getattr(self.client, resources + "_path") - self.client.httpclient.request( - MyUrlComparator(end_url(path, query, format=self.format), - self.client), - 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr)) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - if response_contents is None: - self.assertTrue('myid1' in _str) - return _str - - def _test_list_resources_with_pagination(self, resources, cmd): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - path = getattr(self.client, resources + "_path") - fake_query = "marker=myid2&limit=2" - reses1 = {resources: [{'id': 'myid1', }, - {'id': 'myid2', }], - '%s_links' % resources: [{'href': end_url(path, fake_query), - 'rel': 'next'}]} - reses2 = {resources: [{'id': 'myid3', }, - {'id': 'myid4', }]} - self.client.format = self.format - resstr1 = self.client.serialize(reses1) - resstr2 = self.client.serialize(reses2) - self.client.httpclient.request( - end_url(path, "", format=self.format), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr1)) - self.client.httpclient.request( - end_url(path, fake_query, format=self.format), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr2)) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources) - args = ['--request-format', self.format] - shell.run_command(cmd, cmd_parser, args) - #parsed_args = cmd_parser.parse_args("") - #cmd.run(parsed_args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def _test_update_resource(self, resource, cmd, myid, args, extrafields): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - body = {resource: extrafields} - path = getattr(self.client, resource + "_path") - self.client.httpclient.request( - MyUrlComparator(end_url(path % myid, format=self.format), - self.client), - 'PUT', - body=MyComparator(body, self.client), - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(204), None)) - args.extend(['--request-format', self.format]) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("update_" + resource) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertTrue(myid in _str) - - def _test_show_resource(self, resource, cmd, myid, args, fields=[]): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - query = "&".join(["fields=%s" % field for field in fields]) - expected_res = {resource: - {self.id_field: myid, - 'name': 'myname', }, } - self.client.format = self.format - resstr = self.client.serialize(expected_res) - path = getattr(self.client, resource + "_path") - self.client.httpclient.request( - end_url(path % myid, query, format=self.format), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr)) - args.extend(['--request-format', self.format]) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("show_" + resource) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertTrue(myid in _str) - self.assertTrue('myname' in _str) - - def _test_delete_resource(self, resource, cmd, myid, args): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - path = getattr(self.client, resource + "_path") - self.client.httpclient.request( - end_url(path % myid, format=self.format), 'DELETE', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(204), None)) - args.extend(['--request-format', self.format]) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("delete_" + resource) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertTrue(myid in _str) - - def _test_update_resource_action(self, resource, cmd, myid, action, args, - body, retval=None): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - path = getattr(self.client, resource + "_path") - path_action = '%s/%s' % (myid, action) - self.client.httpclient.request( - end_url(path % path_action, format=self.format), 'PUT', - body=MyComparator(body, self.client), - headers=mox.ContainsKeyValue( - 'X-Auth-Token', TOKEN)).AndReturn((MyResp(204), retval)) - args.extend(['--request-format', self.format]) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("delete_" + resource) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertTrue(myid in _str) - - -class ClientV2UnicodeTestJson(CLITestV20Base): - def test_do_request(self): - self.client.format = self.format - self.mox.StubOutWithMock(self.client.httpclient, "request") - unicode_text = u'\u7f51\u7edc' - # url with unicode - action = u'/test' - expected_action = action.encode('utf-8') - # query string with unicode - params = {'test': unicode_text} - expect_query = urllib.urlencode({'test': - unicode_text.encode('utf-8')}) - # request body with unicode - body = params - expect_body = self.client.serialize(body) - # headers with unicode - self.client.httpclient.auth_token = unicode_text - expected_auth_token = unicode_text.encode('utf-8') - - self.client.httpclient.request( - end_url(expected_action, query=expect_query, format=self.format), - 'PUT', body=expect_body, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', - expected_auth_token)).AndReturn((MyResp(200), expect_body)) - - self.mox.ReplayAll() - res_body = self.client.do_request('PUT', action, body=body, - params=params) - self.mox.VerifyAll() - self.mox.UnsetStubs() - - # test response with unicode - self.assertEqual(res_body, body) - - -class ClientV2UnicodeTestXML(ClientV2UnicodeTestJson): - format = 'xml' diff --git a/tests/unit/test_cli20_extensions.py b/tests/unit/test_cli20_extensions.py deleted file mode 100644 index 874de77..0000000 --- a/tests/unit/test_cli20_extensions.py +++ /dev/null @@ -1,49 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 NEC Corporation -# 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 sys - -from quantumclient.quantum.v2_0.extension import ListExt -from quantumclient.quantum.v2_0.extension import ShowExt -from tests.unit.test_cli20 import CLITestV20Base -from tests.unit.test_cli20 import MyApp - - -class CLITestV20Extension(CLITestV20Base): - id_field = 'alias' - - def test_list_extensions(self): - resources = 'extensions' - cmd = ListExt(MyApp(sys.stdout), None) - contents = [{'alias': 'ext1', 'name': 'name1', 'other': 'other1'}, - {'alias': 'ext2', 'name': 'name2', 'other': 'other2'}] - ret = self._test_list_resources(resources, cmd, - response_contents=contents) - ret_words = set(ret.split()) - # Check only the default columns are shown. - self.assertTrue('name' in ret_words) - self.assertTrue('alias' in ret_words) - self.assertFalse('other' in ret_words) - - def test_show_extension(self): - # -F option does not work for ext-show at the moment, so -F option - # is not passed in the commandline args as other tests do. - resource = 'extension' - cmd = ShowExt(MyApp(sys.stdout), None) - args = [self.test_id] - ext_alias = self.test_id - self._test_show_resource(resource, cmd, ext_alias, args, fields=[]) diff --git a/tests/unit/test_cli20_floatingips.py b/tests/unit/test_cli20_floatingips.py deleted file mode 100644 index b640112..0000000 --- a/tests/unit/test_cli20_floatingips.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Red Hat -# 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 sys - -from quantumclient.quantum.v2_0 import floatingip as fip -from tests.unit import test_cli20 - - -class CLITestV20FloatingIpsJSON(test_cli20.CLITestV20Base): - def test_create_floatingip(self): - """Create floatingip: fip1.""" - resource = 'floatingip' - cmd = fip.CreateFloatingIP(test_cli20.MyApp(sys.stdout), None) - name = 'fip1' - myid = 'myid' - args = [name] - position_names = ['floating_network_id'] - position_values = [name] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_floatingip_and_port(self): - """Create floatingip: fip1.""" - resource = 'floatingip' - cmd = fip.CreateFloatingIP(test_cli20.MyApp(sys.stdout), None) - name = 'fip1' - myid = 'myid' - pid = 'mypid' - args = [name, '--port_id', pid] - position_names = ['floating_network_id', 'port_id'] - position_values = [name, pid] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - # Test dashed options - args = [name, '--port-id', pid] - position_names = ['floating_network_id', 'port_id'] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_floatingip_and_port_and_address(self): - """Create floatingip: fip1 with a given port and address.""" - resource = 'floatingip' - cmd = fip.CreateFloatingIP(test_cli20.MyApp(sys.stdout), None) - name = 'fip1' - myid = 'myid' - pid = 'mypid' - addr = '10.0.0.99' - args = [name, '--port_id', pid, '--fixed_ip_address', addr] - position_names = ['floating_network_id', 'port_id', 'fixed_ip_address'] - position_values = [name, pid, addr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - # Test dashed options - args = [name, '--port-id', pid, '--fixed-ip-address', addr] - position_names = ['floating_network_id', 'port_id', 'fixed_ip_address'] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_list_floatingips(self): - """list floatingips: -D.""" - resources = 'floatingips' - cmd = fip.ListFloatingIP(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_floatingips_pagination(self): - resources = 'floatingips' - cmd = fip.ListFloatingIP(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_floatingips_sort(self): - """list floatingips: --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = 'floatingips' - cmd = fip.ListFloatingIP(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_floatingips_limit(self): - """list floatingips: -P.""" - resources = 'floatingips' - cmd = fip.ListFloatingIP(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_delete_floatingip(self): - """Delete floatingip: fip1.""" - resource = 'floatingip' - cmd = fip.DeleteFloatingIP(test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - def test_show_floatingip(self): - """Show floatingip: --fields id.""" - resource = 'floatingip' - cmd = fip.ShowFloatingIP(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id']) - - def test_disassociate_ip(self): - """Disassociate floating IP: myid.""" - resource = 'floatingip' - cmd = fip.DisassociateFloatingIP(test_cli20.MyApp(sys.stdout), None) - args = ['myid'] - self._test_update_resource(resource, cmd, 'myid', - args, {"port_id": None} - ) - - def test_associate_ip(self): - """Associate floating IP: myid portid.""" - resource = 'floatingip' - cmd = fip.AssociateFloatingIP(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'portid'] - self._test_update_resource(resource, cmd, 'myid', - args, {"port_id": "portid"} - ) - - -class CLITestV20FloatingIpsXML(CLITestV20FloatingIpsJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_network.py b/tests/unit/test_cli20_network.py deleted file mode 100644 index 7df54ff..0000000 --- a/tests/unit/test_cli20_network.py +++ /dev/null @@ -1,533 +0,0 @@ -# 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 sys - -import mox - -from quantumclient.common import exceptions -from quantumclient.common import utils -from quantumclient.quantum.v2_0 import network -from quantumclient import shell -from tests.unit import test_cli20 - - -class CLITestV20NetworkJSON(test_cli20.CLITestV20Base): - def setUp(self): - super(CLITestV20NetworkJSON, self).setUp(plurals={'tags': 'tag'}) - - def test_create_network(self): - """Create net: myname.""" - resource = 'network' - cmd = network.CreateNetwork(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - args = [name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_network_with_unicode(self): - """Create net: u'\u7f51\u7edc'.""" - resource = 'network' - cmd = network.CreateNetwork(test_cli20.MyApp(sys.stdout), None) - name = u'\u7f51\u7edc' - myid = 'myid' - args = [name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_network_tenant(self): - """Create net: --tenant_id tenantid myname.""" - resource = 'network' - cmd = network.CreateNetwork(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - args = ['--tenant_id', 'tenantid', name] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - # Test dashed options - args = ['--tenant-id', 'tenantid', name] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_network_tags(self): - """Create net: myname --tags a b.""" - resource = 'network' - cmd = network.CreateNetwork(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - args = [name, '--tags', 'a', 'b'] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tags=['a', 'b']) - - def test_create_network_state(self): - """Create net: --admin_state_down myname.""" - resource = 'network' - cmd = network.CreateNetwork(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - args = ['--admin_state_down', name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - admin_state_up=False) - - # Test dashed options - args = ['--admin-state-down', name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - admin_state_up=False) - - def test_list_nets_empty_with_column(self): - resources = "networks" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - self.mox.StubOutWithMock(network.ListNetwork, "extend_list") - network.ListNetwork.extend_list(mox.IsA(list), mox.IgnoreArg()) - cmd.get_client().MultipleTimes().AndReturn(self.client) - reses = {resources: []} - resstr = self.client.serialize(reses) - # url method body - query = "id=myfakeid" - args = ['-c', 'id', '--', '--id', 'myfakeid'] - path = getattr(self.client, resources + "_path") - self.client.httpclient.request( - test_cli20.end_url(path, query), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', - test_cli20.TOKEN)).AndReturn( - (test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertEquals('\n', _str) - - def _test_list_networks(self, cmd, detail=False, tags=[], - fields_1=[], fields_2=[], page_size=None, - sort_key=[], sort_dir=[]): - resources = "networks" - self.mox.StubOutWithMock(network.ListNetwork, "extend_list") - network.ListNetwork.extend_list(mox.IsA(list), mox.IgnoreArg()) - self._test_list_resources(resources, cmd, detail, tags, - fields_1, fields_2, page_size=page_size, - sort_key=sort_key, sort_dir=sort_dir) - - def test_list_nets_pagination(self): - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(network.ListNetwork, "extend_list") - network.ListNetwork.extend_list(mox.IsA(list), mox.IgnoreArg()) - self._test_list_resources_with_pagination("networks", cmd) - - def test_list_nets_sort(self): - """list nets: --sort-key name --sort-key id --sort-dir asc - --sort-dir desc - """ - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, sort_key=['name', 'id'], - sort_dir=['asc', 'desc']) - - def test_list_nets_sort_with_keys_more_than_dirs(self): - """list nets: --sort-key name --sort-key id --sort-dir desc - """ - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, sort_key=['name', 'id'], - sort_dir=['desc']) - - def test_list_nets_sort_with_dirs_more_than_keys(self): - """list nets: --sort-key name --sort-dir desc --sort-dir asc - """ - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, sort_key=['name'], - sort_dir=['desc', 'asc']) - - def test_list_nets_limit(self): - """list nets: -P.""" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, page_size=1000) - - def test_list_nets_detail(self): - """list nets: -D.""" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, True) - - def test_list_nets_tags(self): - """List nets: -- --tags a b.""" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, tags=['a', 'b']) - - def test_list_nets_tags_with_unicode(self): - """List nets: -- --tags u'\u7f51\u7edc'.""" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, tags=[u'\u7f51\u7edc']) - - def test_list_nets_detail_tags(self): - """List nets: -D -- --tags a b.""" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, detail=True, tags=['a', 'b']) - - def _test_list_nets_extend_subnets(self, data, expected): - def setup_list_stub(resources, data, query): - reses = {resources: data} - resstr = self.client.serialize(reses) - resp = (test_cli20.MyResp(200), resstr) - path = getattr(self.client, resources + '_path') - self.client.httpclient.request( - test_cli20.end_url(path, query), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(resp) - - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(cmd, 'get_client') - self.mox.StubOutWithMock(self.client.httpclient, 'request') - cmd.get_client().AndReturn(self.client) - setup_list_stub('networks', data, '') - cmd.get_client().AndReturn(self.client) - filters = '' - for n in data: - for s in n['subnets']: - filters = filters + "&id=%s" % s - setup_list_stub('subnets', - [{'id': 'mysubid1', 'cidr': '192.168.1.0/24'}, - {'id': 'mysubid2', 'cidr': '172.16.0.0/24'}, - {'id': 'mysubid3', 'cidr': '10.1.1.0/24'}], - query='fields=id&fields=cidr' + filters) - self.mox.ReplayAll() - - args = [] - cmd_parser = cmd.get_parser('list_networks') - parsed_args = cmd_parser.parse_args(args) - result = cmd.get_data(parsed_args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _result = [x for x in result[1]] - self.assertEqual(len(_result), len(expected)) - for res, exp in zip(_result, expected): - self.assertEqual(len(res), len(exp)) - for a, b in zip(res, exp): - self.assertEqual(a, b) - - def test_list_nets_extend_subnets(self): - data = [{'id': 'netid1', 'name': 'net1', 'subnets': ['mysubid1']}, - {'id': 'netid2', 'name': 'net2', 'subnets': ['mysubid2', - 'mysubid3']}] - # id, name, subnets - expected = [('netid1', 'net1', 'mysubid1 192.168.1.0/24'), - ('netid2', 'net2', - 'mysubid2 172.16.0.0/24\nmysubid3 10.1.1.0/24')] - self._test_list_nets_extend_subnets(data, expected) - - def test_list_nets_extend_subnets_no_subnet(self): - data = [{'id': 'netid1', 'name': 'net1', 'subnets': ['mysubid1']}, - {'id': 'netid2', 'name': 'net2', 'subnets': ['mysubid4']}] - # id, name, subnets - expected = [('netid1', 'net1', 'mysubid1 192.168.1.0/24'), - ('netid2', 'net2', 'mysubid4 ')] - self._test_list_nets_extend_subnets(data, expected) - - def test_list_nets_fields(self): - """List nets: --fields a --fields b -- --fields c d.""" - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_networks(cmd, - fields_1=['a', 'b'], fields_2=['c', 'd']) - - def _test_list_nets_columns(self, cmd, returned_body, - args=['-f', 'json']): - resources = 'networks' - self.mox.StubOutWithMock(network.ListNetwork, "extend_list") - network.ListNetwork.extend_list(mox.IsA(list), mox.IgnoreArg()) - self._test_list_columns(cmd, resources, returned_body, args=args) - - def test_list_nets_defined_column(self): - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - returned_body = {"networks": [{"name": "buildname3", - "id": "id3", - "tenant_id": "tenant_3", - "subnets": []}]} - self._test_list_nets_columns(cmd, returned_body, - args=['-f', 'json', '-c', 'id']) - _str = self.fake_stdout.make_string() - returned_networks = utils.loads(_str) - self.assertEquals(1, len(returned_networks)) - net = returned_networks[0] - self.assertEquals(1, len(net)) - self.assertEquals("id", net.keys()[0]) - - def test_list_nets_with_default_column(self): - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - returned_body = {"networks": [{"name": "buildname3", - "id": "id3", - "tenant_id": "tenant_3", - "subnets": []}]} - self._test_list_nets_columns(cmd, returned_body) - _str = self.fake_stdout.make_string() - returned_networks = utils.loads(_str) - self.assertEquals(1, len(returned_networks)) - net = returned_networks[0] - self.assertEquals(3, len(net)) - self.assertEquals(0, len(set(net) ^ set(cmd.list_columns))) - - def test_list_external_nets_empty_with_column(self): - resources = "networks" - cmd = network.ListExternalNetwork(test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - self.mox.StubOutWithMock(network.ListNetwork, "extend_list") - network.ListNetwork.extend_list(mox.IsA(list), mox.IgnoreArg()) - cmd.get_client().MultipleTimes().AndReturn(self.client) - reses = {resources: []} - resstr = self.client.serialize(reses) - # url method body - query = "router%3Aexternal=True&id=myfakeid" - args = ['-c', 'id', '--', '--id', 'myfakeid'] - path = getattr(self.client, resources + "_path") - self.client.httpclient.request( - test_cli20.end_url(path, query), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', - test_cli20.TOKEN)).AndReturn( - (test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - self.assertEquals('\n', _str) - - def _test_list_external_nets(self, resources, cmd, - detail=False, tags=[], - fields_1=[], fields_2=[]): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - self.mox.StubOutWithMock(network.ListNetwork, "extend_list") - network.ListNetwork.extend_list(mox.IsA(list), mox.IgnoreArg()) - cmd.get_client().MultipleTimes().AndReturn(self.client) - reses = {resources: [{'id': 'myid1', }, - {'id': 'myid2', }, ], } - - resstr = self.client.serialize(reses) - - # url method body - query = "" - args = detail and ['-D', ] or [] - if fields_1: - for field in fields_1: - args.append('--fields') - args.append(field) - if tags: - args.append('--') - args.append("--tag") - for tag in tags: - args.append(tag) - if (not tags) and fields_2: - args.append('--') - if fields_2: - args.append("--fields") - for field in fields_2: - args.append(field) - fields_1.extend(fields_2) - for field in fields_1: - if query: - query += "&fields=" + field - else: - query = "fields=" + field - if query: - query += '&router%3Aexternal=True' - else: - query += 'router%3Aexternal=True' - for tag in tags: - if query: - query += "&tag=" + tag - else: - query = "tag=" + tag - if detail: - query = query and query + '&verbose=True' or 'verbose=True' - path = getattr(self.client, resources + "_path") - - self.client.httpclient.request( - test_cli20.end_url(path, query), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - - self.assertTrue('myid1' in _str) - - def test_list_external_nets_detail(self): - """list external nets: -D.""" - resources = "networks" - cmd = network.ListExternalNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_external_nets(resources, cmd, True) - - def test_list_external_nets_tags(self): - """List external nets: -- --tags a b.""" - resources = "networks" - cmd = network.ListExternalNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_external_nets(resources, - cmd, tags=['a', 'b']) - - def test_list_external_nets_detail_tags(self): - """List external nets: -D -- --tags a b.""" - resources = "networks" - cmd = network.ListExternalNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_external_nets(resources, cmd, - detail=True, tags=['a', 'b']) - - def test_list_externel_nets_fields(self): - """List external nets: --fields a --fields b -- --fields c d.""" - resources = "networks" - cmd = network.ListExternalNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_list_external_nets(resources, cmd, - fields_1=['a', 'b'], - fields_2=['c', 'd']) - - def test_update_network_exception(self): - """Update net: myid.""" - resource = 'network' - cmd = network.UpdateNetwork(test_cli20.MyApp(sys.stdout), None) - self.assertRaises(exceptions.CommandError, self._test_update_resource, - resource, cmd, 'myid', ['myid'], {}) - - def test_update_network(self): - """Update net: myid --name myname --tags a b.""" - resource = 'network' - cmd = network.UpdateNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--tags', 'a', 'b'], - {'name': 'myname', 'tags': ['a', 'b'], } - ) - - def test_update_network_with_unicode(self): - """Update net: myid --name u'\u7f51\u7edc' --tags a b.""" - resource = 'network' - cmd = network.UpdateNetwork(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', u'\u7f51\u7edc', - '--tags', 'a', 'b'], - {'name': u'\u7f51\u7edc', - 'tags': ['a', 'b'], } - ) - - def test_show_network(self): - """Show net: --fields id --fields name myid.""" - resource = 'network' - cmd = network.ShowNetwork(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args, - ['id', 'name']) - - def test_delete_network(self): - """Delete net: myid.""" - resource = 'network' - cmd = network.DeleteNetwork(test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - def _test_extend_list(self, mox_calls): - data = [{'id': 'netid%d' % i, 'name': 'net%d' % i, - 'subnets': ['mysubid%d' % i]} - for i in range(0, 10)] - self.mox.StubOutWithMock(self.client.httpclient, "request") - path = getattr(self.client, 'subnets_path') - cmd = network.ListNetwork(test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(cmd, "get_client") - cmd.get_client().MultipleTimes().AndReturn(self.client) - mox_calls(path, data) - self.mox.ReplayAll() - known_args, _vs = cmd.get_parser('create_subnets').parse_known_args() - cmd.extend_list(data, known_args) - self.mox.VerifyAll() - - def _build_test_data(self, data): - subnet_ids = [] - response = [] - filters = "" - for n in data: - if 'subnets' in n: - subnet_ids.extend(n['subnets']) - for subnet_id in n['subnets']: - filters = "%s&id=%s" % (filters, subnet_id) - response.append({'id': subnet_id, - 'cidr': '192.168.0.0/16'}) - resp_str = self.client.serialize({'subnets': response}) - resp = (test_cli20.MyResp(200), resp_str) - return filters, resp - - def test_extend_list(self): - def mox_calls(path, data): - filters, response = self._build_test_data(data) - self.client.httpclient.request( - test_cli20.end_url(path, 'fields=id&fields=cidr' + filters), - 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(response) - - self._test_extend_list(mox_calls) - - def test_extend_list_exceed_max_uri_len(self): - def mox_calls(path, data): - sub_data_lists = [data[:len(data) - 1], data[len(data) - 1:]] - filters, response = self._build_test_data(data) - - # 1 char of extra URI len will cause a split in 2 requests - self.mox.StubOutWithMock(self.client, "_check_uri_length") - self.client._check_uri_length(mox.IgnoreArg()).AndRaise( - exceptions.RequestURITooLong(excess=1)) - - for data in sub_data_lists: - filters, response = self._build_test_data(data) - self.client._check_uri_length(mox.IgnoreArg()).AndReturn(None) - self.client.httpclient.request( - test_cli20.end_url(path, - 'fields=id&fields=cidr%s' % filters), - 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(response) - - self._test_extend_list(mox_calls) - - -class CLITestV20NetworkXML(CLITestV20NetworkJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_nvp_queue.py b/tests/unit/test_cli20_nvp_queue.py deleted file mode 100644 index d84d9df..0000000 --- a/tests/unit/test_cli20_nvp_queue.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -# 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 sys - -from quantumclient.quantum.v2_0 import nvp_qos_queue as qos -from tests.unit import test_cli20 - - -class CLITestV20NvpQosQueueJSON(test_cli20.CLITestV20Base): - def setUp(self): - super(CLITestV20NvpQosQueueJSON, self).setUp( - plurals={'qos_queues': 'qos_queue'}) - - def test_create_qos_queue(self): - """Create a qos queue.""" - resource = 'qos_queue' - cmd = qos.CreateQoSQueue( - test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - name = 'my_queue' - default = False - args = ['--default', default, name] - position_names = ['name', 'default'] - position_values = [name, default] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_qos_queue_all_values(self): - """Create a qos queue.""" - resource = 'qos_queue' - cmd = qos.CreateQoSQueue( - test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - name = 'my_queue' - default = False - min = '10' - max = '40' - qos_marking = 'untrusted' - dscp = '0' - args = ['--default', default, '--min', min, '--max', max, - '--qos-marking', qos_marking, '--dscp', dscp, name] - position_names = ['name', 'default', 'min', 'max', 'qos_marking', - 'dscp'] - position_values = [name, default, min, max, qos_marking, dscp] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_list_qos_queue(self): - resources = "qos_queues" - cmd = qos.ListQoSQueue( - test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_show_qos_queue_id(self): - resource = 'qos_queue' - cmd = qos.ShowQoSQueue( - test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id']) - - def test_delete_qos_queue(self): - resource = 'qos_queue' - cmd = qos.DeleteQoSQueue( - test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - -class CLITestV20NvpQosQueueXML(CLITestV20NvpQosQueueJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_nvpnetworkgateway.py b/tests/unit/test_cli20_nvpnetworkgateway.py deleted file mode 100644 index ebf730a..0000000 --- a/tests/unit/test_cli20_nvpnetworkgateway.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2012 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. -# -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -import sys - -from quantumclient.quantum.v2_0 import nvpnetworkgateway as nwgw -from tests.unit import test_cli20 - - -class CLITestV20NetworkGatewayJSON(test_cli20.CLITestV20Base): - - resource = "network_gateway" - - def setUp(self): - super(CLITestV20NetworkGatewayJSON, self).setUp( - plurals={'devices': 'device', - 'network_gateways': 'network_gateway'}) - - def test_create_gateway(self): - cmd = nwgw.CreateNetworkGateway(test_cli20.MyApp(sys.stdout), None) - name = 'gw-test' - myid = 'myid' - args = [name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(self.resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_gateway_with_tenant(self): - cmd = nwgw.CreateNetworkGateway(test_cli20.MyApp(sys.stdout), None) - name = 'gw-test' - myid = 'myid' - args = ['--tenant_id', 'tenantid', name] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(self.resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_gateway_with_device(self): - cmd = nwgw.CreateNetworkGateway(test_cli20.MyApp(sys.stdout), None) - name = 'gw-test' - myid = 'myid' - args = ['--device', 'device_id=test', name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(self.resource, cmd, name, myid, args, - position_names, position_values, - devices=[{'device_id': 'test'}]) - - def test_list_gateways(self): - resources = '%ss' % self.resource - cmd = nwgw.ListNetworkGateway(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_update_gateway(self): - cmd = nwgw.UpdateNetworkGateway(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(self.resource, cmd, 'myid', - ['myid', '--name', 'cavani'], - {'name': 'cavani'}) - - def test_delete_gateway(self): - cmd = nwgw.DeleteNetworkGateway(test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(self.resource, cmd, myid, args) - - def test_show_gateway(self): - cmd = nwgw.ShowNetworkGateway(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(self.resource, cmd, self.test_id, args, - ['id', 'name']) - - def test_connect_network_to_gateway(self): - cmd = nwgw.ConnectNetworkGateway(test_cli20.MyApp(sys.stdout), None) - args = ['gw_id', 'net_id', - '--segmentation-type', 'edi', - '--segmentation-id', '7'] - self._test_update_resource_action(self.resource, cmd, 'gw_id', - 'connect_network', - args, - {'network_id': 'net_id', - 'segmentation_type': 'edi', - 'segmentation_id': '7'}) - - def test_disconnect_network_from_gateway(self): - cmd = nwgw.DisconnectNetworkGateway(test_cli20.MyApp(sys.stdout), None) - args = ['gw_id', 'net_id', - '--segmentation-type', 'edi', - '--segmentation-id', '7'] - self._test_update_resource_action(self.resource, cmd, 'gw_id', - 'disconnect_network', - args, - {'network_id': 'net_id', - 'segmentation_type': 'edi', - 'segmentation_id': '7'}) - - -class CLITestV20NetworkGatewayXML(CLITestV20NetworkGatewayJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_port.py b/tests/unit/test_cli20_port.py deleted file mode 100644 index 545f35b..0000000 --- a/tests/unit/test_cli20_port.py +++ /dev/null @@ -1,304 +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 sys - -import mox - -from quantumclient.quantum.v2_0 import port -from quantumclient import shell -from tests.unit import test_cli20 - - -class CLITestV20PortJSON(test_cli20.CLITestV20Base): - def setUp(self): - super(CLITestV20PortJSON, self).setUp(plurals={'tags': 'tag'}) - - def test_create_port(self): - """Create port: netid.""" - resource = 'port' - cmd = port.CreatePort(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - args = [netid] - position_names = ['network_id'] - position_values = [] - position_values.extend([netid]) - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_port_full(self): - """Create port: --mac_address mac --device_id deviceid netid.""" - resource = 'port' - cmd = port.CreatePort(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - args = ['--mac_address', 'mac', '--device_id', 'deviceid', netid] - position_names = ['network_id', 'mac_address', 'device_id'] - position_values = [netid, 'mac', 'deviceid'] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - # Test dashed options - args = ['--mac-address', 'mac', '--device-id', 'deviceid', netid] - position_names = ['network_id', 'mac_address', 'device_id'] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_port_tenant(self): - """Create port: --tenant_id tenantid netid.""" - resource = 'port' - cmd = port.CreatePort(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - args = ['--tenant_id', 'tenantid', netid, ] - position_names = ['network_id'] - position_values = [] - position_values.extend([netid]) - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - # Test dashed options - args = ['--tenant-id', 'tenantid', netid, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_port_tags(self): - """Create port: netid mac_address device_id --tags a b.""" - resource = 'port' - cmd = port.CreatePort(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - args = [netid, '--tags', 'a', 'b'] - position_names = ['network_id'] - position_values = [] - position_values.extend([netid]) - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tags=['a', 'b']) - - def test_create_port_secgroup(self): - """Create port: --security-group sg1_id netid.""" - resource = 'port' - cmd = port.CreatePort(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - args = ['--security-group', 'sg1_id', netid] - position_names = ['network_id', 'security_groups'] - position_values = [netid, ['sg1_id']] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_port_secgroups(self): - """Create port: netid - - The are - --security-group sg1_id --security-group sg2_id - """ - resource = 'port' - cmd = port.CreatePort(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - args = ['--security-group', 'sg1_id', - '--security-group', 'sg2_id', - netid] - position_names = ['network_id', 'security_groups'] - position_values = [netid, ['sg1_id', 'sg2_id']] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_list_ports(self): - """List ports: -D.""" - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_ports_pagination(self): - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_ports_sort(self): - """list ports: --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_ports_limit(self): - """list ports: -P.""" - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_list_ports_tags(self): - """List ports: -- --tags a b.""" - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, tags=['a', 'b']) - - def test_list_ports_detail_tags(self): - """List ports: -D -- --tags a b.""" - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, detail=True, tags=['a', 'b']) - - def test_list_ports_fields(self): - """List ports: --fields a --fields b -- --fields c d.""" - resources = "ports" - cmd = port.ListPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - fields_1=['a', 'b'], fields_2=['c', 'd']) - - def _test_list_router_port(self, resources, cmd, - myid, detail=False, tags=[], - fields_1=[], fields_2=[]): - self.mox.StubOutWithMock(cmd, "get_client") - self.mox.StubOutWithMock(self.client.httpclient, "request") - cmd.get_client().MultipleTimes().AndReturn(self.client) - reses = {resources: [{'id': 'myid1', }, - {'id': 'myid2', }, ], } - - resstr = self.client.serialize(reses) - - # url method body - query = "" - args = detail and ['-D', ] or [] - - if fields_1: - for field in fields_1: - args.append('--fields') - args.append(field) - args.append(myid) - if tags: - args.append('--') - args.append("--tag") - for tag in tags: - args.append(tag) - if (not tags) and fields_2: - args.append('--') - if fields_2: - args.append("--fields") - for field in fields_2: - args.append(field) - fields_1.extend(fields_2) - for field in fields_1: - if query: - query += "&fields=" + field - else: - query = "fields=" + field - - for tag in tags: - if query: - query += "&tag=" + tag - else: - query = "tag=" + tag - if detail: - query = query and query + '&verbose=True' or 'verbose=True' - query = query and query + '&device_id=%s' or 'device_id=%s' - path = getattr(self.client, resources + "_path") - self.client.httpclient.request( - test_cli20.end_url(path, query % myid), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - cmd_parser = cmd.get_parser("list_" + resources) - shell.run_command(cmd, cmd_parser, args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - _str = self.fake_stdout.make_string() - - self.assertTrue('myid1' in _str) - - def test_list_router_ports(self): - """List router ports: -D.""" - resources = "ports" - cmd = port.ListRouterPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_router_port(resources, cmd, - self.test_id, True) - - def test_list_router_ports_tags(self): - """List router ports: -- --tags a b.""" - resources = "ports" - cmd = port.ListRouterPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_router_port(resources, cmd, - self.test_id, tags=['a', 'b']) - - def test_list_router_ports_detail_tags(self): - """List router ports: -D -- --tags a b.""" - resources = "ports" - cmd = port.ListRouterPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_router_port(resources, cmd, self.test_id, - detail=True, tags=['a', 'b']) - - def test_list_router_ports_fields(self): - """List ports: --fields a --fields b -- --fields c d.""" - resources = "ports" - cmd = port.ListRouterPort(test_cli20.MyApp(sys.stdout), None) - self._test_list_router_port(resources, cmd, self.test_id, - fields_1=['a', 'b'], - fields_2=['c', 'd']) - - def test_update_port(self): - """Update port: myid --name myname --tags a b.""" - resource = 'port' - cmd = port.UpdatePort(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--tags', 'a', 'b'], - {'name': 'myname', 'tags': ['a', 'b'], } - ) - - def test_update_port_security_group_off(self): - """Update port: --no-security-groups myid.""" - resource = 'port' - cmd = port.UpdatePort(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['--no-security-groups', 'myid'], - {'security_groups': None}) - - def test_show_port(self): - """Show port: --fields id --fields name myid.""" - resource = 'port' - cmd = port.ShowPort(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_delete_port(self): - """Delete port: myid.""" - resource = 'port' - cmd = port.DeletePort(test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - -class CLITestV20PortXML(CLITestV20PortJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_router.py b/tests/unit/test_cli20_router.py deleted file mode 100644 index 35ac577..0000000 --- a/tests/unit/test_cli20_router.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright 2012 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. -# -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -import sys - -from quantumclient.common import exceptions -from quantumclient.quantum.v2_0 import router -from tests.unit import test_cli20 - - -class CLITestV20RouterJSON(test_cli20.CLITestV20Base): - def test_create_router(self): - """Create router: router1.""" - resource = 'router' - cmd = router.CreateRouter(test_cli20.MyApp(sys.stdout), None) - name = 'router1' - myid = 'myid' - args = [name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_router_tenant(self): - """Create router: --tenant_id tenantid myname.""" - resource = 'router' - cmd = router.CreateRouter(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - args = ['--tenant_id', 'tenantid', name] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_router_admin_state(self): - """Create router: --admin_state_down myname.""" - resource = 'router' - cmd = router.CreateRouter(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - args = ['--admin_state_down', name, ] - position_names = ['name', ] - position_values = [name, ] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - admin_state_up=False) - - def test_list_routers_detail(self): - """list routers: -D.""" - resources = "routers" - cmd = router.ListRouter(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_routers_pagination(self): - resources = "routers" - cmd = router.ListRouter(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_routers_sort(self): - """list routers: --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "routers" - cmd = router.ListRouter(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_routers_limit(self): - """list routers: -P.""" - resources = "routers" - cmd = router.ListRouter(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_update_router_exception(self): - """Update router: myid.""" - resource = 'router' - cmd = router.UpdateRouter(test_cli20.MyApp(sys.stdout), None) - self.assertRaises(exceptions.CommandError, self._test_update_resource, - resource, cmd, 'myid', ['myid'], {}) - - def test_update_router(self): - """Update router: myid --name myname --tags a b.""" - resource = 'router' - cmd = router.UpdateRouter(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname'], - {'name': 'myname'} - ) - - def test_delete_router(self): - """Delete router: myid.""" - resource = 'router' - cmd = router.DeleteRouter(test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - def test_show_router(self): - """Show router: myid.""" - resource = 'router' - cmd = router.ShowRouter(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args, - ['id', 'name']) - - def _test_add_remove_interface(self, action, mode, cmd, args): - resource = 'router' - subcmd = '%s_router_interface' % action - if mode == 'port': - body = {'port_id': 'portid'} - else: - body = {'subnet_id': 'subnetid'} - if action == 'add': - retval = {'subnet_id': 'subnetid', 'port_id': 'portid'} - else: - retval = None - self._test_update_resource_action(resource, cmd, 'myid', - subcmd, args, - body, retval) - - def test_add_interface_compat(self): - """Add interface to router: myid subnetid.""" - cmd = router.AddInterfaceRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'subnetid'] - self._test_add_remove_interface('add', 'subnet', cmd, args) - - def test_add_interface_by_subnet(self): - """Add interface to router: myid subnet=subnetid.""" - cmd = router.AddInterfaceRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'subnet=subnetid'] - self._test_add_remove_interface('add', 'subnet', cmd, args) - - def test_add_interface_by_port(self): - """Add interface to router: myid port=portid.""" - cmd = router.AddInterfaceRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'port=portid'] - self._test_add_remove_interface('add', 'port', cmd, args) - - def test_del_interface_compat(self): - """Delete interface from router: myid subnetid.""" - cmd = router.RemoveInterfaceRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'subnetid'] - self._test_add_remove_interface('remove', 'subnet', cmd, args) - - def test_del_interface_by_subnet(self): - """Delete interface from router: myid subnet=subnetid.""" - cmd = router.RemoveInterfaceRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'subnet=subnetid'] - self._test_add_remove_interface('remove', 'subnet', cmd, args) - - def test_del_interface_by_port(self): - """Delete interface from router: myid port=portid.""" - cmd = router.RemoveInterfaceRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'port=portid'] - self._test_add_remove_interface('remove', 'port', cmd, args) - - def test_set_gateway(self): - """Set external gateway for router: myid externalid.""" - resource = 'router' - cmd = router.SetGatewayRouter(test_cli20.MyApp(sys.stdout), None) - args = ['myid', 'externalid'] - self._test_update_resource(resource, cmd, 'myid', - args, - {"external_gateway_info": - {"network_id": "externalid", - "enable_snat": True}} - ) - - def test_remove_gateway(self): - """Remove external gateway from router: externalid.""" - resource = 'router' - cmd = router.RemoveGatewayRouter(test_cli20.MyApp(sys.stdout), None) - args = ['externalid'] - self._test_update_resource(resource, cmd, 'externalid', - args, {"external_gateway_info": {}} - ) - - -class CLITestV20RouterXML(CLITestV20RouterJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_securitygroup.py b/tests/unit/test_cli20_securitygroup.py deleted file mode 100644 index 4302093..0000000 --- a/tests/unit/test_cli20_securitygroup.py +++ /dev/null @@ -1,333 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Red Hat -# 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 sys - -import mox - -from quantumclient.quantum.v2_0 import securitygroup -from tests.unit import test_cli20 - - -class CLITestV20SecurityGroupsJSON(test_cli20.CLITestV20Base): - def test_create_security_group(self): - """Create security group: webservers.""" - resource = 'security_group' - cmd = securitygroup.CreateSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - name = 'webservers' - myid = 'myid' - args = [name, ] - position_names = ['name'] - position_values = [name] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_security_group_tenant(self): - """Create security group: webservers.""" - resource = 'security_group' - cmd = securitygroup.CreateSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - name = 'webservers' - description = 'my webservers' - myid = 'myid' - args = ['--tenant_id', 'tenant_id', '--description', description, name] - position_names = ['name', 'description'] - position_values = [name, description] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenant_id') - - def test_create_security_group_with_description(self): - """Create security group: webservers.""" - resource = 'security_group' - cmd = securitygroup.CreateSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - name = 'webservers' - description = 'my webservers' - myid = 'myid' - args = [name, '--description', description] - position_names = ['name', 'description'] - position_values = [name, description] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_list_security_groups(self): - resources = "security_groups" - cmd = securitygroup.ListSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_security_groups_pagination(self): - resources = "security_groups" - cmd = securitygroup.ListSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_security_groups_sort(self): - resources = "security_groups" - cmd = securitygroup.ListSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_security_groups_limit(self): - resources = "security_groups" - cmd = securitygroup.ListSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_show_security_group_id(self): - resource = 'security_group' - cmd = securitygroup.ShowSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id']) - - def test_show_security_group_id_name(self): - resource = 'security_group' - cmd = securitygroup.ShowSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_delete_security_group(self): - """Delete security group: myid.""" - resource = 'security_group' - cmd = securitygroup.DeleteSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - def test_update_security_group(self): - """Update security group: myid --name myname --description desc.""" - resource = 'security_group' - cmd = securitygroup.UpdateSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--description', 'mydescription'], - {'name': 'myname', - 'description': 'mydescription'} - ) - - def test_update_security_group_with_unicode(self): - resource = 'security_group' - cmd = securitygroup.UpdateSecurityGroup( - test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', u'\u7f51\u7edc', - '--description', u'\u7f51\u7edc'], - {'name': u'\u7f51\u7edc', - 'description': u'\u7f51\u7edc'} - ) - - def test_create_security_group_rule_full(self): - """Create security group rule.""" - resource = 'security_group_rule' - cmd = securitygroup.CreateSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - direction = 'ingress' - ethertype = 'IPv4' - protocol = 'tcp' - port_range_min = '22' - port_range_max = '22' - remote_ip_prefix = '10.0.0.0/24' - security_group_id = '1' - remote_group_id = '1' - args = ['--remote_ip_prefix', remote_ip_prefix, '--direction', - direction, '--ethertype', ethertype, '--protocol', protocol, - '--port_range_min', port_range_min, '--port_range_max', - port_range_max, '--remote_group_id', remote_group_id, - security_group_id] - position_names = ['remote_ip_prefix', 'direction', 'ethertype', - 'protocol', 'port_range_min', 'port_range_max', - 'remote_group_id', 'security_group_id'] - position_values = [remote_ip_prefix, direction, ethertype, protocol, - port_range_min, port_range_max, remote_group_id, - security_group_id] - self._test_create_resource(resource, cmd, None, myid, args, - position_names, position_values) - - def test_delete_security_group_rule(self): - """Delete security group rule: myid.""" - resource = 'security_group_rule' - cmd = securitygroup.DeleteSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - def test_list_security_group_rules(self): - resources = "security_group_rules" - cmd = securitygroup.ListSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(securitygroup.ListSecurityGroupRule, - "extend_list") - securitygroup.ListSecurityGroupRule.extend_list(mox.IsA(list), - mox.IgnoreArg()) - self._test_list_resources(resources, cmd, True) - - def test_list_security_group_rules_pagination(self): - resources = "security_group_rules" - cmd = securitygroup.ListSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(securitygroup.ListSecurityGroupRule, - "extend_list") - securitygroup.ListSecurityGroupRule.extend_list(mox.IsA(list), - mox.IgnoreArg()) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_security_group_rules_sort(self): - resources = "security_group_rules" - cmd = securitygroup.ListSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(securitygroup.ListSecurityGroupRule, - "extend_list") - securitygroup.ListSecurityGroupRule.extend_list(mox.IsA(list), - mox.IgnoreArg()) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_security_group_rules_limit(self): - resources = "security_group_rules" - cmd = securitygroup.ListSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(securitygroup.ListSecurityGroupRule, - "extend_list") - securitygroup.ListSecurityGroupRule.extend_list(mox.IsA(list), - mox.IgnoreArg()) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_show_security_group_rule(self): - resource = 'security_group_rule' - cmd = securitygroup.ShowSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id']) - - def _test_list_security_group_rules_extend(self, data=None, expected=None, - args=[], conv=True, - query_field=False): - def setup_list_stub(resources, data, query): - reses = {resources: data} - resstr = self.client.serialize(reses) - resp = (test_cli20.MyResp(200), resstr) - path = getattr(self.client, resources + '_path') - self.client.httpclient.request( - test_cli20.end_url(path, query), 'GET', - body=None, - headers=mox.ContainsKeyValue( - 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(resp) - - # Setup the default data - _data = {'cols': ['id', 'security_group_id', 'remote_group_id'], - 'data': [('ruleid1', 'myid1', 'myid1'), - ('ruleid2', 'myid2', 'myid3'), - ('ruleid3', 'myid2', 'myid2')]} - _expected = {'cols': ['id', 'security_group', 'remote_group'], - 'data': [('ruleid1', 'group1', 'group1'), - ('ruleid2', 'group2', 'group3'), - ('ruleid3', 'group2', 'group2')]} - if data is None: - data = _data - list_data = [dict(zip(data['cols'], d)) for d in data['data']] - if expected is None: - expected = {} - expected['cols'] = expected.get('cols', _expected['cols']) - expected['data'] = expected.get('data', _expected['data']) - - cmd = securitygroup.ListSecurityGroupRule( - test_cli20.MyApp(sys.stdout), None) - self.mox.StubOutWithMock(cmd, 'get_client') - self.mox.StubOutWithMock(self.client.httpclient, 'request') - cmd.get_client().AndReturn(self.client) - query = '' - if query_field: - query = '&'.join(['fields=' + f for f in data['cols']]) - setup_list_stub('security_group_rules', list_data, query) - if conv: - cmd.get_client().AndReturn(self.client) - sec_ids = set() - for n in data['data']: - sec_ids.add(n[1]) - sec_ids.add(n[2]) - filters = '' - for id in sec_ids: - filters = filters + "&id=%s" % id - setup_list_stub('security_groups', - [{'id': 'myid1', 'name': 'group1'}, - {'id': 'myid2', 'name': 'group2'}, - {'id': 'myid3', 'name': 'group3'}], - query='fields=id&fields=name' + filters) - self.mox.ReplayAll() - - cmd_parser = cmd.get_parser('list_security_group_rules') - parsed_args = cmd_parser.parse_args(args) - result = cmd.get_data(parsed_args) - self.mox.VerifyAll() - self.mox.UnsetStubs() - # Check columns - self.assertEqual(result[0], expected['cols']) - # Check data - _result = [x for x in result[1]] - self.assertEqual(len(_result), len(expected['data'])) - for res, exp in zip(_result, expected['data']): - self.assertEqual(len(res), len(exp)) - self.assertEqual(res, exp) - - def test_list_security_group_rules_extend_source_id(self): - self._test_list_security_group_rules_extend() - - def test_list_security_group_rules_extend_no_nameconv(self): - expected = {'cols': ['id', 'security_group_id', 'remote_group_id'], - 'data': [('ruleid1', 'myid1', 'myid1'), - ('ruleid2', 'myid2', 'myid3'), - ('ruleid3', 'myid2', 'myid2')]} - args = ['--no-nameconv'] - self._test_list_security_group_rules_extend(expected=expected, - args=args, conv=False) - - def test_list_security_group_rules_extend_with_columns(self): - args = '-c id -c security_group_id -c remote_group_id'.split() - self._test_list_security_group_rules_extend(args=args) - - def test_list_security_group_rules_extend_with_columns_no_id(self): - args = '-c id -c security_group -c remote_group'.split() - self._test_list_security_group_rules_extend(args=args) - - def test_list_security_group_rules_extend_with_fields(self): - args = '-F id -F security_group_id -F remote_group_id'.split() - self._test_list_security_group_rules_extend(args=args, - query_field=True) - - def test_list_security_group_rules_extend_with_fields_no_id(self): - args = '-F id -F security_group -F remote_group'.split() - self._test_list_security_group_rules_extend(args=args, - query_field=True) - - -class CLITestV20SecurityGroupsXML(CLITestV20SecurityGroupsJSON): - format = 'xml' diff --git a/tests/unit/test_cli20_subnet.py b/tests/unit/test_cli20_subnet.py deleted file mode 100644 index 5c048a6..0000000 --- a/tests/unit/test_cli20_subnet.py +++ /dev/null @@ -1,402 +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 sys - -from quantumclient.quantum.v2_0 import subnet -from tests.unit import test_cli20 - - -class CLITestV20SubnetJSON(test_cli20.CLITestV20Base): - def setUp(self): - super(CLITestV20SubnetJSON, self).setUp(plurals={'tags': 'tag'}) - - def test_create_subnet(self): - """Create subnet: --gateway gateway netid cidr.""" - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'cidrvalue' - gateway = 'gatewayvalue' - args = ['--gateway', gateway, netid, cidr] - position_names = ['ip_version', 'network_id', 'cidr', 'gateway_ip'] - position_values = [4, netid, cidr, gateway] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_subnet_with_no_gateway(self): - """Create subnet: --no-gateway netid cidr.""" - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'cidrvalue' - args = ['--no-gateway', netid, cidr] - position_names = ['ip_version', 'network_id', 'cidr', 'gateway_ip'] - position_values = [4, netid, cidr, None] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - - def test_create_subnet_with_bad_gateway_option(self): - """Create sbunet: --no-gateway netid cidr.""" - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'cidrvalue' - gateway = 'gatewayvalue' - args = ['--gateway', gateway, '--no-gateway', netid, cidr] - position_names = ['ip_version', 'network_id', 'cidr', 'gateway_ip'] - position_values = [4, netid, cidr, None] - try: - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values) - except Exception: - return - self.fail('No exception for bad gateway option') - - def test_create_subnet_tenant(self): - """Create subnet: --tenant_id tenantid netid cidr.""" - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', netid, cidr] - position_names = ['ip_version', 'network_id', 'cidr'] - position_values = [4, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_tags(self): - """Create subnet: netid cidr --tags a b.""" - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = [netid, cidr, '--tags', 'a', 'b'] - position_names = ['ip_version', 'network_id', 'cidr'] - position_values = [4, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tags=['a', 'b']) - - def test_create_subnet_allocation_pool(self): - """Create subnet: --tenant_id tenantid netid cidr. - The is --allocation_pool start=1.1.1.10,end=1.1.1.20 - """ - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--allocation_pool', 'start=1.1.1.10,end=1.1.1.20', - netid, cidr] - position_names = ['ip_version', 'allocation_pools', 'network_id', - 'cidr'] - pool = [{'start': '1.1.1.10', 'end': '1.1.1.20'}] - position_values = [4, pool, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_allocation_pools(self): - """Create subnet: --tenant-id tenantid netid cidr. - The are --allocation_pool start=1.1.1.10,end=1.1.1.20 and - --allocation_pool start=1.1.1.30,end=1.1.1.40 - """ - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--allocation_pool', 'start=1.1.1.10,end=1.1.1.20', - '--allocation_pool', 'start=1.1.1.30,end=1.1.1.40', - netid, cidr] - position_names = ['ip_version', 'allocation_pools', 'network_id', - 'cidr'] - pools = [{'start': '1.1.1.10', 'end': '1.1.1.20'}, - {'start': '1.1.1.30', 'end': '1.1.1.40'}] - position_values = [4, pools, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_host_route(self): - """Create subnet: --tenant_id tenantid netid cidr. - The is - --host-route destination=172.16.1.0/24,nexthop=1.1.1.20 - """ - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--host-route', 'destination=172.16.1.0/24,nexthop=1.1.1.20', - netid, cidr] - position_names = ['ip_version', 'host_routes', 'network_id', - 'cidr'] - route = [{'destination': '172.16.1.0/24', 'nexthop': '1.1.1.20'}] - position_values = [4, route, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_host_routes(self): - """Create subnet: --tenant-id tenantid netid cidr. - The are - --host-route destination=172.16.1.0/24,nexthop=1.1.1.20 and - --host-route destination=172.17.7.0/24,nexthop=1.1.1.40 - """ - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--host-route', 'destination=172.16.1.0/24,nexthop=1.1.1.20', - '--host-route', 'destination=172.17.7.0/24,nexthop=1.1.1.40', - netid, cidr] - position_names = ['ip_version', 'host_routes', 'network_id', - 'cidr'] - routes = [{'destination': '172.16.1.0/24', 'nexthop': '1.1.1.20'}, - {'destination': '172.17.7.0/24', 'nexthop': '1.1.1.40'}] - position_values = [4, routes, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_dns_nameservers(self): - """Create subnet: --tenant-id tenantid netid cidr. - The are - --dns-nameserver 1.1.1.20 and --dns-nameserver 1.1.1.40 - """ - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--dns-nameserver', '1.1.1.20', - '--dns-nameserver', '1.1.1.40', - netid, cidr] - position_names = ['ip_version', 'dns_nameservers', 'network_id', - 'cidr'] - nameservers = ['1.1.1.20', '1.1.1.40'] - position_values = [4, nameservers, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_with_disable_dhcp(self): - """Create subnet: --tenant-id tenantid --disable-dhcp netid cidr.""" - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--disable-dhcp', - netid, cidr] - position_names = ['ip_version', 'enable_dhcp', 'network_id', - 'cidr'] - position_values = [4, False, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_merge_single_plurar(self): - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--allocation-pool', 'start=1.1.1.10,end=1.1.1.20', - netid, cidr, - '--allocation-pools', 'list=true', 'type=dict', - 'start=1.1.1.30,end=1.1.1.40'] - position_names = ['ip_version', 'allocation_pools', 'network_id', - 'cidr'] - pools = [{'start': '1.1.1.10', 'end': '1.1.1.20'}, - {'start': '1.1.1.30', 'end': '1.1.1.40'}] - position_values = [4, pools, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_merge_plurar(self): - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - netid, cidr, - '--allocation-pools', 'list=true', 'type=dict', - 'start=1.1.1.30,end=1.1.1.40'] - position_names = ['ip_version', 'allocation_pools', 'network_id', - 'cidr'] - pools = [{'start': '1.1.1.30', 'end': '1.1.1.40'}] - position_values = [4, pools, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_create_subnet_merge_single_single(self): - resource = 'subnet' - cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None) - name = 'myname' - myid = 'myid' - netid = 'netid' - cidr = 'prefixvalue' - args = ['--tenant_id', 'tenantid', - '--allocation-pool', 'start=1.1.1.10,end=1.1.1.20', - netid, cidr, - '--allocation-pool', - 'start=1.1.1.30,end=1.1.1.40'] - position_names = ['ip_version', 'allocation_pools', 'network_id', - 'cidr'] - pools = [{'start': '1.1.1.10', 'end': '1.1.1.20'}, - {'start': '1.1.1.30', 'end': '1.1.1.40'}] - position_values = [4, pools, netid, cidr] - self._test_create_resource(resource, cmd, name, myid, args, - position_names, position_values, - tenant_id='tenantid') - - def test_list_subnets_detail(self): - """List subnets: -D.""" - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, True) - - def test_list_subnets_tags(self): - """List subnets: -- --tags a b.""" - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, tags=['a', 'b']) - - def test_list_subnets_known_option_after_unknown(self): - """List subnets: -- --tags a b --request-format xml.""" - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, tags=['a', 'b']) - - def test_list_subnets_detail_tags(self): - """List subnets: -D -- --tags a b.""" - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, detail=True, tags=['a', 'b']) - - def test_list_subnets_fields(self): - """List subnets: --fields a --fields b -- --fields c d.""" - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - fields_1=['a', 'b'], fields_2=['c', 'd']) - - def test_list_subnets_pagination(self): - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources_with_pagination(resources, cmd) - - def test_list_subnets_sort(self): - """List subnets: --sort-key name --sort-key id --sort-key asc - --sort-key desc - """ - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, - sort_key=["name", "id"], - sort_dir=["asc", "desc"]) - - def test_list_subnets_limit(self): - """List subnets: -P.""" - resources = "subnets" - cmd = subnet.ListSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_list_resources(resources, cmd, page_size=1000) - - def test_update_subnet(self): - """Update subnet: myid --name myname --tags a b.""" - resource = 'subnet' - cmd = subnet.UpdateSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--tags', 'a', 'b'], - {'name': 'myname', 'tags': ['a', 'b'], } - ) - - def test_update_subnet_known_option_before_id(self): - """Update subnet: --request-format json myid --name myname.""" - # --request-format xml is known option - resource = 'subnet' - cmd = subnet.UpdateSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['--request-format', 'json', - 'myid', '--name', 'myname'], - {'name': 'myname', } - ) - - def test_update_subnet_known_option_after_id(self): - """Update subnet: myid --name myname --request-format json.""" - # --request-format xml is known option - resource = 'subnet' - cmd = subnet.UpdateSubnet(test_cli20.MyApp(sys.stdout), None) - self._test_update_resource(resource, cmd, 'myid', - ['myid', '--name', 'myname', - '--request-format', 'json'], - {'name': 'myname', } - ) - - def test_show_subnet(self): - """Show subnet: --fields id --fields name myid.""" - resource = 'subnet' - cmd = subnet.ShowSubnet(test_cli20.MyApp(sys.stdout), None) - args = ['--fields', 'id', '--fields', 'name', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, - args, ['id', 'name']) - - def test_delete_subnet(self): - """Delete subnet: subnetid.""" - resource = 'subnet' - cmd = subnet.DeleteSubnet(test_cli20.MyApp(sys.stdout), None) - myid = 'myid' - args = [myid] - self._test_delete_resource(resource, cmd, myid, args) - - -class CLITestV20SubnetXML(CLITestV20SubnetJSON): - format = 'xml' diff --git a/tests/unit/test_name_or_id.py b/tests/unit/test_name_or_id.py deleted file mode 100644 index fc3bdac..0000000 --- a/tests/unit/test_name_or_id.py +++ /dev/null @@ -1,132 +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 uuid - -import mox -import testtools - -from quantumclient.common import exceptions -from quantumclient.quantum import v2_0 as quantumv20 -from quantumclient.v2_0 import client -from tests.unit import test_cli20 - - -class CLITestNameorID(testtools.TestCase): - - def setUp(self): - """Prepare the test environment.""" - super(CLITestNameorID, self).setUp() - self.mox = mox.Mox() - self.endurl = test_cli20.ENDURL - self.client = client.Client(token=test_cli20.TOKEN, - endpoint_url=self.endurl) - self.addCleanup(self.mox.VerifyAll) - self.addCleanup(self.mox.UnsetStubs) - - def test_get_id_from_id(self): - _id = str(uuid.uuid4()) - reses = {'networks': [{'id': _id, }, ], } - resstr = self.client.serialize(reses) - self.mox.StubOutWithMock(self.client.httpclient, "request") - path = getattr(self.client, "networks_path") - self.client.httpclient.request( - test_cli20.end_url(path, "fields=id&id=" + _id), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - returned_id = quantumv20.find_resourceid_by_name_or_id( - self.client, 'network', _id) - self.assertEqual(_id, returned_id) - - def test_get_id_from_id_then_name_empty(self): - _id = str(uuid.uuid4()) - reses = {'networks': [{'id': _id, }, ], } - resstr = self.client.serialize(reses) - resstr1 = self.client.serialize({'networks': []}) - self.mox.StubOutWithMock(self.client.httpclient, "request") - path = getattr(self.client, "networks_path") - self.client.httpclient.request( - test_cli20.end_url(path, "fields=id&id=" + _id), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr1)) - self.client.httpclient.request( - test_cli20.end_url(path, "fields=id&name=" + _id), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - returned_id = quantumv20.find_resourceid_by_name_or_id( - self.client, 'network', _id) - self.assertEqual(_id, returned_id) - - def test_get_id_from_name(self): - name = 'myname' - _id = str(uuid.uuid4()) - reses = {'networks': [{'id': _id, }, ], } - resstr = self.client.serialize(reses) - self.mox.StubOutWithMock(self.client.httpclient, "request") - path = getattr(self.client, "networks_path") - self.client.httpclient.request( - test_cli20.end_url(path, "fields=id&name=" + name), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - returned_id = quantumv20.find_resourceid_by_name_or_id( - self.client, 'network', name) - self.assertEqual(_id, returned_id) - - def test_get_id_from_name_multiple(self): - name = 'myname' - reses = {'networks': [{'id': str(uuid.uuid4())}, - {'id': str(uuid.uuid4())}]} - resstr = self.client.serialize(reses) - self.mox.StubOutWithMock(self.client.httpclient, "request") - path = getattr(self.client, "networks_path") - self.client.httpclient.request( - test_cli20.end_url(path, "fields=id&name=" + name), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - try: - quantumv20.find_resourceid_by_name_or_id( - self.client, 'network', name) - except exceptions.QuantumClientException as ex: - self.assertTrue('Multiple' in ex.message) - - def test_get_id_from_name_notfound(self): - name = 'myname' - reses = {'networks': []} - resstr = self.client.serialize(reses) - self.mox.StubOutWithMock(self.client.httpclient, "request") - path = getattr(self.client, "networks_path") - self.client.httpclient.request( - test_cli20.end_url(path, "fields=id&name=" + name), 'GET', - body=None, - headers=mox.ContainsKeyValue('X-Auth-Token', test_cli20.TOKEN) - ).AndReturn((test_cli20.MyResp(200), resstr)) - self.mox.ReplayAll() - try: - quantumv20.find_resourceid_by_name_or_id( - self.client, 'network', name) - except exceptions.QuantumClientException as ex: - self.assertTrue('Unable to find' in ex.message) - self.assertEqual(404, ex.status_code) diff --git a/tests/unit/test_quota.py b/tests/unit/test_quota.py deleted file mode 100644 index 633ff62..0000000 --- a/tests/unit/test_quota.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2013 Yahoo! 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. -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -import sys - -from quantumclient.common import exceptions -from quantumclient.quantum.v2_0 import quota as test_quota -from tests.unit import test_cli20 - - -class CLITestV20Quota(test_cli20.CLITestV20Base): - def test_show_quota(self): - resource = 'quota' - cmd = test_quota.ShowQuota( - test_cli20.MyApp(sys.stdout), None) - args = ['--tenant-id', self.test_id] - self._test_show_resource(resource, cmd, self.test_id, args) - - def test_update_quota(self): - resource = 'quota' - cmd = test_quota.UpdateQuota( - test_cli20.MyApp(sys.stdout), None) - args = ['--tenant-id', self.test_id, '--network', 'test'] - self.assertRaises( - exceptions.QuantumClientException, self._test_update_resource, - resource, cmd, self.test_id, args=args, - extrafields={'network': 'new'}) - - def test_delete_quota_get_parser(self): - cmd = test_cli20.MyApp(sys.stdout) - test_quota.DeleteQuota(cmd, None).get_parser(cmd) diff --git a/tests/unit/test_shell.py b/tests/unit/test_shell.py deleted file mode 100644 index b6a8e14..0000000 --- a/tests/unit/test_shell.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (C) 2013 Yahoo! 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. -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -import argparse -import cStringIO -import os -import re -import sys - -import fixtures -import mox -import testtools -from testtools import matchers - -from quantumclient.common import exceptions -from quantumclient import shell as openstack_shell - - -DEFAULT_USERNAME = 'username' -DEFAULT_PASSWORD = 'password' -DEFAULT_TENANT_ID = 'tenant_id' -DEFAULT_TENANT_NAME = 'tenant_name' -DEFAULT_AUTH_URL = 'http://127.0.0.1:5000/v2.0/' -DEFAULT_TOKEN = '3bcc3d3a03f44e3d8377f9247b0ad155' -DEFAULT_URL = 'http://quantum.example.org:9696/' - - -class NoExitArgumentParser(argparse.ArgumentParser): - def error(self, message): - raise exceptions.CommandError(message) - - -class ShellTest(testtools.TestCase): - - FAKE_ENV = { - 'OS_USERNAME': DEFAULT_USERNAME, - 'OS_PASSWORD': DEFAULT_PASSWORD, - 'OS_TENANT_ID': DEFAULT_TENANT_ID, - 'OS_TENANT_NAME': DEFAULT_TENANT_NAME, - 'OS_AUTH_URL': DEFAULT_AUTH_URL} - - def _tolerant_shell(self, cmd): - t_shell = openstack_shell.QuantumShell('2.0') - t_shell.run(cmd.split()) - - # Patch os.environ to avoid required auth info. - def setUp(self): - super(ShellTest, self).setUp() - self.mox = mox.Mox() - for var in self.FAKE_ENV: - self.useFixture( - fixtures.EnvironmentVariable( - var, self.FAKE_ENV[var])) - - # Make a fake shell object, a helping wrapper to call it, and a quick - # way of asserting that certain API calls were made. - global shell, _shell, assert_called, assert_called_anytime - _shell = openstack_shell.QuantumShell('2.0') - shell = lambda cmd: _shell.run(cmd.split()) - - def shell(self, argstr): - orig = sys.stdout - clean_env = {} - _old_env, os.environ = os.environ, clean_env.copy() - try: - sys.stdout = cStringIO.StringIO() - _shell = openstack_shell.QuantumShell('2.0') - _shell.run(argstr.split()) - except SystemExit: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.assertEqual(exc_value.code, 0) - finally: - out = sys.stdout.getvalue() - sys.stdout.close() - sys.stdout = orig - os.environ = _old_env - return out - - def test_run_unknown_command(self): - openstack_shell.QuantumShell('2.0').run('fake') - - def test_help(self): - required = 'usage:' - help_text = self.shell('help') - self.assertThat( - help_text, - matchers.MatchesRegex(required)) - - def test_help_on_subcommand(self): - required = [ - '.*?^usage: .* quota-list'] - stdout = self.shell('help quota-list') - for r in required: - self.assertThat( - stdout, - matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE)) - - def test_help_command(self): - required = 'usage:' - help_text = self.shell('help network-create') - self.assertThat( - help_text, - matchers.MatchesRegex(required)) - - def test_unknown_auth_strategy(self): - self.shell('--os-auth-strategy fake quota-list') - - def test_auth(self): - self.shell(' --os-username test' - ' --os-password test' - ' --os-tenant-name test' - ' --os-auth-url http://127.0.0.1:5000/' - ' --os-auth-strategy keystone quota-list') - - def test_build_option_parser(self): - quant_shell = openstack_shell.QuantumShell('2.0') - result = quant_shell.build_option_parser('descr', '2.0') - self.assertEqual(True, isinstance(result, argparse.ArgumentParser)) - - def test_main_with_unicode(self): - self.mox.StubOutClassWithMocks(openstack_shell, 'QuantumShell') - qshell_mock = openstack_shell.QuantumShell('2.0') - #self.mox.StubOutWithMock(qshell_mock, 'run') - unicode_text = u'\u7f51\u7edc' - argv = ['net-list', unicode_text, unicode_text.encode('utf-8')] - qshell_mock.run([u'net-list', unicode_text, - unicode_text]).AndReturn(0) - self.mox.ReplayAll() - ret = openstack_shell.main(argv=argv) - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual(ret, 0) - - def test_endpoint_option(self): - shell = openstack_shell.QuantumShell('2.0') - parser = shell.build_option_parser('descr', '2.0') - - # Neither $OS_ENDPOINT_TYPE nor --endpoint-type - namespace = parser.parse_args([]) - self.assertEqual('publicURL', namespace.endpoint_type) - - # --endpoint-type but not $OS_ENDPOINT_TYPE - namespace = parser.parse_args(['--endpoint-type=admin']) - self.assertEqual('admin', namespace.endpoint_type) - - def test_endpoint_environment_variable(self): - fixture = fixtures.EnvironmentVariable("OS_ENDPOINT_TYPE", - "public") - self.useFixture(fixture) - - shell = openstack_shell.QuantumShell('2.0') - parser = shell.build_option_parser('descr', '2.0') - - # $OS_ENDPOINT_TYPE but not --endpoint-type - namespace = parser.parse_args([]) - self.assertEqual("public", namespace.endpoint_type) - - # --endpoint-type and $OS_ENDPOINT_TYPE - namespace = parser.parse_args(['--endpoint-type=admin']) - self.assertEqual('admin', namespace.endpoint_type) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py deleted file mode 100644 index d7d1520..0000000 --- a/tests/unit/test_utils.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright (C) 2013 Yahoo! 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. -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -import datetime -import sys - -import testtools - -from quantumclient.common import exceptions -from quantumclient.common import utils - - -class TestUtils(testtools.TestCase): - def test_string_to_bool_true(self): - self.assertTrue(utils.str2bool('true')) - - def test_string_to_bool_false(self): - self.assertFalse(utils.str2bool('false')) - - def test_string_to_bool_None(self): - self.assertIsNone(utils.str2bool(None)) - - def test_string_to_dictionary(self): - input_str = 'key1=value1,key2=value2' - expected = {'key1': 'value1', 'key2': 'value2'} - self.assertEqual(expected, utils.str2dict(input_str)) - - def test_get_dict_item_properties(self): - item = {'name': 'test_name', 'id': 'test_id'} - fields = ('name', 'id') - actual = utils.get_item_properties(item=item, fields=fields) - self.assertEqual(('test_name', 'test_id'), actual) - - def test_get_object_item_properties_mixed_case_fields(self): - class Fake(object): - def __init__(self): - self.id = 'test_id' - self.name = 'test_name' - self.test_user = 'test' - - fields = ('name', 'id', 'test user') - mixed_fields = ('test user', 'ID') - item = Fake() - actual = utils.get_item_properties(item, fields, mixed_fields) - self.assertEqual(('test_name', 'test_id', 'test'), actual) - - def test_get_object_item_desired_fields_differ_from_item(self): - class Fake(object): - def __init__(self): - self.id = 'test_id_1' - self.name = 'test_name' - self.test_user = 'test' - - fields = ('name', 'id', 'test user') - item = Fake() - actual = utils.get_item_properties(item, fields) - self.assertNotEqual(('test_name', 'test_id', 'test'), actual) - - def test_get_object_item_desired_fields_is_empty(self): - class Fake(object): - def __init__(self): - self.id = 'test_id_1' - self.name = 'test_name' - self.test_user = 'test' - - fields = [] - item = Fake() - actual = utils.get_item_properties(item, fields) - self.assertEqual((), actual) - - def test_get_object_item_with_formatters(self): - class Fake(object): - def __init__(self): - self.id = 'test_id' - self.name = 'test_name' - self.test_user = 'test' - - class FakeCallable(object): - def __call__(self, *args, **kwargs): - return 'pass' - - fields = ('name', 'id', 'test user', 'is_public') - formatters = {'is_public': FakeCallable()} - item = Fake() - act = utils.get_item_properties(item, fields, formatters=formatters) - self.assertEqual(('test_name', 'test_id', 'test', 'pass'), act) - - -class JSONUtilsTestCase(testtools.TestCase): - def test_dumps(self): - self.assertEqual(utils.dumps({'a': 'b'}), '{"a": "b"}') - - def test_dumps_dict_with_date_value(self): - x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7) - res = utils.dumps({1: 'a', 2: x}) - expected = '{"1": "a", "2": "1920-02-03 04:05:06.000007"}' - self.assertEqual(expected, res) - - def test_dumps_dict_with_spaces(self): - x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7) - res = utils.dumps({1: 'a ', 2: x}) - expected = '{"1": "a ", "2": "1920-02-03 04:05:06.000007"}' - self.assertEqual(expected, res) - - def test_loads(self): - self.assertEqual(utils.loads('{"a": "b"}'), {'a': 'b'}) - - -class ToPrimitiveTestCase(testtools.TestCase): - def test_list(self): - self.assertEqual(utils.to_primitive([1, 2, 3]), [1, 2, 3]) - - def test_empty_list(self): - self.assertEqual(utils.to_primitive([]), []) - - def test_tuple(self): - self.assertEqual(utils.to_primitive((1, 2, 3)), [1, 2, 3]) - - def test_empty_tuple(self): - self.assertEqual(utils.to_primitive(()), []) - - def test_dict(self): - self.assertEqual( - utils.to_primitive(dict(a=1, b=2, c=3)), - dict(a=1, b=2, c=3)) - - def test_empty_dict(self): - self.assertEqual(utils.to_primitive({}), {}) - - def test_datetime(self): - x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7) - self.assertEqual( - utils.to_primitive(x), - '1920-02-03 04:05:06.000007') - - def test_iter(self): - x = xrange(1, 6) - self.assertEqual(utils.to_primitive(x), [1, 2, 3, 4, 5]) - - def test_iteritems(self): - d = {'a': 1, 'b': 2, 'c': 3} - - class IterItemsClass(object): - def iteritems(self): - return d.iteritems() - - x = IterItemsClass() - p = utils.to_primitive(x) - self.assertEqual(p, {'a': 1, 'b': 2, 'c': 3}) - - def test_nasties(self): - def foo(): - pass - x = [datetime, foo, dir] - ret = utils.to_primitive(x) - self.assertEqual(len(ret), 3) - - def test_to_primitive_dict_with_date_value(self): - x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7) - res = utils.to_primitive({'a': x}) - self.assertEqual({'a': '1920-02-03 04:05:06.000007'}, res) - - -class ImportClassTestCase(testtools.TestCase): - def test_import_class(self): - dt = utils.import_class('datetime.datetime') - self.assertTrue(sys.modules['datetime'].datetime is dt) - - def test_import_bad_class(self): - self.assertRaises( - ImportError, utils.import_class, - 'lol.u_mad.brah') - - def test_get_client_class_invalid_version(self): - self.assertRaises( - exceptions.UnsupportedVersion, - utils.get_client_class, 'image', '2', {'image': '2'})