From 78ad376117590ed30226364ef9fc221e244ac388 Mon Sep 17 00:00:00 2001 From: Dongcan Ye Date: Fri, 27 Nov 2015 01:04:57 +0800 Subject: [PATCH] Validate connection limit for LBaaS Currently, LBaaS V1 vip's connection_limit and LBaaS V2 listeners' connection_limit can be set to a value less than -1. This patch add a validation for V1 vip's and V2 listeners' connection_limit resource. Setting value less than -1 is not allowed. Closes-Bug: #1520138 Change-Id: I9332cfeda89b87dfda9cd16dcc8b1d78b6e1dc41 --- neutron_lbaas/extensions/loadbalancer.py | 10 +++- neutron_lbaas/extensions/loadbalancerv2.py | 18 +++++- .../services/loadbalancer/constants.py | 5 ++ .../loadbalancer/test_loadbalancer_plugin.py | 55 +++++++++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/neutron_lbaas/extensions/loadbalancer.py b/neutron_lbaas/extensions/loadbalancer.py index 65eec8f9c..9d93424b5 100644 --- a/neutron_lbaas/extensions/loadbalancer.py +++ b/neutron_lbaas/extensions/loadbalancer.py @@ -26,6 +26,8 @@ from neutron.common import exceptions as nexception from neutron import manager from neutron.plugins.common import constants from neutron.services import service_base +from neutron_lbaas.extensions import loadbalancerv2 +from neutron_lbaas.services.loadbalancer import constants as lb_const LOADBALANCER_PREFIX = "/lb" @@ -96,6 +98,10 @@ class MemberExists(nexception.NeutronException): "already present in pool %(pool)s") +attr.validators['type:connection_limit'] = ( + loadbalancerv2._validate_connection_limit) + + RESOURCE_ATTRIBUTE_MAP = { 'vips': { 'id': {'allow_post': False, 'allow_put': False, @@ -146,7 +152,9 @@ RESOURCE_ATTRIBUTE_MAP = { 'required': False}}}, 'is_visible': True}, 'connection_limit': {'allow_post': True, 'allow_put': True, - 'default': -1, + 'validate': {'type:connection_limit': + lb_const.MIN_CONNECT_VALUE}, + 'default': lb_const.MIN_CONNECT_VALUE, 'convert_to': attr.convert_to_int, 'is_visible': True}, 'admin_state_up': {'allow_post': True, 'allow_put': True, diff --git a/neutron_lbaas/extensions/loadbalancerv2.py b/neutron_lbaas/extensions/loadbalancerv2.py index d3d084a25..702760981 100644 --- a/neutron_lbaas/extensions/loadbalancerv2.py +++ b/neutron_lbaas/extensions/loadbalancerv2.py @@ -17,6 +17,7 @@ import abc from oslo_config import cfg +from oslo_log import log as logging import six from neutron.api import extensions @@ -32,6 +33,8 @@ from neutron_lbaas.services.loadbalancer import constants as lb_const LOADBALANCERV2_PREFIX = "/lbaas" +LOG = logging.getLogger(__name__) + # Loadbalancer Exceptions # This exception is only for a workaround when having v1 and v2 lbaas extension @@ -132,6 +135,17 @@ class FlavorsPluginNotLoaded(nexception.NotFound): message = _("Flavors plugin not found") +def _validate_connection_limit(data, min_value=lb_const.MIN_CONNECT_VALUE): + if int(data) < min_value: + msg = (_("'%(data)s' is not a valid value, " + "because it cannot be less than %(min_value)s") % + {'data': data, 'min_value': min_value}) + LOG.debug(msg) + return msg + +attr.validators['type:connection_limit'] = _validate_connection_limit + + RESOURCE_ATTRIBUTE_MAP = { 'loadbalancers': { 'id': {'allow_post': False, 'allow_put': False, @@ -210,7 +224,9 @@ RESOURCE_ATTRIBUTE_MAP = { 'convert_to': attr.convert_to_list, 'is_visible': True}, 'connection_limit': {'allow_post': True, 'allow_put': True, - 'default': -1, + 'validate': {'type:connection_limit': + lb_const.MIN_CONNECT_VALUE}, + 'default': lb_const.MIN_CONNECT_VALUE, 'convert_to': attr.convert_to_int, 'is_visible': True}, 'protocol': {'allow_post': True, 'allow_put': False, diff --git a/neutron_lbaas/services/loadbalancer/constants.py b/neutron_lbaas/services/loadbalancer/constants.py index df42c0164..0a726ef90 100644 --- a/neutron_lbaas/services/loadbalancer/constants.py +++ b/neutron_lbaas/services/loadbalancer/constants.py @@ -113,3 +113,8 @@ LOADBALANCER_AGENT = 'n-lbaas_agent' LOADBALANCER = "LOADBALANCER" LOADBALANCERV2 = "LOADBALANCERV2" + +# Used to check number of connections per second allowed +# for the LBaaS V1 vip and LBaaS V2 listeners. -1 indicates +# no limit, the value cannot be less than -1. +MIN_CONNECT_VALUE = -1 diff --git a/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py b/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py index 098b2cd00..744dd75a2 100644 --- a/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py +++ b/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py @@ -69,6 +69,24 @@ class LoadBalancerExtensionTestCase(base.ExtensionTestCase): self.assertIn('vip', res) self.assertEqual(return_value, res['vip']) + def test_vip_create_with_connection_limit_smaller_than_min_value(self): + data = {'vip': {'name': 'vip1', + 'description': 'descr_vip1', + 'subnet_id': _uuid(), + 'address': '127.0.0.1', + 'protocol_port': 80, + 'protocol': 'HTTP', + 'pool_id': _uuid(), + 'session_persistence': {'type': 'HTTP_COOKIE'}, + 'connection_limit': -4, + 'admin_state_up': True, + 'tenant_id': _uuid()}} + res = self.api.post(_get_path('lb/vips', fmt=self.fmt), + self.serialize(data), + content_type='application/%s' % self.fmt, + expect_errors=True) + self.assertEqual(exc.HTTPBadRequest.code, res.status_int) + def test_vip_list(self): vip_id = _uuid() return_value = [{'name': 'vip1', @@ -107,6 +125,15 @@ class LoadBalancerExtensionTestCase(base.ExtensionTestCase): self.assertIn('vip', res) self.assertEqual(return_value, res['vip']) + def test_vip_update_with_connection_limit_smaller_than_min_value(self): + vip_id = _uuid() + data = {'vip': {'connection_limit': -4}} + res = self.api.put(_get_path('lb/vips', id=vip_id, fmt=self.fmt), + self.serialize(data), + content_type='application/%s' % self.fmt, + expect_errors=True) + self.assertEqual(exc.HTTPBadRequest.code, res.status_int) + def test_vip_get(self): vip_id = _uuid() return_value = {'name': 'vip1', @@ -651,6 +678,24 @@ class LoadBalancerExtensionV2TestCase(base.ExtensionTestCase): self.assertIn('listener', res) self.assertEqual(res['listener'], return_value) + def test_listener_create_with_connection_limit_less_than_min_value(self): + data = {'listener': {'tenant_id': _uuid(), + 'name': 'listen-name-1', + 'description': 'listen-1-desc', + 'protocol': 'HTTP', + 'protocol_port': 80, + 'default_tls_container_ref': None, + 'sni_container_refs': [], + 'connection_limit': -4, + 'admin_state_up': True, + 'loadbalancer_id': _uuid()}} + + res = self.api.post(_get_path('lbaas/listeners', fmt=self.fmt), + self.serialize(data), + content_type='application/{0}'.format(self.fmt), + expect_errors=True) + self.assertEqual(exc.HTTPBadRequest.code, res.status_int) + def test_listener_list(self): listener_id = _uuid() return_value = [{'admin_state_up': True, @@ -718,6 +763,16 @@ class LoadBalancerExtensionV2TestCase(base.ExtensionTestCase): self.assertIn('listener', res) self.assertEqual(res['listener'], return_value) + def test_listener_update_with_connection_limit_less_than_min_value(self): + listener_id = _uuid() + update_data = {'listener': {'connection_limit': -4}} + res = self.api.put(_get_path('lbaas/listeners', + id=listener_id, + fmt=self.fmt), + self.serialize(update_data), + expect_errors=True) + self.assertEqual(exc.HTTPBadRequest.code, res.status_int) + def test_listener_get(self): listener_id = _uuid() return_value = {'name': 'listener1',