Add qos_network_policy_id to Port OVO

Added field "qos_network_policy_id" to Port OVO. This parameter
will be used to retrieve the QoS policy bound to the port network.
This reduces the number of calls to the database by creating a join
between the QosNetworkPolicyBinding table and the Port table, based
on the network ID.

This backref association is not persistent (marked as "viewonly").
This relationship is using for loading the QoS policy ID of the
port network in the Port OVO.

Related-Bug: #1834484

Change-Id: I219a925d5e269b8c73a0481daa879d72c399fd8f
(cherry picked from commit 66fca96e52)
This commit is contained in:
Rodolfo Alonso Hernandez 2019-06-27 15:02:33 +00:00 committed by Nate Johnston
parent 9f4e596f1c
commit b452c508b6
5 changed files with 52 additions and 11 deletions

View File

@ -54,6 +54,12 @@ class QosNetworkPolicyBinding(model_base.BASEV2):
models_v2.Network, load_on_pending=True,
backref=sa.orm.backref("qos_policy_binding", uselist=False,
cascade='delete', lazy='joined'))
port = sa.orm.relationship(
models_v2.Port,
primaryjoin='QosNetworkPolicyBinding.network_id == Port.network_id',
foreign_keys=network_id,
backref=sa.orm.backref('qos_network_policy_binding', uselist=False,
viewonly=True))
class QosFIPPolicyBinding(model_base.BASEV2):

View File

@ -265,7 +265,8 @@ class Port(base.NeutronDbObject):
# Version 1.2: Added segment_id to binding_levels
# Version 1.3: distributed_binding -> distributed_bindings
# Version 1.4: Attribute binding becomes ListOfObjectsField
VERSION = '1.4'
# Version 1.5: Added qos_network_policy_id field
VERSION = '1.5'
db_model = models_v2.Port
@ -309,6 +310,8 @@ class Port(base.NeutronDbObject):
default=None,
),
'qos_policy_id': common_types.UUIDField(nullable=True, default=None),
'qos_network_policy_id': common_types.UUIDField(nullable=True,
default=None),
'binding_levels': obj_fields.ListOfObjectsField(
'PortBindingLevel', nullable=True
@ -332,6 +335,7 @@ class Port(base.NeutronDbObject):
'dns',
'fixed_ips',
'qos_policy_id',
'qos_network_policy_id',
'security',
'security_group_ids',
]
@ -460,16 +464,18 @@ class Port(base.NeutronDbObject):
}
else:
self.security_group_ids = set()
self.obj_reset_changes(['security_group_ids'])
fields_to_change = ['security_group_ids']
# extract qos policy binding
if db_obj.get('qos_policy_binding'):
self.qos_policy_id = (
db_obj.qos_policy_binding.policy_id
)
else:
self.qos_policy_id = None
self.obj_reset_changes(['qos_policy_id'])
self.qos_policy_id = db_obj.qos_policy_binding.policy_id
fields_to_change.append('qos_policy_id')
if db_obj.get('qos_network_policy_binding'):
self.qos_network_policy_id = (
db_obj.qos_network_policy_binding.policy_id)
fields_to_change.append('qos_network_policy_binding')
self.obj_reset_changes(fields_to_change)
def obj_make_compatible(self, primitive, target_version):
_target_version = versionutils.convert_version_to_tuple(target_version)
@ -497,6 +503,8 @@ class Port(base.NeutronDbObject):
constants.ACTIVE):
primitive['binding'] = a_binding
break
if _target_version < (1, 5):
primitive.pop('qos_network_policy_id', None)
@classmethod
def get_ports_by_router(cls, context, router_id, owner, subnet):

View File

@ -1523,10 +1523,12 @@ class BaseDbObjectTestCase(_BaseObjectTestCase,
objclass.db_model(**objclass_fields)
]
def _create_test_network(self, name='test-network1', network_id=None):
def _create_test_network(self, name='test-network1', network_id=None,
qos_policy_id=None):
network_id = (uuidutils.generate_uuid() if network_id is None
else network_id)
_network = net_obj.Network(self.context, name=name, id=network_id)
_network = net_obj.Network(self.context, name=name, id=network_id,
qos_policy_id=qos_policy_id)
_network.create()
return _network

View File

@ -63,7 +63,7 @@ object_data = {
'NetworkRBAC': '1.2-192845c5ed0718e1c54fac36936fcd7d',
'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',
'NetworkSegmentRange': '1.0-bdec1fffc9058ea676089b1f2f2b3cf3',
'Port': '1.4-1b6183bccfc2cd210919a1a72faefce1',
'Port': '1.5-98f35183d876c9beb188f4bf44d4d886',
'PortBinding': '1.0-3306deeaa6deb01e33af06777d48d578',
'PortBindingLevel': '1.1-50d47f63218f87581b6cd9a62db574e5',
'PortDataPlaneStatus': '1.0-25be74bda46c749653a10357676c0ab2',

View File

@ -354,6 +354,25 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
self.context, policy_id=old_policy_id)
self.assertEqual(0, len(qos_binding_obj))
@mock.patch.object(policy.QosPolicy, 'unset_default')
def test_qos_network_policy_id(self, *mocks):
policy_obj = policy.QosPolicy(self.context)
policy_obj.create()
obj = self._make_object(self.obj_fields[0])
obj.create()
obj = ports.Port.get_object(self.context, id=obj.id)
self.assertIsNone(obj.qos_network_policy_id)
self.assertIsNone(obj.qos_policy_id)
network = self._create_test_network(qos_policy_id=policy_obj.id)
self.update_obj_fields({'network_id': network.id})
obj = self._make_object(self.obj_fields[1])
obj.create()
obj = ports.Port.get_object(self.context, id=obj.id)
self.assertEqual(policy_obj.id, obj.qos_network_policy_id)
self.assertIsNone(obj.qos_policy_id)
def test_get_objects_queries_constant(self):
self.skipTest(
'Port object loads segment info without relationships')
@ -461,6 +480,12 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
port_v1_4_no_binding = port_v1_4.obj_from_primitive(primitive)
port_v1_4_no_binding.obj_to_primitive(target_version='1.3')
def test_v1_5_to_v1_4_drops_qos_network_policy_id(self):
port_new = self._create_test_port()
port_v1_4 = port_new.obj_to_primitive(target_version='1.4')
self.assertNotIn('qos_network_policy_id',
port_v1_4['versioned_object.data'])
def test_get_ports_ids_by_security_groups_except_router(self):
sg_id = self._create_test_security_group_id()
filter_owner = constants.ROUTER_INTERFACE_OWNERS_SNAT