Pools Config Changes

Implement the beginning of a structured pattern for Plugin's to provide
configuration into Designate. The chosen pattern has been built to support
both config generation, and the ability to define "extra" config options
which are based on other config options (i.e. the dynamic sections for each
pool server).

Change-Id: I1889ac1de3dc90b95533bea3f456ea2bf8e9b845
This commit is contained in:
Kiall Mac Innes 2014-12-11 21:05:52 +00:00
parent 490118d9ce
commit 504a2607a8
18 changed files with 348 additions and 394 deletions

View File

@ -38,40 +38,6 @@ if is_fedora; then
BIND_GROUP=named
fi
# Local functions
#----------------
# Set an option in an INI file
# wildcard_iniset config-file section option value
#
# This function is needed to handle sections that have a wildcard in them.
function wildcard_iniset {
local xtrace=$(set +o | grep xtrace)
set +o xtrace
local file=$1
local section=$2
local option=$3
local value=$4
[[ -z $section || -z $option ]] && return
if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then
eval wildcardless_section=$section
# Add section at the end
echo -e "\n[$wildcardless_section]" >>"$file"
fi
if ! ini_has_option "$file" "$section" "$option"; then
# Add it
sed -i -e "/^\[$section\]/ a\\
$option = $value
" "$file"
else
local sep=$(echo -ne "\x01")
# Replace it
sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('${option}'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file"
fi
$xtrace
}
# Entry Points
# ------------
@ -109,11 +75,15 @@ EOF
# configure_designate_backend - make configuration changes, including those to other services
function configure_designate_backend {
wildcard_iniset $DESIGNATE_CONF backend:bind9_pool:\\\* masters $DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS
wildcard_iniset $DESIGNATE_CONF backend:bind9_pool:\\\* rndc_port $DESIGNATE_SERVICE_PORT_RNDC
wildcard_iniset $DESIGNATE_CONF backend:bind9_pool:\\\* rndc_host $DESIGNATE_SERVICE_HOST
wildcard_iniset $DESIGNATE_CONF backend:bind9_pool:\\\* rndc_config_file "$BIND_CFG_DIR/rndc.conf"
wildcard_iniset $DESIGNATE_CONF backend:bind9_pool:\\\* rndc_key_file "$BIND_CFG_DIR/rndc.key"
iniset $DESIGNATE_CONF service:pool_manager backends bind9_pool
iniset $DESIGNATE_CONF service:mdns slave_nameserver_ips_and_ports "$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_DNS"
iniset $DESIGNATE_CONF backend:bind9_pool masters $DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS
iniset $DESIGNATE_CONF backend:bind9_pool server_ids $DESIGNATE_SERVER_ID
iniset $DESIGNATE_CONF backend:bind9_pool rndc_port $DESIGNATE_SERVICE_PORT_RNDC
iniset $DESIGNATE_CONF backend:bind9_pool rndc_host $DESIGNATE_SERVICE_HOST
iniset $DESIGNATE_CONF backend:bind9_pool rndc_config_file "$BIND_CFG_DIR/rndc.conf"
iniset $DESIGNATE_CONF backend:bind9_pool rndc_key_file "$BIND_CFG_DIR/rndc.key"
iniset $DESIGNATE_CONF backend:bind9_pool:$DESIGNATE_SERVER_ID host $DESIGNATE_SERVICE_HOST
iniset $DESIGNATE_CONF backend:bind9_pool:$DESIGNATE_SERVER_ID port $DESIGNATE_SERVICE_PORT_DNS

View File

@ -14,10 +14,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import abc
import copy
from oslo.config import cfg
import designate.pool_manager.backend_section_name as backend_section_name
from designate.openstack.common import log as logging
from designate.i18n import _LW
from designate import exceptions
@ -162,6 +162,69 @@ class Backend(DriverPlugin):
class PoolBackend(Backend):
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name=cls.get_canonical_name(),
title='Backend options for %s Backend' % cls.get_plugin_name()
)
opts = [
cfg.ListOpt('server_ids', default=[]),
cfg.ListOpt('masters', default=['127.0.0.1:5354'],
help='Comma-separated list of master DNS servers, in '
'<ip-address>:<port> format. If <port> is '
'omitted, the default 5354 is used. These are '
'mdns servers.'),
]
opts.extend(cls._get_common_cfg_opts())
opts.extend(cls._get_global_cfg_opts())
return [(group, opts)]
@classmethod
def get_extra_cfg_opts(cls):
# Common options fot all backends
opts = [
cfg.ListOpt('masters'),
cfg.StrOpt('host', default='127.0.0.1', help='Server Host'),
cfg.IntOpt('port', default=53, help='Server Port'),
cfg.StrOpt('tsig-key', help='Server TSIG Key'),
]
# Backend specific common options
common_cfg_opts = copy.deepcopy(cls._get_common_cfg_opts())
# Ensure the default value for all common options is reset to None
for opt in common_cfg_opts:
opt.default = None
opts.extend(common_cfg_opts)
# Add any server only config options
opts.extend(cls._get_server_cfg_opts())
result = []
global_group = cls.get_canonical_name()
for server_id in cfg.CONF[global_group].server_ids:
group = cfg.OptGroup(name='%s:%s' % (global_group, server_id))
result.append((group, opts))
return result
@classmethod
def _get_common_cfg_opts(cls):
return []
@classmethod
def _get_global_cfg_opts(cls):
return []
@classmethod
def _get_server_cfg_opts(cls):
return []
def __init__(self, backend_options):
super(PoolBackend, self).__init__(None)
@ -203,60 +266,28 @@ class PoolBackend(Backend):
Create the backend_option object. If a server specific backend option
value exists, use it. Otherwise use the global backend option value.
"""
value = cfg.CONF[server_section_name].get(key)
value = None
try:
value = cfg.CONF[server_section_name].get(key)
except cfg.NoSuchOptError:
pass
if value is None:
value = cfg.CONF[global_section_name].get(key)
backend_option_values = {
'key': key,
'value': value
}
return objects.BackendOption(**backend_option_values)
@classmethod
def _register_opts(cls, backend, server_id):
"""
Register the global and server specific backend options.
"""
global_section_name = backend_section_name \
.generate_global_section_name(backend)
server_section_name = backend_section_name \
.generate_server_section_name(backend, server_id)
# Register the global backend options.
global_opts = cls.get_cfg_opts()
cfg.CONF.register_group(cfg.OptGroup(name=global_section_name))
cfg.CONF.register_opts(global_opts, group=global_section_name)
# Register the server specific backend options.
server_opts = global_opts
server_opts.append(cfg.StrOpt('host', default='127.0.0.1',
help='Server Host'))
server_opts.append(cfg.IntOpt('port', default=53, help='Server Port'))
server_opts.append(cfg.StrOpt('tsig-key', help='Server TSIG Key'))
cfg.CONF.register_group(cfg.OptGroup(name=server_section_name))
cfg.CONF.register_opts(server_opts, group=server_section_name)
# Ensure the server specific backend options do not have a default
# value. This is necessary so the default value does not override
# a global backend option value set in the configuration file.
for key in cfg.CONF[global_section_name].keys():
cfg.CONF.set_default(key, None, group=server_section_name)
return global_section_name, server_section_name
@abc.abstractmethod
def get_cfg_opts(self):
"""
Get the configuration options.
"""
@classmethod
def get_server_object(cls, backend, server_id):
"""
Get the server object from the backend driver for the server_id.
"""
global_section_name, server_section_name = cls._register_opts(
backend, server_id)
global_section_name = 'backend:%s' % (backend,)
server_section_name = 'backend:%s:%s' % (backend, server_id)
backend_options = cls._create_backend_option_objects(
global_section_name, server_section_name)

View File

@ -29,24 +29,28 @@ from designate.backend import base
LOG = logging.getLogger(__name__)
cfg.CONF.register_group(cfg.OptGroup(
name='backend:bind9', title="Configuration for BIND9 Backend"
))
cfg.CONF.register_opts([
cfg.StrOpt('rndc-host', default='127.0.0.1', help='RNDC Host'),
cfg.IntOpt('rndc-port', default=953, help='RNDC Port'),
cfg.StrOpt('rndc-config-file', default=None,
help='RNDC Config File'),
cfg.StrOpt('rndc-key-file', default=None, help='RNDC Key File'),
cfg.StrOpt('nzf-path', default='/var/cache/bind',
help='Path where Bind9 stores the nzf files'),
], group='backend:bind9')
class Bind9Backend(base.Backend):
__plugin_name__ = 'bind9'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name='backend:bind9', title="Configuration for BIND9 Backend"
)
opts = [
cfg.StrOpt('rndc-host', default='127.0.0.1', help='RNDC Host'),
cfg.IntOpt('rndc-port', default=953, help='RNDC Port'),
cfg.StrOpt('rndc-config-file', default=None,
help='RNDC Config File'),
cfg.StrOpt('rndc-key-file', default=None, help='RNDC Key File'),
cfg.StrOpt('nzf-path', default='/var/cache/bind',
help='Path where Bind9 stores the nzf files'),
]
return [(group, opts)]
def start(self):
super(Bind9Backend, self).start()

View File

@ -24,23 +24,22 @@ from designate.backend import base
LOG = logging.getLogger(__name__)
cfg_opts = [
cfg.ListOpt('masters', default=['127.0.0.1:5354'],
help='Comma-separated list of master DNS servers, in '
' <ip-address>:<port> format. If <port> is omitted, '
'the default 5354 is used. These are mdns servers.'),
cfg.StrOpt('rndc-host', default='127.0.0.1', help='RNDC Host'),
cfg.IntOpt('rndc-port', default=953, help='RNDC Port'),
cfg.StrOpt('rndc-config-file', default=None, help='RNDC Config File'),
cfg.StrOpt('rndc-key-file', default=None, help='RNDC Key File'),
]
DEFAULT_PORT = 5354
class Bind9PoolBackend(base.PoolBackend):
__plugin_name__ = 'bind9_pool'
@classmethod
def _get_common_cfg_opts(cls):
return [
cfg.StrOpt('rndc-host', default='127.0.0.1', help='RNDC Host'),
cfg.IntOpt('rndc-port', default=953, help='RNDC Port'),
cfg.StrOpt('rndc-config-file', default=None,
help='RNDC Config File'),
cfg.StrOpt('rndc-key-file', default=None, help='RNDC Key File'),
]
def __init__(self, backend_options):
super(Bind9PoolBackend, self).__init__(backend_options)
self.masters = [self._parse_master(master)
@ -73,10 +72,6 @@ class Bind9PoolBackend(base.PoolBackend):
'Invalid IP address "%s" in masters option.' % ip_address)
return {'ip-address': ip_address, 'port': port}
@classmethod
def get_cfg_opts(cls):
return cfg_opts
def create_domain(self, context, domain):
LOG.debug('Create Domain')
masters = []

View File

@ -30,29 +30,7 @@ from designate.i18n import _LW
LOG = logging.getLogger(__name__)
GROUP = 'backend:dynect'
OPTS = [
cfg.StrOpt('customer_name', help="Customer name at DynECT."),
cfg.StrOpt('username', help="Username to auth with DynECT."),
cfg.StrOpt('password', help="Password to auth with DynECT.", secret=True),
cfg.ListOpt('masters',
help="Master servers from which to transfer from."),
cfg.StrOpt('contact_nickname',
help="Nickname that will receive notifications."),
cfg.StrOpt('tsig_key_name', help="TSIG key name."),
cfg.IntOpt('job_timeout', default=30,
help="Timeout in seconds for pulling a job in DynECT."),
cfg.IntOpt('timeout', help="Timeout in seconds for API Requests.",
default=10),
cfg.BoolOpt('timings', help="Measure requests timings.", default=False)
]
cfg.CONF.register_group(
cfg.OptGroup(name=GROUP, title='Backend options for DynECT'))
cfg.CONF.register_opts(OPTS, group=GROUP)
CFG_GROUP = 'backend:dynect'
class DynClientError(exceptions.Backend):
@ -247,7 +225,7 @@ class DynClient(object):
"""
status = response.status
timeout = Timeout(cfg.CONF[GROUP].job_timeout)
timeout = Timeout(cfg.CONF[CFG_GROUP].job_timeout)
try:
while status == 307:
time.sleep(1)
@ -324,13 +302,39 @@ class DynECTBackend(base.Backend):
"""
__plugin_name__ = 'dynect'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name=CFG_GROUP, title='Backend options for DynECT'
)
opts = [
cfg.StrOpt('customer_name', help="Customer name at DynECT."),
cfg.StrOpt('username', help="Username to auth with DynECT."),
cfg.StrOpt('password', help="Password to auth with DynECT.",
secret=True),
cfg.ListOpt('masters',
help="Master servers from which to transfer from."),
cfg.StrOpt('contact_nickname',
help="Nickname that will receive notifications."),
cfg.StrOpt('tsig_key_name', help="TSIG key name."),
cfg.IntOpt('job_timeout', default=30,
help="Timeout in seconds for pulling a job in DynECT."),
cfg.IntOpt('timeout', help="Timeout in seconds for API Requests.",
default=10),
cfg.BoolOpt('timings', help="Measure requests timings.",
default=False)
]
return [(group, opts)]
def get_client(self):
return DynClient(
customer_name=cfg.CONF[GROUP].customer_name,
user_name=cfg.CONF[GROUP].username,
password=cfg.CONF[GROUP].password,
timeout=cfg.CONF[GROUP].timeout,
timings=cfg.CONF[GROUP].timings)
customer_name=cfg.CONF[CFG_GROUP].customer_name,
user_name=cfg.CONF[CFG_GROUP].username,
password=cfg.CONF[CFG_GROUP].password,
timeout=cfg.CONF[CFG_GROUP].timeout,
timings=cfg.CONF[CFG_GROUP].timings)
def create_domain(self, context, domain):
LOG.info(_LI('Creating domain %(d_id)s / %(d_name)s') %
@ -338,14 +342,14 @@ class DynECTBackend(base.Backend):
url = '/Secondary/%s' % domain['name'].rstrip('.')
data = {
'masters': cfg.CONF[GROUP].masters
'masters': cfg.CONF[CFG_GROUP].masters
}
if cfg.CONF[GROUP].contact_nickname is not None:
data['contact_nickname'] = cfg.CONF[GROUP].contact_nickname
if cfg.CONF[CFG_GROUP].contact_nickname is not None:
data['contact_nickname'] = cfg.CONF[CFG_GROUP].contact_nickname
if cfg.CONF[GROUP].tsig_key_name is not None:
data['tsig_key_name'] = cfg.CONF[GROUP].tsig_key_name
if cfg.CONF[CFG_GROUP].tsig_key_name is not None:
data['tsig_key_name'] = cfg.CONF[CFG_GROUP].tsig_key_name
client = self.get_client()

View File

@ -29,44 +29,8 @@ from designate.i18n import _LE
LOG = logging.getLogger(__name__)
cfg.CONF.register_group(cfg.OptGroup(
name='backend:ipa', title="Configuration for IPA Backend"
))
IPA_DEFAULT_PORT = 443
OPTS = [
cfg.StrOpt('ipa-host', default='localhost.localdomain',
help='IPA RPC listener host - must be FQDN'),
cfg.IntOpt('ipa-port', default=IPA_DEFAULT_PORT,
help='IPA RPC listener port'),
cfg.StrOpt('ipa-client-keytab', default=None,
help='Kerberos client keytab file'),
cfg.StrOpt('ipa-auth-driver-class',
default='designate.backend.impl_ipa.auth.IPAAuth',
help='Class that implements the authentication '
'driver for IPA'),
cfg.StrOpt('ipa-ca-cert', default=None,
help='CA certificate for use with https to IPA'),
cfg.StrOpt('ipa-base-url', default='/ipa',
help='Base URL for IPA RPC, relative to host[:port]'),
cfg.StrOpt('ipa-json-url',
default='/json',
help='URL for IPA JSON RPC, relative to IPA base URL'),
cfg.IntOpt('ipa-connect-retries', default=1,
help='How many times Designate will attempt to retry '
'the connection to IPA before giving up'),
cfg.BoolOpt('ipa-force-ns-use', default=False,
help='IPA requires that a specified '
'name server or SOA MNAME is resolvable - if this '
'option is set, Designate will force IPA to use a '
'given name server even if it is not resolvable'),
cfg.StrOpt('ipa-version', default='2.65',
help='IPA RPC JSON version')
]
cfg.CONF.register_opts(OPTS, group='backend:ipa')
class IPABaseError(exceptions.Backend):
error_code = 500
@ -182,6 +146,44 @@ def abs2rel_name(domain, rsetname):
class IPABackend(base.Backend):
__plugin_name__ = 'ipa'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name='backend:ipa', title="Configuration for IPA Backend"
)
opts = [
cfg.StrOpt('ipa-host', default='localhost.localdomain',
help='IPA RPC listener host - must be FQDN'),
cfg.IntOpt('ipa-port', default=IPA_DEFAULT_PORT,
help='IPA RPC listener port'),
cfg.StrOpt('ipa-client-keytab', default=None,
help='Kerberos client keytab file'),
cfg.StrOpt('ipa-auth-driver-class',
default='designate.backend.impl_ipa.auth.IPAAuth',
help='Class that implements the authentication '
'driver for IPA'),
cfg.StrOpt('ipa-ca-cert', default=None,
help='CA certificate for use with https to IPA'),
cfg.StrOpt('ipa-base-url', default='/ipa',
help='Base URL for IPA RPC, relative to host[:port]'),
cfg.StrOpt('ipa-json-url',
default='/json',
help='URL for IPA JSON RPC, relative to IPA base URL'),
cfg.IntOpt('ipa-connect-retries', default=1,
help='How many times Designate will attempt to retry '
'the connection to IPA before giving up'),
cfg.BoolOpt('ipa-force-ns-use', default=False,
help='IPA requires that a specified '
'name server or SOA MNAME is resolvable - if this '
'option is set, Designate will force IPA to use a '
'given name server even if it is not resolvable'),
cfg.StrOpt('ipa-version', default='2.65',
help='IPA RPC JSON version')
]
return [(group, opts)]
def start(self):
LOG.debug('IPABackend start')
self.request = requests.Session()

View File

@ -24,17 +24,7 @@ from designate.backend import base
LOG = logging.getLogger(__name__)
CFG_GRP = 'backend:multi'
cfg.CONF.register_group(cfg.OptGroup(
name=CFG_GRP, title="Configuration for multi-backend Backend"
))
cfg.CONF.register_opts([
cfg.StrOpt('master', default='fake', help='Master backend'),
cfg.StrOpt('slave', default='fake', help='Slave backend'),
], group=CFG_GRP)
CFG_GROUP = 'backend:multi'
class MultiBackend(base.Backend):
@ -59,12 +49,25 @@ class MultiBackend(base.Backend):
"""
__plugin_name__ = 'multi'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name=CFG_GROUP, title="Configuration for multi-backend Backend"
)
opts = [
cfg.StrOpt('master', default='fake', help='Master backend'),
cfg.StrOpt('slave', default='fake', help='Slave backend'),
]
return [(group, opts)]
def __init__(self, central_service):
super(MultiBackend, self).__init__(central_service)
self.central = central_service
self.master = backend.get_backend(cfg.CONF[CFG_GRP].master,
self.master = backend.get_backend(cfg.CONF[CFG_GROUP].master,
central_service)
self.slave = backend.get_backend(cfg.CONF[CFG_GRP].slave,
self.slave = backend.get_backend(cfg.CONF[CFG_GROUP].slave,
central_service)
def start(self):

View File

@ -28,29 +28,7 @@ from designate.openstack.common import log as logging
LOG = logging.getLogger(__name__)
CFG_GRP = 'backend:nsd4slave'
cfg.CONF.register_group(
cfg.OptGroup(name=CFG_GRP, title='Configuration for NSD4-slave backend')
)
cfg.CONF.register_opts([
cfg.StrOpt('keyfile', default='/etc/nsd/nsd_control.key',
help='Keyfile to use when connecting to the NSD4 servers over '
'SSL'),
cfg.StrOpt('certfile', default='/etc/nsd/nsd_control.pem',
help='Certfile to use when connecting to the NSD4 servers over '
'SSL'),
cfg.ListOpt('servers',
help='Comma-separated list of servers to control, in '
' <host>:<port> format. If <port> is omitted, '
' the default 8952 is used.'),
cfg.StrOpt('pattern', default='slave',
help='Pattern to use when creating zones on the NSD4 servers. '
'This pattern must be identically configured on all NSD4 '
'servers.'),
], group=CFG_GRP)
CFG_GROUP = 'backend:nsd4slave'
DEFAULT_PORT = 8952
@ -58,9 +36,34 @@ class NSD4SlaveBackend(base.Backend):
__plugin__name__ = 'nsd4slave'
NSDCT_VERSION = 'NSDCT1'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name=CFG_GROUP, title="Configuration for NSD4-slave backend"
)
opts = [
cfg.StrOpt('keyfile', default='/etc/nsd/nsd_control.key',
help='Keyfile to use when connecting to the NSD4 '
'servers over SSL'),
cfg.StrOpt('certfile', default='/etc/nsd/nsd_control.pem',
help='Certfile to use when connecting to the NSD4 '
'servers over SSL'),
cfg.ListOpt('servers',
help='Comma-separated list of servers to control, in '
' <host>:<port> format. If <port> is omitted, '
' the default 8952 is used.'),
cfg.StrOpt('pattern', default='slave',
help='Pattern to use when creating zones on the NSD4 '
'servers. This pattern must be identically '
'configured on all NSD4 servers.'),
]
return [(group, opts)]
def __init__(self, central_service):
self._keyfile = cfg.CONF[CFG_GRP].keyfile
self._certfile = cfg.CONF[CFG_GRP].certfile
self._keyfile = cfg.CONF[CFG_GROUP].keyfile
self._certfile = cfg.CONF[CFG_GROUP].certfile
# Make sure keyfile and certfile are readable to avoid cryptic SSL
# errors later
if not os.access(self._keyfile, os.R_OK):
@ -69,10 +72,10 @@ class NSD4SlaveBackend(base.Backend):
if not os.access(self._certfile, os.R_OK):
raise exceptions.NSD4SlaveBackendError(
'Certfile %s missing or permission denied' % self._certfile)
self._pattern = cfg.CONF[CFG_GRP].pattern
self._pattern = cfg.CONF[CFG_GROUP].pattern
try:
self._servers = [self._parse_server(cfg_server)
for cfg_server in cfg.CONF[CFG_GRP].servers]
for cfg_server in cfg.CONF[CFG_GROUP].servers]
except TypeError:
raise exceptions.ConfigurationError('No NSD4 servers defined')

