Add backend for Designate using SECONDARY zones
This will allow the use of a Designate installation as a backend using the recently added SECONDARY zones feature. The patch includes bits for devstack and tests. Implement blueprint: d2d-driver Change-Id: I5fcaf36482cf692432f7871ef08b2ae7fefe749a
This commit is contained in:
parent
746fa57eae
commit
e90dbe1ae5
136
contrib/devstack/lib/designate_plugins/backend-designate
Normal file
136
contrib/devstack/lib/designate_plugins/backend-designate
Normal file
@ -0,0 +1,136 @@
|
||||
# lib/designate_plugins/backend-designate
|
||||
# Configure the designate backend
|
||||
|
||||
# Requirements:
|
||||
# Another Designate service is needed in order to install the SECONDARY zones in it.
|
||||
|
||||
# Enable with:
|
||||
# DESIGNATE_BACKEND_DRIVER=designate
|
||||
|
||||
# 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_D2D_XTRACE=$(set +o | grep xtrace)
|
||||
set +o xtrace
|
||||
|
||||
# Defaults
|
||||
# --------
|
||||
|
||||
# This is the Primary Designate MDNS servers.
|
||||
DESIGNATE_D2D_MASTERS=${DESIGNATE_D2D_MASTERS:-""}
|
||||
|
||||
# DNS server to notify (MiniDNS ip:port)
|
||||
DESIGNATE_D2D_ALSO_NOTIES=${DESIGNATE_D2D_ALSO_NOTIES:-""}
|
||||
|
||||
# DNS server to check SOA etc against
|
||||
DESIGNATE_D2D_NAMESERVERS=${DESIGNATE_D2D_NAMESERVERS:-""}
|
||||
|
||||
# Destination openstack credentials
|
||||
DESIGNATE_D2D_KS_VERSION=${DESIGNATE_D2D_KS_VERSION:-3}
|
||||
|
||||
DESIGNATE_D2D_AUTH_URL=${DESIGNATE_D2D_AUTH_URL:-}
|
||||
DESIGNATE_D2D_USERNAME=${DESIGNATE_D2D_USERNAME:-}
|
||||
DESIGNATE_D2D_PASSWORD=${DESIGNATE_D2D_PASSWORD:-}
|
||||
|
||||
# Keystone V2
|
||||
DESIGNATE_D2D_TENANT_NAME=${DESIGNATE_D2D_TENANT_NAME:-}
|
||||
DESIGNATE_D2D_TENANT_NAME=${DESIGNATE_D2D_TENANT_ID:-}
|
||||
|
||||
# Keystone V3
|
||||
DESIGNATE_D2D_PROJECT_NAME=${DESIGNATE_D2D_PROJECT_NAME:-}
|
||||
DESIGNATE_D2D_PROJECT_DOMAIN_NAME=${DESIGNATE_D2D_PROJECT_DOMAIN_NAME:-}
|
||||
DESIGNATE_D2D_USER_DOMAIN_NAME=${DESIGNATE_D2D_USER_DOMAIN_NAME:-}
|
||||
|
||||
|
||||
# Entry Points
|
||||
# ------------
|
||||
|
||||
# install_designate_backend - install any external requirements
|
||||
function install_designate_backend {
|
||||
:
|
||||
}
|
||||
|
||||
# configure_designate_backend - make configuration changes, including those to other services
|
||||
function configure_designate_backend {
|
||||
iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID type designate
|
||||
iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID masters $DESIGNATE_D2D_MASTERS
|
||||
|
||||
options="auth_url: $DESIGNATE_D2D_AUTH_URL, username: $DESIGNATE_D2D_USERNAME, password: $DESIGNATE_D2D_PASSWORD,"
|
||||
if [ "$DESIGNATE_D2D_KS_VERSION" == "2" ]; then
|
||||
if [ ! -z "$DESIGNATE_D2D_TENANT_NAME" ]; then
|
||||
options="$options tenant_name=$DESIGNATE_D2D_TENANT_NAME,"
|
||||
fi
|
||||
|
||||
if [ ! -z "$DESIGNATE_D2D_TENANT_ID" ]; then
|
||||
options="$options tenant_id=$DESIGNATE_D2D_TENANT_ID,"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$DESIGNATE_D2D_KS_VERSION" == "3" ]; then
|
||||
options="$options project_name: $DESIGNATE_D2D_PROJECT_NAME, project_domain_name=$DESIGNATE_D2D_PROJECT_DOMAIN_NAME, user_domain_name=$DESIGNATE_D2D_USER_DOMAIN_NAME"
|
||||
fi
|
||||
|
||||
iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID options $options
|
||||
|
||||
# Create a Pool Nameserver for each of the Designate nameservers
|
||||
local nameserver_ids=""
|
||||
IFS=',' read -a nameservers <<< "$DESIGNATE_D2D_NAMESERVERS"
|
||||
|
||||
for nameserver in "${nameservers[@]}"; do
|
||||
local nameserver_id=`uuidgen`
|
||||
iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id host $(dig +short A $nameserver | head -n 1)
|
||||
iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id port 53
|
||||
|
||||
# Append the Nameserver ID to the list
|
||||
nameserver_ids+=${nameserver_id},
|
||||
done
|
||||
|
||||
# Configure the Pool for the set of nameserver IDs, minus the trailing comma
|
||||
iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID nameservers "${nameserver_ids:0:-1}"
|
||||
|
||||
# Configure the Pool to Notify the destination Mdns
|
||||
iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID also_notifies "$DESIGNATE_D2D_ALSO_NOTIFIES"
|
||||
}
|
||||
|
||||
# create_designate_ns_records - Create Pool NS Records
|
||||
function create_designate_ns_records_backend {
|
||||
# Build an array of the Designate nameservers.
|
||||
IFS=',' read -a ns_records <<< "$DESIGNATE_D2D_NAMESERVERS"
|
||||
|
||||
# Create a NS Record for each of the Designate nameservers
|
||||
for ns_record in "${ns_records[@]}"; do
|
||||
designate server-create --name "${ns_record%%.}."
|
||||
done
|
||||
}
|
||||
|
||||
# init_designate_backend - initialize databases, etc.
|
||||
function init_designate_backend {
|
||||
:
|
||||
}
|
||||
|
||||
# start_designate_backend - start any external services
|
||||
function start_designate_backend {
|
||||
:
|
||||
}
|
||||
|
||||
# stop_designate_backend - stop any external services
|
||||
function stop_designate_backend {
|
||||
:
|
||||
}
|
||||
|
||||
# cleanup_designate_backend - remove transient data and cache
|
||||
function cleanup_designate_backend {
|
||||
:
|
||||
}
|
||||
|
||||
# Restore xtrace
|
||||
$DP_D2D_XTRACE
|
@ -56,6 +56,33 @@ ENABLED_SERVICES+=,designate,designate-central,designate-api,designate-pool-mana
|
||||
#DESIGNATE_AKAMAI_NAMESERVERS=a5-64.akam.net,a11-65.akam.net,a13-66.akam.net,a14-64.akam.net,a20-65.akam.net,a22-66.akam.net
|
||||
#DESIGNATE_AKAMAI_MASTERS=
|
||||
|
||||
# Designate D2D Backend
|
||||
# NOTEs:
|
||||
# - DESIGNATE_D2D_ALSO_NOTIFIES needs to be set to the source mdns ip:port in
|
||||
# order for designate to receive the proper NOTIFY
|
||||
# - DESIGNATE_D2D_* credentials should be setup either to the source keystone
|
||||
# or the destination
|
||||
#DESIGNATE_D2D_MASTERS=
|
||||
#DESIGNATE_D2D_ALSO_NOTIFIES=
|
||||
#DESIGNATE_D2D_NAMESERVERS=
|
||||
|
||||
# Authentication options
|
||||
#DESIGNATE_D2D_KS_VERSION=3
|
||||
|
||||
#DESIGNATE_D2D_AUTH_URL=
|
||||
#DESIGNATE_D2D_USERNAME=
|
||||
#DESIGNATE_D2D_PASSWORD=
|
||||
|
||||
# Keystone V2
|
||||
#DESIGNATE_D2D_TENANT_NAME=${DESIGNATE_D2D_TENANT_NAME:-}
|
||||
#DESIGNATE_D2D_TENANT_NAME=${DESIGNATE_D2D_TENANT_ID:-}
|
||||
|
||||
# Keystone V3
|
||||
#DESIGNATE_D2D_PROJECT_NAME=
|
||||
#DESIGNATE_D2D_PROJECT_DOMAIN_NAME=
|
||||
#DESIGNATE_D2D_USER_DOMAIN_NAME=
|
||||
|
||||
|
||||
# Designate Misc Config
|
||||
# =====================
|
||||
|
||||
|
106
designate/backend/impl_designate.py
Normal file
106
designate/backend/impl_designate.py
Normal file
@ -0,0 +1,106 @@
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Author: Endre Karlson <endre.karlson@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 designateclient.v2 import client
|
||||
from designateclient import exceptions
|
||||
from keystoneclient.auth.identity import v2 as v2_auth
|
||||
from keystoneclient.auth.identity import v3 as v3_auth
|
||||
from keystoneclient import session as ks_session
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from designate.backend import base
|
||||
from designate.i18n import _LI
|
||||
from designate.i18n import _LW
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
CFG_GROUP = 'backend:designate'
|
||||
|
||||
|
||||
class DesignateBackend(base.Backend):
|
||||
"""
|
||||
Support for Designate to Designate using Secondary zones.
|
||||
"""
|
||||
__plugin_name__ = 'designate'
|
||||
__backend_status__ = 'release-compatible'
|
||||
|
||||
def __init__(self, target):
|
||||
super(DesignateBackend, self).__init__(target)
|
||||
|
||||
self.auth_url = self.options.get('auth_url')
|
||||
self.username = self.options.get('username')
|
||||
self.password = self.options.get('password')
|
||||
|
||||
# ks v2
|
||||
self.tenant_name = self.options.get('tenant_name')
|
||||
self.tenant_id = self.options.get('tenant_id')
|
||||
|
||||
# ks v3
|
||||
self.project_name = self.options.get('project_name')
|
||||
self.project_domain_name = self.options.get(
|
||||
'project_domain_name', 'default')
|
||||
self.user_domain_name = self.options.get('user_domain_name', 'default')
|
||||
self.service_type = self.options.get('service_type', 'dns')
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
return self._get_client()
|
||||
|
||||
def _get_client(self):
|
||||
if self._client is not None:
|
||||
return self._client
|
||||
|
||||
if (self.tenant_id is not None or self.tenant_name is not None):
|
||||
auth = v2_auth.Password(
|
||||
auth_url=self.auth_url,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
tenant_id=self.tenant_id,
|
||||
tenant_name=self.tenant_name)
|
||||
elif self.project_name is not None:
|
||||
auth = v3_auth.Password(
|
||||
auth_url=self.auth_url,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
project_name=self.project_name,
|
||||
project_domain_name=self.project_domain_name,
|
||||
user_domain_name=self.user_domain_name)
|
||||
else:
|
||||
auth = None
|
||||
|
||||
session = ks_session.Session(auth=auth)
|
||||
self._client = client.Client(
|
||||
session=session, service_type=self.service_type)
|
||||
return self._client
|
||||
|
||||
def create_domain(self, context, domain):
|
||||
msg = _LI('Creating domain %(d_id)s / %(d_name)s')
|
||||
LOG.info(msg, {'d_id': domain['id'], 'd_name': domain['name']})
|
||||
|
||||
masters = ["%s:%s" % (i.host, i.port) for i in self.masters]
|
||||
self.client.zones.create(
|
||||
domain.name, 'SECONDARY', masters=masters)
|
||||
|
||||
def delete_domain(self, context, domain):
|
||||
msg = _LI('Deleting domain %(d_id)s / %(d_name)s')
|
||||
LOG.info(msg, {'d_id': domain['id'], 'd_name': domain['name']})
|
||||
|
||||
try:
|
||||
self.client.zones.delete(domain.name)
|
||||
except exceptions.NotFound:
|
||||
msg = _LW("Zone %s not found on remote Designate, Ignoring")
|
||||
LOG.warn(msg, domain.id)
|
0
designate/tests/unit/test_backend/__init__.py
Normal file
0
designate/tests/unit/test_backend/__init__.py
Normal file
120
designate/tests/unit/test_backend/test_designate.py
Normal file
120
designate/tests/unit/test_backend/test_designate.py
Normal file
@ -0,0 +1,120 @@
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Author: Endre Karlson <endre.karlson@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 uuid
|
||||
|
||||
|
||||
from designateclient import exceptions
|
||||
from mock import patch
|
||||
from mock import NonCallableMagicMock
|
||||
from mock import Mock
|
||||
from oslo_log import log as logging
|
||||
import oslotest.base
|
||||
import testtools
|
||||
|
||||
from designate import objects
|
||||
from designate.backend import impl_designate
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_zone():
|
||||
id_ = str(uuid.uuid4())
|
||||
return objects.Domain(
|
||||
id=id_,
|
||||
name='%s-example.com.' % id_,
|
||||
email='root@example.com',
|
||||
)
|
||||
|
||||
|
||||
class RoObject(dict):
|
||||
def __setitem__(self, *a):
|
||||
raise NotImplementedError
|
||||
|
||||
def __setattr__(self, *a):
|
||||
raise NotImplementedError
|
||||
|
||||
def __getattr__(self, k):
|
||||
return self[k]
|
||||
|
||||
|
||||
class DesignateBackendTest(oslotest.base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(DesignateBackendTest, self).setUp()
|
||||
opts = RoObject(
|
||||
username='user',
|
||||
password='secret',
|
||||
project_name='project',
|
||||
project_domain_name='project_domain',
|
||||
user_domain_name='user_domain'
|
||||
)
|
||||
self.target = RoObject({
|
||||
'id': '4588652b-50e7-46b9-b688-a9bad40a873e',
|
||||
'type': 'dyndns',
|
||||
'masters': [RoObject({'host': '192.0.2.1', 'port': 53})],
|
||||
'options': opts
|
||||
})
|
||||
|
||||
# Backends blow up when trying to self.admin_context = ... due to
|
||||
# policy not being initialized
|
||||
self.admin_context = Mock()
|
||||
get_context_patcher = patch(
|
||||
'designate.context.DesignateContext.get_admin_context')
|
||||
get_context = get_context_patcher.start()
|
||||
get_context.return_value = self.admin_context
|
||||
|
||||
self.backend = impl_designate.DesignateBackend(self.target)
|
||||
|
||||
# Mock client
|
||||
self.client = NonCallableMagicMock()
|
||||
zones = NonCallableMagicMock(spec_set=[
|
||||
'create', 'delete'])
|
||||
self.client.configure_mock(zones=zones)
|
||||
|
||||
def test_create_domain(self):
|
||||
zone = create_zone()
|
||||
masters = ["%(host)s:%(port)s" % self.target.masters[0]]
|
||||
with patch.object(
|
||||
self.backend, '_get_client', return_value=self.client):
|
||||
self.backend.create_domain(self.admin_context, zone)
|
||||
self.client.zones.create.assert_called_once_with(
|
||||
zone.name, 'SECONDARY', masters=masters)
|
||||
|
||||
def test_delete_domain(self):
|
||||
zone = create_zone()
|
||||
with patch.object(
|
||||
self.backend, '_get_client', return_value=self.client):
|
||||
self.backend.delete_domain(self.admin_context, zone)
|
||||
self.client.zones.delete.assert_called_once_with(zone.name)
|
||||
|
||||
def test_delete_domain_notfound(self):
|
||||
zone = create_zone()
|
||||
self.client.delete.side_effect = exceptions.NotFound
|
||||
with patch.object(
|
||||
self.backend, '_get_client', return_value=self.client):
|
||||
self.backend.delete_domain(self.admin_context, zone)
|
||||
self.client.zones.delete.assert_called_once_with(zone.name)
|
||||
|
||||
def test_delete_domain_exc(self):
|
||||
class Exc(Exception):
|
||||
pass
|
||||
|
||||
zone = create_zone()
|
||||
self.client.zones.delete.side_effect = Exc()
|
||||
with testtools.ExpectedException(Exc):
|
||||
with patch.object(
|
||||
self.backend, '_get_client', return_value=self.client):
|
||||
self.backend.delete_domain(self.admin_context, zone)
|
||||
self.client.zones.delete.assert_called_once_with(zone.name)
|
@ -24,6 +24,7 @@ Paste
|
||||
PasteDeploy>=1.5.0
|
||||
pbr<2.0,>=1.6
|
||||
pecan>=1.0.0
|
||||
python-designateclient>=1.0.0
|
||||
python-neutronclient>=2.6.0
|
||||
Routes!=2.0,!=2.1,>=1.12.3;python_version=='2.7'
|
||||
Routes!=2.0,>=1.12.3;python_version!='2.7'
|
||||
|
@ -81,6 +81,7 @@ designate.notification.handler =
|
||||
|
||||
designate.backend =
|
||||
bind9 = designate.backend.impl_bind9:Bind9Backend
|
||||
designate = designate.backend.impl_designate:DesignateBackend
|
||||
powerdns = designate.backend.impl_powerdns:PowerDNSBackend
|
||||
dynect = designate.backend.impl_dynect:DynECTBackend
|
||||
akamai = designate.backend.impl_akamai:AkamaiBackend
|
||||
|
Loading…
Reference in New Issue
Block a user