diff --git a/contrib/devstack/lib/designate_plugins/backend-bind9_pool b/contrib/devstack/lib/designate_plugins/backend-bind9_pool index 91c8f620f..2e989fd50 100644 --- a/contrib/devstack/lib/designate_plugins/backend-bind9_pool +++ b/contrib/devstack/lib/designate_plugins/backend-bind9_pool @@ -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 diff --git a/designate/backend/base.py b/designate/backend/base.py index cff9ca11c..1f5270727 100644 --- a/designate/backend/base.py +++ b/designate/backend/base.py @@ -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 ' + ': format. If 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) diff --git a/designate/backend/impl_bind9.py b/designate/backend/impl_bind9.py index 286f90a4e..8b1ce4a27 100644 --- a/designate/backend/impl_bind9.py +++ b/designate/backend/impl_bind9.py @@ -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() diff --git a/designate/backend/impl_bind9_pool.py b/designate/backend/impl_bind9_pool.py index 209dee194..9da127c51 100644 --- a/designate/backend/impl_bind9_pool.py +++ b/designate/backend/impl_bind9_pool.py @@ -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 ' - ' : format. If 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 = [] diff --git a/designate/backend/impl_dynect.py b/designate/backend/impl_dynect.py index c97e91f80..6c97f7768 100644 --- a/designate/backend/impl_dynect.py +++ b/designate/backend/impl_dynect.py @@ -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() diff --git a/designate/backend/impl_ipa/__init__.py b/designate/backend/impl_ipa/__init__.py index 87b3ff598..52b575095 100644 --- a/designate/backend/impl_ipa/__init__.py +++ b/designate/backend/impl_ipa/__init__.py @@ -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() diff --git a/designate/backend/impl_multi.py b/designate/backend/impl_multi.py index 7eba6045a..4f9d9580e 100644 --- a/designate/backend/impl_multi.py +++ b/designate/backend/impl_multi.py @@ -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): diff --git a/designate/backend/impl_nsd4slave.py b/designate/backend/impl_nsd4slave.py index 30576187e..04ee8048f 100644 --- a/designate/backend/impl_nsd4slave.py +++ b/designate/backend/impl_nsd4slave.py @@ -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 ' - ' : format. If 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 ' + ' : format. If 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') diff --git a/designate/backend/impl_powerdns/__init__.py b/designate/backend/impl_powerdns/__init__.py index 818aba412..2bf84c3e8 100644 --- a/designate/backend/impl_powerdns/__init__.py +++ b/designate/backend/impl_powerdns/__init__.py @@ -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) diff --git a/designate/backend/impl_powerdns_mdns/__init__.py b/designate/backend/impl_powerdns_mdns/__init__.py index f60471291..9aabc097d 100644 --- a/designate/backend/impl_powerdns_mdns/__init__.py +++ b/designate/backend/impl_powerdns_mdns/__init__.py @@ -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) diff --git a/designate/manage/powerdns.py b/designate/manage/powerdns.py index 7cb63d611..416b7dffa 100644 --- a/designate/manage/powerdns.py +++ b/designate/manage/powerdns.py @@ -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(): diff --git a/designate/plugin.py b/designate/plugin.py index e239e24b2..f7f157aa7 100644 --- a/designate/plugin.py +++ b/designate/plugin.py @@ -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): """ diff --git a/designate/pool_manager/__init__.py b/designate/pool_manager/__init__.py index c2f6193c4..58ecb53db 100644 --- a/designate/pool_manager/__init__.py +++ b/designate/pool_manager/__init__.py @@ -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', diff --git a/designate/pool_manager/backend_section_name.py b/designate/pool_manager/backend_section_name.py deleted file mode 100644 index 09d106f5e..000000000 --- a/designate/pool_manager/backend_section_name.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2014 eBay Inc. -# -# Author: Ron Rickard -# -# 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::] - """ - 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::