View File

@ -37,21 +37,6 @@ LOG = logging.getLogger(__name__)
CONF = cfg.CONF
TSIG_SUPPORTED_ALGORITHMS = ['hmac-md5']
CONF.register_group(cfg.OptGroup(
name='backend:powerdns', title="Configuration for Powerdns Backend"
))
CONF.register_opts([
cfg.StrOpt('domain-type', default='NATIVE', help='PowerDNS Domain Type'),
cfg.ListOpt('also-notify', default=[], help='List of additional IPs to '
'send NOTIFYs to'),
] + options.database_opts, group='backend:powerdns')
# Overide the default DB connection registered above, to avoid name conflicts
# between the Designate and PowerDNS databases.
CONF.set_default('connection', 'sqlite:///$state_path/powerdns.sqlite',
group='backend:powerdns')
def _map_col(keys, col):
return dict([(keys[i], col[i]) for i in range(len(keys))])
@ -60,6 +45,27 @@ def _map_col(keys, col):
class PowerDNSBackend(base.Backend):
__plugin_name__ = 'powerdns'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name='backend:powerdns', title="Configuration for PowerDNS Backend"
)
opts = [
cfg.StrOpt('domain-type', default='NATIVE',
help='PowerDNS Domain Type'),
cfg.ListOpt('also-notify', default=[],
help='List of additional IPs to send NOTIFYs to'),
] + options.database_opts
# TODO(kiall):
# Overide the default DB connection registered above, to avoid name
# conflicts between the Designate and PowerDNS databases.
# CONF.set_default('connection',
# 'sqlite:///$state_path/powerdns.sqlite',
# group='backend:powerdns')
return [(group, opts)]
def __init__(self, *args, **kwargs):
super(PowerDNSBackend, self).__init__(*args, **kwargs)

