diff options
19 files changed, 185 insertions, 122 deletions
diff --git a/doc/source/contributor/testing/ci_scenario_jobs.rst b/doc/source/contributor/testing/ci_scenario_jobs.rst index af81cef608..6d0e030374 100644 --- a/doc/source/contributor/testing/ci_scenario_jobs.rst +++ b/doc/source/contributor/testing/ci_scenario_jobs.rst @@ -139,11 +139,6 @@ Currently we have in that queue jobs like listed below. | |(only tests related to | | | | | | | | | | | |Neutron and Nova) | | | | | | | | | | +----------------------------------------------+----------------------------------+-------+------------------+-------------+-----------------+----------+-------+--------+------------+-------------+ - |neutron-tempest-with-uwsgi-loki |tempest.api (without slow tests) | 1 | Ubuntu Jammy | openvswitch | openvswitch | legacy | False | False | True | No | - |(non-voting) |tempest.scenario | | | | | | | | | | - | |(only tests related to | | | | | | | | | | - | |Neutron and Nova) | | | | | | | | | | - +----------------------------------------------+----------------------------------+-------+------------------+-------------+-----------------+----------+-------+--------+------------+-------------+ |neutron-ovn-tempest-ipv6-only-ovs-master |tempest.api (without slow tests) | 1 | Ubuntu Jammy | ovn | ovn | --- | False | False | True | Yes | | |(only tests related to | | | | | | | | | | | |Neutron and Nova) | | | | | | | | | | diff --git a/neutron/conf/policies/port.py b/neutron/conf/policies/port.py index faab5c8f62..5783f080bb 100644 --- a/neutron/conf/policies/port.py +++ b/neutron/conf/policies/port.py @@ -276,6 +276,7 @@ rules = [ check_str=neutron_policy.policy_or( base.ADMIN, neutron_policy.RULE_ADVSVC, + base.RULE_NET_OWNER, base.PROJECT_READER ), scope_types=['project'], diff --git a/neutron/db/dvr_mac_db.py b/neutron/db/dvr_mac_db.py index 68ec42ae59..4f69ffd995 100644 --- a/neutron/db/dvr_mac_db.py +++ b/neutron/db/dvr_mac_db.py @@ -157,6 +157,7 @@ class DVRDbMixin(ext_dvr.DVRMacAddressPluginBase): @log_helpers.log_method_call @db_api.retry_if_session_inactive() + @db_api.CONTEXT_READER def get_ports_on_host_by_subnet(self, context, host, subnet): """Returns DVR serviced ports on a given subnet in the input host diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py index a9edbbd4f5..37898652df 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py @@ -2323,7 +2323,7 @@ class OVNClient(object): mport_updated = False if subnet['ip_version'] == const.IP_VERSION_4: mport_updated = self.update_metadata_port( - context, network['id'], subnet=subnet) + context, network, subnet=subnet) if subnet['ip_version'] == const.IP_VERSION_6 or not mport_updated: # NOTE(ralonsoh): if IPv4 but the metadata port has not been # updated, the DHPC options register has not been created. @@ -2343,7 +2343,7 @@ class OVNClient(object): subnet['id'])['subnet'] if subnet['enable_dhcp'] or ovn_subnet: - self.update_metadata_port(context, network['id'], subnet=subnet) + self.update_metadata_port(context, network, subnet=subnet) check_rev_cmd = self._nb_idl.check_revision_number( subnet['id'], subnet, ovn_const.TYPE_SUBNETS) @@ -2439,8 +2439,9 @@ class OVNClient(object): if not ovn_conf.is_ovn_metadata_enabled(): return - if self._find_metadata_port(context, network['id']): - return + metadata_port = self._find_metadata_port(context, network['id']) + if metadata_port: + return metadata_port # Create a neutron port for DHCP/metadata services filters = {'network_id': [network['id']]} @@ -2455,16 +2456,19 @@ class OVNClient(object): } } # TODO(boden): rehome create_port into neutron-lib - p_utils.create_port(self._plugin, context, port) + return p_utils.create_port(self._plugin, context, port) - def update_metadata_port(self, context, network_id, subnet=None): + def update_metadata_port(self, context, network, subnet=None): """Update metadata port. This function will allocate an IP address for the metadata port of the given network in all its IPv4 subnets or the given subnet. Returns "True" if the metadata port has been updated and "False" if OVN - metadata is disabled or the metadata port does not exist. + metadata is disabled or the metadata port does not exist or + cannot be created. """ + network_id = network['id'] + def update_metadata_port_fixed_ips(metadata_port, add_subnet_ids, del_subnet_ids): wanted_fixed_ips = [ @@ -2483,11 +2487,11 @@ class OVNClient(object): if not ovn_conf.is_ovn_metadata_enabled(): return False - # Retrieve the metadata port of this network - metadata_port = self._find_metadata_port(context, network_id) + # Retrieve or create the metadata port of this network + metadata_port = self.create_metadata_port(context, network) if not metadata_port: - LOG.error("Metadata port couldn't be found for network %s", - network_id) + LOG.error("Metadata port could not be found or created " + "for network %s", network_id) return False port_subnet_ids = set(ip['subnet_id'] for ip in diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py index 0a307f78ee..f53bc8423b 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py @@ -960,7 +960,7 @@ class OvnNbSynchronizer(OvnDbSynchronizer): try: # Make sure that this port has an IP address in all the # subnets - self._ovn_client.update_metadata_port(ctx, net['id']) + self._ovn_client.update_metadata_port(ctx, net) except n_exc.IpAddressGenerationFailure: LOG.error('Could not allocate IP addresses for ' 'metadata port in network %s', net['id']) diff --git a/neutron/tests/functional/base.py b/neutron/tests/functional/base.py index 8321c2a6ee..8ef793989e 100644 --- a/neutron/tests/functional/base.py +++ b/neutron/tests/functional/base.py @@ -21,13 +21,9 @@ from unittest import mock import warnings import fixtures -from neutron_lib import fixture from neutron_lib.plugins import constants from neutron_lib.plugins import directory -from oslo_concurrency import lockutils from oslo_config import cfg -from oslo_db import exception as os_db_exc -from oslo_db.sqlalchemy import provision from oslo_log import log from oslo_utils import timeutils from oslo_utils import uuidutils @@ -61,7 +57,6 @@ LOG = log.getLogger(__name__) # This is the directory from which infra fetches log files for functional tests DEFAULT_LOG_DIR = os.path.join(helpers.get_test_log_path(), 'dsvm-functional-logs') -SQL_FIXTURE_LOCK = 'sql_fixture_lock' def config_decorator(method_to_decorate, config_tuples): @@ -134,27 +129,6 @@ class BaseSudoTestCase(BaseLoggingTestCase): new=ovs_agent_decorator).start() -class OVNSqlFixture(fixture.StaticSqlFixture): - - @classmethod - @lockutils.synchronized(SQL_FIXTURE_LOCK) - def _init_resources(cls): - cls.schema_resource = provision.SchemaResource( - provision.DatabaseResource("sqlite"), - cls._generate_schema, teardown=False) - dependency_resources = {} - for name, resource in cls.schema_resource.resources: - dependency_resources[name] = resource.getResource() - cls.schema_resource.make(dependency_resources) - cls.engine = dependency_resources['database'].engine - - def _delete_from_schema(self, engine): - try: - super(OVNSqlFixture, self)._delete_from_schema(engine) - except os_db_exc.DBNonExistentTable: - pass - - class TestOVNFunctionalBase(test_plugin.Ml2PluginV2TestCase, BaseLoggingTestCase): @@ -251,16 +225,6 @@ class TestOVNFunctionalBase(test_plugin.Ml2PluginV2TestCase, raise FileNotFoundError( errno.ENOENT, os.strerror(errno.ENOENT), msg) - # FIXME(lucasagomes): Workaround for - # https://bugs.launchpad.net/networking-ovn/+bug/1808146. We should - # investigate and properly fix the problem. This method is just a - # workaround to alleviate the gate for now and should not be considered - # a proper fix. - def _setup_database_fixtures(self): - fixture = OVNSqlFixture() - self.useFixture(fixture) - self.engine = fixture.engine - def get_additional_service_plugins(self): p = super(TestOVNFunctionalBase, self).get_additional_service_plugins() p.update({'revision_plugin_name': 'revisions', diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py index 18f3f0d554..ee92f68dbd 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py @@ -995,6 +995,7 @@ class TestMetadataPorts(base.TestOVNFunctionalBase): def setUp(self, *args, **kwargs): super().setUp(*args, **kwargs) + self.plugin = self.mech_driver._plugin self._ovn_client = self.mech_driver._ovn_client self.meta_regex = re.compile(r'%s,(\d+\.\d+\.\d+\.\d+)' % constants.METADATA_V4_CIDR) @@ -1017,7 +1018,7 @@ class TestMetadataPorts(base.TestOVNFunctionalBase): res = self._list_ports(self.fmt, net_id=net_id) return self.deserialize(self.fmt, res)['ports'] - def _check_metadata_port(self, net_id, fixed_ip): + def _check_metadata_port(self, net_id, fixed_ip, fail=True): for port in self._list_ports_ovn(net_id=net_id): if ovn_client.OVNClient.is_metadata_port(port): self.assertEqual(net_id, port['network_id']) @@ -1027,13 +1028,17 @@ class TestMetadataPorts(base.TestOVNFunctionalBase): self.assertEqual([], port['fixed_ips']) return port['id'] - self.fail('Metadata port is not present in network %s or data is not ' - 'correct' % self.n1_id) + if fail: + self.fail('Metadata port is not present in network %s or data is ' + 'not correct' % self.n1_id) def _check_subnet_dhcp_options(self, subnet_id, cidr): - # This method checks the DHCP options CIDR and returns, if exits, the - # metadata port IP address, included in the classless static routes. + # This method checks DHCP options for a subnet ID, and if they exist, + # verifies the CIDR matches. Returns the metadata port IP address + # if it is included in the classless static routes, else returns None. dhcp_opts = self._ovn_client._nb_idl.get_subnet_dhcp_options(subnet_id) + if not dhcp_opts['subnet']: + return self.assertEqual(cidr, dhcp_opts['subnet']['cidr']) routes = dhcp_opts['subnet']['options'].get('classless_static_route') if not routes: @@ -1062,6 +1067,35 @@ class TestMetadataPorts(base.TestOVNFunctionalBase): fixed_ip = {'subnet_id': subnet['id'], 'ip_address': metatada_ip} self._check_metadata_port(self.n1_id, fixed_ip) + def test_update_subnet_ipv4(self): + self._create_network_ovn(metadata_enabled=True) + subnet = self._create_subnet_ovn('10.0.0.0/24') + metatada_ip = self._check_subnet_dhcp_options(subnet['id'], + '10.0.0.0/24') + fixed_ip = {'subnet_id': subnet['id'], 'ip_address': metatada_ip} + port_id = self._check_metadata_port(self.n1_id, fixed_ip) + + # Disable DHCP, port should still be present + subnet['enable_dhcp'] = False + self._ovn_client.update_subnet(self.context, subnet, + self.n1['network']) + port_id = self._check_metadata_port(self.n1_id, None) + self.assertIsNone(self._check_subnet_dhcp_options(subnet['id'], [])) + + # Delete metadata port + self.plugin.delete_port(self.context, port_id) + port_id = self._check_metadata_port(self.n1_id, None, fail=False) + self.assertIsNone(port_id) + + # Enable DHCP, metadata port should have been re-created + subnet['enable_dhcp'] = True + self._ovn_client.update_subnet(self.context, subnet, + self.n1['network']) + metatada_ip = self._check_subnet_dhcp_options(subnet['id'], + '10.0.0.0/24') + fixed_ip = {'subnet_id': subnet['id'], 'ip_address': metatada_ip} + port_id = self._check_metadata_port(self.n1_id, fixed_ip) + def test_subnet_ipv4_no_metadata(self): self._create_network_ovn(metadata_enabled=False) subnet = self._create_subnet_ovn('10.0.0.0/24') diff --git a/neutron/tests/unit/extensions/test_network_segment_range.py b/neutron/tests/unit/extensions/test_network_segment_range.py index af43081e6f..2592a0366a 100644 --- a/neutron/tests/unit/extensions/test_network_segment_range.py +++ b/neutron/tests/unit/extensions/test_network_segment_range.py @@ -19,6 +19,7 @@ from neutron_lib import context from oslo_config import cfg import webob.exc +from neutron.common import config from neutron.db import db_base_plugin_v2 from neutron.db import segments_db from neutron.extensions import network_segment_range as ext_range @@ -112,6 +113,7 @@ class NetworkSegmentRangeTestPlugin(db_base_plugin_v2.NeutronDbPluginV2, class TestNetworkSegmentRange(NetworkSegmentRangeTestBase): def setUp(self, plugin=None): + config.register_common_config_options() if not plugin: plugin = TEST_PLUGIN_KLASS service_plugins = {'network_segment_range_plugin_name': diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py index f768bf7635..72e1ce4b74 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py @@ -34,6 +34,7 @@ from neutron_lib import context from neutron_lib import exceptions as n_exc from neutron_lib.placement import utils as place_utils from neutron_lib.plugins import directory +from neutron_lib.plugins import utils as p_utils from neutron_lib.tests import tools from neutron_lib.utils import net as n_net from oslo_concurrency import processutils @@ -1754,7 +1755,8 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): self.mech_driver.update_subnet_postcommit(context) esd.assert_called_once_with( context.current, context.network.current, mock.ANY) - umd.assert_called_once_with(mock.ANY, 'id', subnet=subnet) + umd.assert_called_once_with(mock.ANY, context.network.current, + subnet=subnet) def test_update_subnet_postcommit_disable_dhcp(self): self.mech_driver.nb_ovn.get_subnet_dhcp_options.return_value = { @@ -1770,7 +1772,8 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): 'update_metadata_port') as umd: self.mech_driver.update_subnet_postcommit(context) dsd.assert_called_once_with(context.current['id'], mock.ANY) - umd.assert_called_once_with(mock.ANY, 'id', subnet=subnet) + umd.assert_called_once_with(mock.ANY, context.network.current, + subnet=subnet) def test_update_subnet_postcommit_update_dhcp(self): self.mech_driver.nb_ovn.get_subnet_dhcp_options.return_value = { @@ -1787,7 +1790,8 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): self.mech_driver.update_subnet_postcommit(context) usd.assert_called_once_with( context.current, context.network.current, mock.ANY) - umd.assert_called_once_with(mock.ANY, 'id', subnet=subnet) + umd.assert_called_once_with(mock.ANY, context.network.current, + subnet=subnet) def test__get_port_options(self): with mock.patch.object(self.mech_driver._plugin, 'get_subnets') as \ @@ -1979,9 +1983,10 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): mock_metaport.return_value = {'fixed_ips': fixed_ips, 'id': 'metadata_id'} mock_get_subnets.return_value = [{'id': 'subnet1'}] + network = {'id': 'net_id'} subnet = {'id': 'subnet1', 'enable_dhcp': True} self.mech_driver._ovn_client.update_metadata_port( - self.context, 'net_id', subnet=subnet) + self.context, network, subnet=subnet) mock_update_port.assert_not_called() # Subnet without DHCP, present in port. @@ -1991,7 +1996,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): mock_get_subnets.return_value = [{'id': 'subnet1'}] subnet = {'id': 'subnet1', 'enable_dhcp': False} self.mech_driver._ovn_client.update_metadata_port( - self.context, 'net_id', subnet=subnet) + self.context, network, subnet=subnet) port = {'id': 'metadata_id', 'port': {'network_id': 'net_id', 'fixed_ips': []}} mock_update_port.assert_called_once_with(mock.ANY, 'metadata_id', @@ -2004,7 +2009,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): mock_get_subnets.return_value = [] subnet = {'id': 'subnet1', 'enable_dhcp': True} self.mech_driver._ovn_client.update_metadata_port( - self.context, 'net_id', subnet=subnet) + self.context, network, subnet=subnet) fixed_ips = [{'subnet_id': 'subnet1'}] port = {'id': 'metadata_id', 'port': {'network_id': 'net_id', 'fixed_ips': fixed_ips}} @@ -2018,7 +2023,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): mock_get_subnets.return_value = [] subnet = {'id': 'subnet1', 'enable_dhcp': False} self.mech_driver._ovn_client.update_metadata_port( - self.context, 'net_id', subnet=subnet) + self.context, network, subnet=subnet) mock_update_port.assert_not_called() def test_update_metadata_port_no_subnet(self): @@ -2035,10 +2040,11 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): mock_get_subnets.return_value = [{'id': 'subnet1'}, {'id': 'subnet2'}] fixed_ips = [{'subnet_id': 'subnet1', 'ip_address': 'ip_add1'}] + network = {'id': 'net_id'} mock_metaport.return_value = {'fixed_ips': fixed_ips, 'id': 'metadata_id'} self.mech_driver._ovn_client.update_metadata_port(self.context, - 'net_id') + network) port = {'id': 'metadata_id', 'port': {'network_id': 'net_id', 'fixed_ips': fixed_ips}} fixed_ips.append({'subnet_id': 'subnet2'}) @@ -2049,10 +2055,11 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): # Port with IP in subnet1; subnet1 with DHCP, subnet2 without DHCP. mock_get_subnets.return_value = [{'id': 'subnet1'}] fixed_ips = [{'subnet_id': 'subnet1', 'ip_address': 'ip_add1'}] + network = {'id': 'net_id'} mock_metaport.return_value = {'fixed_ips': fixed_ips, 'id': 'metadata_id'} self.mech_driver._ovn_client.update_metadata_port(self.context, - 'net_id') + network) mock_update_port.assert_not_called() # Port with IP in subnet1; subnet1 without DHCP. @@ -2061,13 +2068,51 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): mock_metaport.return_value = {'fixed_ips': fixed_ips, 'id': 'metadata_id'} self.mech_driver._ovn_client.update_metadata_port(self.context, - 'net_id') + network) port = {'id': 'metadata_id', 'port': {'network_id': 'net_id', 'fixed_ips': []}} mock_update_port.assert_called_once_with( mock.ANY, 'metadata_id', port) mock_update_port.reset_mock() + def test_update_metadata_port_no_port(self): + ovn_conf.cfg.CONF.set_override('ovn_metadata_enabled', True, + group='ovn') + + with mock.patch.object( + self.mech_driver._ovn_client, '_find_metadata_port') as \ + mock_find_metaport, \ + mock.patch.object(self.mech_driver._plugin, 'get_subnets') as \ + mock_get_subnets, \ + mock.patch.object(p_utils, 'create_port') as \ + mock_create_port: + # Subnet with DHCP, no port, port created. + network = {'id': 'net_id', 'project_id': 'project_id-foo'} + subnet = {'id': 'subnet1', 'enable_dhcp': True} + fixed_ips = [{'subnet_id': 'subnet1', 'ip_address': 'ip_add1'}] + port = {'id': 'metadata_id', + 'network_id': 'net_id', + 'device_owner': const.DEVICE_OWNER_DISTRIBUTED, + 'device_id': 'ovnmeta-%s' % 'net_id', + 'fixed_ips': fixed_ips} + mock_get_subnets.return_value = [subnet] + mock_find_metaport.return_value = None + + # Subnet with DHCP, no port, port create failure. + mock_create_port.return_value = None + ret_status = self.mech_driver._ovn_client.update_metadata_port( + self.context, network, subnet=subnet) + self.assertFalse(ret_status) + mock_create_port.assert_called_once() + + # Subnet with DHCP, no port, port created successfully. + mock_create_port.reset_mock() + mock_create_port.return_value = port + ret_status = self.mech_driver._ovn_client.update_metadata_port( + self.context, network, subnet=subnet) + self.assertTrue(ret_status) + mock_create_port.assert_called_once() + @mock.patch.object(provisioning_blocks, 'is_object_blocked') @mock.patch.object(provisioning_blocks, 'provisioning_complete') def test_notify_dhcp_updated(self, mock_prov_complete, mock_is_obj_block): diff --git a/neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py b/neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py index 75783ad0b4..d04e525a4f 100644 --- a/neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py +++ b/neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py @@ -27,6 +27,7 @@ from oslo_config import cfg from oslo_utils import uuidutils import testtools +from neutron.common import config from neutron.objects import ports as port_obj from neutron.plugins.ml2.extensions import dns_integration from neutron.services.externaldns.drivers.designate import driver @@ -53,6 +54,7 @@ class DNSIntegrationTestCase(test_plugin.Ml2PluginV2TestCase): _domain = DNSDOMAIN def setUp(self): + config.register_common_config_options() cfg.CONF.set_override('extension_drivers', self._extension_drivers, group='ml2') diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py index ccc72464f8..9e40801adc 100644 --- a/neutron/tests/unit/plugins/ml2/test_plugin.py +++ b/neutron/tests/unit/plugins/ml2/test_plugin.py @@ -49,6 +49,7 @@ import webob from neutron._i18n import _ from neutron.agent import rpc as agent_rpc +from neutron.common import config from neutron.common import utils from neutron.db import agents_db from neutron.db import ipam_pluggable_backend @@ -673,6 +674,7 @@ class TestMl2NetworksWithVlanTransparencyBase(TestMl2NetworksV2): 'vlan_transparent': 'True'}} def setUp(self, plugin=None): + config.register_common_config_options() cfg.CONF.set_override('vlan_transparent', True) super(TestMl2NetworksWithVlanTransparencyBase, self).setUp(plugin) @@ -903,6 +905,9 @@ class TestMl2DbOperationBounds(test_plugin.DbOperationBoundMixin, def setUp(self): super(TestMl2DbOperationBounds, self).setUp() self.kwargs = self.get_api_kwargs() + # NOTE(slaweq): In this class we are not testing any operations related + # to policy module so we don't need to checu policies + mock.patch('neutron.policy.check').start() def make_network(self): return self._make_network(self.fmt, 'name', True, **self.kwargs) diff --git a/neutron/tests/unit/services/metering/test_metering_plugin.py b/neutron/tests/unit/services/metering/test_metering_plugin.py index c83d21a94e..87a593bcf9 100644 --- a/neutron/tests/unit/services/metering/test_metering_plugin.py +++ b/neutron/tests/unit/services/metering/test_metering_plugin.py @@ -220,10 +220,10 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, with self.router(tenant_id=self.project_id, set_context=True): with self.metering_label(tenant_id=self.project_id, set_context=True) as label: - self.mock_add.assert_called_with(self.ctx, expected) + self.mock_add.assert_called_with(mock.ANY, expected) self._delete('metering-labels', label['metering_label']['id']) - self.mock_remove.assert_called_with(self.ctx, expected) + self.mock_remove.assert_called_with(mock.ANY, expected) def test_remove_one_metering_label_rpc_call(self): second_uuid = 'e27fe2df-376e-4ac7-ae13-92f050a21f84' @@ -259,10 +259,10 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, self.mock_uuid.return_value = second_uuid with self.metering_label(tenant_id=self.project_id, set_context=True) as label: - self.mock_add.assert_called_with(self.ctx, expected_add) + self.mock_add.assert_called_with(mock.ANY, expected_add) self._delete('metering-labels', label['metering_label']['id']) - self.mock_remove.assert_called_with(self.ctx, expected_remove) + self.mock_remove.assert_called_with(mock.ANY, expected_remove) def test_add_and_remove_metering_label_rule_rpc_call(self): second_uuid = 'e27fe2df-376e-4ac7-ae13-92f050a21f84' @@ -313,10 +313,10 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, la = label['metering_label'] self.mock_uuid.return_value = second_uuid with self.metering_label_rule(la['id'], **remote_ip_prefix): - self.mock_add_rule.assert_called_with(self.ctx, + self.mock_add_rule.assert_called_with(mock.ANY, expected_add) self._delete('metering-label-rules', second_uuid) - self.mock_remove_rule.assert_called_with(self.ctx, + self.mock_remove_rule.assert_called_with(mock.ANY, expected_del) def test_add_and_remove_metering_label_rule_source_ip_only(self): @@ -369,10 +369,10 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, self.mock_uuid.return_value = second_uuid with self.metering_label_rule(la['id'], **source_ip_prefix): - self.mock_add_rule.assert_called_with(self.ctx, + self.mock_add_rule.assert_called_with(mock.ANY, expected_add) self._delete('metering-label-rules', second_uuid) - self.mock_remove_rule.assert_called_with(self.ctx, + self.mock_remove_rule.assert_called_with(mock.ANY, expected_del) def test_add_and_remove_metering_label_rule_dest_ip_only(self): @@ -425,10 +425,10 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, self.mock_uuid.return_value = second_uuid with self.metering_label_rule(la['id'], **source_ip_prefix): - self.mock_add_rule.assert_called_with(self.ctx, + self.mock_add_rule.assert_called_with(mock.ANY, expected_add) self._delete('metering-label-rules', second_uuid) - self.mock_remove_rule.assert_called_with(self.ctx, + self.mock_remove_rule.assert_called_with(mock.ANY, expected_del) def test_add_and_remove_metering_label_rule_src_and_dest_ip_only(self): @@ -484,10 +484,10 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, self.mock_uuid.return_value = second_uuid with self.metering_label_rule(la['id'], **ip_prefixes): - self.mock_add_rule.assert_called_with(self.ctx, + self.mock_add_rule.assert_called_with(mock.ANY, expected_add) self._delete('metering-label-rules', second_uuid) - self.mock_remove_rule.assert_called_with(self.ctx, + self.mock_remove_rule.assert_called_with(mock.ANY, expected_del) def test_add_and_remove_metering_label_rule_src_and_remote_ip(self): diff --git a/releasenotes/notes/ovn-recreate-metadata-port-76e2c0e651267aa0.yaml b/releasenotes/notes/ovn-recreate-metadata-port-76e2c0e651267aa0.yaml new file mode 100644 index 0000000000..dfe077945b --- /dev/null +++ b/releasenotes/notes/ovn-recreate-metadata-port-76e2c0e651267aa0.yaml @@ -0,0 +1,11 @@ +--- +fixes: + - | + Fix an issue in the OVN driver where network metadata could + become unavailable if the metadata port was ever deleted, even + if accidental. To re-create the port, a user can now disable, + then enable, DHCP for one of the subnets associated with the + network using the Neutron API. This will try and create the + port, similar to what happens in the DHCP agent for ML2/OVS. + For more information, see bug `2015377 + <https://bugs.launchpad.net/ubuntu/+source/neutron/+bug/2015377>`_. @@ -79,8 +79,8 @@ setenv = {[testenv:dsvm-functional]setenv} deps = {[testenv:dsvm-functional]deps} commands = bash {toxinidir}/tools/deploy_rootwrap.sh {toxinidir} {envdir}/etc {envdir}/bin - stestr run --exclude-regex (.*MySQL\.|.*PostgreSQL\.|.*test_get_all_devices|.*TestMetadataAgent\.) {posargs} - stestr run --combine --concurrency 1 (.*MySQL\.|.*PostgreSQL\.|.*test_get_all_devices|.*TestMetadataAgent\.) {posargs} + stestr run --slowest --exclude-regex (.*MySQL\.|.*PostgreSQL\.|.*test_get_all_devices|.*TestMetadataAgent\.) {posargs} + stestr run --slowest --combine --concurrency 1 (.*MySQL\.|.*PostgreSQL\.|.*test_get_all_devices|.*TestMetadataAgent\.) {posargs} [testenv:dsvm-fullstack] setenv = {[testenv]setenv} @@ -105,8 +105,8 @@ deps = {[testenv:dsvm-fullstack]deps} commands = bash {toxinidir}/tools/generate_dhclient_script_for_fullstack.sh {envdir} bash {toxinidir}/tools/deploy_rootwrap.sh {toxinidir} {envdir}/etc {envdir}/bin - stestr run --concurrency 2 --exclude-regex neutron.tests.fullstack.test_securitygroup.TestSecurityGroupsSameNetwork.test_securitygroup {posargs} - stestr run --combine --concurrency 1 neutron.tests.fullstack.test_securitygroup.TestSecurityGroupsSameNetwork.test_securitygroup {posargs} + stestr run --slowest --concurrency 2 --exclude-regex neutron.tests.fullstack.test_securitygroup.TestSecurityGroupsSameNetwork.test_securitygroup {posargs} + stestr run --slowest --combine --concurrency 1 neutron.tests.fullstack.test_securitygroup.TestSecurityGroupsSameNetwork.test_securitygroup {posargs} [testenv:releasenotes] envdir = {toxworkdir}/docs diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index 64301d9990..073ea3218f 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -117,12 +117,14 @@ - job: name: neutron-fullstack-with-uwsgi-with-neutron-lib-master + branches: ^master$ parent: neutron-fullstack-with-uwsgi required-projects: - openstack/neutron-lib - job: name: neutron-fullstack-with-pyroute2-master + branches: ^master$ parent: neutron-fullstack required-projects: - name: github.com/svinota/pyroute2 @@ -142,6 +144,7 @@ - job: name: neutron-functional-with-uwsgi-with-neutron-lib-master + branches: ^master$ parent: neutron-functional-with-uwsgi required-projects: - openstack/neutron-lib @@ -166,12 +169,14 @@ - job: name: neutron-functional-with-pyroute2-master + branches: ^master$ parent: neutron-functional required-projects: - name: github.com/svinota/pyroute2 - job: name: neutron-functional-with-oslo-master + branches: ^master$ parent: neutron-functional description: | This job installs all oslo libraries from source and executes the @@ -212,6 +217,7 @@ - job: name: neutron-functional-with-sqlalchemy-master + branches: ^master$ parent: neutron-functional required-projects: - name: github.com/sqlalchemy/sqlalchemy diff --git a/zuul.d/grenade.yaml b/zuul.d/grenade.yaml index 921726724f..0c35f846c3 100644 --- a/zuul.d/grenade.yaml +++ b/zuul.d/grenade.yaml @@ -293,6 +293,8 @@ zuul_copy_output: '{{ devstack_base_dir }}/data/ovs': 'logs' '{{ devstack_base_dir }}/data/ovn': 'logs' + '/opt/stack/old/logs': 'logs' + '/opt/stack/new/logs': 'logs' extensions_to_txt: db: true devstack_services: diff --git a/zuul.d/job-templates.yaml b/zuul.d/job-templates.yaml index dbea01ec9e..c092cabc4b 100644 --- a/zuul.d/job-templates.yaml +++ b/zuul.d/job-templates.yaml @@ -23,6 +23,9 @@ - ^roles/.*$ - ^rally-jobs/.*$ - ^zuul.d/(?!(job-templates)).*\.yaml + - openstack-tox-py39: # from openstack-python3-jobs template + timeout: 3600 + irrelevant-files: *irrelevant-files - openstack-tox-py310: # from openstack-python3-jobs template timeout: 3600 irrelevant-files: *irrelevant-files @@ -40,6 +43,9 @@ - openstack-tox-py38-arm64: # from openstack-python3-jobs-arm64 template timeout: 4800 irrelevant-files: *irrelevant-files + - openstack-tox-py39-arm64: # from openstack-python3-jobs-arm64 template + timeout: 4800 + irrelevant-files: *irrelevant-files - openstack-tox-py310-arm64: # from openstack-python3-jobs-arm64 template timeout: 4800 irrelevant-files: *irrelevant-files @@ -48,6 +54,9 @@ - openstack-tox-py38: # from openstack-python3-jobs template timeout: 3600 irrelevant-files: *irrelevant-files + - openstack-tox-py39: # from openstack-python3-jobs template + timeout: 3600 + irrelevant-files: *irrelevant-files - openstack-tox-py310: # from openstack-python3-jobs template timeout: 3600 irrelevant-files: *irrelevant-files @@ -56,51 +65,19 @@ name: neutron-experimental-jobs experimental: jobs: - - neutron-functional - - neutron-functional-with-uwsgi-fips - neutron-functional-with-uwsgi-with-neutron-lib-master - - neutron-functional-with-pyroute2-master - - neutron-functional-with-sqlalchemy-master - - neutron-fullstack - - neutron-fullstack-with-uwsgi-fips - neutron-fullstack-with-uwsgi-with-neutron-lib-master - - neutron-fullstack-with-pyroute2-master - - neutron-ovn-grenade-multinode - - neutron-ovn-tempest-with-uwsgi-loki - neutron-ovn-tempest-full-multinode-ovs-master + - neutron-ovn-grenade-multinode - neutron-ovn-tempest-ovs-master - - neutron-ovn-tempest-with-neutron-lib-master - - neutron-ovs-tempest-with-neutron-lib-master - - neutron-ovs-tempest-slow - - neutron-ovn-tempest-slow - - neutron-ovs-tempest-with-os-ken-master - - neutron-ovn-tempest-postgres-full - - neutron-ovn-tempest-mariadb-full - neutron-ovn-tempest-ovs-release - - neutron-ovn-tempest-ipv6-only-ovs-master - - neutron-ovn-tempest-ovs-master-centos-9-stream - - neutron-ovn-tempest-with-sqlalchemy-master - - neutron-ovs-tempest-with-sqlalchemy-master - - neutron-ovs-tempest-fips - - neutron-ovn-tempest-ovs-release-fips - - devstack-tobiko-neutron: - voting: true - - ironic-tempest-ipa-wholedisk-bios-agent_ipmitool-tinyipa - - openstacksdk-functional-devstack-networking - - neutron-linuxbridge-tempest-plugin-scenario-nftables - - neutron-ovs-tempest-plugin-scenario-iptables_hybrid-nftables - - devstack-enforce-scope - - openstack-tox-py39-with-oslo-master: - timeout: 3600 - irrelevant-files: *irrelevant-files - - neutron-functional-with-oslo-master - - neutron-ovs-tempest-with-oslo-master - - neutron-ovn-tempest-ovs-release-with-oslo-master + - neutron-ovs-tempest-with-neutron-lib-master + - neutron-ovn-tempest-with-uwsgi-loki - project-template: name: neutron-periodic-jobs periodic: - jobs: + jobs: &neutron-periodic-jobs # NOTE(ralonsoh): to be removed when "openstack-tox-py311" is defined # and added to "openstack-python3-jobs" template. - tox-py311: @@ -137,6 +114,8 @@ - neutron-functional-with-oslo-master - neutron-ovs-tempest-with-oslo-master - neutron-ovn-tempest-ovs-release-with-oslo-master + experimental: + jobs: *neutron-periodic-jobs - project-template: name: neutron-skip-level-jobs diff --git a/zuul.d/tempest-multinode.yaml b/zuul.d/tempest-multinode.yaml index 740570ee59..d86914482a 100644 --- a/zuul.d/tempest-multinode.yaml +++ b/zuul.d/tempest-multinode.yaml @@ -528,6 +528,7 @@ # TODO(slaweq): propose job with ovs-release and move -master one to # experimental queue name: neutron-ovn-tempest-full-multinode-ovs-master + branches: ^master$ parent: neutron-ovn-multinode-base run: playbooks/multinode-devstack-custom.yaml vars: diff --git a/zuul.d/tempest-singlenode.yaml b/zuul.d/tempest-singlenode.yaml index 1fa3e5b716..e4823c56eb 100644 --- a/zuul.d/tempest-singlenode.yaml +++ b/zuul.d/tempest-singlenode.yaml @@ -295,6 +295,7 @@ - job: name: neutron-ovs-tempest-with-os-ken-master + branches: ^master$ parent: neutron-ovs-tempest-base timeout: 10800 required-projects: @@ -343,6 +344,7 @@ - job: name: neutron-ovn-tempest-with-neutron-lib-master + branches: ^master$ parent: tempest-integrated-networking timeout: 10800 required-projects: @@ -373,12 +375,14 @@ - job: name: neutron-ovs-tempest-with-neutron-lib-master + branches: ^master$ parent: neutron-ovs-tempest-base required-projects: - openstack/neutron-lib - job: name: neutron-ovs-tempest-with-oslo-master + branches: ^master$ parent: neutron-ovs-tempest-base description: | Job testing for devstack/tempest testing Neutron with OVS driver. @@ -420,7 +424,9 @@ timeout: 10800 vars: devstack_localrc: - NEUTRON_DEPLOY_MOD_WSGI: true + # TODO(ykarel) can be enabled once + # https://bugs.launchpad.net/neutron/+bug/1912359 fixed + NEUTRON_DEPLOY_MOD_WSGI: false MYSQL_REDUCE_MEMORY: true devstack_plugins: neutron: https://opendev.org/openstack/neutron.git @@ -468,7 +474,7 @@ - job: name: neutron-ovn-tempest-with-uwsgi-loki - parent: neutron-tempest-with-uwsgi + parent: neutron-ovn-tempest-with-uwsgi timeout: 10800 vars: devstack_services: @@ -622,6 +628,7 @@ - job: name: neutron-ovn-tempest-ovs-master + branches: ^master$ description: Job testing for devstack/tempest testing Neutron with ovn driver and OVN master branch parent: neutron-ovn-base vars: @@ -634,6 +641,7 @@ - job: name: neutron-ovn-tempest-ovs-release-with-oslo-master + branches: ^master$ description: | Job testing for devstack/tempest testing Neutron with OVN driver. This job installs all oslo libraries from source. @@ -768,6 +776,7 @@ - job: name: neutron-ovn-tempest-ipv6-only-ovs-master + branches: ^master$ parent: neutron-ovn-tempest-ipv6-only-base vars: devstack_localrc: @@ -779,6 +788,7 @@ - job: name: neutron-ovn-tempest-with-sqlalchemy-master + branches: ^master$ parent: tempest-integrated-networking timeout: 10800 required-projects: @@ -814,6 +824,7 @@ - job: name: neutron-ovs-tempest-with-sqlalchemy-master + branches: ^master$ parent: neutron-ovs-tempest-base required-projects: - name: github.com/sqlalchemy/sqlalchemy |