Add "qos_policy_id" field to "Router" OVO

This new synthetic field is linked to a
"QosRouterGatewayIPPolicyBinding" register. This binding register will
bind a QoS policy and a Router.  Now is possible to provide this field
in the create/update input parameters. If provided, the "Router" OVO will
create/delete the "QosRouterGatewayIPPolicyBinding" register.

The "Router" OVO takes this parameter from the DB object. When the DB
object is retrieved, the QoS policy binding register is retrieved too
due to a backref link in the "QosRouterGatewayIPPolicyBinding" DB model to
the "Router" DB model.

Related-Bug: #1893625
Related-Bug: #1950454

Change-Id: I59ed68b2c1e19f1f31e72b4868e3db750ef06d6f
This commit is contained in:
Rodolfo Alonso Hernandez 2022-03-17 07:43:52 +00:00
parent a903fd20ef
commit 7c2420e3af
5 changed files with 88 additions and 4 deletions

View File

@ -43,6 +43,7 @@ class L3_gw_ip_qos_dbonly_mixin(l3_gwmode_db.L3_NAT_dbonly_mixin):
policy_id = router_db.qos_policy_binding.policy_id
router_res[l3_apidef.EXTERNAL_GW_INFO].update(
{qos_consts.QOS_POLICY_ID: policy_id})
router_res[qos_consts.QOS_POLICY_ID] = policy_id
@property
def _is_gw_ip_qos_supported(self):

View File

@ -194,7 +194,8 @@ class DVRMacAddress(base.NeutronDbObject):
@base.NeutronObjectRegistry.register
class Router(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Added "qos_policy_id" field
VERSION = '1.1'
db_model = l3.Router
@ -209,9 +210,12 @@ class Router(base.NeutronDbObject):
'flavor_id': common_types.UUIDField(nullable=True),
'extra_attributes': obj_fields.ObjectField(
'RouterExtraAttributes', nullable=True),
'qos_policy_id': common_types.UUIDField(nullable=True, default=None),
}
synthetic_fields = ['extra_attributes']
synthetic_fields = ['extra_attributes',
'qos_policy_id',
]
fields_no_update = ['project_id']
@ -230,6 +234,46 @@ class Router(base.NeutronDbObject):
return bool(query.count())
def _attach_qos_policy(self, qos_policy_id):
qos_binding.QosPolicyRouterGatewayIPBinding.delete_objects(
self.obj_context, router_id=self.id)
if qos_policy_id:
qos_binding.QosPolicyRouterGatewayIPBinding(
self.obj_context, policy_id=qos_policy_id,
router_id=self.id).create()
self.qos_policy_id = qos_policy_id
self.obj_reset_changes(['qos_policy_id'])
def create(self):
fields = self.obj_get_changes()
with self.db_context_writer(self.obj_context):
qos_policy_id = self.qos_policy_id
super().create()
if 'qos_policy_id' in fields:
self._attach_qos_policy(qos_policy_id)
def update(self):
fields = self.obj_get_changes()
with self.db_context_writer(self.obj_context):
super().update()
if 'qos_policy_id' in fields:
self._attach_qos_policy(fields['qos_policy_id'])
def from_db_object(self, db_obj):
super().from_db_object(db_obj)
fields_to_change = []
if db_obj.get('qos_policy_binding'):
self.qos_policy_id = db_obj.qos_policy_binding.policy_id
fields_to_change.append('qos_policy_id')
self.obj_reset_changes(fields_to_change)
def obj_make_compatible(self, primitive, target_version):
_target_version = versionutils.convert_version_to_tuple(target_version)
if _target_version < (1, 1):
primitive.pop('qos_policy_id', None)
@base.NeutronObjectRegistry.register
class FloatingIP(base.NeutronDbObject):

View File

@ -385,7 +385,7 @@ class OVNClientQosExtension(object):
def update_router(self, txn, router):
gw_info = router.get(l3_api.EXTERNAL_GW_INFO) or {}
qos_policy_id = gw_info.get('qos_policy_id')
qos_policy_id = router.get('qos_policy_id')
router_id = router.get('id')
gw_port_id = router.get('gw_port_id')
gw_network_id = gw_info.get('network_id')

View File

@ -104,7 +104,7 @@ object_data = {
'Reservation': '1.0-49929fef8e82051660342eed51b48f2a',
'ResourceDelta': '1.0-a980b37e0a52618b5af8db29af18be76',
'Route': '1.0-a9883a63b416126f9e345523ec09483b',
'Router': '1.0-adb984d9b73aa11566d40abbeb790df1',
'Router': '1.1-614fa16cc99c60e4fc19ac1b31a52291',
'RouterExtraAttributes': '1.0-ef8d61ae2864f0ec9af0ab7939cab318',
'RouterL3AgentBinding': '1.0-c5ba6c95e3a4c1236a55f490cd67da82',
'RouterNDPProxyState': '1.0-4042e475bf173d1d8d17adb962eae1b2',

View File

@ -127,6 +127,45 @@ class RouterDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
[project, new_project])
self.assertFalse(router_exist)
def test_qos_policy(self):
_qos_policy_1 = self._create_test_qos_policy()
_qos_policy_2 = self._create_test_qos_policy()
self.obj_fields[0]['qos_policy_id'] = _qos_policy_1.id
obj = self._test_class(
self.context, **obj_test_base.remove_timestamps_from_fields(
self.obj_fields[0], self._test_class.fields))
obj.create()
self.assertEqual(_qos_policy_1.id, obj.qos_policy_id)
obj.qos_policy_id = _qos_policy_2.id
obj.update()
self.assertEqual(_qos_policy_2.id, obj.qos_policy_id)
obj.qos_policy_id = None
obj.update()
self.assertIsNone(obj.qos_policy_id)
obj.qos_policy_id = _qos_policy_1.id
obj.update()
router_id = obj.id
gw_binding = qos_binding.QosPolicyRouterGatewayIPBinding.get_objects(
self.context, router_id=router_id)
self.assertEqual(1, len(gw_binding))
self.assertEqual(_qos_policy_1.id, gw_binding[0].policy_id)
obj.delete()
gw_binding = qos_binding.QosPolicyRouterGatewayIPBinding.get_objects(
self.context, router_id=router_id)
self.assertEqual([], gw_binding)
def test_object_version_degradation_1_1_to_1_0_no_qos_policy_id(self):
self.objs[0].create()
router_obj = self.objs[0]
router_dict = router_obj.obj_to_primitive('1.1')
self.assertIn('qos_policy_id', router_dict['versioned_object.data'])
router_dict = router_obj.obj_to_primitive('1.0')
self.assertNotIn('qos_policy_id', router_dict['versioned_object.data'])
class RouterPortIfaceObjectTestCase(obj_test_base.BaseObjectIfaceTestCase):