From 5d328f07aa9ffbe8fb96df2365dadd0dd3f4705e Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Wed, 20 Apr 2016 16:49:48 +0100 Subject: [PATCH] Add Knot DNS backend Change-Id: I885c003afc2496ba4aa9631568be02e7d4654e52 --- designate/agent/__init__.py | 6 +- designate/backend/agent_backend/impl_knot2.py | 216 ++++++++++++++++++ designate/dnsutils.py | 4 +- designate/tests/unit/test_agent/__init__.py | 0 .../unit/test_agent/test_backends/__init__.py | 0 .../test_agent/test_backends/test_knot2.py | 200 ++++++++++++++++ .../designate_plugins/backend-agent-knot2 | 130 +++++++++++ doc/source/backend.rst | 11 + doc/source/backends/knot2_agent.rst | 201 ++++++++++++++++ doc/source/support-matrix.ini | 6 +- etc/designate/designate.conf.sample | 20 +- etc/designate/rootwrap.d/knot2.filters | 3 + .../knot-agent-backend-db2893aa97d85a1d.yaml | 3 + setup.cfg | 1 + 14 files changed, 793 insertions(+), 8 deletions(-) create mode 100644 designate/backend/agent_backend/impl_knot2.py create mode 100644 designate/tests/unit/test_agent/__init__.py create mode 100644 designate/tests/unit/test_agent/test_backends/__init__.py create mode 100644 designate/tests/unit/test_agent/test_backends/test_knot2.py create mode 100644 devstack/designate_plugins/backend-agent-knot2 create mode 100644 doc/source/backends/knot2_agent.rst create mode 100644 etc/designate/rootwrap.d/knot2.filters create mode 100644 releasenotes/notes/knot-agent-backend-db2893aa97d85a1d.yaml diff --git a/designate/agent/__init__.py b/designate/agent/__init__.py index 641c9569f..5dacb1d1c 100644 --- a/designate/agent/__init__.py +++ b/designate/agent/__init__.py @@ -47,12 +47,12 @@ OPTS = [ cfg.ListOpt('masters', default=[], help='List of masters for the Agent, format ip:port'), cfg.StrOpt('backend-driver', default='bind9', - help='The backend driver to use'), + help='The backend driver to use: bind9 or knot2'), cfg.StrOpt('transfer-source', help='An IP address to be used to fetch zones transferred in'), cfg.FloatOpt('notify-delay', default=0.0, - help='Delay after a NOTIFY arrives for a zone that the Agent ' - 'will pause and drop subsequent NOTIFYs for that zone'), + help='Delay after a NOTIFY arrives for a zone that the Agent ' + 'will pause and drop subsequent NOTIFYs for that zone'), ] cfg.CONF.register_opts(OPTS, group='service:agent') diff --git a/designate/backend/agent_backend/impl_knot2.py b/designate/backend/agent_backend/impl_knot2.py new file mode 100644 index 000000000..06a2131a7 --- /dev/null +++ b/designate/backend/agent_backend/impl_knot2.py @@ -0,0 +1,216 @@ +# Copyright 2016 Hewlett Packard Enterprise Development Company LP +# +# Author: Federico Ceratto +# +# 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. + +""" +backend.agent_backend.impl_knot2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Knot DNS agent backend + +Create, update, delete zones locally on a Knot DNS resolver using the +knotc utility. + +Supported Knot versions: >= 2.1, < 3 + +`User documentation `_ + +.. WARNING:: + + Untested, do not use in production. + +.. NOTE:: + + If the backend is killed during a configuration transaction it might be + required to manually abort the transaction with `sudo knotc conf-abort` + +Configured in [service:agent:knot2] +""" + +from oslo_concurrency import lockutils +from oslo_concurrency.processutils import ProcessExecutionError +from oslo_config import cfg +from oslo_log import log as logging + +from designate import exceptions +from designate.backend.agent_backend import base +from designate.i18n import _LI +from designate.i18n import _LE +from designate.utils import execute + +LOG = logging.getLogger(__name__) +CFG_GROUP = 'backend:agent:knot2' +# rootwrap requires a command name instead of full path +KNOTC_DEFAULT_PATH = 'knotc' + +# TODO(Federico) on zone creation and update, agent.handler unnecessarily +# perfors AXFR from MiniDNS to the Agent to populate the `zone` argument +# (needed by the Bind backend) + + +class Knot2Backend(base.AgentBackend): + __plugin_name__ = 'knot2' + __backend_status__ = 'untested' + _lock_name = 'knot2.lock' + + @classmethod + def get_cfg_opts(cls): + group = cfg.OptGroup( + name='backend:agent:knot2', title="Configuration for Knot2 backend" + ) + opts = [ + cfg.StrOpt('knotc-cmd-name', + help='knotc executable path or rootwrap command name', + default=KNOTC_DEFAULT_PATH), + cfg.StrOpt('query-destination', default='127.0.0.1', + help='Host to query when finding zones') + ] + return [(group, opts)] + + def __init__(self, *a, **kw): + """Configure the backend""" + super(Knot2Backend, self).__init__(*a, **kw) + + self._knotc_cmd_name = cfg.CONF[CFG_GROUP].knotc_cmd_name + + def start(self): + """Start the backend""" + LOG.info(_LI("Started knot2 backend")) + + def _execute_knotc(self, *knotc_args, **kw): + """Run the Knot client and check the output + + :param expected_output: expected output (default: 'OK') + :type expected_output: str + :param expected_error: expected alternative output, will be \ + logged as info(). Default: not set. + :type expected_error: str + """ + # Knotc returns "0" even on failure, we have to check for 'OK' + # https://gitlab.labs.nic.cz/labs/knot/issues/456 + + LOG.debug("Executing knotc with %r", knotc_args) + expected = kw.get('expected_output', 'OK') + expected_alt = kw.get('expected_error', None) + try: + out, err = execute(self._knotc_cmd_name, *knotc_args) + out = out.rstrip() + LOG.debug("Command output: %r" % out) + if out != expected: + if expected_alt is not None and out == expected_alt: + LOG.info(_LI("Ignoring error: %r"), out) + else: + raise ProcessExecutionError(stdout=out, stderr=err) + + except ProcessExecutionError as e: + LOG.error(_LE("Command output: %(out)r Stderr: %(err)r"), { + 'out': e.stdout, 'err': e.stderr + }) + raise exceptions.Backend(e) + + def _start_minidns_to_knot_axfr(self, zone_name): + """Instruct Knot to request an AXFR from MiniDNS. No need to lock + or enter a configuration transaction. + """ + self._execute_knotc('zone-refresh', zone_name) + + def _modify_zone(self, *knotc_args, **kw): + """Create or delete a zone while locking, and within a + Knot transaction. + Knot supports only one config transaction at a time. + + :raises: exceptions.Backend + """ + with lockutils.lock(self._lock_name): + self._execute_knotc('conf-begin') + try: + self._execute_knotc(*knotc_args, **kw) + # conf-diff can be used for debugging + # self._execute_knotc('conf-diff') + except Exception as e: + self._execute_knotc('conf-abort') + LOG.info(_LI("Zone change aborted: %r"), e) + raise e + else: + self._execute_knotc('conf-commit') + + def find_zone_serial(self, zone_name): + """Get serial from a zone by running knotc + + :returns: serial (int or None) + :raises: exceptions.Backend + """ + zone_name = zone_name.rstrip('.') + LOG.debug("Finding %s", zone_name) + # Output example: + # [530336536.com.] type: slave | serial: 0 | next-event: idle | + # auto-dnssec: disabled] + try: + out, err = execute(self._knotc_cmd_name, 'zone-status', zone_name) + except ProcessExecutionError as e: + if 'no such zone' in e.stdout: + # Zone not found + return None + + LOG.error(_LE("Command output: %(out)r Stderr: %(err)r"), { + 'out': e.stdout, 'err': e.stderr + }) + raise exceptions.Backend(e) + + try: + serial = out.split('|')[1].split()[1] + return int(serial) + except Exception as e: + LOG.error(_LE("Unable to parse knotc output: %r"), out) + raise exceptions.Backend("Unexpected knotc zone-status output") + + def create_zone(self, zone): + """Create a new Zone by executing knotc + Do not raise exceptions if the zone already exists. + + :param zone: zone to be created + :type zone: raw pythondns Zone + """ + zone_name = zone.origin.to_text().rstrip('.') + LOG.debug("Creating %s", zone_name) + # The zone might be already in place due to a race condition between + # checking if the zone is there and creating it across different + # greenlets + self._modify_zone('conf-set', 'zone[%s]' % zone_name, + expected_error='duplicate identifier') + + LOG.debug("Triggering initial AXFR from MiniDNS to Knot for %s", + zone_name) + self._start_minidns_to_knot_axfr(zone_name) + + def update_zone(self, zone): + """Instruct Knot DNS to perform AXFR from MiniDNS + + :param zone: zone to be created + :type zone: raw pythondns Zone + """ + zone_name = zone.origin.to_text() + LOG.debug("Triggering AXFR from MiniDNS to Knot for %s", zone_name) + self._start_minidns_to_knot_axfr(zone_name) + + def delete_zone(self, zone_name): + """Delete a new Zone by executing knotc + Do not raise exceptions if the zone does not exist. + + :param zone_name: zone name + :type zone_name: str + """ + LOG.debug('Delete Zone: %s' % zone_name) + self._modify_zone('conf-unset', 'zone[%s]' % zone_name, + expected_error='invalid identifier') diff --git a/designate/dnsutils.py b/designate/dnsutils.py index 3ea289da4..5a12f301f 100644 --- a/designate/dnsutils.py +++ b/designate/dnsutils.py @@ -329,7 +329,9 @@ def dnspythonrecord_to_recordset(rname, rdataset): def do_axfr(zone_name, servers, timeout=None, source=None): """ - Performs an AXFR for a given zone name + Requests an AXFR for a given zone name and process the response + + :returns: Zone instance from dnspython """ random.shuffle(servers) timeout = timeout or cfg.CONF["service:mdns"].xfr_timeout diff --git a/designate/tests/unit/test_agent/__init__.py b/designate/tests/unit/test_agent/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/designate/tests/unit/test_agent/test_backends/__init__.py b/designate/tests/unit/test_agent/test_backends/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/designate/tests/unit/test_agent/test_backends/test_knot2.py b/designate/tests/unit/test_agent/test_backends/test_knot2.py new file mode 100644 index 000000000..d315bee55 --- /dev/null +++ b/designate/tests/unit/test_agent/test_backends/test_knot2.py @@ -0,0 +1,200 @@ +# Copyright 2016 Hewlett Packard Enterprise Development Company LP +# +# Author: Federico Ceratto +# +# 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. + +""" + Unit-test the Knot 2 agent backend + knotc is not being executed +""" + +from mock import call +from oslo_concurrency.processutils import ProcessExecutionError +import dns.zone +import fixtures +import mock + +from designate import exceptions +from designate.backend.agent_backend.impl_knot2 import Knot2Backend +from designate.tests import TestCase +import designate.backend.agent_backend.impl_knot2 # noqa + + +class Knot2AgentBackendBasicUnitTestCase(TestCase): + + def test_init(self): + kb = Knot2Backend('foo') + self.assertEqual('knotc', kb._knotc_cmd_name) + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test__execute_knotc_ok(self, mock_exe): + mock_exe.return_value = ('OK', '') + kb = Knot2Backend('foo') + kb._execute_knotc('a1', 'a2') + mock_exe.assert_called_with('knotc', 'a1', 'a2') + self.assertEqual(1, mock_exe.call_count) + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test__execute_knotc_expected_error(self, mock_exe): + mock_exe.return_value = ('xyz', '') + kb = Knot2Backend('foo') + kb._execute_knotc('a1', 'a2', expected_error='xyz') + mock_exe.assert_called_once_with('knotc', 'a1', 'a2') + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test__execute_knotc_expected_output(self, mock_exe): + mock_exe.return_value = ('xyz', '') + kb = Knot2Backend('foo') + kb._execute_knotc('a1', 'a2', expected_output='xyz') + mock_exe.assert_called_once_with('knotc', 'a1', 'a2') + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test__execute_knotc_with_error(self, mock_exe): + mock_exe.return_value = ('xyz', '') + kb = Knot2Backend('foo') + self.assertRaises( + exceptions.Backend, + kb._execute_knotc, 'a1', 'a2') + mock_exe.assert_called_once_with('knotc', 'a1', 'a2') + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test__execute_knotc_raising_exception(self, mock_exe): + mock_exe.side_effect = ProcessExecutionError + kb = Knot2Backend('foo') + self.assertRaises( + exceptions.Backend, + kb._execute_knotc, 'a1', 'a2') + mock_exe.assert_called_once_with('knotc', 'a1', 'a2') + + +class Knot2AgentBackendUnitTestCase(TestCase): + + def _create_dnspy_zone(self, name): + zone_text = ( + '$ORIGIN %(name)s\n%(name)s 3600 IN SOA %(ns)s ' + 'email.email.com. 1421777854 3600 600 86400 3600\n%(name)s ' + '3600 IN NS %(ns)s\n') % {'name': name, 'ns': 'ns1.designate.com'} + + return dns.zone.from_text(zone_text, check_origin=False) + + def setUp(self): + super(Knot2AgentBackendUnitTestCase, self).setUp() + self.kb = Knot2Backend('foo') + self.patch_ob(self.kb, '_execute_knotc') + + def tearDown(self): + super(Knot2AgentBackendUnitTestCase, self).tearDown() + + def patch_ob(self, *a, **kw): + self.useFixture(fixtures.MockPatchObject(*a, **kw)) + + def test_create_zone(self, *mocks): + zone = self._create_dnspy_zone('example.org') + self.kb.create_zone(zone) + self.kb._execute_knotc.assert_has_calls([ + call('conf-begin'), + call('conf-set', 'zone[example.org]', + expected_error='duplicate identifier'), + call('conf-commit'), + call('zone-refresh', 'example.org') + ]) + + def test_create_zone_already_there(self, *mocks): + self.kb._execute_knotc.return_value = 'duplicate identifier' + zone = self._create_dnspy_zone('example.org') + self.kb.create_zone(zone) + self.kb._execute_knotc.assert_has_calls([ + call('conf-begin'), + call('conf-set', 'zone[example.org]', + expected_error='duplicate identifier'), + call('conf-commit'), + call('zone-refresh', 'example.org') + ]) + + def test__start_minidns_to_knot_axfr(self): + self.kb._start_minidns_to_knot_axfr('foo') + self.kb._execute_knotc.assert_called_with('zone-refresh', 'foo') + + @mock.patch('oslo_concurrency.lockutils.lock') + def test__modify_zone(self, *mocks): + self.kb._modify_zone('blah', 'bar') + self.assertEqual(3, self.kb._execute_knotc.call_count) + self.kb._execute_knotc.assert_called_with('conf-commit') + + @mock.patch('oslo_concurrency.lockutils.lock') + def test__modify_zone_exception(self, *mocks): + # Raise an exception during the second call to _execute_knotc + self.kb._execute_knotc.side_effect = [None, exceptions.Backend, None] + self.assertRaises( + exceptions.Backend, + self.kb._modify_zone, 'blah', 'bar') + self.assertEqual(3, self.kb._execute_knotc.call_count) + self.kb._execute_knotc.assert_has_calls([ + call('conf-begin'), + call('blah', 'bar'), + call('conf-abort'), + ]) + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test_find_zone_serial(self, mock_exe): + mock_exe.return_value = "[example.com.] type: slave | serial: 20 | " \ + "next-event: idle | auto-dnssec: disabled]", "" + serial = self.kb.find_zone_serial('example.com') + self.assertEqual(20, serial) + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test_find_zone_serial__zone_not_found(self, mock_exe): + mock_exe.side_effect = ProcessExecutionError( + "error: [example.com.] (no such zone found)") + serial = self.kb.find_zone_serial('example.com') + self.assertEqual(None, serial) + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test_find_zone_serial_unexpected_output(self, mock_exe): + mock_exe.return_value = "bogus output", "" + self.assertRaises( + exceptions.Backend, + self.kb.find_zone_serial, 'example.com') + + @mock.patch('designate.backend.agent_backend.impl_knot2.execute') + def test_find_zone_serial_error(self, mock_exe): + mock_exe.side_effect = ProcessExecutionError("blah") + self.assertRaises( + exceptions.Backend, + self.kb.find_zone_serial, 'example.com') + + def test_update_zone(self): + zone = self._create_dnspy_zone('example.org') + self.kb.update_zone(zone) + self.kb._execute_knotc.assert_called_once_with( + 'zone-refresh', 'example.org') + + def test_delete_zone(self): + self.kb.delete_zone('example.org') + self.kb._execute_knotc.assert_has_calls([ + call('conf-begin'), + call('conf-unset', 'zone[example.org]', + expected_error='invalid identifier'), + call('conf-commit'), + ]) + + def test_delete_zone_already_gone(self): + self.kb._execute_knotc.return_value = 'duplicate identifier' + self.kb.delete_zone('example.org') + self.kb._execute_knotc.assert_has_calls([ + call('conf-begin'), + call('conf-unset', 'zone[example.org]', + expected_error='invalid identifier'), + call('conf-commit'), + ]) diff --git a/devstack/designate_plugins/backend-agent-knot2 b/devstack/designate_plugins/backend-agent-knot2 new file mode 100644 index 000000000..88d41e396 --- /dev/null +++ b/devstack/designate_plugins/backend-agent-knot2 @@ -0,0 +1,130 @@ +# Configure the Knot2 agent backend for Devstack + +# Enable this pluging by adding these line to local.conf: +# +# DESIGNATE_BACKEND_DRIVER=agent +# DESIGNATE_AGENT_BACKEND_DRIVER=knot2 + +# install_designate_agent_backend - install any external requirements +# configure_designate_agent_backend - make configuration changes, including those to other services +# init_designate_agent_backend - initialize databases, etc. +# start_designate_agent_backend - start any external services +# stop_designate_agent_backend - stop any external services +# cleanup_designate_agent_backend - remove transient data and cache + +# Save trace setting +DP_AGENT_KNOT_XTRACE=$(set +o | grep xtrace) +set +o xtrace + +# Defaults +# -------- +KNOT_SERVICE_NAME=knot +KNOT_CFG_DIR=/etc/knot +KNOT_VAR_DIR=/var/lib/knot +KNOT_USER=knot +KNOT_GROUP=knot + +if is_fedora; then + echo "only Ubuntu is supported right now" +fi + +# Entry Points +# ------------ + +# install_designate_agent_backend - install any external requirements +function install_designate_agent_backend { + if is_ubuntu; then + # https://github.com/oerdnj/deb.sury.org/issues/56 + LC_ALL=C.UTF-8 sudo add-apt-repository --yes ppa:cz.nic-labs/knot-dns + sudo apt-get update + echo "---- available knot package ---" + sudo apt-cache show knot + echo "---- installing knot ---" + sudo apt-get install -y knot + else + echo "only Ubuntu is supported right now" + exit 1 + fi +} + +# configure_designate_agent_backend - make configuration changes, including those to other services +function configure_designate_agent_backend { + + # [re]create the config database + stop_service knot + sudo sh -c "rm /var/lib/knot/*zone /var/lib/knot/*/*.mdb -f" + sudo knotc conf-init -v + + # Create /etc/default/knot + cat < + + 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. + +Knot DNS 2 Agent backend +************************ + + +User documentation +================== + +This page documents the Agent backend for `Knot DNS `_. + +The agent runs on the same host as the resolver. It receives DNS messages from Mini DNS using private DNS OPCODEs and classes and creates or deletes zones on Knot using the knotc tool. +It also instructs Knot to request AXFR from MiniDNS when a zone is created or updated. + +Support matrix: + +* 2.0 and older: not supported +* 2.1.1: supported, tested +* 2.2.0: `affected by a bug `_ + + +`Knot DNS 2.x documentation `_ + +Setting up Knot DNS on Ubuntu Trusty +------------------------------------ + +Knot DNS 2.1 is not part of Ubuntu Trusty. You can ues the CZ.NIC PPA with: + +.. code-block:: bash + + service pdns stop + add-apt-repository ppa:cz.nic-labs/knot-dns + apt-get update + apt-get install knot + + +Configuring Knot DNS +-------------------- + +Assuming Knot has been freshly installed on the system, run as root: + +.. code-block:: bash + + # Monitor syslog during the next steps + tail -f /var/log/syslog + + # Start the daemon, ensure it's running + service knot start + netstat -npltu | grep knotd + + # Create the config database + knotc conf-init + + # Edit /etc/default/knot + # Set the variable: + # KNOTD_ARGS="-C /var/lib/knot/confdb" + + # Restart + service knot restart + + # Check if the deamon is still running from the conf file in /etc/knot/ + ps axuw | grep knotd + + # if so, apply this workaround for bug + # https://gitlab.labs.nic.cz/labs/knot/issues/455 + ( cd /etc/default/ && ln -s knot knotd ) + service knot restart + ps axuw | grep knotd + + # Ensure the confdb is present + test -f /var/lib/knot/confdb/data.mdb && echo OK + + # Create the configuration + # Populate the variable with the MiniDNS ipaddr: + MINIDNS_IPADDR= + + knotc conf-begin + knotc conf-set server.listen 0.0.0.0@53 + # To listen on IPv6 as well, also run this: + # knotc conf-set server.listen '::@53' + knotc conf-set remote[minidns] + knotc conf-set remote[minidns].address $MINIDNS_IPADDR@5354 + knotc conf-set template[default] + knotc conf-set template[default].master minidns + knotc conf-set template[default].acl acl_minidns + knotc conf-set template[default].semantic-checks on + knotc conf-set zone[example.com] + knotc conf-set log.any info + knotc conf-set log.target syslog + knotc conf-set acl[acl_minidns] + knotc conf-set acl[acl_minidns].address $MINIDNS_IPADDR + knotc conf-set acl[acl_minidns].action notify + # Review the changes and commit + knotc conf-diff + knotc conf-commit + + # Optionally check and back up the conf + knotc conf-check + knotc conf-export knot.conf.bak && cat knot.conf.bak + + # Ensure the zone survives a restart + service knot restart + knotc zone-status example.com + + # Test Knot: this should return the version + dig @127.0.0.1 version.server CH TXT + +If needed, create a rootwrap filter, as root: + +.. code-block:: bash + + cat > /etc/designate/rootwrap.d/knot2.filters < + port: 5354 + options: {} + options: + - host: + port: 5358 + type: agent + +Developer documentation +======================= + +Devstack testbed +---------------- + +Follow "Setting up Knot DNS on Ubuntu Trusty" + +Configure Knot to slave from MiniDNS on 192.168.121.131 + +Knotd configuration example (sudo knotc conf-export ): + +.. code-block:: yaml + + # Configuration export (Knot DNS 2.1.1) + + server: + listen: "0.0.0.0@53" + + log: + - target: "syslog" + any: "debug" + + acl: + - id: "acl_minidns" + address: [ "192.168.121.131" ] + action: [ "notify" ] + + remote: + - id: "minidns" + address: "192.168.121.131@5354" + + template: + - id: "default" + master: "minidns" + acl: "acl_minidns" + semantic-checks: "on" + diff --git a/doc/source/support-matrix.ini b/doc/source/support-matrix.ini index e703257bd..29202f00e 100644 --- a/doc/source/support-matrix.ini +++ b/doc/source/support-matrix.ini @@ -47,13 +47,14 @@ backend-impl-bind9=Bind9 backend-impl-powerdns-mysql=Power DNS (MySQL) backend-impl-designate=Designate to Designate backend-impl-dynect=DynECT -backend-impl-dynect=DynECT backend-impl-akamai=Akamai eDNS backend-impl-infoblox-xfr=Infoblox (XFR) backend-impl-nsd4=NSD4 backend-impl-agent=Agent backend-impl-bind9-agent=Bind9 (Agent) backend-impl-denominator=Denominator +backend-impl-knot2-agent=Knot2 (Agent) + [backends.backend-impl-bind9] @@ -75,6 +76,9 @@ maintainers=HP DNSaaS Team [backends.backend-impl-bind9-agent] type=agent +[backends.backend-impl-knot2-agent] +type=agent + [backends.backend-impl-infoblox-xfr] status=release-compatible maintainers=Infoblox OpenStack Team diff --git a/etc/designate/designate.conf.sample b/etc/designate/designate.conf.sample index 243a5f226..e1032355a 100644 --- a/etc/designate/designate.conf.sample +++ b/etc/designate/designate.conf.sample @@ -256,13 +256,19 @@ debug = False #----------------------- # Agent Service #----------------------- +# The agent runs on the resolver hosts [service:agent] #workers = None #listen = 0.0.0.0:5358 #tcp_backlog = 100 #allow_notify = 127.0.0.1 + +# MiniDNS IP address and port #masters = 127.0.0.1:5354 + +# Set to "fake", "bind9" or "knot2" #backend_driver = fake + #transfer_source = None #notify_delay = 0 @@ -441,9 +447,12 @@ debug = False #format = '%(hostname)s.%(project)s.%(domain)s' #format = '%(hostname)s.%(domain)s' -############################# +############################## ## Agent Backend Configuration -############################# +############################## + +# Set backend_driver in the [service:agent] section + [backend:agent:bind9] #rndc_host = 127.0.0.1 #rndc_port = 953 @@ -451,7 +460,12 @@ debug = False #rndc_key_file = /etc/rndc.key #zone_file_path = $state_path/zones #query_destination = 127.0.0.1 -# + +[backend:agent:knot2] +# knotc command name when rootwrap is used. Location of the knotc executable +# on the resolver host if rootwrap is not used +#knotc_cmd_name = /usr/sbin/knotc + [backend:agent:denominator] #name = dynect #config_file = /etc/denominator.conf diff --git a/etc/designate/rootwrap.d/knot2.filters b/etc/designate/rootwrap.d/knot2.filters new file mode 100644 index 000000000..d6c96b497 --- /dev/null +++ b/etc/designate/rootwrap.d/knot2.filters @@ -0,0 +1,3 @@ +# cmd-name: filter-name, raw-command, user, args +[Filters] +knotc: CommandFilter, /usr/sbin/knotc, root diff --git a/releasenotes/notes/knot-agent-backend-db2893aa97d85a1d.yaml b/releasenotes/notes/knot-agent-backend-db2893aa97d85a1d.yaml new file mode 100644 index 000000000..8fcffffc3 --- /dev/null +++ b/releasenotes/notes/knot-agent-backend-db2893aa97d85a1d.yaml @@ -0,0 +1,3 @@ +--- +features: + - An experimental agent backend to support Knot DNS 2 diff --git a/setup.cfg b/setup.cfg index cf081792c..96413b78a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -91,6 +91,7 @@ designate.backend = designate.backend.agent_backend = bind9 = designate.backend.agent_backend.impl_bind9:Bind9Backend + knot2 = designate.backend.agent_backend.impl_knot2:Knot2Backend denominator = designate.backend.agent_backend.impl_denominator:DenominatorBackend fake = designate.backend.agent_backend.impl_fake:FakeBackend