[python-neutronclient/f21] Fix listing security group rules

Jakub Ruzicka jruzicka at fedoraproject.org
Thu Aug 21 15:39:18 UTC 2014


commit 7ddca4eba148fdcf4563b337578a0b69a397e8fd
Author: Jakub Ruzicka <jruzicka at redhat.com>
Date:   Thu Aug 21 17:38:56 2014 +0200

    Fix listing security group rules

 0002-Fix-listing-security-group-rules.patch |  180 +++++++++++++++++++++++++++
 python-neutronclient.spec                   |    7 +-
 2 files changed, 186 insertions(+), 1 deletions(-)
---
diff --git a/0002-Fix-listing-security-group-rules.patch b/0002-Fix-listing-security-group-rules.patch
new file mode 100644
index 0000000..06255dc
--- /dev/null
+++ b/0002-Fix-listing-security-group-rules.patch
@@ -0,0 +1,180 @@
+From 1bc908fdd08ae207785ab2ad572e7289acf4d246 Mon Sep 17 00:00:00 2001
+From: liuweicai <liuuweicai at gmail.com>
+Date: Wed, 28 May 2014 10:07:43 +0800
+Subject: [PATCH] Fix listing security group rules
+
+It was failing when there are too many security groups, since we're
+hitting a RequestURITooLong exception.
+
+Co-Authored-By: Vincent Untz <vuntz at suse.com>
+Co-Authored-By: Ilya Shakhat <ishakhat at mirantis.com>
+Change-Id: If94b6a2ed6878efad1224e056ecf43e65e85e821
+Closes-Bug: 1271462
+---
+ neutronclient/neutron/v2_0/securitygroup.py        | 29 ++++++-
+ .../tests/unit/test_cli20_securitygroup.py         | 97 ++++++++++++++++++++++
+ 2 files changed, 123 insertions(+), 3 deletions(-)
+
+diff --git a/neutronclient/neutron/v2_0/securitygroup.py b/neutronclient/neutron/v2_0/securitygroup.py
+index b59eba5..06d1c4a 100644
+--- a/neutronclient/neutron/v2_0/securitygroup.py
++++ b/neutronclient/neutron/v2_0/securitygroup.py
+@@ -17,6 +17,7 @@
+ import argparse
+ import logging
+ 
++from neutronclient.common import exceptions
+ from neutronclient.neutron import v2_0 as neutronV20
+ from neutronclient.openstack.common.gettextutils import _
+ 
+@@ -141,9 +142,31 @@ class ListSecurityGroupRule(neutronV20.ListCommand):
+         for rule in data:
+             for key in self.replace_rules:
+                 sec_group_ids.add(rule[key])
+-        search_opts.update({"id": sec_group_ids})
+-        secgroups = neutron_client.list_security_groups(**search_opts)
+-        secgroups = secgroups.get('security_groups', [])
++        sec_group_ids = list(sec_group_ids)
++
++        def _get_sec_group_list(sec_group_ids):
++            search_opts['id'] = sec_group_ids
++            return neutron_client.list_security_groups(
++                **search_opts).get('security_groups', [])
++
++        try:
++            secgroups = _get_sec_group_list(sec_group_ids)
++        except exceptions.RequestURITooLong as uri_len_exc:
++            # Length of a query filter on security group rule id
++            # id=<uuid>& (with len(uuid)=36)
++            sec_group_id_filter_len = 40
++            # The URI is too long because of too many sec_group_id filters
++            # Use the excess attribute of the exception to know how many
++            # sec_group_id filters can be inserted into a single request
++            sec_group_count = len(sec_group_ids)
++            max_size = ((sec_group_id_filter_len * sec_group_count) -
++                        uri_len_exc.excess)
++            chunk_size = max_size / sec_group_id_filter_len
++            secgroups = []
++            for i in range(0, sec_group_count, chunk_size):
++                secgroups.extend(
++                    _get_sec_group_list(sec_group_ids[i: i + chunk_size]))
++
+         sg_dict = dict([(sg['id'], sg['name'])
+                         for sg in secgroups if sg['name']])
+         for rule in data:
+diff --git a/neutronclient/tests/unit/test_cli20_securitygroup.py b/neutronclient/tests/unit/test_cli20_securitygroup.py
+index 3ffd023..72267c7 100644
+--- a/neutronclient/tests/unit/test_cli20_securitygroup.py
++++ b/neutronclient/tests/unit/test_cli20_securitygroup.py
+@@ -17,7 +17,10 @@
+ import sys
+ 
+ import mox
++import six
+ 
++from neutronclient.common import exceptions
++from neutronclient.common import utils
+ from neutronclient.neutron.v2_0 import securitygroup
+ from neutronclient.tests.unit import test_cli20
+ 
+@@ -186,6 +189,100 @@ class CLITestV20SecurityGroupsJSON(test_cli20.CLITestV20Base):
+                                                         mox.IgnoreArg())
+         self._test_list_resources(resources, cmd, True)
+ 
++    def _test_extend_list(self, mox_calls):
++        resources = "security_groups"
++
++        data = [{'name': 'default',
++                 'security_group_id': 'secgroupid%02d' % i,
++                 'remote_group_id': 'remgroupid%02d' % i}
++                for i in range(10)]
++
++        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().MultipleTimes().AndReturn(self.client)
++        path = getattr(self.client, resources + '_path')
++        mox_calls(path, data)
++        self.mox.ReplayAll()
++        known_args, _vs = cmd.get_parser(
++            'list' + resources).parse_known_args()
++
++        cmd.extend_list(data, known_args)
++        self.mox.VerifyAll()
++        self.mox.UnsetStubs()
++
++    def _build_test_data(self, data, excess=0):
++        # Length of a query filter on security group rule id
++        # in these testcases, id='secgroupid%02d' (with len(id)=12)
++        sec_group_id_filter_len = 12
++
++        response = []
++        replace_rules = {'security_group_id': 'security_group',
++                         'remote_group_id': 'remote_group'}
++
++        search_opts = {'fields': ['id', 'name']}
++        sec_group_ids = set()
++        for rule in data:
++            for key in replace_rules:
++                sec_group_ids.add(rule[key])
++                response.append({'id': rule[key], 'name': 'default'})
++        sec_group_ids = list(sec_group_ids)
++
++        result = []
++
++        sec_group_count = len(sec_group_ids)
++        max_size = ((sec_group_id_filter_len * sec_group_count) - excess)
++        chunk_size = max_size / sec_group_id_filter_len
++
++        for i in range(0, sec_group_count, chunk_size):
++            search_opts['id'] = sec_group_ids[i: i + chunk_size]
++            params = utils.safe_encode_dict(search_opts)
++            resp_str = self.client.serialize({'security_groups': response})
++
++            result.append({
++                'filter': six.moves.urllib.parse.urlencode(params, doseq=1),
++                'response': (test_cli20.MyResp(200), resp_str),
++            })
++
++        return result
++
++    def test_extend_list(self):
++        def mox_calls(path, data):
++            responses = self._build_test_data(data)
++            self.client.httpclient.request(
++                test_cli20.MyUrlComparator(test_cli20.end_url(
++                    path, responses[0]['filter']), self.client),
++                'GET',
++                body=None,
++                headers=mox.ContainsKeyValue(
++                    'X-Auth-Token', test_cli20.TOKEN)).AndReturn(
++                        responses[0]['response'])
++
++        self._test_extend_list(mox_calls)
++
++    def test_extend_list_exceed_max_uri_len(self):
++        def mox_calls(path, 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))
++            responses = self._build_test_data(data, excess=1)
++
++            for item in responses:
++                self.client._check_uri_length(
++                    mox.IgnoreArg()).AndReturn(None)
++                self.client.httpclient.request(
++                    test_cli20.end_url(path, item['filter']),
++                    'GET',
++                    body=None,
++                    headers=mox.ContainsKeyValue(
++                        'X-Auth-Token', test_cli20.TOKEN)).AndReturn(
++                            item['response'])
++
++        self._test_extend_list(mox_calls)
++
+     def test_list_security_group_rules_pagination(self):
+         resources = "security_group_rules"
+         cmd = securitygroup.ListSecurityGroupRule(
diff --git a/python-neutronclient.spec b/python-neutronclient.spec
index db0c8fa..3d2e9aa 100644
--- a/python-neutronclient.spec
+++ b/python-neutronclient.spec
@@ -1,6 +1,6 @@
 Name:       python-neutronclient
 Version:    2.3.4
-Release:    2%{?dist}
+Release:    3%{?dist}
 Summary:    Python API and CLI for OpenStack Neutron
 
 Group:      Development/Languages
@@ -12,6 +12,7 @@ Source0:    https://pypi.python.org/packages/source/p/%{name}/%{name}-%{version}
 # patches_base=2.3.4
 #
 Patch0001: 0001-Remove-runtime-dependency-on-python-pbr.patch
+Patch0002: 0002-Fix-listing-security-group-rules.patch
 
 BuildArch:  noarch
 
@@ -34,6 +35,7 @@ Neutron's API.
 %setup -q -n %{name}-%{version}
 
 %patch0001 -p1
+%patch0002 -p1
 
 # We provide version like this in order to remove runtime dep on pbr.
 sed -i s/REDHATNEUTRONCLIENTVERSION/%{version}/ neutronclient/version.py
@@ -63,6 +65,9 @@ rm -rf %{buildroot}%{python_sitelib}/neutronclient/tests
 %{_sysconfdir}/bash_completion.d
 
 %changelog
+* Thu Aug 21 2014 Jakub Ruzicka <jruzicka at redhat.com> 2.3.4-3
+- Fix listing security group rules
+
 * Sat Jun 07 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 2.3.4-2
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
 


More information about the scm-commits mailing list