Fix creation of trusted queues for the NVP plugin.

Currently if an admin tries to create a trusted queue, Neutron will
fail with MissingDSCPForTrusted exception. However, the NVP semantic
is exactly the opposite, namely the DSCP field must be specified for
untrusted queues and omitted trusted ones.

Fixes bug #1204256

Change-Id: I935fab45fc811a296411283a641b66c5ca96264d
This commit is contained in:
armando-migliaccio 2013-07-23 14:19:27 -07:00
parent 617119dbaa
commit 5d8e7dacdd
3 changed files with 31 additions and 8 deletions

View File

@ -22,11 +22,15 @@ from sqlalchemy.orm import exc
from neutron.api.v2 import attributes as attr from neutron.api.v2 import attributes as attr
from neutron.db import model_base from neutron.db import model_base
from neutron.db import models_v2 from neutron.db import models_v2
from neutron.openstack.common import log
from neutron.openstack.common import uuidutils from neutron.openstack.common import uuidutils
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira import nvplib from neutron.plugins.nicira import nvplib
LOG = log.getLogger(__name__)
class QoSQueue(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant): class QoSQueue(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
name = sa.Column(sa.String(255)) name = sa.Column(sa.String(255))
default = sa.Column(sa.Boolean, default=False) default = sa.Column(sa.Boolean, default=False)
@ -267,9 +271,10 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
raise ext_qos.DefaultQueueAlreadyExists() raise ext_qos.DefaultQueueAlreadyExists()
else: else:
raise ext_qos.DefaultQueueCreateNotAdmin() raise ext_qos.DefaultQueueCreateNotAdmin()
if (qos_queue.get('qos_marking') == 'trusted' and if qos_queue.get('qos_marking') == 'trusted':
not qos_queue.get('dscp')): dscp = qos_queue.pop('dscp')
raise ext_qos.MissingDSCPForTrusted() LOG.info(_("DSCP value (%s) will be ignored with 'trusted' "
"marking"), dscp)
max = qos_queue.get('max') max = qos_queue.get('max')
min = qos_queue.get('min') min = qos_queue.get('min')
# Max can be None # Max can be None

View File

@ -56,10 +56,6 @@ class QueueInvalidBandwidth(qexception.InvalidInput):
" integer.") " integer.")
class MissingDSCPForTrusted(qexception.InvalidInput):
message = _("No DSCP field needed when QoS workload marked trusted")
class QueueNotFound(qexception.NotFound): class QueueNotFound(qexception.NotFound):
message = _("Queue %(id)s does not exist") message = _("Queue %(id)s does not exist")
@ -91,7 +87,19 @@ def convert_to_unsigned_int_or_none_max_63(val):
raise QueueInvalidDscp(data=val) raise QueueInvalidDscp(data=val)
return val return val
# Attribute Map # As per NVP API, if a queue is trusted, DSCP must be omitted; if a queue is
# untrusted, DSCP must be specified. Whichever default values we choose for
# the tuple (qos_marking, dscp), there will be at least one combination of a
# request with conflicting values: for instance, with the following default:
#
# qos_marking = 'untrusted', dscp = '0'
#
# requests with qos_marking = 'trusted' and a default dscp will fail. Since
# it is convoluted to ask the admin to specify a None value for dscp when
# qos_marking is 'trusted', it is best to ignore the dscp value, regardless
# of whether it has been specified or not. This preserves the chosen default
# and keeps backward compatibility with the API. A warning will be logged, as
# the server is overriding a potentially conflicting request from the admin
RESOURCE_ATTRIBUTE_MAP = { RESOURCE_ATTRIBUTE_MAP = {
'qos_queues': { 'qos_queues': {
'id': {'allow_post': False, 'allow_put': False, 'id': {'allow_post': False, 'allow_put': False,

View File

@ -31,6 +31,7 @@ from neutron.extensions import securitygroup as secgrp
from neutron import manager from neutron import manager
from neutron.openstack.common import uuidutils from neutron.openstack.common import uuidutils
import neutron.plugins.nicira as nvp_plugin import neutron.plugins.nicira as nvp_plugin
from neutron.plugins.nicira.dbexts import nicira_qos_db as qos_db
from neutron.plugins.nicira.extensions import nvp_networkgw from neutron.plugins.nicira.extensions import nvp_networkgw
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira import NeutronPlugin from neutron.plugins.nicira import NeutronPlugin
@ -666,6 +667,15 @@ class TestNiciraQoSQueue(NiciraPluginV2TestCase):
self.assertEqual(q['qos_queue']['qos_marking'], 'untrusted') self.assertEqual(q['qos_queue']['qos_marking'], 'untrusted')
self.assertFalse(q['qos_queue']['default']) self.assertFalse(q['qos_queue']['default'])
def test_create_trusted_qos_queue(self):
with mock.patch.object(qos_db.LOG, 'info') as log:
with mock.patch.object(nvplib, 'do_request',
return_value={"uuid": "fake_queue"}):
with self.qos_queue(name='fake_lqueue', min=34, max=44,
qos_marking='trusted', default=False) as q:
self.assertEqual(q['qos_queue']['dscp'], None)
self.assertTrue(log.called)
def test_create_qos_queue_name_exceeds_40_chars(self): def test_create_qos_queue_name_exceeds_40_chars(self):
name = 'this_is_a_queue_whose_name_is_longer_than_40_chars' name = 'this_is_a_queue_whose_name_is_longer_than_40_chars'
with self.qos_queue(name=name) as queue: with self.qos_queue(name=name) as queue: