Sean Mooney 2df01e8845 address test stablity under load
vif_plug_ovs.tests.functional.ovsdb.test_ovsdb_lib.TestOVSDBLib.test_create_ovs_vif_port_with_default_qos(native)
can fail under load as the ovs-db requires the ovsvswitchd
to acknowlage the requested configution
before the db tansaction is complete.

currently os-vif works around this using a wait_until_true retry loop
with a hardcoded 2 second timeout. This change bumps the default timeout
to 10 seconds and make it configurable via a new env var.

OS_VIF_CHECK_PARAMETER_TIMEOUT

this should stablise the test under load such as in ci and allow the timeout
to be turned via ci jobs if requried.

note 10 seconds is already over kill so if we see instablity after this
change we likely shoudl reduce concurrency instead.

Related-Bug: #2087982
Change-Id: Icd0b69a7f3a121fbe4fe2b754c1fc1d993d2a741
2024-11-20 21:21:44 +00:00

342 lines
14 KiB
Python

# 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 fixtures
import random
from unittest import mock
import testscenarios
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_utils import uuidutils
from vif_plug_ovs import constants
from vif_plug_ovs import linux_net
from vif_plug_ovs import ovs
from vif_plug_ovs.ovsdb import ovsdb_lib
from vif_plug_ovs import privsep
from vif_plug_ovs.tests.functional import base
CONF = cfg.CONF
@privsep.vif_plug_test.entrypoint
def run_privileged(*full_args):
return processutils.execute(*full_args)[0].rstrip()
class TestOVSDBLib(testscenarios.WithScenarios,
base.VifPlugOvsBaseFunctionalTestCase):
scenarios = [
('native', {'interface': 'native'}),
('vsctl', {'interface': 'vsctl'})
]
def setUp(self):
super(TestOVSDBLib, self).setUp()
run_privileged('ovs-vsctl', 'set-manager', 'ptcp:6640')
# NOTE: (ralonsoh) load default configuration variables "CONFIG_OPTS"
ovs.OvsPlugin.load('ovs')
self.flags(ovsdb_interface=self.interface, group='os_vif_ovs')
self.ovs = ovsdb_lib.BaseOVS(CONF.os_vif_ovs)
self._ovsdb = self.ovs.ovsdb
self.brname = ('br' + str(random.randint(1000, 9999)) + '-' +
self.interface)
# Make sure exceptions pass through by calling do_post_commit directly
post_commit = (
'ovsdbapp.schema.open_vswitch.impl_idl.'
'OvsVsctlTransaction.post_commit'
)
# "this" is the self parmater which is a reference to the
# OvsVsctlTransaction instance on which do_post_commit is defiend.
def direct_post_commit(this, transaction):
this.do_post_commit(transaction)
self.useFixture(fixtures.MonkeyPatch(post_commit, direct_post_commit))
def _add_port(self, bridge, port, may_exist=True):
with self._ovsdb.transaction() as txn:
txn.add(self._ovsdb.add_port(bridge, port, may_exist=may_exist))
txn.add(self._ovsdb.db_set('Interface', port,
('type', 'internal')))
self.assertIn(port, self._list_ports_in_bridge(bridge))
def _list_ports_in_bridge(self, bridge):
return self._ovsdb.list_ports(bridge).execute()
def test__set_mtu_request(self):
port_name = 'port1-' + self.interface
self._add_bridge(self.brname)
self.addCleanup(self._del_bridge, self.brname)
self._add_port(self.brname, port_name)
if self.ovs._ovs_supports_mtu_requests():
with self._ovsdb.transaction() as txn:
self.ovs._set_mtu_request(txn, port_name, 1000)
self._check_parameter('Interface', port_name, 'mtu', 1000)
with self._ovsdb.transaction() as txn:
self.ovs._set_mtu_request(txn, port_name, 1500)
self._check_parameter('Interface', port_name, 'mtu', 1500)
else:
self.skipTest('Current version of Open vSwitch does not support '
'"mtu_request" parameter')
def test_create_ovs_vif_port(self):
port_name = 'port2-' + self.interface
iface_id = 'iface_id'
mac = 'ca:fe:ca:fe:ca:fe'
instance_id = uuidutils.generate_uuid()
interface_type = constants.OVS_VHOSTUSER_INTERFACE_TYPE
vhost_server_path = '/fake/path'
mtu = 1500
self._add_bridge(self.brname)
self.addCleanup(self._del_bridge, self.brname)
self.ovs.create_ovs_vif_port(self.brname, port_name, iface_id, mac,
instance_id, mtu=mtu,
interface_type=interface_type,
vhost_server_path=vhost_server_path,
tag=2000)
expected_external_ids = {'iface-status': 'active',
'iface-id': iface_id,
'attached-mac': mac,
'vm-uuid': instance_id}
self._check_parameter('Interface', port_name, 'external_ids',
expected_external_ids)
self._check_parameter('Interface', port_name, 'type', interface_type)
expected_vhost_server_path = {'vhost-server-path': vhost_server_path}
self._check_parameter(
'Interface', port_name, 'options', expected_vhost_server_path
)
self._check_parameter('Port', port_name, 'tag', 2000)
self._check_parameter('Port', port_name, 'qos', [])
@mock.patch.object(linux_net, 'delete_net_dev')
def test_delete_ovs_vif_port(self, *mock):
port_name = 'port3-' + self.interface
self._add_bridge(self.brname)
self.addCleanup(self._del_bridge, self.brname)
self._add_port(self.brname, port_name)
self.ovs.delete_ovs_vif_port(self.brname, port_name)
self.assertNotIn(port_name, self._list_ports_in_bridge(self.brname))
def test_ensure_ovs_bridge(self):
bridge_name = 'bridge2-' + self.interface
self.ovs.ensure_ovs_bridge(bridge_name, constants.OVS_DATAPATH_SYSTEM)
self.assertTrue(self._check_bridge(bridge_name))
self.addCleanup(self._del_bridge, bridge_name)
def test_create_patch_port_pair(self):
port_bridge = 'fake-pb'
port_bridge_port = 'fake-pbp'
int_bridge = 'pb-int'
int_bridge_port = 'fake-ibp'
iface_id = 'iface_id'
mac = 'ca:fe:ca:fe:ca:fe'
instance_id = uuidutils.generate_uuid()
# deleting a bridge deletes all ports on bridges so we register the
# bridge cleanup first so if we fail anywhere it runs.
self.addCleanup(self._del_bridge, port_bridge)
self.addCleanup(self._del_bridge, int_bridge)
self.ovs.ensure_ovs_bridge(port_bridge, constants.OVS_DATAPATH_SYSTEM)
self.ovs.ensure_ovs_bridge(int_bridge, constants.OVS_DATAPATH_SYSTEM)
self.ovs.create_patch_port_pair(
port_bridge, port_bridge_port, int_bridge, int_bridge_port,
iface_id, mac, instance_id, tag=2000)
self.assertTrue(self._check_bridge(port_bridge))
self.assertTrue(self._check_bridge(int_bridge))
expected_external_ids = {'iface-status': 'active',
'iface-id': iface_id,
'attached-mac': mac,
'vm-uuid': instance_id}
self._check_parameter(
'Interface', int_bridge_port, 'external_ids',
expected_external_ids)
self._check_parameter('Interface', int_bridge_port, 'type', 'patch')
port_opts = {'peer': port_bridge_port}
self._check_parameter(
'Interface', int_bridge_port, 'options', port_opts)
self._check_parameter('Port', int_bridge_port, 'tag', 2000)
port_opts = {'peer': int_bridge_port}
self._check_parameter(
'Interface', port_bridge_port, 'options', port_opts)
def test_create_ovs_vif_port_with_default_qos(self):
if self.interface == 'native':
self.skipTest(
'test_create_ovs_vif_port_with_default_qos is unstable '
'when run with the native driver, see: '
'https://bugs.launchpad.net/os-vif/+bug/2087982')
port_name = 'qos-port-' + self.interface
iface_id = 'iface_id'
mac = 'ca:fe:ca:fe:ca:fe'
instance_id = uuidutils.generate_uuid()
mtu = 1500
interface_type = 'internal'
qos_type = CONF.os_vif_ovs.default_qos_type
self.addCleanup(self._del_bridge, self.brname)
self._add_bridge(self.brname)
self.addCleanup(
self.ovs.delete_ovs_vif_port, self.brname, port_name,
delete_netdev=False, qos_type=qos_type
)
self.ovs.create_ovs_vif_port(
self.brname, port_name, iface_id, mac,
instance_id, mtu=mtu, interface_type=interface_type,
tag=2000, qos_type=qos_type
)
# first we assert that the standard parameters are set correctly
expected_external_ids = {'iface-status': 'active',
'iface-id': iface_id,
'attached-mac': mac,
'vm-uuid': instance_id}
self._check_parameter('Interface', port_name, 'external_ids',
expected_external_ids)
self._check_parameter('Interface', port_name, 'type', interface_type)
self._check_parameter('Port', port_name, 'tag', 2000)
# now we check that the port has a qos policy attached
qos_uuid = self.ovs.get_qos(
port_name, qos_type
)[0]['_uuid']
self._check_parameter('Port', port_name, 'qos', qos_uuid)
# finally we check that the qos policy has the correct parameters
self._check_parameter(
'QoS', str(qos_uuid), 'type', qos_type
)
def test_delete_qos_if_exists(self):
port_name = 'del-qos-port-' + self.interface
iface_id = 'iface_id'
mac = 'ca:fe:ca:fe:ca:fe'
instance_id = uuidutils.generate_uuid()
interface_type = 'internal'
qos_type = CONF.os_vif_ovs.default_qos_type
# setup test by creating a bridge and port, and register
# cleanup funcitons to avoid leaking them.
self.addCleanup(self._del_bridge, self.brname)
self._add_bridge(self.brname)
self.addCleanup(
self.ovs.delete_ovs_vif_port, self.brname, port_name,
delete_netdev=False, qos_type=qos_type
)
self.ovs.create_ovs_vif_port(
self.brname, port_name, iface_id, mac,
instance_id, interface_type=interface_type,
qos_type=qos_type
)
# now we check that the port has a qos policy attached
qos_uuid = self.ovs.get_qos(
port_name, CONF.os_vif_ovs.default_qos_type
)[0]['_uuid']
self._check_parameter('Port', port_name, 'qos', qos_uuid)
# finally we check that the qos policy has the correct parameters
self._check_parameter(
'QoS', str(qos_uuid), 'type', qos_type
)
# we need to delete the port directly in the db to remove
# any references to the qos policy
self.ovs.ovsdb.del_port(
port_name, bridge=self.brname, if_exists=True).execute()
# then we can delete the qos policy
self.ovs.delete_qos_if_exists(port_name, qos_type)
self._check_parameter(
'QoS', str(qos_uuid), 'type', None
)
# invoking the delete when the policy does not exist
# should not result in an error
self.ovs.delete_qos_if_exists(port_name, qos_type)
self._check_parameter(
'QoS', str(qos_uuid), 'type', None
)
def test_get_qos(self):
port_name = 'get-qos-' + self.interface
iface_id = 'iface_id'
mac = 'ca:fe:ca:fe:ca:fe'
instance_id = uuidutils.generate_uuid()
interface_type = 'internal'
qos_type = CONF.os_vif_ovs.default_qos_type
# initally no qos policy should exist
self.assertEqual(0, len(self.ovs.get_qos(port_name, qos_type)))
# if we create a port with a qos policy get_qos should
# return the policy
self.addCleanup(self._del_bridge, self.brname)
self._add_bridge(self.brname)
self.addCleanup(
self.ovs.delete_ovs_vif_port, self.brname, port_name,
delete_netdev=False, qos_type=qos_type
)
self.ovs.create_ovs_vif_port(
self.brname, port_name, iface_id, mac,
instance_id, interface_type=interface_type,
qos_type=qos_type
)
# result should be a list of lenght 1 containing the
# qos policy created for the port we defied.
result = self.ovs.get_qos(port_name, qos_type)
self.assertEqual(1, len(result))
self.assertIn('_uuid', result[0])
self._check_parameter(
'Port', port_name, 'qos', result[0]['_uuid']
)
# if we delete the port and its qos policy get_qos should
# not return it.
self.ovs.delete_ovs_vif_port(
self.brname, port_name,
delete_netdev=False, qos_type=qos_type
)
self.assertEqual(0, len(self.ovs.get_qos(port_name, qos_type)))
def test_port_exists(self):
port_name = 'port-exists-' + self.interface
iface_id = 'iface_id'
mac = 'ca:fe:ca:fe:ca:fe'
instance_id = uuidutils.generate_uuid()
interface_type = 'internal'
self.assertFalse(self.ovs.port_exists(port_name, self.brname))
self.addCleanup(self._del_bridge, self.brname)
self._add_bridge(self.brname)
self.addCleanup(
self.ovs.delete_ovs_vif_port, self.brname, port_name,
delete_netdev=False,
)
self.ovs.create_ovs_vif_port(
self.brname, port_name, iface_id, mac,
instance_id, interface_type=interface_type,
)
self.assertTrue(self.ovs.port_exists(port_name, self.brname))