diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/base_oskenapp.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/base_oskenapp.py index 354acb4cac2..1387fe7befc 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/base_oskenapp.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/base_oskenapp.py @@ -24,7 +24,10 @@ class BaseNeutronAgentOSKenApp(app_manager.OSKenApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] - packet_in_handlers = [] + + def __init__(self): + super().__init__() + self.packet_in_handlers = [] def register_packet_in_handler(self, caller): self.packet_in_handlers.append(caller) diff --git a/neutron/services/externaldns/drivers/designate/driver.py b/neutron/services/externaldns/drivers/designate/driver.py index 6b85e6dba29..9ec1a534a2c 100644 --- a/neutron/services/externaldns/drivers/designate/driver.py +++ b/neutron/services/externaldns/drivers/designate/driver.py @@ -165,8 +165,6 @@ def _get_ids_ips_to_delete(self, dns_domain, name, records, dns_domain, criterion={"name": "%s" % name}) except (d_exc.NotFound, d_exc.Forbidden): raise dns_exc.DNSDomainNotFound(dns_domain=dns_domain) - ids = [rec['id'] for rec in recordsets] - ips = [str(ip) for rec in recordsets for ip in rec['records']] - if set(ips) != set(records): - raise dns_exc.DuplicateRecordSet(dns_name=name) - return ids + return [rec['id'] for rec in recordsets + for ip in rec['records'] + if ip in records] diff --git a/neutron/tests/functional/agent/ovsdb/native/test_helpers.py b/neutron/tests/functional/agent/ovsdb/native/test_helpers.py index 76877965e7e..3b365533df4 100644 --- a/neutron/tests/functional/agent/ovsdb/native/test_helpers.py +++ b/neutron/tests/functional/agent/ovsdb/native/test_helpers.py @@ -14,6 +14,7 @@ # under the License. from neutron_lib import constants as const +from ovsdbapp.backend.ovs_idl import event from neutron.agent.common import ovs_lib from neutron.agent.ovsdb.native import helpers @@ -22,6 +23,16 @@ from neutron.tests.functional import base +class WaitOvsManagerEvent(event.WaitEvent): + event_name = 'WaitOvsManagerEvent' + + def __init__(self, manager_target): + table = 'Manager' + events = (self.ROW_CREATE,) + conditions = (('target', '=', manager_target),) + super().__init__(events, table, conditions, timeout=10) + + class EnableConnectionUriTestCase(base.BaseSudoTestCase): def test_add_manager_appends(self): @@ -39,10 +50,15 @@ def test_add_manager_appends(self): manager_connections.append('ptcp:%s:127.0.0.1' % _port) for index, conn_uri in enumerate(ovsdb_cfg_connections): + target_event = WaitOvsManagerEvent(manager_connections[index]) + ovs.ovsdb.idl.notify_handler.watch_event(target_event) helpers.enable_connection_uri(conn_uri) manager_removal.append(ovs.ovsdb.remove_manager( manager_connections[index])) self.addCleanup(manager_removal[index].execute) + target_event.wait() + # This check is redundant, the ``target_event`` ensures the + # ``Manager`` register with the expected targer is created. self.assertIn(manager_connections[index], ovs.ovsdb.get_manager().execute()) diff --git a/neutron/tests/unit/plugins/ml2/extensions/test_dns_domain_keywords.py b/neutron/tests/unit/plugins/ml2/extensions/test_dns_domain_keywords.py index 680cb74c1f3..b1bb595e969 100644 --- a/neutron/tests/unit/plugins/ml2/extensions/test_dns_domain_keywords.py +++ b/neutron/tests/unit/plugins/ml2/extensions/test_dns_domain_keywords.py @@ -84,10 +84,10 @@ def _update_port_for_test(self, port, new_dns_name=test_dns_integration.NEWDNSNAME, new_dns_domain=None, **kwargs): test_dns_integration.mock_client.reset_mock() - ip_addresses = [netaddr.IPAddress(ip['ip_address']) - for ip in port['fixed_ips']] - records_v4 = [ip for ip in ip_addresses if ip.version == 4] - records_v6 = [ip for ip in ip_addresses if ip.version == 6] + records_v4 = [ip['ip_address'] for ip in port['fixed_ips'] + if netaddr.IPAddress(ip['ip_address']).version == 4] + records_v6 = [ip['ip_address'] for ip in port['fixed_ips'] + if netaddr.IPAddress(ip['ip_address']).version == 6] recordsets = [] if records_v4: recordsets.append({'id': test_dns_integration.V4UUID, 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 8552532c9ac..615b4016f0c 100644 --- a/neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py +++ b/neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py @@ -126,10 +126,10 @@ def _create_subnet_for_test(self, network_id, cidr): def _update_port_for_test(self, port, new_dns_name=NEWDNSNAME, new_dns_domain=None, **kwargs): mock_client.reset_mock() - ip_addresses = [netaddr.IPAddress(ip['ip_address']) - for ip in port['fixed_ips']] - records_v4 = [ip for ip in ip_addresses if ip.version == 4] - records_v6 = [ip for ip in ip_addresses if ip.version == 6] + records_v4 = [ip['ip_address'] for ip in port['fixed_ips'] + if netaddr.IPAddress(ip['ip_address']).version == 4] + records_v6 = [ip['ip_address'] for ip in port['fixed_ips'] + if netaddr.IPAddress(ip['ip_address']).version == 6] recordsets = [] if records_v4: recordsets.append({'id': V4UUID, 'records': records_v4}) diff --git a/neutron/tests/unit/services/externaldns/drivers/designate/test_driver.py b/neutron/tests/unit/services/externaldns/drivers/designate/test_driver.py index 63fe978112d..0ca64bb2b8d 100644 --- a/neutron/tests/unit/services/externaldns/drivers/designate/test_driver.py +++ b/neutron/tests/unit/services/externaldns/drivers/designate/test_driver.py @@ -169,6 +169,31 @@ def test_delete_record_set(self): ) self.admin_client.recordsets.delete.assert_not_called() + def test_delete_single_record_from_two_records(self): + # Set up two records similar to test_delete_record_set + self.client.recordsets.list.return_value = [ + {'id': 123, 'records': ['192.168.0.10']}, + {'id': 456, 'records': ['2001:db8:0:1::1']} + ] + + cfg.CONF.set_override( + 'allow_reverse_dns_lookup', False, group='designate' + ) + + # Delete only the first record (IPv4) out of the two + self.driver.delete_record_set( + self.context, 'example.test.', 'test', + ['192.168.0.10'] + ) + + # Verify that only the IPv4 record was deleted + self.client.recordsets.delete.assert_called_once_with( + 'example.test.', 123 + ) + + # Admin client should not be called since reverse DNS is disabled + self.admin_client.recordsets.delete.assert_not_called() + def test_delete_record_set_with_reverse_dns(self): self.client.recordsets.list.return_value = [ {'id': 123, 'records': ['192.168.0.10']}, diff --git a/zuul.d/tempest-singlenode.yaml b/zuul.d/tempest-singlenode.yaml index a9863a67af1..e656527deb9 100644 --- a/zuul.d/tempest-singlenode.yaml +++ b/zuul.d/tempest-singlenode.yaml @@ -702,6 +702,7 @@ br-ex-tcpdump: true br-int-flows: true devstack_localrc: + TEMPEST_BRANCH: 45.0.0 TEMPEST_VENV_UPPER_CONSTRAINTS: '/opt/stack/requirements/upper-constraints.txt' devstack_local_conf: test-config: @@ -720,6 +721,7 @@ nslookup_target: 'opendev.org' configure_swap_size: 4096 devstack_localrc: + TEMPEST_BRANCH: 45.0.0 TEMPEST_VENV_UPPER_CONSTRAINTS: '/opt/stack/requirements/upper-constraints.txt' devstack_local_conf: test-config: