Merge "Avoid error 414 when retrieving subnet cidrs for ListNetworks"

This commit is contained in:
Jenkins 2013-05-22 08:58:37 +00:00 committed by Gerrit Code Review
commit 5011a21cb3
5 changed files with 110 additions and 4 deletions

View File

@ -140,12 +140,14 @@ class HTTPClient(httplib2.Http):
raise exceptions.Forbidden(message=body)
return resp, body
def do_request(self, url, method, **kwargs):
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.

View File

@ -131,6 +131,14 @@ class QuantumCLIError(QuantumClientException):
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")

View File

@ -18,6 +18,7 @@
import argparse
import logging
from quantumclient.common import exceptions
from quantumclient.quantum.v2_0 import CreateCommand
from quantumclient.quantum.v2_0 import DeleteCommand
from quantumclient.quantum.v2_0 import ListCommand
@ -36,6 +37,9 @@ def _format_subnets(network):
class ListNetwork(ListCommand):
"""List networks that belong to a given tenant."""
# Length of a query filter on subnet id
# id=<uuid>& (with len(uuid)=36)
subnet_id_filter_len = 40
resource = 'network'
log = logging.getLogger(__name__ + '.ListNetwork')
_formatters = {'subnets': _format_subnets, }
@ -55,8 +59,27 @@ class ListNetwork(ListCommand):
for n in data:
if 'subnets' in n:
subnet_ids.extend(n['subnets'])
search_opts.update({'id': subnet_ids})
subnets = quantum_client.list_subnets(**search_opts).get('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:

View File

@ -199,6 +199,8 @@ class Client(object):
'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':
@ -912,6 +914,12 @@ class Client(object):
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()
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)
if body:
body = self.serialize(body)
self.httpclient.content_type = self.content_type()

View File

@ -1,4 +1,3 @@
# Copyright 2012 OpenStack LLC.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -473,6 +472,72 @@ class CLITestV20NetworkJSON(CLITestV20Base):
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 = ListNetwork(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=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.client.httpclient.request(
test_cli20.end_url(path, 'fields=id&fields=cidr%s' % filters),
'GET',
body=None,
headers=ContainsKeyValue(
'X-Auth-Token', test_cli20.TOKEN)).AndRaise(
exceptions.RequestURITooLong(excess=1))
for data in sub_data_lists:
filters, response = self._build_test_data(data)
self.client.httpclient.request(
test_cli20.end_url(path,
'fields=id&fields=cidr%s' % filters),
'GET',
body=None,
headers=ContainsKeyValue(
'X-Auth-Token', test_cli20.TOKEN)).AndReturn(response)
self._test_extend_list(mox_calls)
class CLITestV20NetworkXML(CLITestV20NetworkJSON):
format = 'xml'