summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-03-04 23:47:19 +0000
committerGerrit Code Review <review@openstack.org>2021-03-04 23:47:19 +0000
commitf101fab29540ba11481abbf9c7558f976d14b26b (patch)
tree6500f56de228060deca4c948a726a0b68dda4d2a
parent39c2566fcd70f8e38ff898bb411aa6a63fe11a2c (diff)
parent953492904772933f5f8e265d1ae6cc1e6385fcc6 (diff)
downloaddesignate-stable/train.tar.gz
Merge "Update zones masters using pool target masters." into stable/trainstable/train
-rw-r--r--designate/backend/impl_bind9.py37
-rw-r--r--designate/manage/pool.py28
-rw-r--r--designate/tests/test_manage/__init__.py5
-rw-r--r--designate/tests/test_manage/test_update_pool.py65
-rw-r--r--designate/tests/unit/backend/test_bind9.py12
5 files changed, 147 insertions, 0 deletions
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
@@ -66,6 +66,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(
{'key': 'view', 'value': 'guest'},