View File

@ -30,22 +30,6 @@ from designate.sqlalchemy import session
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
OPTS = [
cfg.ListOpt('masters', help="Master servers from which to transfer from."),
]
CONF.register_group(cfg.OptGroup(
name='backend:powerdns_mdns',
title="Configuration for PowerDNS MDNS Backend"
))
CONF.register_opts(OPTS + options.database_opts, group='backend:powerdns_mdns')
# Overide the default DB connection registered above, to avoid name conflicts
# between the Designate and PowerDNS databases.
CONF.set_default('connection', 'sqlite:///$state_path/powerdns_mdns.sqlite',
group='backend:powerdns_mdns')
def _map_col(keys, col):
return dict([(keys[i], col[i]) for i in range(len(keys))])
@ -54,6 +38,26 @@ def _map_col(keys, col):
class PowerDNSMDNSBackend(base.Backend):
__plugin_name__ = 'powerdns_mdns'
@classmethod
def get_cfg_opts(cls):
group = cfg.OptGroup(
name='backend:powerdns_mdns',
title="Configuration for PowerDNS MDNS Backend"
)
opts = [
cfg.ListOpt('masters',
help="Master servers from which to transfer from."),
] + options.database_opts
# TODO(kiall):
# Overide the default DB connection registered above, to avoid name
# conflicts between the Designate and PowerDNS databases.
# CONF.set_default('connection',
# 'sqlite:///$state_path/powerdns.sqlite',
# group='backend:powerdns')
return [(group, opts)]
def __init__(self, *args, **kwargs):
super(PowerDNSMDNSBackend, self).__init__(*args, **kwargs)

