Merge "Add djbdns backend"
This commit is contained in:
commit
ab121e66b9
110
contrib/djbdns/tinydns.init
Executable file
110
contrib/djbdns/tinydns.init
Executable file
@ -0,0 +1,110 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: tinydns
|
||||||
|
# Required-Start: $local_fs $remote_fs $network
|
||||||
|
# Required-Stop: $local_fs $remote_fs $network
|
||||||
|
# Should-Start: $syslog
|
||||||
|
# Should-Stop: $syslog
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: tinydns daemon processes
|
||||||
|
# Description: Start the TinyDNS resolver
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
# man tinydns
|
||||||
|
|
||||||
|
# Load the VERBOSE setting and other rcS variables
|
||||||
|
. /lib/init/vars.sh
|
||||||
|
|
||||||
|
# Define LSB log_* functions.
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
|
||||||
|
NAME=tinydns
|
||||||
|
DAEMON=/usr/bin/$NAME
|
||||||
|
DAEMON_USER=djbdns
|
||||||
|
DESC="the tinydns daemon"
|
||||||
|
ROOTDIR=/var/lib/djbdns
|
||||||
|
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
LAUNCHER=/usr/bin/envuidgid
|
||||||
|
LAUNCHER_ARGS="$DAEMON_USER envdir ./env softlimit -d300000 $DAEMON"
|
||||||
|
|
||||||
|
PIDFILE=/run/$NAME.pid
|
||||||
|
|
||||||
|
# Exit if executable is not installed
|
||||||
|
[ -x "$DAEMON" ] || exit 0
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
if [ ! -d "$ROOTDIR" ]; then
|
||||||
|
log_action_msg "Not starting $DESC: $ROOTDIR is missing."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_action_begin_msg "Starting $DESC"
|
||||||
|
|
||||||
|
if start-stop-daemon --stop --signal 0 --quiet --pidfile $PIDFILE --exec $DAEMON; then
|
||||||
|
log_action_end_msg 0 "already running"
|
||||||
|
else
|
||||||
|
if start-stop-daemon --start --verbose --make-pidfile --chdir $ROOTDIR --pidfile $PIDFILE --exec $LAUNCHER -- $LAUNCHER_ARGS
|
||||||
|
then
|
||||||
|
log_action_end_msg 0
|
||||||
|
else
|
||||||
|
log_action_end_msg 1
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
log_action_begin_msg "Stopping $DESC"
|
||||||
|
pid=$(cat $PIDFILE 2>/dev/null) || true
|
||||||
|
if test ! -f $PIDFILE -o -z "$pid"; then
|
||||||
|
log_action_end_msg 0 "not running - there is no $PIDFILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if start-stop-daemon --stop --signal INT --quiet --pidfile $PIDFILE --exec $DAEMON; then
|
||||||
|
rm -f $PIDFILE
|
||||||
|
elif kill -0 $pid 2>/dev/null; then
|
||||||
|
log_action_end_msg 1 "Is $pid not $NAME? Is $DAEMON a different binary now?"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
log_action_end_msg 1 "$DAEMON died: process $pid not running; or permission denied"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
reload)
|
||||||
|
echo "Not implemented, use restart"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
$0 stop
|
||||||
|
$0 start
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
if test ! -r $(dirname $PIDFILE); then
|
||||||
|
log_failure_msg "cannot read PID file $PIDFILE"
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
pid=$(cat $PIDFILE 2>/dev/null) || true
|
||||||
|
if test ! -f $PIDFILE -o -z "$pid"; then
|
||||||
|
log_failure_msg "$NAME is not running"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
if ps "$pid" >/dev/null 2>&1; then
|
||||||
|
log_success_msg "$NAME is running"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
log_failure_msg "$NAME is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_action_msg "Usage: $0 {start|stop|restart|force-reload|status}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
44
contrib/djbdns/tinydns.service
Normal file
44
contrib/djbdns/tinydns.service
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# Replace /var/lib/djbdns if needed
|
||||||
|
#
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=tinydns DNS resolver
|
||||||
|
Documentation=man:tinydns
|
||||||
|
Documentation=https://cr.yp.to/djbdns.html
|
||||||
|
After=network.target
|
||||||
|
Requires=network.target
|
||||||
|
Wants=network.target
|
||||||
|
ConditionPathExists=/var/lib/djbdns
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
PIDFile=/run/tinydns.pid
|
||||||
|
Environment="ROOT=/var/lib/djbdns"
|
||||||
|
ExecStart=/usr/bin/tinydns
|
||||||
|
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry=TERM/5/KILL/5 --pidfile /run/tinydns.pid
|
||||||
|
TimeoutStopSec=30
|
||||||
|
KillMode=mixed
|
||||||
|
|
||||||
|
PermissionsStartOnly=true
|
||||||
|
Restart=on-abnormal
|
||||||
|
RestartSec=2s
|
||||||
|
LimitNOFILE=65536
|
||||||
|
|
||||||
|
WorkingDirectory=/var/lib/djbdns
|
||||||
|
User=$ug_name
|
||||||
|
Group=$ug_name
|
||||||
|
|
||||||
|
# Hardening
|
||||||
|
# CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN CAP_FOWNER
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
ProtectHome=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
# TODO: restrict ReadOnlyDirectories
|
||||||
|
ReadOnlyDirectories=/
|
||||||
|
ReadWriteDirectories=-/var/lib/djbdns
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -47,7 +47,7 @@ OPTS = [
|
|||||||
cfg.ListOpt('masters', default=[],
|
cfg.ListOpt('masters', default=[],
|
||||||
help='List of masters for the Agent, format ip:port'),
|
help='List of masters for the Agent, format ip:port'),
|
||||||
cfg.StrOpt('backend-driver', default='bind9',
|
cfg.StrOpt('backend-driver', default='bind9',
|
||||||
help='The backend driver to use: bind9 or knot2'),
|
help='The backend driver to use, e.g. bind9, djbdns, knot2'),
|
||||||
cfg.StrOpt('transfer-source',
|
cfg.StrOpt('transfer-source',
|
||||||
help='An IP address to be used to fetch zones transferred in'),
|
help='An IP address to be used to fetch zones transferred in'),
|
||||||
cfg.FloatOpt('notify-delay', default=0.0,
|
cfg.FloatOpt('notify-delay', default=0.0,
|
||||||
|
350
designate/backend/agent_backend/impl_djbdns.py
Normal file
350
designate/backend/agent_backend/impl_djbdns.py
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
# 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_djbdns
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Djbdns DNS agent backend
|
||||||
|
|
||||||
|
Create, update, delete zones locally on a Djbdns DNS resolver using the
|
||||||
|
axfr-get utility.
|
||||||
|
|
||||||
|
`User documentation <backends/djbdns_agent.html>`_
|
||||||
|
|
||||||
|
.. WARNING::
|
||||||
|
|
||||||
|
Untested, do not use in production.
|
||||||
|
|
||||||
|
|
||||||
|
Configured in [service:agent:djbdns]
|
||||||
|
|
||||||
|
Requires rootwrap (or equivalent sudo privileges) to execute:
|
||||||
|
- tcpclient
|
||||||
|
- axfr-get
|
||||||
|
- tinydns-data
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import dns
|
||||||
|
import dns.resolver
|
||||||
|
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 import utils
|
||||||
|
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:djbdns'
|
||||||
|
# rootwrap requires a command name instead of full path
|
||||||
|
TCPCLIENT_DEFAULT_PATH = 'tcpclient'
|
||||||
|
AXFR_GET_DEFAULT_PATH = 'axfr-get'
|
||||||
|
TINYDNS_DATA_DEFAULT_PATH = 'tinydns-data'
|
||||||
|
|
||||||
|
TINYDNS_DATADIR_DEFAULT_PATH = '/var/lib/djbdns'
|
||||||
|
SOA_QUERY_TIMEOUT = 1
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_exceptions(fn):
|
||||||
|
# Let Backend() exceptions pass through, log out every other exception
|
||||||
|
# and re-raise it as Backend()
|
||||||
|
def wrapper(*a, **kw):
|
||||||
|
try:
|
||||||
|
return fn(*a, **kw)
|
||||||
|
except exceptions.Backend as e:
|
||||||
|
raise e
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE("Unhandled exception %s"), str(e), exc_info=True)
|
||||||
|
raise exceptions.Backend(str(e))
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class DjbdnsBackend(base.AgentBackend):
|
||||||
|
__plugin_name__ = 'djbdns'
|
||||||
|
__backend_status__ = 'experimental'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_cfg_opts(cls):
|
||||||
|
group = cfg.OptGroup(
|
||||||
|
name='backend:agent:djbdns',
|
||||||
|
title="Configuration for Djbdns backend"
|
||||||
|
)
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt(
|
||||||
|
'tcpclient-cmd-name',
|
||||||
|
help='tcpclient executable path or rootwrap command name',
|
||||||
|
default=TCPCLIENT_DEFAULT_PATH
|
||||||
|
),
|
||||||
|
cfg.StrOpt(
|
||||||
|
'axfr-get-cmd-name',
|
||||||
|
help='axfr-get executable path or rootwrap command name',
|
||||||
|
default=AXFR_GET_DEFAULT_PATH
|
||||||
|
),
|
||||||
|
cfg.StrOpt(
|
||||||
|
'tinydns-data-cmd-name',
|
||||||
|
help='tinydns-data executable path or rootwrap command name',
|
||||||
|
default=TINYDNS_DATA_DEFAULT_PATH
|
||||||
|
),
|
||||||
|
cfg.StrOpt(
|
||||||
|
'tinydns-datadir',
|
||||||
|
help='TinyDNS data directory',
|
||||||
|
default=TINYDNS_DATADIR_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(DjbdnsBackend, self).__init__(*a, **kw)
|
||||||
|
|
||||||
|
self._resolver = dns.resolver.Resolver(configure=False)
|
||||||
|
self._resolver.timeout = SOA_QUERY_TIMEOUT
|
||||||
|
self._resolver.lifetime = SOA_QUERY_TIMEOUT
|
||||||
|
self._resolver.nameservers = [cfg.CONF[CFG_GROUP].query_destination]
|
||||||
|
self._masters = [utils.split_host_port(ns)
|
||||||
|
for ns in cfg.CONF['service:agent'].masters]
|
||||||
|
LOG.info(_LI("Resolvers: %r"), self._resolver.nameservers)
|
||||||
|
LOG.info(_LI("AXFR masters: %r"), self._masters)
|
||||||
|
if not self._masters:
|
||||||
|
raise exceptions.Backend("Missing agent AXFR masters")
|
||||||
|
|
||||||
|
self._tcpclient_cmd_name = cfg.CONF[CFG_GROUP].tcpclient_cmd_name
|
||||||
|
self._axfr_get_cmd_name = cfg.CONF[CFG_GROUP].axfr_get_cmd_name
|
||||||
|
|
||||||
|
# Directory where data.cdb lives, usually /var/lib/djbdns/root
|
||||||
|
tinydns_root_dir = os.path.join(cfg.CONF[CFG_GROUP].tinydns_datadir,
|
||||||
|
'root')
|
||||||
|
|
||||||
|
# Usually /var/lib/djbdns/root/data.cdb
|
||||||
|
self._tinydns_cdb_filename = os.path.join(tinydns_root_dir, 'data.cdb')
|
||||||
|
LOG.info(_LI("data.cdb path: %r"), self._tinydns_cdb_filename)
|
||||||
|
|
||||||
|
# Where the agent puts the zone datafiles,
|
||||||
|
# usually /var/lib/djbdns/datafiles
|
||||||
|
self._datafiles_dir = datafiles_dir = os.path.join(
|
||||||
|
cfg.CONF[CFG_GROUP].tinydns_datadir,
|
||||||
|
'datafiles')
|
||||||
|
self._datafiles_tmp_path_tpl = os.path.join(datafiles_dir, "%s.ztmp")
|
||||||
|
self._datafiles_path_tpl = os.path.join(datafiles_dir, "%s.zonedata")
|
||||||
|
self._datafiles_path_glob = self._datafiles_path_tpl % '*'
|
||||||
|
|
||||||
|
self._check_dirs(tinydns_root_dir, datafiles_dir)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _check_dirs(*dirnames):
|
||||||
|
"""Check if directories are writable
|
||||||
|
"""
|
||||||
|
for dn in dirnames:
|
||||||
|
if not os.path.isdir(dn):
|
||||||
|
raise exceptions.Backend("Missing directory %s" % dn)
|
||||||
|
if not os.access(dn, os.W_OK):
|
||||||
|
raise exceptions.Backend("Directory not writable: %s" % dn)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Start the backend"""
|
||||||
|
LOG.info(_LI("Started djbdns backend"))
|
||||||
|
|
||||||
|
def find_zone_serial(self, zone_name):
|
||||||
|
"""Query the local resolver for a zone
|
||||||
|
Times out after SOA_QUERY_TIMEOUT
|
||||||
|
"""
|
||||||
|
LOG.debug("Finding %s", zone_name)
|
||||||
|
try:
|
||||||
|
rdata = self._resolver.query(
|
||||||
|
zone_name, rdtype=dns.rdatatype.SOA)[0]
|
||||||
|
return rdata.serial
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _concatenate_zone_datafiles(data_fn, path_glob):
|
||||||
|
"""Concatenate all zone datafiles into 'data'
|
||||||
|
"""
|
||||||
|
with open(data_fn, 'w') as data_f:
|
||||||
|
zone_cnt = 0
|
||||||
|
for zone_fn in glob.glob(path_glob):
|
||||||
|
zone_cnt += 1
|
||||||
|
with open(zone_fn) as zf:
|
||||||
|
data_f.write(zf.read())
|
||||||
|
|
||||||
|
LOG.info(_LI("Loaded %d zone datafiles."), zone_cnt)
|
||||||
|
|
||||||
|
def _rebuild_data_cdb(self):
|
||||||
|
"""Rebuild data.cdb file from zone datafiles
|
||||||
|
Requires global lock
|
||||||
|
|
||||||
|
On zone creation, axfr-get creates datafiles atomically by doing
|
||||||
|
rename. On zone deletion, os.remove deletes the file atomically
|
||||||
|
Globbing and reading the datafiles can be done without locking on
|
||||||
|
them.
|
||||||
|
The data and data.cdb files are written into a unique temp directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
tmpdir = tempfile.mkdtemp(dir=self._datafiles_dir)
|
||||||
|
data_fn = os.path.join(tmpdir, 'data')
|
||||||
|
tmp_cdb_fn = os.path.join(tmpdir, 'data.cdb')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._concatenate_zone_datafiles(data_fn,
|
||||||
|
self._datafiles_path_glob)
|
||||||
|
# Generate the data.cdb file
|
||||||
|
LOG.info(_LI("Updating data.cdb"))
|
||||||
|
LOG.debug("Convert %s to %s", data_fn, tmp_cdb_fn)
|
||||||
|
try:
|
||||||
|
out, err = execute(
|
||||||
|
cfg.CONF[CFG_GROUP].tinydns_data_cmd_name,
|
||||||
|
cwd=tmpdir
|
||||||
|
)
|
||||||
|
except ProcessExecutionError as e:
|
||||||
|
LOG.error(_LE("Failed to generate data.cdb"))
|
||||||
|
LOG.error(_LE("Command output: %(out)r Stderr: %(err)r"), {
|
||||||
|
'out': e.stdout, 'err': e.stderr
|
||||||
|
})
|
||||||
|
raise exceptions.Backend("Failed to generate data.cdb")
|
||||||
|
|
||||||
|
LOG.debug("Move %s to %s", tmp_cdb_fn, self._tinydns_cdb_filename)
|
||||||
|
try:
|
||||||
|
os.rename(tmp_cdb_fn, self._tinydns_cdb_filename)
|
||||||
|
except OSError:
|
||||||
|
os.remove(tmp_cdb_fn)
|
||||||
|
LOG.error(_LE("Unable to move data.cdb to %s"),
|
||||||
|
self._tinydns_cdb_filename)
|
||||||
|
raise exceptions.Backend("Unable to move data.cdb")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.remove(data_fn)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
os.removedirs(tmpdir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _perform_axfr_from_minidns(self, zone_name):
|
||||||
|
"""Instruct axfr-get to request an AXFR from MiniDNS.
|
||||||
|
|
||||||
|
:raises: exceptions.Backend on error
|
||||||
|
"""
|
||||||
|
zone_fn = self._datafiles_path_tpl % zone_name
|
||||||
|
zone_tmp_fn = self._datafiles_tmp_path_tpl % zone_name
|
||||||
|
|
||||||
|
# Perform AXFR, create or update a zone datafile
|
||||||
|
# No need to lock globally here.
|
||||||
|
# Axfr-get creates the datafile atomically by doing rename
|
||||||
|
mdns_hostname, mdns_port = random.choice(self._masters)
|
||||||
|
with lockutils.lock("%s.lock" % zone_name):
|
||||||
|
LOG.debug("writing to %s", zone_fn)
|
||||||
|
cmd = (
|
||||||
|
self._tcpclient_cmd_name,
|
||||||
|
mdns_hostname,
|
||||||
|
"%d" % mdns_port,
|
||||||
|
self._axfr_get_cmd_name,
|
||||||
|
zone_name,
|
||||||
|
zone_fn,
|
||||||
|
zone_tmp_fn
|
||||||
|
)
|
||||||
|
|
||||||
|
LOG.debug("Executing AXFR as %r", ' '.join(cmd))
|
||||||
|
try:
|
||||||
|
out, err = execute(*cmd)
|
||||||
|
except ProcessExecutionError as e:
|
||||||
|
LOG.error(_LE("Error executing AXFR as %r"), ' '.join(cmd))
|
||||||
|
LOG.error(_LE("Command output: %(out)r Stderr: %(err)r"), {
|
||||||
|
'out': e.stdout, 'err': e.stderr
|
||||||
|
})
|
||||||
|
raise exceptions.Backend(str(e))
|
||||||
|
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.remove(zone_tmp_fn)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@filter_exceptions
|
||||||
|
def create_zone(self, zone):
|
||||||
|
"""Create a new Zone
|
||||||
|
Do not raise exceptions if the zone already exists.
|
||||||
|
|
||||||
|
:param zone: zone to be created
|
||||||
|
:type zone: raw pythondns Zone
|
||||||
|
:raises: exceptions.Backend on error
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
LOG.debug("Triggering initial AXFR from MiniDNS to Djbdns for %s",
|
||||||
|
zone_name)
|
||||||
|
self._perform_axfr_from_minidns(zone_name)
|
||||||
|
self._rebuild_data_cdb()
|
||||||
|
|
||||||
|
@filter_exceptions
|
||||||
|
def update_zone(self, zone):
|
||||||
|
"""Instruct Djbdns DNS to perform AXFR from MiniDNS
|
||||||
|
|
||||||
|
:param zone: zone to be created
|
||||||
|
:type zone: raw pythondns Zone
|
||||||
|
:raises: exceptions.Backend on error
|
||||||
|
"""
|
||||||
|
zone_name = zone.origin.to_text().rstrip('.')
|
||||||
|
LOG.debug("Triggering AXFR from MiniDNS to Djbdns for %s", zone_name)
|
||||||
|
self._perform_axfr_from_minidns(zone_name)
|
||||||
|
self._rebuild_data_cdb()
|
||||||
|
|
||||||
|
@filter_exceptions
|
||||||
|
def delete_zone(self, zone_name):
|
||||||
|
"""Delete a new Zone
|
||||||
|
Do not raise exceptions if the zone does not exist.
|
||||||
|
|
||||||
|
:param zone_name: zone name
|
||||||
|
:type zone_name: str
|
||||||
|
:raises: exceptions.Backend on error
|
||||||
|
"""
|
||||||
|
zone_name = zone_name.rstrip('.')
|
||||||
|
LOG.debug('Deleting Zone: %s', zone_name)
|
||||||
|
zone_fn = self._datafiles_path_tpl % zone_name
|
||||||
|
try:
|
||||||
|
os.remove(zone_fn)
|
||||||
|
LOG.debug('Deleted Zone: %s', zone_name)
|
||||||
|
except OSError as e:
|
||||||
|
if os.errno.ENOENT == e.errno:
|
||||||
|
LOG.info(_LI("Zone datafile %s was already deleted"), zone_fn)
|
||||||
|
return
|
||||||
|
|
||||||
|
raise
|
||||||
|
|
||||||
|
self._rebuild_data_cdb()
|
127
designate/tests/test_agent/test_backends/test_djbdns.py
Normal file
127
designate/tests/test_agent/test_backends/test_djbdns.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Test the Djbdns agent backend
|
||||||
|
|
||||||
|
These tests *do* rely on creating directories and files or running
|
||||||
|
executables from the djbdns suite
|
||||||
|
|
||||||
|
If djbdns is not available some tests are skipped.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import fixtures
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from designate import exceptions
|
||||||
|
from designate.backend.agent_backend.impl_djbdns import DjbdnsBackend
|
||||||
|
from designate.tests import TestCase
|
||||||
|
import designate.backend.agent_backend.impl_djbdns
|
||||||
|
|
||||||
|
TINYDNSDATA_PATH = '/usr/bin/tinydns-data'
|
||||||
|
|
||||||
|
|
||||||
|
class DjbdnsAgentBackendSimpleTestCase(TestCase):
|
||||||
|
|
||||||
|
def test__check_dirs(self):
|
||||||
|
DjbdnsBackend._check_dirs('/tmp')
|
||||||
|
|
||||||
|
def test__check_dirs_not_found(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.Backend,
|
||||||
|
DjbdnsBackend._check_dirs,
|
||||||
|
'/nonexistent_dir_name'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DjbdnsAgentBackendTestCase(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DjbdnsAgentBackendTestCase, self).setUp()
|
||||||
|
self.CONF.set_override('masters', ('127.0.0.1:5354',), 'service:agent')
|
||||||
|
tmp_datafiles_dir = tempfile.mkdtemp()
|
||||||
|
os.mkdir(os.path.join(tmp_datafiles_dir, 'datafiles'))
|
||||||
|
self.CONF.set_override(
|
||||||
|
'tinydns_datadir',
|
||||||
|
tmp_datafiles_dir,
|
||||||
|
designate.backend.agent_backend.impl_djbdns.CFG_GROUP
|
||||||
|
)
|
||||||
|
self.useFixture(fixtures.MockPatchObject(
|
||||||
|
DjbdnsBackend, '_check_dirs'
|
||||||
|
))
|
||||||
|
self.backend = DjbdnsBackend('foo')
|
||||||
|
self.patch_ob(self.backend._resolver, 'query')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(DjbdnsAgentBackendTestCase, self).tearDown()
|
||||||
|
|
||||||
|
def patch_ob(self, *a, **kw):
|
||||||
|
self.useFixture(fixtures.MockPatchObject(*a, **kw))
|
||||||
|
|
||||||
|
@mock.patch('designate.backend.agent_backend.impl_djbdns.os.remove')
|
||||||
|
@mock.patch('designate.backend.agent_backend.impl_djbdns.execute')
|
||||||
|
def test__perform_axfr_from_minidns(self, mock_exe, mock_rm):
|
||||||
|
mock_exe.return_value = (None, None)
|
||||||
|
|
||||||
|
self.backend._perform_axfr_from_minidns('foo')
|
||||||
|
|
||||||
|
mock_exe.assert_called_once_with(
|
||||||
|
'tcpclient', '127.0.0.1', '5354', 'axfr-get', 'foo',
|
||||||
|
os.path.join(self.backend._datafiles_dir, 'foo.zonedata'),
|
||||||
|
os.path.join(self.backend._datafiles_dir, 'foo.ztmp')
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_delete_zone_no_file(self):
|
||||||
|
self.patch_ob(self.backend, '_rebuild_data_cdb')
|
||||||
|
# Should not raise exceptions
|
||||||
|
self.backend.delete_zone('non_existent_zone_file')
|
||||||
|
|
||||||
|
@unittest.skipIf(not os.path.isfile(TINYDNSDATA_PATH),
|
||||||
|
"tinydns-data not installed")
|
||||||
|
def test__rebuild_data_cdb_empty(self):
|
||||||
|
# Check that tinydns-data can be run and the required files are
|
||||||
|
# generated / renamed as needed
|
||||||
|
self.CONF.set_override('root_helper', ' ') # disable rootwrap
|
||||||
|
self.backend._tinydns_cdb_filename = tempfile.mkstemp()[1]
|
||||||
|
|
||||||
|
self.backend._rebuild_data_cdb()
|
||||||
|
|
||||||
|
assert os.path.isfile(self.backend._tinydns_cdb_filename)
|
||||||
|
os.remove(self.backend._tinydns_cdb_filename)
|
||||||
|
|
||||||
|
@unittest.skipIf(not os.path.isfile(TINYDNSDATA_PATH),
|
||||||
|
"tinydns-data not installed")
|
||||||
|
def test__rebuild_data_cdb(self):
|
||||||
|
# Check that tinydns-data can be run and the required files are
|
||||||
|
# generated / renamed as needed
|
||||||
|
self.CONF.set_override('root_helper', ' ') # disable rootwrap
|
||||||
|
self.backend._tinydns_cdb_filename = tempfile.mkstemp()[1]
|
||||||
|
|
||||||
|
fn = os.path.join(self.backend._datafiles_dir, 'example.org.zonedata')
|
||||||
|
with open(fn, 'w') as f:
|
||||||
|
f.write(""".example.org::ns1.example.org
|
||||||
|
+ns1.example.org:127.0.0.1
|
||||||
|
+www.example.org:127.0.0.1
|
||||||
|
""")
|
||||||
|
|
||||||
|
self.backend._rebuild_data_cdb()
|
||||||
|
|
||||||
|
assert os.path.isfile(self.backend._tinydns_cdb_filename)
|
||||||
|
os.remove(self.backend._tinydns_cdb_filename)
|
126
designate/tests/unit/test_agent/test_backends/test_djbdns.py
Normal file
126
designate/tests/unit/test_agent/test_backends/test_djbdns.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# 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 Djbdns agent backend
|
||||||
|
|
||||||
|
These tests do not rely on creating directories and files or running
|
||||||
|
executables from the djbdns suite
|
||||||
|
"""
|
||||||
|
|
||||||
|
import dns.zone
|
||||||
|
import fixtures
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from designate import exceptions
|
||||||
|
from designate.backend.agent_backend.impl_djbdns import DjbdnsBackend
|
||||||
|
from designate.tests import TestCase
|
||||||
|
import designate.backend.agent_backend.impl_djbdns # noqa
|
||||||
|
|
||||||
|
|
||||||
|
class DjbdnsAgentBackendUnitTestCase(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DjbdnsAgentBackendUnitTestCase, self).setUp()
|
||||||
|
self.CONF.set_override('masters', ('127.0.0.1:5354',), 'service:agent')
|
||||||
|
self.useFixture(fixtures.MockPatchObject(
|
||||||
|
DjbdnsBackend, '_check_dirs'
|
||||||
|
))
|
||||||
|
self.backend = DjbdnsBackend('foo')
|
||||||
|
self.patch_ob(self.backend._resolver, 'query')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(DjbdnsAgentBackendUnitTestCase, self).tearDown()
|
||||||
|
|
||||||
|
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 patch_ob(self, *a, **kw):
|
||||||
|
self.useFixture(fixtures.MockPatchObject(*a, **kw))
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
self.assertTrue(hasattr(self.backend, '_resolver'))
|
||||||
|
self.assertEqual(1, self.backend._resolver.timeout)
|
||||||
|
self.assertEqual(1, self.backend._resolver.lifetime)
|
||||||
|
self.assertEqual(['127.0.0.1'], self.backend._resolver.nameservers)
|
||||||
|
self.assertEqual('/var/lib/djbdns/root/data.cdb',
|
||||||
|
self.backend._tinydns_cdb_filename)
|
||||||
|
self.assertEqual('/var/lib/djbdns/datafiles',
|
||||||
|
self.backend._datafiles_dir)
|
||||||
|
self.assertEqual('/var/lib/djbdns/datafiles/%s.zonedata',
|
||||||
|
self.backend._datafiles_path_tpl)
|
||||||
|
self.assertEqual([('127.0.0.1', 5354)], self.backend._masters)
|
||||||
|
|
||||||
|
def test_find_zone_serial(self):
|
||||||
|
class Data(object):
|
||||||
|
serial = 3
|
||||||
|
|
||||||
|
self.backend._resolver.query.return_value = [Data(), ]
|
||||||
|
serial = self.backend.find_zone_serial('example.com')
|
||||||
|
self.assertEqual(3, serial)
|
||||||
|
|
||||||
|
def test_find_zone_serial_error(self):
|
||||||
|
self.backend._resolver.query.side_effect = RuntimeError('foo')
|
||||||
|
|
||||||
|
serial = self.backend.find_zone_serial('example.com')
|
||||||
|
self.assertEqual(None, serial)
|
||||||
|
|
||||||
|
@mock.patch('designate.backend.agent_backend.impl_djbdns.execute')
|
||||||
|
def test_create_zone(self, mock_exe):
|
||||||
|
self.patch_ob(self.backend, '_perform_axfr_from_minidns')
|
||||||
|
self.patch_ob(self.backend, '_rebuild_data_cdb')
|
||||||
|
zone = self._create_dnspy_zone('example.org')
|
||||||
|
self.backend.create_zone(zone)
|
||||||
|
|
||||||
|
def test_update_zone(self):
|
||||||
|
self.patch_ob(self.backend, '_perform_axfr_from_minidns')
|
||||||
|
self.patch_ob(self.backend, '_rebuild_data_cdb')
|
||||||
|
zone = self._create_dnspy_zone('example.org')
|
||||||
|
self.backend.update_zone(zone)
|
||||||
|
|
||||||
|
@mock.patch('designate.backend.agent_backend.impl_djbdns.os.remove')
|
||||||
|
def test_delete_zone(self, mock_rm):
|
||||||
|
self.patch_ob(self.backend, '_rebuild_data_cdb')
|
||||||
|
|
||||||
|
self.backend.delete_zone('foo')
|
||||||
|
|
||||||
|
mock_rm.assert_called_once_with(
|
||||||
|
'/var/lib/djbdns/datafiles/foo.zonedata'
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch('designate.backend.agent_backend.impl_djbdns.os.remove')
|
||||||
|
def test_exception_filter(self, *mocks):
|
||||||
|
self.patch_ob(self.backend, '_rebuild_data_cdb')
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.Backend,
|
||||||
|
self.backend.delete_zone,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch('designate.backend.agent_backend.impl_djbdns.os.remove')
|
||||||
|
def test_exception_filter_pass_through(self, mock_rm):
|
||||||
|
self.patch_ob(self.backend, '_rebuild_data_cdb')
|
||||||
|
mock_rm.side_effect = exceptions.Backend
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.Backend,
|
||||||
|
self.backend.delete_zone,
|
||||||
|
'foo'
|
||||||
|
)
|
@ -87,3 +87,12 @@ Agent Backend KnotDNS
|
|||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
Agent Backend Djbdns
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. automodule:: designate.backend.agent_backend.impl_djbdns
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:private-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
132
doc/source/backends/djbdns_agent.rst
Normal file
132
doc/source/backends/djbdns_agent.rst
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
..
|
||||||
|
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.
|
||||||
|
|
||||||
|
Djbdns Agent backend
|
||||||
|
********************
|
||||||
|
|
||||||
|
|
||||||
|
User documentation
|
||||||
|
==================
|
||||||
|
|
||||||
|
This page documents the Agent backend for `djbdns <https://cr.yp.to/djbdns.html>`_.
|
||||||
|
|
||||||
|
The agent runs on the same host as the `tinydns <https://cr.yp.to/djbdns/tinydns.html>`_ resolver.
|
||||||
|
It receives DNS messages from Mini DNS using private DNS OPCODEs and classes and creates or deletes
|
||||||
|
zones in the data.cdb file using `axfr-get <https://cr.yp.to/djbdns/axfr-get.html>`_ and
|
||||||
|
`tinydns-data <https://cr.yp.to/djbdns/tinydns-data.html>`_
|
||||||
|
|
||||||
|
Setting up Djbdns on Ubuntu Trusty
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Assuming no DNS resolver is already installed, run as root:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
set -u
|
||||||
|
datadir=/var/lib/djbdns
|
||||||
|
ug_name=djbdns
|
||||||
|
tinydns_ipaddr=127.0.0.1
|
||||||
|
|
||||||
|
[[ -d $datadir ]] && echo "$datadir already exists" && exit 1
|
||||||
|
set -e
|
||||||
|
apt-get update
|
||||||
|
apt-get install dbndns daemontools
|
||||||
|
if ! getent passwd $ug_name >/dev/null; then
|
||||||
|
adduser --quiet --system --group --no-create-home --home /nonexistent $ug_name
|
||||||
|
fi
|
||||||
|
tinydns-conf $ug_name $ug_name $datadir $tinydns_ipaddr
|
||||||
|
cd $datadir/root
|
||||||
|
tinydns-data data
|
||||||
|
chown -Rv $ug_name:$ug_name $datadir
|
||||||
|
|
||||||
|
Setup the a Systemd service or, alternatively, an initfile to start TinyDNS.
|
||||||
|
|
||||||
|
In the contrib/djbdns directory there are example files for both.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
service tinydns start
|
||||||
|
service tinydns status
|
||||||
|
|
||||||
|
|
||||||
|
If needed, create the rootwrap filters, as root:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cat > /etc/designate/rootwrap.d/djbdns.filters <<EOF
|
||||||
|
# cmd-name: filter-name, raw-command, user, args
|
||||||
|
[Filters]
|
||||||
|
tcpclient: CommandFilter, /usr/bin/tcpclient, root
|
||||||
|
axfr-get: CommandFilter, /usr/bin/axfr-get, root
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Check the filter:
|
||||||
|
sudo /usr/local/bin/designate-rootwrap /etc/designate/rootwrap.conf tcpclient -h
|
||||||
|
sudo /usr/local/bin/designate-rootwrap /etc/designate/rootwrap.conf axfr-get -h
|
||||||
|
|
||||||
|
Configure the "service.agent" and "backend.agent.djbdns" 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: gdnsd agent
|
||||||
|
masters:
|
||||||
|
- host: <MiniDNS IP addr>
|
||||||
|
port: 5354
|
||||||
|
options: {}
|
||||||
|
options:
|
||||||
|
- host: <Agent IP addr>
|
||||||
|
port: 5358
|
||||||
|
type: agent
|
||||||
|
|
||||||
|
|
||||||
|
Testing
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
Create new zones and records. Monitor the agent logfile and the contents of the
|
||||||
|
TinyDNS datadir. The data.cdb file should be receiving updates.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
openstack zone create --email example@example.org example.org.
|
||||||
|
openstack recordset create example.org. --type A foo --records 1.2.3.4
|
||||||
|
dig example.org @<tinydns_ipaddr> SOA
|
||||||
|
dig foo.example.org @<tinydns_ipaddr> A
|
||||||
|
|
||||||
|
Developer documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Devstack testbed
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Follow "Setting up Djbdns on Ubuntu Trusty"
|
||||||
|
|
||||||
|
Configure Tinydns to do AXFR from MiniDNS on 192.168.121.131
|
@ -54,6 +54,7 @@ backend-impl-agent=Agent
|
|||||||
backend-impl-bind9-agent=Bind9 (Agent)
|
backend-impl-bind9-agent=Bind9 (Agent)
|
||||||
backend-impl-denominator=Denominator
|
backend-impl-denominator=Denominator
|
||||||
backend-impl-knot2-agent=Knot2 (Agent)
|
backend-impl-knot2-agent=Knot2 (Agent)
|
||||||
|
backend-impl-djbdns-agent=Djbdns (Agent)
|
||||||
|
|
||||||
|
|
||||||
[backends.backend-impl-bind9]
|
[backends.backend-impl-bind9]
|
||||||
@ -79,6 +80,9 @@ type=agent
|
|||||||
[backends.backend-impl-knot2-agent]
|
[backends.backend-impl-knot2-agent]
|
||||||
type=agent
|
type=agent
|
||||||
|
|
||||||
|
[backends.backend-impl-djbdns-agent]
|
||||||
|
type=agent
|
||||||
|
|
||||||
[backends.backend-impl-infoblox-xfr]
|
[backends.backend-impl-infoblox-xfr]
|
||||||
status=release-compatible
|
status=release-compatible
|
||||||
maintainers=Infoblox OpenStack Team <openstack-maintainer@infoblox.com>
|
maintainers=Infoblox OpenStack Team <openstack-maintainer@infoblox.com>
|
||||||
|
@ -465,6 +465,15 @@ debug = False
|
|||||||
# knotc command name when rootwrap is used. Location of the knotc executable
|
# knotc command name when rootwrap is used. Location of the knotc executable
|
||||||
# on the resolver host if rootwrap is not used
|
# on the resolver host if rootwrap is not used
|
||||||
#knotc_cmd_name = /usr/sbin/knotc
|
#knotc_cmd_name = /usr/sbin/knotc
|
||||||
|
#
|
||||||
|
[backend:agent:djbdns]
|
||||||
|
# Command names when rootwrap is used or location of the executables
|
||||||
|
# on the resolver host when rootwrap is not used
|
||||||
|
# tcpclient_cmd_name =
|
||||||
|
# axfr_get_cmd_name =
|
||||||
|
# tinydns_data_cmd_name =
|
||||||
|
# tinydns_datadir =
|
||||||
|
#query_destination = 127.0.0.1
|
||||||
|
|
||||||
[backend:agent:denominator]
|
[backend:agent:denominator]
|
||||||
#name = dynect
|
#name = dynect
|
||||||
|
4
etc/designate/rootwrap.d/djbdns.filters
Normal file
4
etc/designate/rootwrap.d/djbdns.filters
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[Filters]
|
||||||
|
tcpclient: CommandFilter, /usr/bin/tcpclient, root
|
||||||
|
axfr-get: CommandFilter, /usr/bin/axfr-get, root
|
||||||
|
tinydns-data: CommandFilter, /usr/bin/tinydns-data, root
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- An experimental agent backend to support TinyDNS, the DNS resolver
|
||||||
|
from the djbdns tools.
|
@ -92,6 +92,7 @@ designate.backend =
|
|||||||
designate.backend.agent_backend =
|
designate.backend.agent_backend =
|
||||||
bind9 = designate.backend.agent_backend.impl_bind9:Bind9Backend
|
bind9 = designate.backend.agent_backend.impl_bind9:Bind9Backend
|
||||||
knot2 = designate.backend.agent_backend.impl_knot2:Knot2Backend
|
knot2 = designate.backend.agent_backend.impl_knot2:Knot2Backend
|
||||||
|
djbdns = designate.backend.agent_backend.impl_djbdns:DjbdnsBackend
|
||||||
denominator = designate.backend.agent_backend.impl_denominator:DenominatorBackend
|
denominator = designate.backend.agent_backend.impl_denominator:DenominatorBackend
|
||||||
fake = designate.backend.agent_backend.impl_fake:FakeBackend
|
fake = designate.backend.agent_backend.impl_fake:FakeBackend
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user