diff -Nru designate-9.0.2/debian/changelog designate-9.0.2/debian/changelog --- designate-9.0.2/debian/changelog 2021-04-13 06:00:18.000000000 -0600 +++ designate-9.0.2/debian/changelog 2021-08-31 13:14:59.000000000 -0600 @@ -1,3 +1,10 @@ +designate (1:9.0.2-0ubuntu1~cloud1) bionic-train; urgency=medium + + * d/p/0001-Update-zones-masters-using-pool-target-masters.patch: Update zones + masters using pool target masters. + + -- Nicolas Bock Tue, 31 Aug 2021 19:14:59 +0000 + designate (1:9.0.2-0ubuntu1~cloud0) bionic-train; urgency=medium * d/watch: Add trailing slash to URL. diff -Nru designate-9.0.2/debian/patches/0001-Update-zones-masters-using-pool-target-masters.patch designate-9.0.2/debian/patches/0001-Update-zones-masters-using-pool-target-masters.patch --- designate-9.0.2/debian/patches/0001-Update-zones-masters-using-pool-target-masters.patch 1969-12-31 17:00:00.000000000 -0700 +++ designate-9.0.2/debian/patches/0001-Update-zones-masters-using-pool-target-masters.patch 2021-08-31 13:14:59.000000000 -0600 @@ -0,0 +1,241 @@ +From 953492904772933f5f8e265d1ae6cc1e6385fcc6 Mon Sep 17 00:00:00 2001 +From: Jorge Niedbalski +Date: Thu, 28 May 2020 14:57:49 -0400 +Subject: [PATCH] Update zones masters using pool target masters. + +This change enforces the update of the zone masters +for all zones that belongs to a particular pool, using +the pool's defined target(s) masters and forcing a update_zone +call. + +This change also, moves the backend base class update_zone +method as an abstract method, allowing to each backend +implementation to create its own update logic. For the +case of bind9 its extended to allow running a rndc modzone +with the new given masters for the zone fixing the behavior +exposed on LP: #1879798. + +Fixes-Bug: #1879798 + +Change-Id: I9dddd4130a0cbb29311eeb52e077e216c8c03f3a +Signed-off-by: Jorge Niedbalski +(cherry picked from commit 3756fc51e71aaf0ba7cfb9155ca5d1de26ab78bc) +--- + designate/backend/impl_bind9.py | 37 +++++++++++ + designate/manage/pool.py | 28 ++++++++ + designate/tests/test_manage/__init__.py | 5 ++ + .../tests/test_manage/test_update_pool.py | 65 +++++++++++++++++++ + designate/tests/unit/backend/test_bind9.py | 12 ++++ + 5 files changed, 147 insertions(+) + create mode 100644 designate/tests/test_manage/__init__.py + create mode 100644 designate/tests/test_manage/test_update_pool.py + +diff --git a/designate/backend/impl_bind9.py b/designate/backend/impl_bind9.py +index 0c1c853c..b27d1835 100644 +--- a/designate/backend/impl_bind9.py ++++ b/designate/backend/impl_bind9.py +@@ -127,6 +127,43 @@ class Bind9Backend(base.Backend): + LOG.warning('RNDC call failure: %s', e) + raise + ++ def update_zone(self, context, zone): ++ """ ++ Update a DNS zone. ++ ++ This will execute a rndc modzone as the zone ++ already exists but masters might need to be refreshed. ++ ++ :param context: Security context information. ++ :param zone: the DNS zone. ++ """ ++ LOG.debug('Update Zone') ++ ++ masters = [] ++ for master in self.masters: ++ host = master['host'] ++ port = master['port'] ++ masters.append('%s port %s' % (host, port)) ++ ++ # Ensure different MiniDNS instances are targeted for AXFRs ++ random.shuffle(masters) ++ ++ view = 'in %s' % self._view if self._view else '' ++ ++ rndc_op = [ ++ 'modzone', ++ '%s %s { type slave; masters { %s;}; file "slave.%s%s"; };' % ++ (zone['name'].rstrip('.'), view, '; '.join(masters), zone['name'], ++ zone['id']), ++ ] ++ ++ try: ++ self._execute_rndc(rndc_op) ++ except exceptions.Backend as e: ++ LOG.warning("Error updating zone: %s", e) ++ pass ++ super(Bind9Backend, self).update_zone(context, zone) ++ + def _execute_rndc(self, rndc_op): + """Execute rndc + +diff --git a/designate/manage/pool.py b/designate/manage/pool.py +index 40d4aab3..7d11777c 100644 +--- a/designate/manage/pool.py ++++ b/designate/manage/pool.py +@@ -23,6 +23,7 @@ import oslo_messaging as messaging + from designate import exceptions + from designate import rpc + from designate import objects ++from designate import policy + from designate.central import rpcapi as central_rpcapi + from designate.manage import base + from designate.objects.adapters import DesignateAdapter +@@ -43,6 +44,30 @@ class PoolCommands(base.Commands): + rpc.init(cfg.CONF) + self.central_api = central_rpcapi.CentralAPI() + ++ def _update_zones(self, pool): ++ LOG.info("Updating zone masters for pool: {}".format(pool.id)) ++ ++ def __get_masters_from_pool(pool): ++ masters = [] ++ for target in pool.targets: ++ for master in target.get("masters", []): ++ masters.append({'host': master['host'], ++ 'port': master['port']}) ++ return masters ++ ++ policy.init() ++ ++ self.context.all_tenants = True ++ zones = self.central_api.find_zones( ++ self.context, ++ criterion={'pool_id': pool.id}) ++ ++ for zone in zones: ++ zone.masters = objects.ZoneMasterList().from_list( ++ __get_masters_from_pool(pool)) ++ self.central_api.update_zone(self.context, ++ zone) ++ + @base.args('--file', help='The path to the file the yaml output should be ' + 'written to', + default='/etc/designate/pools.yaml') +@@ -138,6 +163,9 @@ class PoolCommands(base.Commands): + output_msg.append("Update Pool: %s" % pool) + else: + pool = self.central_api.update_pool(self.context, pool) ++ # Bug: Changes in the pool targets should trigger a ++ # zone masters update LP: #1879798. ++ self._update_zones(pool) + + except exceptions.PoolNotFound: + pool = DesignateAdapter.parse('YAML', xpool, objects.Pool()) +diff --git a/designate/tests/test_manage/__init__.py b/designate/tests/test_manage/__init__.py +new file mode 100644 +index 00000000..dd671f43 +--- /dev/null ++++ b/designate/tests/test_manage/__init__.py +@@ -0,0 +1,5 @@ ++from designate.tests import TestCase ++ ++ ++class DesignateManageTestCase(TestCase): ++ pass +diff --git a/designate/tests/test_manage/test_update_pool.py b/designate/tests/test_manage/test_update_pool.py +new file mode 100644 +index 00000000..d5b21fbc +--- /dev/null ++++ b/designate/tests/test_manage/test_update_pool.py +@@ -0,0 +1,65 @@ ++# 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. ++from oslo_log import log as logging ++ ++import mock ++from designate.tests.test_manage import DesignateManageTestCase ++from designate.manage.pool import PoolCommands ++from designate.tests import fixtures ++from designate import objects ++ ++LOG = logging.getLogger(__name__) ++ ++ ++class UpdatePoolTestCase(DesignateManageTestCase): ++ def setUp(self): ++ super(DesignateManageTestCase, self).setUp() ++ self.stdlog = fixtures.StandardLogging() ++ self.useFixture(self.stdlog) ++ ++ def hydrate_pool_targets(self, targets): ++ pool_targets = objects.PoolTargetList() ++ masters = objects.PoolTargetMasterList() ++ for target in targets: ++ masters.append(target) ++ target = objects.PoolTarget(masters=masters) ++ target.masters = masters ++ pool_targets.append(target) ++ return pool_targets ++ ++ def test_update_pools_zones(self): ++ values = dict( ++ name='example.com.', ++ email='info@example.com', ++ type='PRIMARY' ++ ) ++ ++ zone = self.central_service.create_zone( ++ self.admin_context, zone=objects.Zone.from_dict(values)) ++ ++ # Ensure the correct NS Records are in place ++ pool = self.central_service.get_pool( ++ self.admin_context, zone.pool_id) ++ ++ pool.targets = self.hydrate_pool_targets([objects.PoolTargetMaster( ++ pool_target_id=pool.id, ++ host="127.0.0.1", ++ port="53")]) ++ ++ command = PoolCommands() ++ command.context = self.admin_context ++ command.central_api = self.central_service ++ ++ with mock.patch.object(self.central_service, ++ "update_zone") as mock_update_zone: ++ command._update_zones(pool) ++ mock_update_zone.assert_called_once() +diff --git a/designate/tests/unit/backend/test_bind9.py b/designate/tests/unit/backend/test_bind9.py +index 6934bec1..4a8654a6 100644 +--- a/designate/tests/unit/backend/test_bind9.py ++++ b/designate/tests/unit/backend/test_bind9.py +@@ -65,6 +65,18 @@ class Bind9BackendTestCase(designate.tests.TestCase): + ] + ) + ++ @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') ++ def test_update_zone(self, mock_execute): ++ with fixtures.random_seed(0): ++ self.backend.update_zone(self.admin_context, self.zone) ++ ++ mock_execute.assert_called_with( ++ [ ++ 'modzone', ++ 'example.com { type slave; masters { 192.168.1.1 port 53; 192.168.1.2 port 35;}; file "slave.example.com.cca7908b-dad4-4c50-adba-fb67d4c556e8"; };' # noqa ++ ] ++ ) ++ + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_create_zone_with_view(self, mock_execute): + self.target['options'].append( +-- +2.32.0 + diff -Nru designate-9.0.2/debian/patches/series designate-9.0.2/debian/patches/series --- designate-9.0.2/debian/patches/series 1969-12-31 17:00:00.000000000 -0700 +++ designate-9.0.2/debian/patches/series 2021-08-31 13:14:59.000000000 -0600 @@ -0,0 +1 @@ +0001-Update-zones-masters-using-pool-target-masters.patch