Merge "Remove the agent service and old-style backend tests"

This commit is contained in:
Jenkins 2014-12-16 00:20:48 +00:00 committed by Gerrit Code Review
commit 7b310d459f
22 changed files with 3 additions and 1176 deletions

View File

@ -37,7 +37,6 @@ cfg.CONF.register_opts([
help='Top-level directory for maintaining designate\'s state'),
cfg.StrOpt('central-topic', default='central', help='Central Topic'),
cfg.StrOpt('agent-topic', default='agent', help='Agent Topic'),
cfg.StrOpt('mdns-topic', default='mdns', help='mDNS Topic'),
cfg.StrOpt('pool-manager-topic', default='pool_manager',
help='Pool Manager Topic'),

View File

@ -1,27 +0,0 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# 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 oslo.config import cfg
cfg.CONF.register_group(cfg.OptGroup(
name='service:agent', title="Configuration for Agent Service"
))
cfg.CONF.register_opts([
cfg.IntOpt('workers', default=None,
help='Number of worker processes to spawn'),
cfg.StrOpt('backend-driver', default='bind9',
help='The backend driver to use'),
], group='service:agent')

View File

@ -1,131 +0,0 @@
# Copyright 2013 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 oslo.config import cfg
from oslo import messaging
from designate.openstack.common import log as logging
from designate import rpc
LOG = logging.getLogger(__name__)
class AgentAPI(object):
"""
Client side of the agent Rpc API.
API version history:
1.0 - Initial version
"""
RPC_API_VERSION = '1.0'
def __init__(self, topic=None):
topic = topic if topic else cfg.CONF.agent_topic
target = messaging.Target(topic=topic, version=self.RPC_API_VERSION)
self.client = rpc.get_client(target, version_cap='1.0')
# Server Methods
def create_server(self, context, server, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'create_server', server=server)
def update_server(self, context, server, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.client.call(context, 'update_server', server=server)
def delete_server(self, context, server, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'delete_server', server=server)
# TSIG Key Methods
def create_tsigkey(self, context, tsigkey, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'create_tsigkey', tsigkey=tsigkey)
def update_tsigkey(self, context, tsigkey, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'update_tsigkey', tsigkey=tsigkey)
def delete_tsigkey(self, context, tsigkey, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'delete_tsigkey', tsigkey=tsigkey)
# Domain Methods
def create_domain(self, context, domain, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'create_domain', domain=domain)
def update_domain(self, context, domain, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'update_domain', domain=domain)
def delete_domain(self, context, domain, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'delete_domain', domain=domain)
# Record Methods
def update_recordset(self, context, domain, recordset, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'update_recordset', domain=domain,
recordset=recordset)
def delete_recordset(self, context, domain, recordset, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'delete_recordset', domain=domain,
recordset=recordset)
def create_record(self, context, domain, recordset, record, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'create_record', domain=domain,
recordset=recordset, record=record)
def update_record(self, context, domain, recordset, record, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'update_record', domain=domain,
recordset=recordset, record=record)
def delete_record(self, context, domain, recordset, record, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'delete_record', domain=domain,
recordset=recordset, record=record)
# Sync Methods
def sync_domain(self, context, domain, records, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'sync_domain', domain=domain,
record=records)
def sync_record(self, context, domain, record, host=None):
cctxt = self.client.prepare(server=host)
return cctxt.call(context, 'sync_record', domain=domain, record=record)

View File

@ -1,37 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 oslo.config import cfg
from designate.openstack.common import log as logging
from designate import backend
from designate import service
from designate.central import rpcapi as central_rpcapi
LOG = logging.getLogger(__name__)
class Service(service.RPCService):
def __init__(self, *args, **kwargs):
super(Service, self).__init__(*args, **kwargs)
central_api = central_rpcapi.CentralAPI.get_instance()
endpoint = backend.get_backend(
cfg.CONF['service:agent'].backend_driver,
central_service=central_api)
kwargs['endpoints'] = [endpoint]

View File

@ -1,74 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 import base
from designate.agent import rpcapi as agent_rpcapi
class RPCBackend(base.Backend):
def __init__(self, central_service):
super(RPCBackend, self).__init__(central_service)
self.agent_api = agent_rpcapi.AgentAPI()
def create_tsigkey(self, context, tsigkey):
return self.agent_api.create_tsigkey(context, tsigkey)
def update_tsigkey(self, context, tsigkey):
return self.agent_api.update_tsigkey(context, tsigkey)
def delete_tsigkey(self, context, tsigkey):
return self.agent_api.delete_tsigkey(context, tsigkey)
def create_server(self, context, server):
return self.agent_api.create_server(context, server)
def update_server(self, context, server):
return self.agent_api.update_server(context, server)
def delete_server(self, context, server):
return self.agent_api.delete_server(context, server)
def create_domain(self, context, domain):
return self.agent_api.create_domain(context, domain)
def update_domain(self, context, domain):
return self.agent_api.update_domain(context, domain)
def delete_domain(self, context, domain):
return self.agent_api.delete_domain(context, domain)
def create_recordset(self, context, domain, recordset):
return self.agent_api.create_recordset(context, domain, recordset)
def update_recordset(self, context, domain, recordset):
return self.agent_api.update_recordset(context, domain, recordset)
def delete_recordset(self, context, domain, recordset):
return self.agent_api.delete_recordset(context, domain, recordset)
def create_record(self, context, domain, recordset, record):
return self.agent_api.create_record(context, domain, recordset, record)
def update_record(self, context, domain, recordset, record):
return self.agent_api.update_record(context, domain, recordset, record)
def delete_record(self, context, domain, recordset, record):
return self.agent_api.delete_record(context, domain, recordset, record)
def sync_domain(self, context, domain, records):
return self.agent_api.sync_domain(context, domain, records)
def sync_record(self, context, domain, record):
return self.agent_api.sync_record(context, domain, record)

View File

@ -1,37 +0,0 @@
# Copyright 2013 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 sys
from oslo.config import cfg
from designate.openstack.common import log as logging
from designate import service
from designate import utils
from designate.agent import service as agent_service
CONF = cfg.CONF
CONF.import_opt('workers', 'designate.agent', group='service:agent')
def main():
utils.read_config('designate', sys.argv)
logging.setup('designate')
server = agent_service.Service.create(
binary='designate-agent')
service.serve(server, workers=CONF['service:agent'].workers)
service.wait()

View File

@ -45,8 +45,8 @@ LOG = logging.getLogger(__name__)
cfg.CONF.import_opt('storage_driver', 'designate.central',
group='service:central')
cfg.CONF.import_opt('backend_driver', 'designate.agent',
group='service:agent')
cfg.CONF.import_opt('backend_driver', 'designate.central',
group='service:central')
cfg.CONF.import_opt('auth_strategy', 'designate.api',
group='service:api')
cfg.CONF.import_opt('connection', 'designate.storage.impl_sqlalchemy',
@ -305,11 +305,6 @@ class TestCase(base.BaseTestCase):
group='service:central'
)
self.config(
backend_driver='fake',
group='service:agent'
)
self.config(
auth_strategy='noauth',
group='service:api'

View File

@ -1,20 +0,0 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# 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.tests import TestCase
class AgentTestCase(TestCase):
pass

View File

@ -1,26 +0,0 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# 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.tests.test_agent import AgentTestCase
class AgentServiceTest(AgentTestCase):
def setUp(self):
super(AgentServiceTest, self).setUp()
self.service = self.start_service('agent')
def test_stop(self):
# NOTE: Start is already done by the fixture in start_service()
self.service.stop()

View File

@ -1,27 +0,0 @@
# Copyright 2013 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 oslo.config import cfg
from designate import backend
class BackendTestMixin(object):
def get_backend_driver(self):
return backend.get_backend(cfg.CONF['service:agent'].backend_driver,
central_service=self.central_service)
def test_constructor(self):
self.get_backend_driver()

View File

@ -1,37 +0,0 @@
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 testscenarios import load_tests_apply_scenarios as load_tests # noqa
from designate import tests
from designate.tests.test_backend.test_nsd4slave import NSD4Fixture
from designate.tests.test_backend import BackendTestMixin
class BackendTestCase(tests.TestCase, BackendTestMixin):
scenarios = [
('fake', dict(backend_driver='fake', group='service:agent')),
('nsd4slave', dict(backend_driver='nsd4slave', group='service:agent',
server_fixture=NSD4Fixture)),
('ipa', dict(backend_driver='ipa', group='service:agent'))
]
def setUp(self):
super(BackendTestCase, self).setUp()
if hasattr(self, 'server_fixture'):
self.useFixture(self.server_fixture())
self.config(backend_driver=self.backend_driver, group=self.group)

View File

@ -1,318 +0,0 @@
# Copyright (C) 2014 Red Hat, Inc.
#
# Author: Rich Megginson <rmeggins@redhat.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 fixtures
from oslotest import mockpatch
from oslo.serialization import jsonutils as json
from requests.auth import AuthBase
from designate import tests
from designate import utils
from designate.tests.test_backend import BackendTestMixin
from designate.backend import impl_ipa
ipamethods = {"dnszone_add": {}, "dnszone_mod": {},
"dnszone_del": {}, "dnsrecord_add": {},
"dnsrecord_mod": {}, "dnsrecord_del": {},
}
class MockIPAAuth(AuthBase):
def __init__(self, hostname, keytab):
self.count = 0
def refresh_auth(self):
self.count += 1
class MockResponse(object):
def __init__(self, status_code, jsontext):
self.status_code = status_code
self.text = jsontext
class MockRequest(object):
def __init__(self, testcase):
self.headers = {}
self.myauth = MockIPAAuth("ignore", "ignore")
self.testcase = testcase
self.error = None
self.needauth = False
@property
def auth(self):
# always return the mock object
return self.myauth
@auth.setter
def auth(self, val):
# disallow setting
pass
def post(self, jsonurl, data):
# convert json data string to dict
ddict = json.loads(data)
# check basic parameters
self.testcase.assertIn('method', ddict)
meth = ddict['method']
self.testcase.assertIn(meth, ipamethods)
self.testcase.assertIn('params', ddict)
self.testcase.assertIsInstance(ddict['params'], list)
self.testcase.assertEqual(len(ddict['params']), 2)
self.testcase.assertIsInstance(ddict['params'][0], list)
self.testcase.assertIsInstance(ddict['params'][1], dict)
self.testcase.assertIn('version', ddict['params'][1])
# check method specific parameters
if meth.startswith('dnsrecord_'):
self.testcase.assertEqual(len(ddict['params'][0]), 2)
# domain params end with a .
param1 = ddict['params'][0][0]
self.testcase.assertEqual(param1[-1], ".")
elif meth.startswith('dnszone_'):
self.testcase.assertEqual(len(ddict['params'][0]), 1)
param1 = ddict['params'][0][0]
self.testcase.assertEqual(param1[-1], ".")
rc = {}
if self.needauth:
self.needauth = False # reset
return MockResponse(401, json.dumps(rc))
if self.error:
rc['error'] = {'code': self.error}
self.error = None # reset
else:
rc['error'] = None
return MockResponse(200, json.dumps(rc))
class IPABackendTestCase(tests.TestCase, BackendTestMixin):
def get_record_fixture(self, recordset_type, fixture=0, values=None):
"""override to ensure all records have a recordset_id"""
values = values or {}
return super(IPABackendTestCase, self).get_record_fixture(
recordset_type, fixture,
values={
'recordset_id': utils.generate_uuid()
}
)
def setUp(self):
super(IPABackendTestCase, self).setUp()
self.request = MockRequest(self)
# make requests return our mock object
def getSession():
return self.request
# replace requests.Session() with our mock version
self.useFixture(fixtures.MonkeyPatch('requests.Session', getSession))
self.config(backend_driver='ipa', group='service:agent')
self.backend = self.get_backend_driver()
self.CONF['backend:ipa'].ipa_auth_driver_class = \
"designate.tests.test_backend.test_ipa.MockIPAAuth"
self.backend.start()
# Since some CRUD methods in impl_ipa call central's find_servers
# and find_records method, mock it up to return our fixture.
self.useFixture(mockpatch.PatchObject(
self.backend.central_service,
'find_servers',
return_value=[self.get_server_fixture()]
))
self.useFixture(mockpatch.PatchObject(
self.backend.central_service,
'find_records',
return_value=[self.get_record_fixture('A')]
))
def test_create_server(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
def test_update_server(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
self.backend.update_server(context, server)
def test_delete_server(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
self.backend.delete_server(context, server)
def test_create_domain(self):
context = self.get_context()
server = self.get_server_fixture()
domain = self.get_domain_fixture()
self.backend.create_server(context, server)
self.backend.create_domain(context, domain)
def test_update_domain(self):
context = self.get_context()
server = self.get_server_fixture()
domain = self.get_domain_fixture()
self.backend.create_server(context, server)
self.backend.create_domain(context, domain)
domain['serial'] = 123456789
self.backend.update_domain(context, domain)
def test_delete_domain(self):
context = self.get_context()
server = self.get_server_fixture()
domain = self.get_domain_fixture()
self.backend.create_server(context, server)
self.backend.create_domain(context, domain)
self.backend.delete_domain(context, domain)
def test_create_domain_dup_domain(self):
context = self.get_context()
server = self.get_server_fixture()
domain = self.get_domain_fixture()
self.backend.create_server(context, server)
self.request.error = impl_ipa.IPA_DUPLICATE
self.assertRaises(impl_ipa.IPADuplicateDomain,
self.backend.create_domain,
context, domain)
self.assertIsNone(self.request.error)
def test_update_domain_error_no_domain(self):
context = self.get_context()
server = self.get_server_fixture()
domain = self.get_domain_fixture()
self.backend.create_server(context, server)
self.backend.create_domain(context, domain)
self.request.error = impl_ipa.IPA_NOT_FOUND
self.assertRaises(impl_ipa.IPADomainNotFound,
self.backend.update_domain,
context, domain)
def test_create_record(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.backend.create_record(context, domain, recordset, record)
self.backend.delete_domain(context, domain)
def test_create_record_error_no_changes(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.request.error = impl_ipa.IPA_NO_CHANGES
# backend should ignore this error
self.backend.create_record(context, domain, recordset, record)
self.assertIsNone(self.request.error)
self.backend.delete_domain(context, domain)
def test_create_domain_error_no_changes(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.request.error = impl_ipa.IPA_NO_CHANGES
# backend should ignore this error
self.backend.create_domain(context, domain)
self.assertIsNone(self.request.error)
self.backend.delete_domain(context, domain)
def test_create_record_error_dup_record(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.request.error = impl_ipa.IPA_DUPLICATE # causes request to raise
self.assertRaises(impl_ipa.IPADuplicateRecord,
self.backend.create_record,
context, domain, recordset, record)
self.assertIsNone(self.request.error)
self.backend.delete_domain(context, domain)
def test_update_record_error_no_record(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.request.error = impl_ipa.IPA_NOT_FOUND # causes request to raise
self.assertRaises(impl_ipa.IPARecordNotFound,
self.backend.update_record,
context, domain, recordset, record)
self.assertIsNone(self.request.error)
self.backend.delete_domain(context, domain)
def test_update_record_unknown_error(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.request.error = 1234 # causes request to raise
self.assertRaises(impl_ipa.IPAUnknownError, self.backend.update_record,
context, domain, recordset, record)
self.assertIsNone(self.request.error)
self.backend.delete_domain(context, domain)
def test_create_record_reauth(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.request.needauth = True # causes request to reauth
beforecount = self.request.myauth.count
self.backend.create_record(context, domain, recordset, record)
self.assertFalse(self.request.needauth)
self.assertEqual(self.request.myauth.count, (beforecount + 1))
self.backend.delete_domain(context, domain)
def test_create_record_reauth_fail(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.create_server(context, server)
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
recordset = self.get_recordset_fixture(domain['name'], "A")
record = self.get_record_fixture("A")
self.request.needauth = True # causes request to reauth
self.backend.ntries = 0 # force exception upon retry
self.assertRaises(impl_ipa.IPACommunicationFailure,
self.backend.create_record, context, domain,
recordset, record)
self.assertFalse(self.request.needauth)
self.assertNotEqual(self.backend.ntries, 0)
self.backend.delete_domain(context, domain)

View File

@ -1,251 +0,0 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Artom Lifshitz <artom.lifshitz@enovance.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 mock
from mock import call
from mock import MagicMock
from designate import exceptions
from designate import objects
from designate import tests
from designate.tests.test_backend import BackendTestMixin
class MultiBackendTestCase(tests.TestCase, BackendTestMixin):
"""
Test the master/slave ordering as defined in MultiBackend.
Test that create for tsigkeys, servers and domains is done on the master
first, then on the slave. At the same time, test that if the slave raises
an exception, delete is called on the master to cleanup.
Test that delete for tsigkeys, servers and domains is done on the slave
first, then on the master. At the same time, test that if the master raises
an exception, create is called on the slave to cleanup.
Test that updates and all operations on records are done on the master
only.
"""
def setUp(self):
super(MultiBackendTestCase, self).setUp()
self.config(backend_driver='multi', group='service:agent')
self.backend = self.get_backend_driver()
self.backends = MagicMock()
self.backend.master = MagicMock()
self.backend.slave = MagicMock()
self.backends.master = self.backend.master
self.backends.slave = self.backend.slave
def test_create_tsigkey(self):
context = self.get_context()
tsigkey = self.get_tsigkey_fixture()
self.backend.slave.create_tsigkey = MagicMock(
side_effect=exceptions.Backend)
self.assertRaises(exceptions.Backend, self.backend.create_tsigkey,
context, tsigkey)
self.assertEqual(self.backends.mock_calls,
[call.master.create_tsigkey(context, tsigkey),
call.slave.create_tsigkey(context, tsigkey),
call.master.delete_tsigkey(context, tsigkey)])
def test_update_tsigkey(self):
context = self.get_context()
tsigkey = self.get_tsigkey_fixture()
self.backend.update_tsigkey(context, tsigkey)
self.assertEqual(self.backends.mock_calls,
[call.master.update_tsigkey(context, tsigkey)])
def test_delete_tsigkey(self):
context = self.get_context()
tsigkey = self.get_tsigkey_fixture()
self.backend.master.delete_tsigkey = MagicMock(
side_effect=exceptions.Backend)
self.assertRaises(exceptions.Backend, self.backend.delete_tsigkey,
context, tsigkey)
self.assertEqual(self.backends.mock_calls,
[call.slave.delete_tsigkey(context, tsigkey),
call.master.delete_tsigkey(context, tsigkey),
call.slave.create_tsigkey(context, tsigkey)])
def test_create_domain(self):
context = self.get_context()
domain = self.get_domain_fixture()
self.backend.slave.create_domain = MagicMock(
side_effect=exceptions.Backend)
self.assertRaises(exceptions.Backend, self.backend.create_domain,
context, domain)
self.assertEqual(self.backends.mock_calls,
[call.master.create_domain(context, domain),
call.slave.create_domain(context, domain),
call.master.delete_domain(context, domain)])
def test_update_domain(self):
context = self.get_context()
domain = self.get_domain_fixture()
self.backend.update_domain(context, domain)
self.assertEqual(self.backends.mock_calls,
[call.master.update_domain(context, domain)])
def test_delete_domain(self):
context = self.get_context()
domain = self.get_domain_fixture()
domain['id'] = 'a8aeb2ee-40da-476b-a9d8-26bf0c0065f6'
# Since multi's delete fetches the domain from central to be able to
# recreate it if something goes wrong, create the domain first
self.backend.central_service.create_server(
self.get_admin_context(),
objects.Server(**self.get_server_fixture()))
created_domain = self.backend.central_service.create_domain(
context, objects.Domain(**domain))
records = self.backend.central_service.find_records(
context, criterion={'domain_id': created_domain['id']})
self.backend.master.delete_domain = MagicMock(
side_effect=exceptions.Backend)
self.assertRaises(exceptions.Backend, self.backend.delete_domain,
context, domain)
self.assertEqual(self.backends.mock_calls,
[call.slave.delete_domain(context, domain),
call.master.delete_domain(context, domain),
call.slave.create_domain(context, domain),
call.slave.create_record(context, domain,
records[0]),
call.slave.create_record(context, domain,
records[1])])
def test_create_server(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.slave.create_server = MagicMock(
side_effect=exceptions.Backend)
self.assertRaises(exceptions.Backend, self.backend.create_server,
context, server)
self.assertEqual(self.backends.mock_calls,
[call.master.create_server(context, server),
call.slave.create_server(context, server),
call.master.delete_server(context, server)])
def test_update_server(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.update_server(context, server)
self.assertEqual(self.backends.mock_calls,
[call.master.update_server(context, server)])
def test_delete_server(self):
context = self.get_context()
server = self.get_server_fixture()
self.backend.master.delete_server = MagicMock(
side_effect=exceptions.Backend)
self.assertRaises(exceptions.Backend, self.backend.delete_server,
context, server)
self.assertEqual(self.backends.mock_calls,
[call.slave.delete_server(context, server),
call.master.delete_server(context, server),
call.slave.create_server(context, server)])
def test_create_recordset(self):
context = self.get_context()
domain = mock.sentinel.domain
recordset = mock.sentinel.recordset
self.backend.create_recordset(context, domain, recordset)
self.assertEqual(
self.backends.mock_calls,
[call.master.create_recordset(context, domain, recordset)])
def test_update_recordset(self):
context = self.get_context()
domain = mock.sentinel.domain
recordset = mock.sentinel.recordset
self.backend.update_recordset(context, domain, recordset)
self.assertEqual(
self.backends.mock_calls,
[call.master.update_recordset(context, domain, recordset)])
def test_delete_recordset(self):
context = self.get_context()
domain = mock.sentinel.domain
recordset = mock.sentinel.recordset
self.backend.delete_recordset(context, domain, recordset)
self.assertEqual(
self.backends.mock_calls,
[call.master.delete_recordset(context, domain, recordset)])
def test_create_record(self):
context = self.get_context()
domain = mock.sentinel.domain
recordset = mock.sentinel.recordset
record = mock.sentinel.record
self.backend.create_record(context, domain, recordset, record)
self.assertEqual(
self.backends.mock_calls,
[call.master.create_record(context, domain, recordset, record)])
def test_update_record(self):
context = self.get_context()
domain = mock.sentinel.domain
recordset = mock.sentinel.recordset
record = mock.sentinel.record
self.backend.update_record(context, domain, recordset, record)
self.assertEqual(
self.backends.mock_calls,
[call.master.update_record(context, domain, recordset, record)])
def test_delete_record(self):
context = self.get_context()
domain = mock.sentinel.domain
recordset = mock.sentinel.recordset
record = mock.sentinel.record
self.backend.delete_record(context, domain, recordset, record)
self.assertEqual(
self.backends.mock_calls,
[call.master.delete_record(context, domain, recordset, record)])
def test_ping(self):
context = self.get_context()
self.backend.ping(context)
self.assertEqual(self.backends.mock_calls,
[call.master.ping(context),
call.slave.ping(context)])
def test_start(self):
self.backend.start()
self.assertEqual(self.backends.mock_calls,
[call.master.start(), call.slave.start()])
def test_stop(self):
self.backend.stop()
self.assertEqual(self.backends.mock_calls,
[call.slave.stop(), call.master.stop()])

View File

@ -1,134 +0,0 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Artom Lifshitz <artom.lifshitz@enovance.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
import socket
import ssl
import eventlet
import fixtures
from mock import MagicMock
from oslo.config import cfg
from designate import exceptions
from designate import tests
from designate.tests.test_backend import BackendTestMixin
from designate.tests import resources
from designate.backend import impl_nsd4slave
class NSD4ServerStub:
recved_command = None
response = 'ok'
keyfile = os.path.join(resources.path, 'ssl', 'nsd_server.key')
certfile = os.path.join(resources.path, 'ssl', 'nsd_server.pem')
def handle(self, client_sock, client_addr):
stream = client_sock.makefile()
self.recved_command = stream.readline()
stream.write(self.response)
stream.flush()
def start(self):
self.port = 1025
while True:
try:
eventlet.spawn_n(eventlet.serve,
eventlet.wrap_ssl(
eventlet.listen(('127.0.0.1', self.port)),
keyfile=self.keyfile,
certfile=self.certfile,
server_side=True),
self.handle)
break
except socket.error:
self.port = self.port + 1
def stop(self):
eventlet.StopServe()
class NSD4Fixture(fixtures.Fixture):
def setUp(self):
super(NSD4Fixture, self).setUp()
self.servers = [NSD4ServerStub(), NSD4ServerStub()]
[server.start() for server in self.servers]
impl_nsd4slave.DEFAULT_PORT = self.servers[0].port
cfg.CONF.set_override('backend_driver', 'nsd4slave', 'service:agent')
cfg.CONF.set_override(
'servers', ['127.0.0.1', '127.0.0.1:%d' % self.servers[1].port],
'backend:nsd4slave')
keyfile = os.path.join(resources.path, 'ssl', 'nsd_control.key')
certfile = os.path.join(resources.path, 'ssl', 'nsd_control.pem')
cfg.CONF.set_override('keyfile', keyfile, 'backend:nsd4slave')
cfg.CONF.set_override('certfile', certfile, 'backend:nsd4slave')
cfg.CONF.set_override('pattern', 'test-pattern', 'backend:nsd4slave')
self.addCleanup(self.tearDown)
def tearDown(self):
[server.stop() for server in self.servers]
# NOTE: We'll only test the specifics to the nsd4 backend here.
# Rest is handled via scenarios
class NSD4SlaveBackendTestCase(tests.TestCase, BackendTestMixin):
def setUp(self):
super(NSD4SlaveBackendTestCase, self).setUp()
self.server_fixture = NSD4Fixture()
self.useFixture(self.server_fixture)
self.backend = self.get_backend_driver()
def test_create_domain(self):
context = self.get_context()
domain = self.get_domain_fixture()
self.backend.create_domain(context, domain)
command = 'NSDCT1 addzone %s test-pattern\n' % domain['name']
[self.assertEqual(server.recved_command, command)
for server in self.server_fixture.servers]
def test_delete_domain(self):
context = self.get_context()
domain = self.get_domain_fixture()
self.backend.delete_domain(context, domain)
command = 'NSDCT1 delzone %s\n' % domain['name']
[self.assertEqual(server.recved_command, command)
for server in self.server_fixture.servers]
def test_server_not_ok(self):
self.server_fixture.servers[0].response = 'goat'
context = self.get_context()
domain = self.get_domain_fixture()
self.assertRaises(exceptions.NSD4SlaveBackendError,
self.backend.create_domain,
context, domain)
def test_ssl_error(self):
self.backend._command = MagicMock(side_effet=ssl.SSLError)
context = self.get_context()
domain = self.get_domain_fixture()
self.assertRaises(exceptions.NSD4SlaveBackendError,
self.backend.create_domain,
context, domain)
def test_socket_error(self):
self.backend._command = MagicMock(side_effet=socket.error)
context = self.get_context()
domain = self.get_domain_fixture()
self.assertRaises(exceptions.NSD4SlaveBackendError,
self.backend.create_domain,
context, domain)

View File

@ -1,26 +0,0 @@
.. _agent:
*****
Agent
*****
.. _agent-rpcapi:
Agent RPC API
=============
.. automodule:: designate.agent.rpcapi
:members:
:undoc-members:
:show-inheritance:
.. _agent-service:
Agent RPC Service
=================
.. automodule:: designate.agent.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -54,12 +54,6 @@ DNS Backend
Backends are drivers for a particular DNS server.
Designate supports multiple backend implementations, PowerDNS, BIND and MySQL BIND, you are also free to implement your own backend to fit your needs, as well as extensions to provide extra functionality to complement existing backends.
.. _designate-agent:
Designate Agent
-----------------------
designate-agents are optional components that interact with DNS servers. Agents are alternatives to backend plugins in :ref:`designate-central`. Agents communicate with :ref:`designate-central` via the :ref:`message-queue`.
.. _message-queue:
Message Queue

View File

@ -33,7 +33,6 @@ Parameter Default Note
api_host 0.0.0.0 API listen host
api_port 9001 API listen port
control_exchange designate The MQ Control exchange
agent_topic agent The topic that the Agent(s) should use
central_topic central The topic that the Central should use
os-username glance Username to use for openstack service access
os-password admin Password to use for openstack service access

View File

@ -52,7 +52,6 @@ Instructions
# Optional Designate services
#ENABLED_SERVICES+=,designate-sink
#ENABLED_SERVICES+=,designate-agent
# ** Everything below is optional ***

View File

@ -22,10 +22,6 @@ Glossary
.. glossary::
agent
Software service running on nodes that executes actions towards typically
nameservers like BIND or similar.
central
Software service running on a central management node that stores
information persistently in a backend storage using a configurable driver

View File

@ -36,7 +36,6 @@ Source Documentation
.. toctree::
:maxdepth: 3
agent
api
backend
central

View File

@ -45,7 +45,7 @@ debug = False
# Central Service
#-----------------------
[service:central]
# Driver used for backend communication (e.g. fake, rpc, bind9, powerdns)
# Driver used for backend communication (e.g. fake, bind9, powerdns)
#backend_driver = fake
# Maximum domain name length
@ -104,13 +104,6 @@ debug = False
#admin_user = designate
#admin_password = designate
#-----------------------
# Agent Service
#-----------------------
[service:agent]
# Driver used for backend communication (e.g. bind9, powerdns)
#backend_driver = powerdns
#-----------------------
# Sink Service
#-----------------------

View File

@ -31,7 +31,6 @@ packages =
[entry_points]
console_scripts =
designate-rootwrap = oslo.rootwrap.cmd:main
designate-agent = designate.cmd.agent:main
designate-api = designate.cmd.api:main
designate-central = designate.cmd.central:main
designate-manage = designate.cmd.manage:main
@ -70,7 +69,6 @@ designate.notification.handler =
designate.backend =
bind9 = designate.backend.impl_bind9:Bind9Backend
powerdns = designate.backend.impl_powerdns:PowerDNSBackend
rpc = designate.backend.impl_rpc:RPCBackend
fake = designate.backend.impl_fake:FakeBackend
nsd4slave = designate.backend.impl_nsd4slave:NSD4SlaveBackend
multi = designate.backend.impl_multi:MultiBackend