Add Knot DNS backend

Change-Id: I885c003afc2496ba4aa9631568be02e7d4654e52
This commit is contained in:
Federico Ceratto 2016-04-20 16:49:48 +01:00
parent e23eb9a030
commit 5d328f07aa
14 changed files with 793 additions and 8 deletions

View File

@ -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')

View File

@ -0,0 +1,216 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Federico Ceratto <federico.ceratto@hpe.com>
#
# 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 <backends/knot2_agent.html>`_
.. 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')

View File

@ -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

View File

@ -0,0 +1,200 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# Author: Federico Ceratto <federico.ceratto@hpe.com>
#
# 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'),
])

View File

@ -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 <<EOF | sudo tee /etc/default/knot
# Created by $0 on $(date)
KNOTD_ARGS="-C /var/lib/knot/confdb"
EOF
# Apply this workaround for bug
# https://gitlab.labs.nic.cz/labs/knot/issues/455
sudo sh -c "cd /etc/default/ && test -f knotd || ln -s knot knotd"
start_service knot
sleep 1
# Ensure the confdb is present
sudo test -f /var/lib/knot/confdb/data.mdb
# Create the configuration
MINIDNS_IPADDR=$DESIGNATE_SERVICE_HOST
sudo knotc conf-begin
sudo knotc conf-set server.listen $DESIGNATE_SERVICE_HOST@$DESIGNATE_SERVICE_PORT_DNS
sudo knotc conf-set remote[minidns]
sudo knotc conf-set remote[minidns].address $DESIGNATE_SERVICE_HOST@$DESIGNATE_SERVICE_PORT_MDNS
sudo knotc conf-set template[default]
sudo knotc conf-set template[default].master minidns
sudo knotc conf-set template[default].acl acl_minidns
sudo knotc conf-set template[default].semantic-checks on
# Create localdomain as a workaround for
# https://gitlab.labs.nic.cz/labs/knot/issues/457
sudo knotc conf-set zone[localdomain]
sudo knotc conf-set log.any info
sudo knotc conf-set log.target syslog
sudo knotc conf-set acl[acl_minidns]
sudo knotc conf-set acl[acl_minidns].address $DESIGNATE_SERVICE_HOST
sudo knotc conf-set acl[acl_minidns].action notify
echo "--------------"
sudo knotc conf-diff
echo "--------------"
sudo knotc conf-commit
sudo knotc conf-check
# Ensure the zone survives a restart
sleep 1
sudo service knot restart
sleep 1
sudo knotc zone-status localdomain
echo "Testing Knot: this should return the daemon version"
dig @$DESIGNATE_SERVICE_HOST -p$DESIGNATE_SERVICE_PORT_DNS version.server CH TXT
}
# init_designate_agent_backend - initialize databases, etc.
function init_designate_agent_backend {
:
}
# start_designate_agent_backend - start any external services
function start_designate_agent_backend {
start_service knot
}
# stop_designate_agent_backend - stop any external services
function stop_designate_agent_backend {
stop_service knot
}
# cleanup_designate_agent_backend - remove transient data and cache
function cleanup_designate_agent_backend {
:
}
# Restore xtrace
$DP_AGENT_KNOT_XTRACE

View File

@ -76,3 +76,14 @@ Backend Powerdns
:members:
:undoc-members:
:show-inheritance:
Agent Backend KnotDNS
=====================
.. automodule:: designate.backend.agent_backend.impl_knot2
:members:
:special-members:
:private-members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,201 @@
..
Copyright 2016 Hewlett Packard Enterprise Development Company LP
Author: Federico Ceratto <federico.ceratto@hpe.com>
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 <https://www.knot-dns.cz/>`_.
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 <https://gitlab.labs.nic.cz/labs/knot/issues/460>`_
`Knot DNS 2.x documentation <https://www.knot-dns.cz/docs/2.x/singlehtml/>`_
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 <<EOF
# cmd-name: filter-name, raw-command, user, args
[Filters]
knotc: CommandFilter, /usr/sbin/knotc, root
EOF
# Check the filter:
sudo /usr/local/bin/designate-rootwrap /etc/designate/rootwrap.conf knotc status
Configure the "service.agent" and "backend.agent.knot2" sections in /etc/designate/designate.conf
Look in designate.conf.example for examples
Create an agent pool:
.. code-block:: bash
# Fetch the existing pool(s) if needed or start from scratch
designate-manage pool generate_file --file /tmp/pool.yaml
# Edit the file (see below) and reload it as:
designate-manage pool update --file /tmp/pool.yaml
The "targets" section in pool.yaml should look like:
.. code-block:: ini
targets:
- description: knot2 agent
masters:
- host: <MiniDNS IP addr>
port: 5354
options: {}
options:
- host: <Agent IP addr>
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 <filename>):
.. 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"

View File

@ -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 <dnsaas@hp.com>
[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 <openstack-maintainer@infoblox.com>

View File

@ -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

View File

@ -0,0 +1,3 @@
# cmd-name: filter-name, raw-command, user, args
[Filters]
knotc: CommandFilter, /usr/sbin/knotc, root

View File

@ -0,0 +1,3 @@
---
features:
- An experimental agent backend to support Knot DNS 2

View File

@ -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