diff --git a/designate/central/service.py b/designate/central/service.py index 861728d9c..c8820cd64 100644 --- a/designate/central/service.py +++ b/designate/central/service.py @@ -2246,19 +2246,7 @@ class Service(service.RPCService): 'zonename': zone_name }) - email = cfg.CONF['service:central'].managed_resource_email - tenant_id = cfg.CONF['service:central'].managed_resource_tenant_id - - zone_values = { - 'type': 'PRIMARY', - 'name': zone_name, - 'email': email, - 'tenant_id': tenant_id - } - - zone = self.create_zone( - elevated_context, objects.Zone(**zone_values) - ) + zone = self._create_ptr_zone(elevated_context, zone_name) record_name = self.network_api.address_name(fip['address']) recordset_values = { @@ -2286,6 +2274,27 @@ class Service(service.RPCService): context, fip, record, zone=zone, recordset=recordset ) + def _create_ptr_zone(self, elevated_context, zone_name): + zone_values = { + 'type': 'PRIMARY', + 'name': zone_name, + 'email': cfg.CONF['service:central'].managed_resource_email, + 'tenant_id': cfg.CONF['service:central'].managed_resource_tenant_id + } + try: + zone = self.create_zone( + elevated_context, objects.Zone(**zone_values) + ) + except exceptions.DuplicateZone: + # NOTE(eandersson): This code is prone to race conditions, and + # it does not hurt to try to handle this if it + # fails. + zone = self.storage.find_zone( + elevated_context, {'name': zone_name} + ) + + return zone + def _unset_floatingip_reverse(self, context, region, floatingip_id): """ Unset the FloatingIP PTR record based on the @@ -2366,6 +2375,7 @@ class Service(service.RPCService): fips.append(fip_ptr) return fips + @transaction def _delete_ptr_record(self, context, record): try: recordset = self.get_recordset( @@ -2392,10 +2402,11 @@ class Service(service.RPCService): except exceptions.RecordSetNotFound: pass + @transaction def _replace_or_create_ptr_recordset(self, context, record, zone_id, name, type, ttl=None): try: - recordset = self.find_recordset(context, { + recordset = self.storage.find_recordset(context, { 'zone_id': zone_id, 'name': name, 'type': type, @@ -2421,7 +2432,6 @@ class Service(service.RPCService): return recordset @rpc.expected_exceptions() - @transaction def update_floatingip(self, context, region, floatingip_id, values): """ We strictly see if values['ptrdname'] is str or None and set / unset diff --git a/designate/tests/__init__.py b/designate/tests/__init__.py index 778dd5379..25258df15 100644 --- a/designate/tests/__init__.py +++ b/designate/tests/__init__.py @@ -211,7 +211,11 @@ class TestCase(base.BaseTestCase): ptr_fixtures = [ {'ptrdname': 'srv1.example.com.'}, - {'ptrdname': 'srv1.example.net.'} + {'ptrdname': 'srv1.example.net.'}, + {'ptrdname': 'srv2.example.com.'}, + {'ptrdname': 'srv3.example.com.'}, + {'ptrdname': 'srv4.example.com.'}, + {'ptrdname': 'srv5.example.com.'}, ] blacklist_fixtures = [{ diff --git a/designate/tests/test_central/test_service.py b/designate/tests/test_central/test_service.py index af75c0ac6..7c14116ea 100644 --- a/designate/tests/test_central/test_service.py +++ b/designate/tests/test_central/test_service.py @@ -16,8 +16,10 @@ # under the License. from collections import namedtuple +from concurrent import futures import copy import datetime +import futurist import random from unittest import mock @@ -2586,6 +2588,28 @@ class CentralServiceTest(CentralTestCase): self.assertIsNone(fip_ptr['description']) self.assertIsNotNone(fip_ptr['ttl']) + def test_set_floatingip_multiple_requests(self): + context = self.get_context() + + def update_floatingip(fixture): + fip = self.network_api.fake.allocate_floatingip(context.project_id) + return self.central_service.update_floatingip( + context, fip['region'], fip['id'], fixture + ) + + with futurist.GreenThreadPoolExecutor() as executor: + results = [] + for fixture in [0, 2, 3, 4, 5]: + results.append(executor.submit( + update_floatingip, fixture=self.get_ptr_fixture(fixture) + )) + for future in futures.as_completed(results): + self.assertTrue(future.result()) + + fips = self.central_service.list_floatingips(context) + + self.assertEqual(5, len(fips)) + def test_set_floatingip_no_managed_resource_tenant_id(self): context = self.get_context(project_id='a')