NSX QoS ext: RXTX factor can be decimal

In Nova flavors it is ok to specify a decimal RXTX factor.
For this reason when applying QoS to a port Neutron should not
convert this factor to an integer value, but simply ensure
it's a valid float number and positive.

This patch ialso drops the conversion to integer that happens
in the NSX-mh plugin but also ensures that the resulting maximum
bandwidth after applying the RXTX factor is still an integer value.

Closes-Bug: #1463363
Patch applied from commit: 9f61b082093fde7db135f400d7d99724c6c01a43
Change-Id: I9f5e166e349de0703a8711fa73a127e90059f506
This commit is contained in:
Salvatore Orlando 2015-06-09 03:41:07 -07:00
parent d9c78880d2
commit 86701a3c7e
5 changed files with 64 additions and 6 deletions

View File

@ -553,6 +553,24 @@ def convert_to_int(data):
raise n_exc.InvalidInput(error_message=msg)
def convert_to_positive_float_or_none(val):
# NOTE(salv-orlando): This conversion function is currently used by
# a vendor specific extension only at the moment It is used for
# port's RXTX factor in neutron.plugins.vmware.extensions.qos.
# It is deemed however generic enough to be in this module as it
# might be used in future for other API attributes.
if val is None:
return
try:
val = float(val)
if val < 0:
raise ValueError()
except (ValueError, TypeError):
msg = _("'%s' must be a non negative decimal.") % val
raise n_exc.InvalidInput(error_message=msg)
return val
def convert_kvp_str_to_list(data):
"""Convert a value of the form 'key=value' to ['key', 'value'].

View File

@ -270,7 +270,8 @@ class QoSDbMixin(qos.QueuePluginBase):
# create the queue
tenant_id = self._get_tenant_id_for_create(context, port)
if port.get(qos.RXTX_FACTOR) and queue_to_create.get('max'):
queue_to_create['max'] *= int(port[qos.RXTX_FACTOR])
queue_to_create['max'] = int(queue_to_create['max'] *
port[qos.RXTX_FACTOR])
queue = {'qos_queue': {'name': queue_to_create.get('name'),
'min': queue_to_create.get('min'),
'max': queue_to_create.get('max'),

View File

@ -145,7 +145,7 @@ EXTENDED_ATTRIBUTES_2_0 = {
'is_visible': False,
'default': 1,
'enforce_policy': True,
'convert_to': convert_to_unsigned_int_or_none},
'convert_to': attr.convert_to_positive_float_or_none},
QUEUE: {'allow_post': False,
'allow_put': False,

View File

@ -774,6 +774,35 @@ class TestConvertToInt(base.BaseTestCase):
value, attributes.convert_none_to_empty_list(value))
class TestConvertToFloat(base.BaseTestCase):
# NOTE: the routine being tested here is a plugin-specific extension
# module. As the plugin split proceed towards its second phase this
# test should either be remove, or the validation routine moved into
# neutron.api.v2.attributes
def test_convert_to_float_positve_value(self):
self.assertEqual(
1.111, attributes.convert_to_positive_float_or_none(1.111))
self.assertEqual(1, attributes.convert_to_positive_float_or_none(1))
self.assertEqual(0, attributes.convert_to_positive_float_or_none(0))
def test_convert_to_float_negative_value(self):
self.assertRaises(n_exc.InvalidInput,
attributes.convert_to_positive_float_or_none,
-1.11)
def test_convert_to_float_string(self):
self.assertEqual(4, attributes.convert_to_positive_float_or_none('4'))
self.assertEqual(
4.44, attributes.convert_to_positive_float_or_none('4.44'))
self.assertRaises(n_exc.InvalidInput,
attributes.convert_to_positive_float_or_none,
'garbage')
def test_convert_to_float_none_value(self):
self.assertIsNone(attributes.convert_to_positive_float_or_none(None))
class TestConvertKvp(base.BaseTestCase):
def test_convert_kvp_list_to_dict_succeeds_for_missing_values(self):

View File

@ -262,8 +262,8 @@ class TestQoSQueue(test_nsx_plugin.NsxPluginV2TestCase):
neutron_context=neutron_context)
self.assertNotIn(ext_qos.QUEUE, port['port'])
def test_rxtx_factor(self):
with self.qos_queue(max=10) as q1:
def _test_rxtx_factor(self, max_value, rxtx_factor):
with self.qos_queue(max=max_value) as q1:
res = self._create_network('json', 'net1', True,
arg_list=(ext_qos.QUEUE,),
@ -271,10 +271,20 @@ class TestQoSQueue(test_nsx_plugin.NsxPluginV2TestCase):
net1 = self.deserialize('json', res)
res = self._create_port('json', net1['network']['id'],
arg_list=(ext_qos.RXTX_FACTOR,),
rxtx_factor=2, device_id='1')
rxtx_factor=rxtx_factor, device_id='1')
port = self.deserialize('json', res)
req = self.new_show_request('qos-queues',
port['port'][ext_qos.QUEUE])
res = req.get_response(self.ext_api)
queue = self.deserialize('json', res)
self.assertEqual(queue['qos_queue']['max'], 20)
self.assertEqual(queue['qos_queue']['max'],
max_value * rxtx_factor)
def test_rxtx_factor(self):
self._test_rxtx_factor(10, 2)
def test_decimal_rxtx_factor(self):
self._test_rxtx_factor(10, 1.5)
def test_decimal_rxtx_factor_below_1(self):
self._test_rxtx_factor(10, 0.5)