neutron/neutron/tests/fullstack/test_qos.py
Rodolfo Alonso Hernandez 92f1281b69 Add a more robust method to check OVSDB values in BaseOVSTestCase
Sometimes, when the OVSDB is too loaded (that could happen during the
functional tests), there is a delay between the OVSDB post transaction
end and when the register (new or updated) can be read. Although this is
something that should not happen (considering the OVSDB is transactional),
tests should deal with this inconvenience and provide a robust method to
retrieve a value and at the same time check the value. This new method
should provide a retrieving mechanism to read again the value in case of
discordance.

In order to solve the gate problem ASAP, another bug is fixed in this
patch: to skip the QoS removal when OVS agent is initialized during
funtional tests

When executing functional tests, several OVS QoS policies specific for
minimum bandwidth rules [1]. Because during the functional tests
execution several threads can create more than one minimum bandwidth
QoS policy (something in a production environment cannot happen), the
OVS QoS driver must skip the execution of [2] to avoid removing other
QoS created in parellel in other tests.

This patch is marking as unstable "test_min_bw_qos_policy_rule_lifecycle"
and "test_bw_limit_qos_port_removed". Those tests will be investigated
once the CI gates are stable.

[1] Those QoS policies are created only to hold minimum bandwidth rules.
    Those policies are marked with:
       external_ids: {'_type'='minimum_bandwidth'}
[2] d6fba30781/neutron/plugins/ml2/drivers/openvswitch/agent/extension_drivers/qos_driver.py (L43)

Closes-Bug: #1818613
Closes-Bug: #1818859
Related-Bug: #1819125

Change-Id: Ia725cc1b36bc3630d2891f86f76b13c16f6cc37c
2019-03-09 15:46:59 +00:00

701 lines
28 KiB
Python

# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
from neutron_lib import constants
from neutron_lib.services.qos import constants as qos_consts
from neutronclient.common import exceptions
from oslo_utils import uuidutils
import testscenarios
from neutron.agent.common import ovs_lib
from neutron.agent.linux import tc_lib
from neutron.common import utils
from neutron.tests import base as tests_base
from neutron.tests.common.agents import l2_extensions
from neutron.tests.fullstack import base
from neutron.tests.fullstack.resources import environment
from neutron.tests.fullstack.resources import machine
from neutron.tests.fullstack import utils as fullstack_utils
from neutron.tests.unit import testlib_api
from neutron.conf.plugins.ml2.drivers import linuxbridge as \
linuxbridge_agent_config
from neutron.plugins.ml2.drivers.linuxbridge.agent import \
linuxbridge_neutron_agent as linuxbridge_agent
from neutron.services.qos.drivers.linuxbridge import driver as lb_drv
from neutron.services.qos.drivers.openvswitch import driver as ovs_drv
load_tests = testlib_api.module_load_tests
BANDWIDTH_BURST = 100
BANDWIDTH_LIMIT = 500
MIN_BANDWIDTH = 300
DSCP_MARK = 16
class BaseQoSRuleTestCase(object):
of_interface = None
number_of_hosts = 1
@property
def reverse_direction(self):
if self.direction == constants.INGRESS_DIRECTION:
return constants.EGRESS_DIRECTION
elif self.direction == constants.EGRESS_DIRECTION:
return constants.INGRESS_DIRECTION
def setUp(self):
host_desc = [
environment.HostDescription(
l3_agent=False,
of_interface=self.of_interface,
l2_agent_type=self.l2_agent_type
) for _ in range(self.number_of_hosts)]
env_desc = environment.EnvironmentDescription(
agent_down_time=10,
qos=True)
env = environment.Environment(env_desc, host_desc)
super(BaseQoSRuleTestCase, self).setUp(env)
self.l2_agent_process = self.environment.hosts[0].l2_agent
self.l2_agent = self.safe_client.client.list_agents(
agent_type=self.l2_agent_type)['agents'][0]
self.tenant_id = uuidutils.generate_uuid()
self.network = self.safe_client.create_network(self.tenant_id,
'network-test')
self.subnet = self.safe_client.create_subnet(
self.tenant_id, self.network['id'],
cidr='10.0.0.0/24',
gateway_ip='10.0.0.1',
name='subnet-test',
enable_dhcp=False)
def _create_qos_policy(self):
return self.safe_client.create_qos_policy(
self.tenant_id, 'fs_policy', 'Fullstack testing policy',
shared='False', is_default='False')
def _prepare_vm_with_qos_policy(self, rule_add_functions):
qos_policy = self._create_qos_policy()
qos_policy_id = qos_policy['id']
port = self.safe_client.create_port(
self.tenant_id, self.network['id'],
self.environment.hosts[0].hostname,
qos_policy_id)
for rule_add in rule_add_functions:
rule_add(qos_policy)
vm = self.useFixture(
machine.FakeFullstackMachine(
self.environment.hosts[0],
self.network['id'],
self.tenant_id,
self.safe_client,
neutron_port=port))
return vm, qos_policy
class _TestBwLimitQoS(BaseQoSRuleTestCase):
number_of_hosts = 1
@staticmethod
def _get_expected_egress_burst_value(limit):
return int(
limit * qos_consts.DEFAULT_BURST_RATE
)
def _wait_for_bw_rule_removed(self, vm, direction):
# No values are provided when port doesn't have qos policy
self._wait_for_bw_rule_applied(vm, None, None, direction)
def _add_bw_limit_rule(self, limit, burst, direction, qos_policy):
qos_policy_id = qos_policy['id']
rule = self.safe_client.create_bandwidth_limit_rule(
self.tenant_id, qos_policy_id, limit, burst, direction)
# Make it consistent with GET reply
rule['type'] = qos_consts.RULE_TYPE_BANDWIDTH_LIMIT
rule['qos_policy_id'] = qos_policy_id
qos_policy['rules'].append(rule)
def _create_vm_with_limit_rules(self):
# Create port with qos policy attached, with different direction
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(
self._add_bw_limit_rule,
BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction),
functools.partial(
self._add_bw_limit_rule,
BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.reverse_direction)])
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.reverse_direction)
return vm, qos_policy
def _restart_agent_and_check_rules_applied(self, policy_id, vm,
final_rules,
add_rules=None,
update_rules=None,
delete_rules=None):
# final_rules: the last valid rule after all operations
# (clear/update/reset rules during the l2-agent stop) are completed.
# add_rules: rules that need to be added during the l2-agent stop.
# update_rules: rules that need to be updated during the l2-agent stop.
# delete_rules:rules that need to be deleted during the l2-agent stop.
add_rules = list() if not add_rules else add_rules
update_rules = list() if not update_rules else update_rules
delete_rules = list() if not delete_rules else delete_rules
# Stop l2_agent and clear/update/reset the port qos rules
self.l2_agent_process.stop()
self._wait_until_agent_down(self.l2_agent['id'])
for rule in delete_rules:
self.client.delete_bandwidth_limit_rule(rule['id'],
policy_id)
for rule in add_rules:
self.safe_client.create_bandwidth_limit_rule(
self.tenant_id, policy_id,
rule.get('limit'), rule.get('burst'), rule['direction'])
for rule in update_rules:
self.client.update_bandwidth_limit_rule(
rule['id'], policy_id,
body={'bandwidth_limit_rule':
{'max_kbps': rule.get('limit'),
'max_burst_kbps': rule.get('burst'),
'direction': rule.get('direction')}})
# Start l2_agent to check if these rules is cleared
self.l2_agent_process.start()
self._wait_until_agent_up(self.l2_agent['id'])
all_directions = set([self.direction, self.reverse_direction])
for final_rule in final_rules:
all_directions -= set([final_rule['direction']])
self._wait_for_bw_rule_applied(
vm, final_rule.get('limit'),
final_rule.get('burst'), final_rule['direction'])
# Make sure there are no other rules.
for direction in list(all_directions):
self._wait_for_bw_rule_applied(vm, None, None, direction)
def test_bw_limit_qos_policy_rule_lifecycle(self):
new_limit = BANDWIDTH_LIMIT + 100
# Create port with qos policy attached
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(
self._add_bw_limit_rule,
BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)])
bw_rule = qos_policy['rules'][0]
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)
qos_policy_id = qos_policy['id']
self.client.delete_bandwidth_limit_rule(bw_rule['id'], qos_policy_id)
self._wait_for_bw_rule_removed(vm, self.direction)
# Create new rule with no given burst value, in such case ovs and lb
# agent should apply burst value as
# bandwidth_limit * qos_consts.DEFAULT_BURST_RATE
new_expected_burst = self._get_expected_burst_value(new_limit,
self.direction)
new_rule = self.safe_client.create_bandwidth_limit_rule(
self.tenant_id, qos_policy_id, new_limit, direction=self.direction)
self._wait_for_bw_rule_applied(
vm, new_limit, new_expected_burst, self.direction)
# Update qos policy rule id
self.client.update_bandwidth_limit_rule(
new_rule['id'], qos_policy_id,
body={'bandwidth_limit_rule': {'max_kbps': BANDWIDTH_LIMIT,
'max_burst_kbps': BANDWIDTH_BURST}})
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)
# Remove qos policy from port
self.client.update_port(
vm.neutron_port['id'],
body={'port': {'qos_policy_id': None}})
self._wait_for_bw_rule_removed(vm, self.direction)
def test_bw_limit_direction_change(self):
# Create port with qos policy attached, with rule self.direction
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(
self._add_bw_limit_rule,
BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)])
bw_rule = qos_policy['rules'][0]
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)
# Update rule by changing direction to opposite then it was before
self.client.update_bandwidth_limit_rule(
bw_rule['id'], qos_policy['id'],
body={'bandwidth_limit_rule': {
'direction': self.reverse_direction}})
self._wait_for_bw_rule_removed(vm, self.direction)
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.reverse_direction)
def test_bw_limit_qos_no_rules_l2_agent_restart(self):
vm, qos_policy = self._create_vm_with_limit_rules()
bw_rule_1 = qos_policy['rules'][0]
bw_rule_2 = qos_policy['rules'][1]
qos_policy_id = qos_policy['id']
# final_rules indicates the last valid rule after all operations
# (clear/update/reset rules during the l2-agent stop) are completed
final_rules = [{'direction': self.direction,
'limit': None},
{'direction': self.reverse_direction,
'limit': None}]
self._restart_agent_and_check_rules_applied(
qos_policy_id, vm, final_rules=final_rules,
delete_rules=[bw_rule_1, bw_rule_2])
def test_bw_limit_qos_rules_deleted_l2_agent_restart(self):
vm, qos_policy = self._create_vm_with_limit_rules()
bw_rule_1 = qos_policy['rules'][0]
qos_policy_id = qos_policy['id']
# final_rules indicates the last valid rule after all operations
# (clear/update/reset rules during the l2-agent stop) are completed
final_rules = [{'direction': self.direction,
'limit': None},
{'direction': self.reverse_direction,
'limit': BANDWIDTH_LIMIT,
'burst': BANDWIDTH_BURST}]
self._restart_agent_and_check_rules_applied(
qos_policy_id, vm, final_rules=final_rules,
delete_rules=[bw_rule_1])
def test_bw_limit_qos_rules_changed_l2_agent_restart(self):
vm, qos_policy = self._create_vm_with_limit_rules()
bw_rule_1 = qos_policy['rules'][0]
bw_rule_2 = qos_policy['rules'][1]
qos_policy_id = qos_policy['id']
add_rules = [{'direction': self.direction,
'limit': BANDWIDTH_LIMIT * 2,
'burst': BANDWIDTH_BURST * 2},
{'direction': self.reverse_direction,
'limit': BANDWIDTH_LIMIT * 2,
'burst': BANDWIDTH_BURST * 2}]
self._restart_agent_and_check_rules_applied(
qos_policy_id, vm, final_rules=add_rules,
add_rules=add_rules,
delete_rules=[bw_rule_1, bw_rule_2])
def test_bw_limit_qos_rules_updated_l2_agent_restart(self):
vm, qos_policy = self._create_vm_with_limit_rules()
bw_rule_1 = qos_policy['rules'][0]
bw_rule_2 = qos_policy['rules'][1]
qos_policy_id = qos_policy['id']
update_rules = [{'id': bw_rule_1['id'],
'direction': bw_rule_1['direction'],
'limit': BANDWIDTH_LIMIT * 2,
'burst': BANDWIDTH_BURST * 2},
{'id': bw_rule_2['id'],
'direction': bw_rule_2['direction'],
'limit': BANDWIDTH_LIMIT * 2,
'burst': BANDWIDTH_BURST * 2}]
self._restart_agent_and_check_rules_applied(
qos_policy_id, vm, final_rules=update_rules,
update_rules=update_rules)
class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase):
l2_agent_type = constants.AGENT_TYPE_OVS
direction_scenarios = [
('ingress', {'direction': constants.INGRESS_DIRECTION}),
('egress', {'direction': constants.EGRESS_DIRECTION})
]
scenarios = testscenarios.multiply_scenarios(
direction_scenarios, fullstack_utils.get_ovs_interface_scenarios())
@staticmethod
def _get_expected_burst_value(limit, direction):
# For egress bandwidth limit this value should be calculated as
# bandwidth_limit * qos_consts.DEFAULT_BURST_RATE
if direction == constants.EGRESS_DIRECTION:
return TestBwLimitQoSOvs._get_expected_egress_burst_value(limit)
else:
return 0
def _wait_for_bw_rule_applied(self, vm, limit, burst, direction):
if direction == constants.EGRESS_DIRECTION:
utils.wait_until_true(
lambda: vm.bridge.get_egress_bw_limit_for_port(
vm.port.name) == (limit, burst))
elif direction == constants.INGRESS_DIRECTION:
utils.wait_until_true(
lambda: vm.bridge.get_ingress_bw_limit_for_port(
vm.port.name) == (limit, burst))
def test_bw_limit_qos_port_removed(self):
"""Test if rate limit config is properly removed when whole port is
removed.
"""
# Create port with qos policy attached
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(
self._add_bw_limit_rule,
BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)])
self._wait_for_bw_rule_applied(
vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction)
# Delete port with qos policy attached
vm.destroy()
self._wait_for_bw_rule_removed(vm, self.direction)
self.assertIsNone(vm.bridge.find_qos(vm.port.name))
self.assertIsNone(vm.bridge.find_queue(vm.port.name,
ovs_lib.QOS_DEFAULT_QUEUE))
class TestBwLimitQoSLinuxbridge(_TestBwLimitQoS, base.BaseFullStackTestCase):
l2_agent_type = constants.AGENT_TYPE_LINUXBRIDGE
scenarios = [
('egress', {'direction': constants.EGRESS_DIRECTION}),
('ingress', {'direction': constants.INGRESS_DIRECTION}),
]
@staticmethod
def _get_expected_burst_value(limit, direction):
# For egress bandwidth limit this value should be calculated as
# bandwidth_limit * qos_consts.DEFAULT_BURST_RATE
if direction == constants.EGRESS_DIRECTION:
return TestBwLimitQoSLinuxbridge._get_expected_egress_burst_value(
limit)
else:
return TestBwLimitQoSLinuxbridge._get_expected_ingress_burst_value(
limit)
@staticmethod
def _get_expected_ingress_burst_value(limit):
return int(
float(limit) /
float(linuxbridge_agent_config.DEFAULT_KERNEL_HZ_VALUE))
def _wait_for_bw_rule_applied(self, vm, limit, burst, direction):
port_name = linuxbridge_agent.LinuxBridgeManager.get_tap_device_name(
vm.neutron_port['id'])
tc = tc_lib.TcCommand(
port_name,
linuxbridge_agent_config.DEFAULT_KERNEL_HZ_VALUE,
namespace=vm.host.host_namespace
)
if direction == constants.EGRESS_DIRECTION:
utils.wait_until_true(
lambda: tc.get_filters_bw_limits() == (limit, burst))
elif direction == constants.INGRESS_DIRECTION:
utils.wait_until_true(
lambda: tc.get_tbf_bw_limits() == (limit, burst))
class _TestDscpMarkingQoS(BaseQoSRuleTestCase):
number_of_hosts = 2
def _wait_for_dscp_marking_rule_removed(self, vm):
self._wait_for_dscp_marking_rule_applied(vm, None)
def _add_dscp_rule(self, dscp_mark, qos_policy):
qos_policy_id = qos_policy['id']
rule = self.safe_client.create_dscp_marking_rule(
self.tenant_id, qos_policy_id, dscp_mark)
# Make it consistent with GET reply
rule['type'] = qos_consts.RULE_TYPE_DSCP_MARKING
rule['qos_policy_id'] = qos_policy_id
qos_policy['rules'].append(rule)
def test_dscp_qos_policy_rule_lifecycle(self):
new_dscp_mark = DSCP_MARK + 8
# Create port with qos policy attached
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(self._add_dscp_rule, DSCP_MARK)])
dscp_rule = qos_policy['rules'][0]
self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK)
qos_policy_id = qos_policy['id']
self.client.delete_dscp_marking_rule(dscp_rule['id'], qos_policy_id)
self._wait_for_dscp_marking_rule_removed(vm)
# Create new rule
new_rule = self.safe_client.create_dscp_marking_rule(
self.tenant_id, qos_policy_id, new_dscp_mark)
self._wait_for_dscp_marking_rule_applied(vm, new_dscp_mark)
# Update qos policy rule id
self.client.update_dscp_marking_rule(
new_rule['id'], qos_policy_id,
body={'dscp_marking_rule': {'dscp_mark': DSCP_MARK}})
self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK)
# Remove qos policy from port
self.client.update_port(
vm.neutron_port['id'],
body={'port': {'qos_policy_id': None}})
self._wait_for_dscp_marking_rule_removed(vm)
def test_dscp_marking_packets(self):
# Create port (vm) which will be used to received and test packets
receiver_port = self.safe_client.create_port(
self.tenant_id, self.network['id'],
self.environment.hosts[1].hostname)
receiver = self.useFixture(
machine.FakeFullstackMachine(
self.environment.hosts[1],
self.network['id'],
self.tenant_id,
self.safe_client,
neutron_port=receiver_port))
# Create port with qos policy attached
sender, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(self._add_dscp_rule, DSCP_MARK)])
sender.block_until_boot()
receiver.block_until_boot()
self._wait_for_dscp_marking_rule_applied(sender, DSCP_MARK)
l2_extensions.wait_for_dscp_marked_packet(
sender, receiver, DSCP_MARK)
def test_dscp_marking_clean_port_removed(self):
"""Test if DSCP marking OpenFlow/iptables rules are removed when
whole port is removed.
"""
# Create port with qos policy attached
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(self._add_dscp_rule, DSCP_MARK)])
self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK)
# Delete port with qos policy attached
vm.destroy()
self._wait_for_dscp_marking_rule_removed(vm)
class TestDscpMarkingQoSOvs(_TestDscpMarkingQoS, base.BaseFullStackTestCase):
scenarios = fullstack_utils.get_ovs_interface_scenarios()
l2_agent_type = constants.AGENT_TYPE_OVS
def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark):
l2_extensions.wait_until_dscp_marking_rule_applied_ovs(
vm.bridge, vm.port.name, dscp_mark)
class TestDscpMarkingQoSLinuxbridge(_TestDscpMarkingQoS,
base.BaseFullStackTestCase):
l2_agent_type = constants.AGENT_TYPE_LINUXBRIDGE
def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark):
l2_extensions.wait_until_dscp_marking_rule_applied_linuxbridge(
vm.host.host_namespace, vm.port.name, dscp_mark)
class TestQoSWithL2Population(base.BaseFullStackTestCase):
scenarios = [
(constants.AGENT_TYPE_OVS,
{'mech_drivers': 'openvswitch',
'supported_rules': ovs_drv.SUPPORTED_RULES}),
(constants.AGENT_TYPE_LINUXBRIDGE,
{'mech_drivers': 'linuxbridge',
'supported_rules': lb_drv.SUPPORTED_RULES})
]
def setUp(self):
host_desc = [] # No need to register agents for this test case
env_desc = environment.EnvironmentDescription(
qos=True, l2_pop=True, mech_drivers=self.mech_drivers)
env = environment.Environment(env_desc, host_desc)
super(TestQoSWithL2Population, self).setUp(env)
def test_supported_qos_rule_types(self):
res = self.client.list_qos_rule_types()
rule_types = {t['type'] for t in res['rule_types']}
expected_rules = set(self.supported_rules)
self.assertEqual(expected_rules, rule_types)
class TestQoSPolicyIsDefault(base.BaseFullStackTestCase):
NAME = 'fs_policy'
DESCRIPTION = 'Fullstack testing policy'
SHARED = True
def setUp(self):
host_desc = [] # No need to register agents for this test case
env_desc = environment.EnvironmentDescription(qos=True)
env = environment.Environment(env_desc, host_desc)
super(TestQoSPolicyIsDefault, self).setUp(env)
def _create_qos_policy(self, project_id, is_default):
return self.safe_client.create_qos_policy(
project_id, self.NAME, self.DESCRIPTION, shared=self.SHARED,
is_default=is_default)
def _update_qos_policy(self, qos_policy_id, is_default):
return self.client.update_qos_policy(
qos_policy_id, body={'policy': {'is_default': is_default}})
def test_create_one_default_qos_policy_per_project(self):
project_ids = [uuidutils.generate_uuid(), uuidutils.generate_uuid()]
for project_id in project_ids:
qos_policy = self._create_qos_policy(project_id, True)
self.assertTrue(qos_policy['is_default'])
self.assertEqual(project_id, qos_policy['project_id'])
qos_policy = self._create_qos_policy(project_id, False)
self.assertFalse(qos_policy['is_default'])
self.assertEqual(project_id, qos_policy['project_id'])
def test_create_two_default_qos_policies_per_project(self):
project_id = uuidutils.generate_uuid()
qos_policy = self._create_qos_policy(project_id, True)
self.assertTrue(qos_policy['is_default'])
self.assertEqual(project_id, qos_policy['project_id'])
self.assertRaises(exceptions.Conflict,
self._create_qos_policy, project_id, True)
def test_update_default_status(self):
project_ids = [uuidutils.generate_uuid(), uuidutils.generate_uuid()]
for project_id in project_ids:
qos_policy = self._create_qos_policy(project_id, True)
self.assertTrue(qos_policy['is_default'])
qos_policy = self._update_qos_policy(qos_policy['id'], False)
self.assertFalse(qos_policy['policy']['is_default'])
def test_update_default_status_conflict(self):
project_id = uuidutils.generate_uuid()
qos_policy_1 = self._create_qos_policy(project_id, True)
self.assertTrue(qos_policy_1['is_default'])
qos_policy_2 = self._create_qos_policy(project_id, False)
self.assertFalse(qos_policy_2['is_default'])
self.assertRaises(exceptions.Conflict,
self._update_qos_policy, qos_policy_2['id'], True)
class _TestMinBwQoS(BaseQoSRuleTestCase):
number_of_hosts = 1
def _wait_for_min_bw_rule_removed(self, vm, direction):
# No values are provided when port doesn't have qos policy
self._wait_for_min_bw_rule_applied(vm, None, direction)
def _add_min_bw_rule(self, min_bw, direction, qos_policy):
qos_policy_id = qos_policy['id']
rule = self.safe_client.create_minimum_bandwidth_rule(
self.tenant_id, qos_policy_id, min_bw, direction)
# Make it consistent with GET reply
rule['type'] = qos_consts.RULE_TYPE_MINIMUM_BANDWIDTH
rule['qos_policy_id'] = qos_policy_id
qos_policy['rules'].append(rule)
@tests_base.unstable_test('bug 1819125')
def test_min_bw_qos_policy_rule_lifecycle(self):
new_limit = MIN_BANDWIDTH - 100
# Create port with qos policy attached
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(
self._add_min_bw_rule, MIN_BANDWIDTH, self.direction)])
bw_rule = qos_policy['rules'][0]
self._wait_for_min_bw_rule_applied(vm, MIN_BANDWIDTH, self.direction)
qos_policy_id = qos_policy['id']
self.client.delete_minimum_bandwidth_rule(bw_rule['id'], qos_policy_id)
self._wait_for_min_bw_rule_removed(vm, self.direction)
new_rule = self.safe_client.create_minimum_bandwidth_rule(
self.tenant_id, qos_policy_id, new_limit, direction=self.direction)
self._wait_for_min_bw_rule_applied(vm, new_limit, self.direction)
# Update qos policy rule id
self.client.update_minimum_bandwidth_rule(
new_rule['id'], qos_policy_id,
body={'minimum_bandwidth_rule': {'min_kbps': MIN_BANDWIDTH}})
self._wait_for_min_bw_rule_applied(vm, MIN_BANDWIDTH, self.direction)
# Remove qos policy from port
self.client.update_port(
vm.neutron_port['id'],
body={'port': {'qos_policy_id': None}})
self._wait_for_min_bw_rule_removed(vm, self.direction)
class TestMinBwQoSOvs(_TestMinBwQoS, base.BaseFullStackTestCase):
l2_agent_type = constants.AGENT_TYPE_OVS
direction_scenarios = [
('egress', {'direction': constants.EGRESS_DIRECTION})
]
scenarios = testscenarios.multiply_scenarios(
direction_scenarios, fullstack_utils.get_ovs_interface_scenarios())
def _wait_for_min_bw_rule_applied(self, vm, min_bw, direction):
if direction == constants.EGRESS_DIRECTION:
utils.wait_until_true(
lambda: vm.bridge.get_egress_min_bw_for_port(
vm.neutron_port['id']) == min_bw)
elif direction == constants.INGRESS_DIRECTION:
self.fail('"%s" direction not implemented'
% constants.INGRESS_DIRECTION)
@tests_base.unstable_test('bug 1819125')
def test_bw_limit_qos_port_removed(self):
"""Test if rate limit config is properly removed when whole port is
removed.
"""
# Create port with qos policy attached
vm, qos_policy = self._prepare_vm_with_qos_policy(
[functools.partial(
self._add_min_bw_rule, MIN_BANDWIDTH, self.direction)])
self._wait_for_min_bw_rule_applied(
vm, MIN_BANDWIDTH, self.direction)
# Delete port with qos policy attached
vm.destroy()
self._wait_for_min_bw_rule_removed(vm, self.direction)
self.assertIsNone(vm.bridge.find_qos(vm.port.name))
self.assertIsNone(vm.bridge.find_queue(vm.port.name,
ovs_lib.QOS_DEFAULT_QUEUE))