Add minimum bw qos rule validation for network
Minimum bandwidth QoS rule is only applicable for the network which is backed by physical networks. It will raise exception when you want to set Minimum bandwidth QoS rule or update rule on network without ports. Closes-Bug: #1913180 Change-Id: I6ab945086b13730ad60957760bbc2eb5c321aca2
This commit is contained in:
parent
90309cf6e2
commit
26f3de0f78
|
@ -154,6 +154,15 @@ class QosServiceDriverManager(object):
|
|||
|
||||
return False
|
||||
|
||||
def validate_rule_for_network(self, context, rule, network_id):
|
||||
for driver in self._drivers:
|
||||
if (driver.is_rule_supported(rule) and
|
||||
driver.validate_rule_for_network(context, rule,
|
||||
network_id)):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def supported_rule_types(self):
|
||||
if not self._drivers:
|
||||
|
|
|
@ -60,11 +60,14 @@ class OVSDriver(base.DriverBase):
|
|||
requires_rpc_notifications=True)
|
||||
|
||||
def validate_rule_for_port(self, context, rule, port):
|
||||
return self.validate_rule_for_network(context, rule, port.network_id)
|
||||
|
||||
def validate_rule_for_network(self, context, rule, network_id):
|
||||
# Minimum-bandwidth rule is only supported on networks whose
|
||||
# first segment is backed by a physnet.
|
||||
if rule.rule_type == qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH:
|
||||
net = network_object.Network.get_object(
|
||||
context, id=port.network_id)
|
||||
context, id=network_id)
|
||||
physnet = net.segments[0].physical_network
|
||||
if physnet is None:
|
||||
return False
|
||||
|
|
|
@ -101,6 +101,10 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||
self._validate_update_network_callback,
|
||||
callbacks_resources.NETWORK,
|
||||
callbacks_events.PRECOMMIT_UPDATE)
|
||||
callbacks_registry.subscribe(
|
||||
self._validate_create_network_callback,
|
||||
callbacks_resources.NETWORK,
|
||||
callbacks_events.PRECOMMIT_CREATE)
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([port_def.COLLECTION_NAME])
|
||||
|
@ -343,6 +347,20 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||
|
||||
self.validate_policy_for_port(context, policy, updated_port)
|
||||
|
||||
def _validate_create_network_callback(self, resource, event, trigger,
|
||||
**kwargs):
|
||||
context = kwargs['context']
|
||||
network_id = kwargs['network']['id']
|
||||
network = network_object.Network.get_object(context, id=network_id)
|
||||
|
||||
policy_id = network.qos_policy_id
|
||||
if policy_id is None:
|
||||
return
|
||||
|
||||
policy = policy_object.QosPolicy.get_object(
|
||||
context.elevated(), id=policy_id)
|
||||
self.validate_policy_for_network(context, policy, network_id)
|
||||
|
||||
def _validate_update_network_callback(self, resource, event, trigger,
|
||||
payload=None):
|
||||
context = payload.context
|
||||
|
@ -357,6 +375,9 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||
|
||||
policy = policy_object.QosPolicy.get_object(
|
||||
context.elevated(), id=policy_id)
|
||||
self.validate_policy_for_network(
|
||||
context, policy, network_id=updated_network['id'])
|
||||
|
||||
ports = ports_object.Port.get_objects(
|
||||
context, network_id=updated_network['id'])
|
||||
# Filter only this ports which don't have overwritten policy
|
||||
|
@ -380,6 +401,13 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||
raise qos_exc.QosRuleNotSupported(rule_type=rule.rule_type,
|
||||
port_id=port['id'])
|
||||
|
||||
def validate_policy_for_network(self, context, policy, network_id):
|
||||
for rule in policy.rules:
|
||||
if not self.driver_manager.validate_rule_for_network(
|
||||
context, rule, network_id):
|
||||
raise qos_exc.QosRuleNotSupportedByNetwork(
|
||||
rule_type=rule.rule_type, network_id=network_id)
|
||||
|
||||
def reject_min_bw_rule_updates(self, context, policy):
|
||||
ports = self._get_ports_with_policy(context, policy)
|
||||
for port in ports:
|
||||
|
|
|
@ -91,7 +91,7 @@ class ClientFixture(fixtures.Fixture):
|
|||
|
||||
def create_network(self, tenant_id, name=None, external=False,
|
||||
network_type=None, segmentation_id=None,
|
||||
physical_network=None, mtu=None):
|
||||
physical_network=None, mtu=None, qos_policy_id=None):
|
||||
resource_type = 'network'
|
||||
|
||||
name = name or utils.get_rand_name(prefix=resource_type)
|
||||
|
@ -106,6 +106,8 @@ class ClientFixture(fixtures.Fixture):
|
|||
spec['provider:physical_network'] = physical_network
|
||||
if mtu is not None:
|
||||
spec['mtu'] = mtu
|
||||
if qos_policy_id is not None:
|
||||
spec['qos_policy_id'] = qos_policy_id
|
||||
|
||||
return self._create_resource(resource_type, spec)
|
||||
|
||||
|
|
|
@ -718,6 +718,31 @@ class TestMinBwQoSOvs(_TestMinBwQoS, base.BaseFullStackTestCase):
|
|||
qoses, queues = self._qos_info(vm.bridge)
|
||||
self.fail(queuenum + qoses + queues)
|
||||
|
||||
def test_min_bw_qos_create_network_vxlan_not_supported(self):
|
||||
qos_policy = self._create_qos_policy()
|
||||
qos_policy_id = qos_policy['id']
|
||||
self.safe_client.create_minimum_bandwidth_rule(
|
||||
self.tenant_id, qos_policy_id, MIN_BANDWIDTH, self.direction)
|
||||
network_args = {'network_type': 'vxlan',
|
||||
'qos_policy_id': qos_policy_id}
|
||||
self.assertRaises(
|
||||
exceptions.Conflict,
|
||||
self.safe_client.create_network,
|
||||
self.tenant_id, name='network-test', **network_args)
|
||||
|
||||
def test_min_bw_qos_update_network_vxlan_not_supported(self):
|
||||
network_args = {'network_type': 'vxlan'}
|
||||
network = self.safe_client.create_network(
|
||||
self.tenant_id, name='network-test', **network_args)
|
||||
qos_policy = self._create_qos_policy()
|
||||
qos_policy_id = qos_policy['id']
|
||||
self.safe_client.create_minimum_bandwidth_rule(
|
||||
self.tenant_id, qos_policy_id, MIN_BANDWIDTH, self.direction)
|
||||
self.assertRaises(
|
||||
exceptions.Conflict,
|
||||
self.client.update_network, network['id'],
|
||||
body={'network': {'qos_policy_id': qos_policy_id}})
|
||||
|
||||
def test_min_bw_qos_port_removed(self):
|
||||
"""Test if min BW limit config is properly removed when port removed.
|
||||
|
||||
|
|
|
@ -43,3 +43,5 @@ class TestOVSDriver(base.BaseQosTestCase):
|
|||
return_value=net):
|
||||
test_method(self.driver.validate_rule_for_port(
|
||||
mock.Mock(), rule, port))
|
||||
test_method(self.driver.validate_rule_for_network(
|
||||
mock.Mock(), rule, network_id=mock.Mock()))
|
||||
|
|
|
@ -119,6 +119,29 @@ class TestQoSDriversRulesValidations(TestQosDriversManagerBase):
|
|||
else:
|
||||
is_rule_supported_mock.assert_not_called()
|
||||
|
||||
def test_validate_rule_for_network(self):
|
||||
driver_manager = self._create_manager_with_drivers({
|
||||
'driver-A': {
|
||||
'is_loaded': True,
|
||||
'rules': {
|
||||
qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH: {
|
||||
"min_kbps": {'type:values': None},
|
||||
'direction': {
|
||||
'type:values': lib_consts.VALID_DIRECTIONS}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
rule = rule_object.QosMinimumBandwidthRule(
|
||||
self.ctxt, id=uuidutils.generate_uuid())
|
||||
|
||||
is_rule_supported_mock = mock.Mock()
|
||||
is_rule_supported_mock.return_value = True
|
||||
driver_manager._drivers[0].is_rule_supported = is_rule_supported_mock
|
||||
self.assertTrue(driver_manager.validate_rule_for_network(
|
||||
mock.Mock(), rule, mock.Mock()))
|
||||
is_rule_supported_mock.assert_called_once_with(rule)
|
||||
|
||||
def test_validate_rule_for_port_rule_vif_type_supported(self):
|
||||
port = self._get_port(
|
||||
portbindings.VIF_TYPE_OVS, portbindings.VNIC_NORMAL)
|
||||
|
|
|
@ -328,6 +328,8 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||
'neutron.objects.qos.policy.QosPolicy.get_object',
|
||||
return_value=policy_mock
|
||||
) as get_policy, mock.patch.object(
|
||||
self.qos_plugin, "validate_policy_for_network"
|
||||
) as validate_policy_for_network, mock.patch.object(
|
||||
self.qos_plugin, "validate_policy_for_ports"
|
||||
) as validate_policy_for_ports, mock.patch.object(
|
||||
self.ctxt, "elevated", return_value=admin_ctxt
|
||||
|
@ -339,6 +341,7 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||
states=(kwargs['original_network'],)))
|
||||
if policy_id is None or policy_id == original_policy_id:
|
||||
get_policy.assert_not_called()
|
||||
validate_policy_for_network.assert_not_called()
|
||||
get_ports.assert_not_called()
|
||||
validate_policy_for_ports.assert_not_called()
|
||||
else:
|
||||
|
@ -386,6 +389,20 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||
except qos_exc.QosRuleNotSupported:
|
||||
self.fail("QosRuleNotSupported exception unexpectedly raised")
|
||||
|
||||
def test_validate_policy_for_network(self):
|
||||
network = uuidutils.generate_uuid()
|
||||
with mock.patch.object(
|
||||
self.qos_plugin.driver_manager, "validate_rule_for_network",
|
||||
return_value=True
|
||||
):
|
||||
self.policy.rules = [self.rule]
|
||||
try:
|
||||
self.qos_plugin.validate_policy_for_network(
|
||||
self.ctxt, self.policy, network_id=network)
|
||||
except qos_exc.QosRuleNotSupportedByNetwork:
|
||||
self.fail("QosRuleNotSupportedByNetwork "
|
||||
"exception unexpectedly raised")
|
||||
|
||||
def test_create_min_bw_rule_on_bound_port(self):
|
||||
policy = self._get_policy()
|
||||
policy.rules = [self.min_rule]
|
||||
|
@ -1246,6 +1263,35 @@ class TestQosPluginDB(base.BaseQosTestCase):
|
|||
network.create()
|
||||
return network
|
||||
|
||||
def _test_validate_create_network_callback(self, network_qos=False):
|
||||
net_qos_obj = self._make_qos_policy()
|
||||
net_qos_id = net_qos_obj.id if network_qos else None
|
||||
network = self._make_network(qos_policy_id=net_qos_id)
|
||||
kwargs = {"context": self.context,
|
||||
"network": network}
|
||||
|
||||
with mock.patch.object(self.qos_plugin,
|
||||
'validate_policy_for_network') \
|
||||
as mock_validate_policy:
|
||||
self.qos_plugin._validate_create_network_callback(
|
||||
'NETWORK', 'precommit_create', 'test_plugin', **kwargs)
|
||||
|
||||
qos_policy = None
|
||||
if network_qos:
|
||||
qos_policy = net_qos_obj
|
||||
|
||||
if qos_policy:
|
||||
mock_validate_policy.assert_called_once_with(
|
||||
self.context, qos_policy, network.id)
|
||||
else:
|
||||
mock_validate_policy.assert_not_called()
|
||||
|
||||
def test_validate_create_network_callback(self):
|
||||
self._test_validate_create_network_callback(network_qos=True)
|
||||
|
||||
def test_validate_create_network_callback_no_qos(self):
|
||||
self._test_validate_create_network_callback(network_qos=False)
|
||||
|
||||
def _test_validate_create_port_callback(self, port_qos=False,
|
||||
network_qos=False):
|
||||
net_qos_obj = self._make_qos_policy()
|
||||
|
|
Loading…
Reference in New Issue