Add a new PowerDNS backend based on MiniDNS
This is stage one of phasing out the old PowerDNS driver, as we move through the Kilo cycle and mDNS/pools become reality, the original driver can be removed. Implements-Blueprint: transition-powerdns-to-mdns Change-Id: I7a3aa0a894e2c0a4fa565e8d58cccba3644e0cac
This commit is contained in:
115
contrib/devstack/lib/designate_plugins/backend-powerdns_mdns
Normal file
115
contrib/devstack/lib/designate_plugins/backend-powerdns_mdns
Normal file
@@ -0,0 +1,115 @@
|
||||
# lib/designate_plugins/backend-powerdns_mdns
|
||||
# Configure the powerdns_mdns backend
|
||||
|
||||
# Enable with:
|
||||
# DESIGNATE_BACKEND_DRIVER=powerdns_mdns
|
||||
|
||||
# Dependencies:
|
||||
# ``functions`` file
|
||||
# ``designate`` configuration
|
||||
|
||||
# install_designate_backend - install any external requirements
|
||||
# configure_designate_backend - make configuration changes, including those to other services
|
||||
# init_designate_backend - initialize databases, etc.
|
||||
# start_designate_backend - start any external services
|
||||
# stop_designate_backend - stop any external services
|
||||
# cleanup_designate_backend - remove transient data and cache
|
||||
|
||||
# Save trace setting
|
||||
DP_PDNS_MDNS_XTRACE=$(set +o | grep xtrace)
|
||||
set +o xtrace
|
||||
|
||||
# Defaults
|
||||
# --------
|
||||
if is_fedora; then
|
||||
POWERDNS_CFG_DIR=/etc/pdns
|
||||
else
|
||||
POWERDNS_CFG_DIR=/etc/powerdns
|
||||
fi
|
||||
|
||||
# Entry Points
|
||||
# ------------
|
||||
|
||||
# install_designate_backend - install any external requirements
|
||||
function install_designate_backend {
|
||||
if is_ubuntu; then
|
||||
PDNS=pdns-server
|
||||
elif is_fedora || is_suse; then
|
||||
PDNS=pdns
|
||||
else
|
||||
PDNS=pdns-server
|
||||
fi
|
||||
|
||||
install_package $PDNS pdns-backend-mysql
|
||||
sudo rm -rf $POWERDNS_CFG_DIR/pdns.d
|
||||
}
|
||||
|
||||
# configure_designate_backend - make configuration changes, including those to other services
|
||||
function configure_designate_backend {
|
||||
iniset $DESIGNATE_CONF backend:powerdns_mdns connection `database_connection_url designate_pdns_mdns`
|
||||
iniset $DESIGNATE_CONF backend:powerdns_mdns masters "$DESIGNATE_SERVICE_HOST:$DESIGNATE_MDNS_PORT"
|
||||
iniset $DESIGNATE_CONF service:mdns slave_nameserver_ips_and_ports "$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_DNS"
|
||||
|
||||
sudo tee $POWERDNS_CFG_DIR/pdns.conf > /dev/null <<EOF
|
||||
# General Config
|
||||
setgid=pdns
|
||||
setuid=pdns
|
||||
config-dir=$POWERDNS_CFG_DIR
|
||||
socket-dir=/var/run
|
||||
guardian=yes
|
||||
daemon=yes
|
||||
disable-axfr=no
|
||||
local-address=$DESIGNATE_SERVICE_HOST
|
||||
local-port=$DESIGNATE_SERVICE_PORT_DNS
|
||||
master=no
|
||||
slave=yes
|
||||
cache-ttl=0
|
||||
query-cache-ttl=0
|
||||
negquery-cache-ttl=0
|
||||
EOF
|
||||
|
||||
if is_service_enabled mysql; then
|
||||
sudo tee -a $POWERDNS_CFG_DIR/pdns.conf > /dev/null <<EOF
|
||||
# Launch gmysql backend
|
||||
launch=gmysql
|
||||
|
||||
# gmysql parameters
|
||||
gmysql-host=$DATABASE_HOST
|
||||
gmysql-user=$DATABASE_USER
|
||||
gmysql-password=$DATABASE_PASSWORD
|
||||
gmysql-dbname=designate_pdns_mdns
|
||||
gmysql-dnssec=yes
|
||||
EOF
|
||||
else
|
||||
die $LINENO "PowerDNS mDNS backend only supports MySQL"
|
||||
fi
|
||||
|
||||
restart_service pdns
|
||||
}
|
||||
|
||||
# init_designate_backend - initialize databases, etc.
|
||||
function init_designate_backend {
|
||||
# (Re)create designate_pdns database
|
||||
recreate_database designate_pdns_mdns utf8
|
||||
|
||||
# Init and migrate designate_pdns database
|
||||
designate-manage powerdns-mdns sync
|
||||
}
|
||||
|
||||
# start_designate_backend - start any external services
|
||||
function start_designate_backend {
|
||||
start_service pdns
|
||||
}
|
||||
|
||||
# stop_designate_backend - stop any external services
|
||||
function stop_designate_backend {
|
||||
stop_service pdns
|
||||
}
|
||||
|
||||
# cleanup_designate_backend - remove transient data and cache
|
||||
function cleanup_designate_backend {
|
||||
:
|
||||
}
|
||||
|
||||
# Restore xtrace
|
||||
$DP_PDNS_MDNS_XTRACE
|
||||
198
designate/backend/impl_powerdns_mdns/__init__.py
Normal file
198
designate/backend/impl_powerdns_mdns/__init__.py
Normal file
@@ -0,0 +1,198 @@
|
||||
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Author: Kiall Mac Innes <kiall@hp.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 threading
|
||||
|
||||
from oslo.config import cfg
|
||||
from oslo.db import options
|
||||
from oslo.utils import excutils
|
||||
from sqlalchemy.sql import select
|
||||
|
||||
from designate.openstack.common import log as logging
|
||||
from designate import exceptions
|
||||
from designate.i18n import _LC
|
||||
from designate.backend import base
|
||||
from designate.backend.impl_powerdns_mdns import tables
|
||||
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))])
|
||||
|
||||
|
||||
class PowerDNSMDNSBackend(base.Backend):
|
||||
__plugin_name__ = 'powerdns_mdns'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PowerDNSMDNSBackend, self).__init__(*args, **kwargs)
|
||||
|
||||
self.local_store = threading.local()
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
# NOTE: This uses a thread local store, allowing each greenthread to
|
||||
# have it's own session stored correctly. Without this, each
|
||||
# greenthread may end up using a single global session, which
|
||||
# leads to bad things happening.
|
||||
global LOCAL_STORE
|
||||
|
||||
if not hasattr(self.local_store, 'session'):
|
||||
self.local_store.session = session.get_session(self.name)
|
||||
|
||||
return self.local_store.session
|
||||
|
||||
def _create(self, table, values):
|
||||
query = table.insert()
|
||||
|
||||
resultproxy = self.session.execute(query, values)
|
||||
|
||||
# Refetch the row, for generated columns etc
|
||||
query = select([table])\
|
||||
.where(table.c.id == resultproxy.inserted_primary_key[0])
|
||||
resultproxy = self.session.execute(query)
|
||||
|
||||
return _map_col(query.columns.keys(), resultproxy.fetchone())
|
||||
|
||||
def _get(self, table, id_, exc_notfound, id_col=None):
|
||||
if id_col is None:
|
||||
id_col = table.c.id
|
||||
|
||||
query = select([table])\
|
||||
.where(id_col == id_)
|
||||
|
||||
resultproxy = self.session.execute(query)
|
||||
|
||||
results = resultproxy.fetchall()
|
||||
|
||||
if len(results) != 1:
|
||||
raise exc_notfound()
|
||||
|
||||
# Map col keys to values in result
|
||||
return _map_col(query.columns.keys(), results[0])
|
||||
|
||||
def _delete(self, table, id_, exc_notfound, id_col=None):
|
||||
if id_col is None:
|
||||
id_col = table.c.id
|
||||
|
||||
query = table.delete()\
|
||||
.where(id_col == id_)
|
||||
|
||||
resultproxy = self.session.execute(query)
|
||||
|
||||
if resultproxy.rowcount != 1:
|
||||
raise exc_notfound()
|
||||
|
||||
def create_tsigkey(self, context, tsigkey):
|
||||
pass
|
||||
|
||||
def update_tsigkey(self, context, tsigkey):
|
||||
pass
|
||||
|
||||
def delete_tsigkey(self, context, tsigkey):
|
||||
pass
|
||||
|
||||
def create_server(self, context, server):
|
||||
pass
|
||||
|
||||
def update_server(self, context, server):
|
||||
pass
|
||||
|
||||
def delete_server(self, context, server):
|
||||
pass
|
||||
|
||||
# Domain Methods
|
||||
def create_domain(self, context, domain):
|
||||
try:
|
||||
self.session.begin()
|
||||
|
||||
domain_values = {
|
||||
'designate_id': domain['id'],
|
||||
'name': domain['name'].rstrip('.'),
|
||||
'master': ','.join(CONF['backend:powerdns_mdns'].masters),
|
||||
'type': 'SLAVE',
|
||||
'account': context.tenant
|
||||
}
|
||||
|
||||
self._create(tables.domains, domain_values)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.session.rollback()
|
||||
else:
|
||||
self.session.commit()
|
||||
|
||||
def update_domain(self, context, domain):
|
||||
pass
|
||||
|
||||
def delete_domain(self, context, domain):
|
||||
try:
|
||||
self._get(tables.domains, domain['id'], exceptions.DomainNotFound,
|
||||
id_col=tables.domains.c.designate_id)
|
||||
except exceptions.DomainNotFound:
|
||||
# If the Domain is already gone, that's ok. We're deleting it
|
||||
# anyway, so just log and continue.
|
||||
LOG.critical(_LC('Attempted to delete a domain which is '
|
||||
'not present in the backend. ID: %s') %
|
||||
domain['id'])
|
||||
return
|
||||
|
||||
self._delete(tables.domains, domain['id'],
|
||||
exceptions.DomainNotFound,
|
||||
id_col=tables.domains.c.designate_id)
|
||||
|
||||
def create_recordset(self, context, domain, recordset):
|
||||
pass
|
||||
|
||||
def update_recordset(self, context, domain, recordset):
|
||||
pass
|
||||
|
||||
def delete_recordset(self, context, domain, recordset):
|
||||
pass
|
||||
|
||||
def create_record(self, context, domain, recordset, record):
|
||||
pass
|
||||
|
||||
def update_record(self, context, domain, recordset, record):
|
||||
pass
|
||||
|
||||
def delete_record(self, context, domain, recordset, record):
|
||||
pass
|
||||
|
||||
def sync_domain(self, context, domain, records):
|
||||
pass
|
||||
|
||||
def sync_record(self, context, domain, record):
|
||||
pass
|
||||
|
||||
def ping(self, context):
|
||||
pass
|
||||
23
designate/backend/impl_powerdns_mdns/tables.py
Normal file
23
designate/backend/impl_powerdns_mdns/tables.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Author: Kiall Mac Innes <kiall@hp.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.
|
||||
from designate.backend.impl_powerdns import tables
|
||||
|
||||
|
||||
# NOTE(kiall): We import the domains table object here in order to ensure
|
||||
# the PowerDNS mDNS based driver uses only this one table. When
|
||||
# the original PowerDNS driver is removed, we'll move the domains
|
||||
# table definition here.
|
||||
domains = tables.domains
|
||||
59
designate/manage/powerdns_mdns.py
Normal file
59
designate/manage/powerdns_mdns.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Author: Kiall Mac Innes <kiall@hp.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 os
|
||||
|
||||
from migrate.versioning import api as versioning_api
|
||||
from oslo.config import cfg
|
||||
from oslo.db.sqlalchemy.migration_cli import manager as migration_manager
|
||||
|
||||
from designate.openstack.common import log as logging
|
||||
from designate.manage import base
|
||||
|
||||
|
||||
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_mdns',
|
||||
group='backend:powerdns_mdns')
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def get_manager():
|
||||
migration_config = {
|
||||
'migration_repo_path': REPOSITORY,
|
||||
'db_url': CONF['backend:powerdns_mdns'].connection}
|
||||
return migration_manager.MigrationManager(migration_config)
|
||||
|
||||
|
||||
class DatabaseCommands(base.Commands):
|
||||
def version(self):
|
||||
current = get_manager().version()
|
||||
latest = versioning_api.version(repository=REPOSITORY).value
|
||||
print("Current: %s Latest: %s" % (current, latest))
|
||||
|
||||
def sync(self):
|
||||
get_manager().upgrade(None)
|
||||
|
||||
@base.args('revision', nargs='?')
|
||||
def upgrade(self, revision):
|
||||
get_manager().upgrade(revision)
|
||||
|
||||
@base.args('revision', nargs='?')
|
||||
def downgrade(self, revision):
|
||||
get_manager().downgrade(revision)
|
||||
@@ -66,6 +66,7 @@ designate.notification.handler =
|
||||
designate.backend =
|
||||
bind9 = designate.backend.impl_bind9:Bind9Backend
|
||||
powerdns = designate.backend.impl_powerdns:PowerDNSBackend
|
||||
powerdns_mdns = designate.backend.impl_powerdns_mdns:PowerDNSMDNSBackend
|
||||
rpc = designate.backend.impl_rpc:RPCBackend
|
||||
fake = designate.backend.impl_fake:FakeBackend
|
||||
nsd4slave = designate.backend.impl_nsd4slave:NSD4SlaveBackend
|
||||
@@ -84,6 +85,7 @@ designate.quota =
|
||||
designate.manage =
|
||||
database = designate.manage.database:DatabaseCommands
|
||||
powerdns = designate.manage.powerdns:DatabaseCommands
|
||||
powerdns-mdns = designate.manage.powerdns_mdns:DatabaseCommands
|
||||
tlds = designate.manage.tlds:TLDCommands
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user