View File

@ -21,17 +21,15 @@ from oslo.db.sqlalchemy.migration_cli import manager as migration_manager
from designate.openstack.common import log as logging
from designate.manage import base
from designate import utils
LOG = logging.getLogger(__name__)
REPOSITORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..',
'backend', 'impl_powerdns',
'migrate_repo'))
cfg.CONF.import_opt('connection', 'designate.backend.impl_powerdns',
group='backend:powerdns')
CONF = cfg.CONF
utils.register_plugin_opts()
def get_manager():

View File

@ -18,11 +18,14 @@ import abc
import six
from stevedore import driver
from stevedore import enabled
from stevedore import extension
from oslo.config import cfg
from designate.openstack.common import log as logging
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@six.add_metaclass(abc.ABCMeta)
@ -53,6 +56,50 @@ class Plugin(object):
def get_plugin_type(cls):
return cls.__plugin_type__
@classmethod
def get_cfg_opts(cls):
"""Get any static configuration options
Returns an array of tuples in the form:
[(group1, [Option1, Option2]), (group2, [Option1, Option2])]
"""
return []
@classmethod
def get_extra_cfg_opts(cls):
"""Get any dynamically built configuration options
Returns an array of tuples in the form:
[(group1, [Option1, Option2]), (group2, [Option1, Option2])]
"""
return []
@classmethod
def register_cfg_opts(cls, namespace):
mgr = extension.ExtensionManager(namespace)
for e in mgr:
for group, opts in e.plugin.get_cfg_opts():
if isinstance(group, six.string_types):
group = cfg.OptGroup(name=group)
CONF.register_group(group)
CONF.register_opts(opts, group=group)
@classmethod
def register_extra_cfg_opts(cls, namespace):
mgr = extension.ExtensionManager(namespace)
for e in mgr:
for group, opts in e.plugin.get_extra_cfg_opts():
if isinstance(group, six.string_types):
group = cfg.OptGroup(name=group)
CONF.register_group(group)
CONF.register_opts(opts, group=group)
class DriverPlugin(Plugin):
"""

View File

@ -20,6 +20,8 @@ cfg.CONF.register_group(cfg.OptGroup(
))
OPTS = [
cfg.ListOpt('backends', default=[],
help='List of enabled backend drivers'),
cfg.IntOpt('workers', default=None,
help='Number of Pool Manager worker processes to spawn'),
cfg.StrOpt('pool-id', default='794ccc2c-d751-44fe-b57f-8894c9f5c842',

View File

@ -1,136 +0,0 @@
# Copyright 2014 eBay Inc.
#
# Author: Ron Rickard <rrickard@ebaysf.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.
import re
from oslo.config import iniparser
from designate import utils
GLOBAL_SECTION_NAME_LABEL = '*'
SECTION_NAME_PREFIX = 'backend'
SECTION_NAME_SEPARATOR = ':'
UUID_PATTERN = '-'.join([
'[0-9A-Fa-f]{8}',
'[0-9A-Fa-f]{4}',
'[0-9A-Fa-f]{4}',
'[0-9A-Fa-f]{4}',
'[0-9A-Fa-f]{12}'
])
SECTION_PATTERN = SECTION_NAME_SEPARATOR.join([
'^%s' % SECTION_NAME_PREFIX,
'(.*)',
'(%s)' % UUID_PATTERN
])
SECTION_LABELS = [
'backend',
'server_id'
]
class SectionNameParser(iniparser.BaseParser):
"""
Used to retrieve the configuration file section names and parse the names.
"""
def __init__(self, pattern, labels):
super(SectionNameParser, self).__init__()
self.regex = re.compile(pattern)
self.labels = labels
self.sections = []
def assignment(self, key, value):
pass
def new_section(self, section):
match = self.regex.match(section)
if match:
value = {
'name': section
}
index = 1
for label in self.labels:
value[label] = match.group(index)
index += 1
self.sections.append(value)
def parse(self, filename):
with open(filename) as f:
return super(SectionNameParser, self).parse(f)
@classmethod
def find_sections(cls, filename, pattern, labels):
parser = cls(pattern, labels)
parser.parse(filename)
return parser.sections
def find_server_sections():
"""
Find the server specific backend section names.
A server specific backend section name is:
[backend:<backend_driver>:<server_id>]
"""
config_files = utils.find_config('designate.conf')
all_sections = []
for filename in config_files:
sections = SectionNameParser.find_sections(
filename, SECTION_PATTERN, SECTION_LABELS)
all_sections.extend(sections)
return all_sections
def _generate_section_name(backend_driver, label):
"""
Generate the section name.
A section name is:
[backend:<backend_driver>:<label>]
"""
return SECTION_NAME_SEPARATOR.join([
SECTION_NAME_PREFIX,
backend_driver,
label
])
def generate_global_section_name(backend_driver):
"""
Generate the global backend section name.
A global backend section name is:
[backend:<backend_driver>:*]
"""
return _generate_section_name(backend_driver, GLOBAL_SECTION_NAME_LABEL)
def generate_server_section_name(backend_driver, server_id):
"""
Generate the server specific backend section name.
A server specific backend section name is:
[backend:<backend_driver>:<server_id>]
"""
return _generate_section_name(backend_driver, server_id)

View File

@ -28,7 +28,6 @@ from designate.context import DesignateContext
from designate.openstack.common import log as logging
from designate.openstack.common import threadgroup
from designate.pool_manager import cache
import designate.pool_manager.backend_section_name as backend_section_name
LOG = logging.getLogger(__name__)
@ -93,7 +92,15 @@ class Service(service.RPCService):
self.delay = cfg.CONF['service:pool_manager'].poll_delay
self.server_backends = []
sections = backend_section_name.find_server_sections()
sections = []
for backend_name in cfg.CONF['service:pool_manager'].backends:
server_ids = cfg.CONF['backend:%s' % backend_name].server_ids
for server_id in server_ids:
sections.append({"backend": backend_name,
"server_id": server_id})
for section in sections:
backend_driver = section['backend']
server_id = section['server_id']

View File

@ -339,6 +339,7 @@ class TestCase(base.BaseTestCase):
# "Read" Configuration
self.CONF([], project='designate')
utils.register_plugin_opts()
self.useFixture(PolicyFixture())
self.network_api = NetworkAPIFixture()

View File

@ -91,6 +91,17 @@ def read_config(prog, argv):
cfg.CONF(argv[1:], project='designate', prog=prog,
default_config_files=config_files)
register_plugin_opts()
def register_plugin_opts():
# Avoid circular dependency imports
from designate import plugin
# Register Backend Plugin Config Options
plugin.Plugin.register_cfg_opts('designate.backend')
plugin.Plugin.register_extra_cfg_opts('designate.backend')
def resource_string(*args):
if len(args) == 0:

View File

@ -132,6 +132,7 @@ debug = False
# Pool Manager Service
#-----------------------
[service:pool_manager]
#backends = bind9_pool
#workers = None
#pool_name = default
#threshold-percentage = 100
@ -267,7 +268,8 @@ debug = False
#-----------------------
# Global Bind9 Pool Backend
#-----------------------
[backend:bind9_pool:*]
[backend:bind9_pool]
#server_ids = 6a5032b6-2d96-43ee-b25b-7d784e2bf3b2
#masters = 127.0.0.1:5354
#rndc_host = 127.0.0.1
#rndc_port = 953