summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/contributor/testing/ci_scenario_jobs.rst5
-rw-r--r--neutron/conf/policies/port.py1
-rw-r--r--neutron/db/dvr_mac_db.py1
-rw-r--r--neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py26
-rw-r--r--neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py2
-rw-r--r--neutron/tests/functional/base.py36
-rw-r--r--neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py44
-rw-r--r--neutron/tests/unit/extensions/test_network_segment_range.py2
-rw-r--r--neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py65
-rw-r--r--neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py2
-rw-r--r--neutron/tests/unit/plugins/ml2/test_plugin.py5
-rw-r--r--neutron/tests/unit/services/metering/test_metering_plugin.py24
-rw-r--r--releasenotes/notes/ovn-recreate-metadata-port-76e2c0e651267aa0.yaml11
-rw-r--r--tox.ini8
-rw-r--r--zuul.d/base.yaml6
-rw-r--r--zuul.d/grenade.yaml2
-rw-r--r--zuul.d/job-templates.yaml51
-rw-r--r--zuul.d/tempest-multinode.yaml1
-rw-r--r--zuul.d/tempest-singlenode.yaml15
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>`_.
diff --git a/tox.ini b/tox.ini
index 34eed72955..7029bfc238 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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