diff --git a/designate/tests/test_backend/test_bind9.py b/designate/tests/test_backend/test_bind9.py deleted file mode 100644 index 46500f84f..000000000 --- a/designate/tests/test_backend/test_bind9.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2015 FUJITSU LIMITED -# -# 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 tempfile -import unittest - -import mock - -from designate import exceptions -from designate import objects -from designate.tests.test_backend import BackendTestCase -from designate.backend.impl_bind9 import Bind9Backend - -RNDC_BIN_PATH = "/usr/sbin/rndc" -RNDC_NOT_AVAILABLE = not os.path.isfile(RNDC_BIN_PATH) - - -class Bind9BackendTestCase(BackendTestCase): - - def setUp(self): - super(Bind9BackendTestCase, self).setUp() - - self.zone = objects.Zone(id='cca7908b-dad4-4c50-adba-fb67d4c556e8', - name='example.com.', - email='example@example.com') - - target = objects.PoolTarget.from_dict({ - 'id': '4588652b-50e7-46b9-b688-a9bad40a873e', - 'type': 'bind9', - 'masters': [{'host': '192.0.2.1', 'port': 53}, - {'host': '192.0.2.2', 'port': 35}], - 'options': [{'key': 'host', 'value': '192.0.2.3'}, - {'key': 'port', 'value': '53'}, - {'key': 'rndc_host', 'value': '192.0.2.4'}, - {'key': 'rndc_port', 'value': '953'}, - {'key': 'rndc_bin_path', 'value': '/usr/sbin/rndc'}, - {'key': 'rndc_config_file', 'value': '/etc/rndc.conf'}, - {'key': 'rndc_key_file', 'value': '/etc/rndc.key'}, - {'key': 'clean_zonefile', 'value': 'true'}], - }) - - self.backend = Bind9Backend(target) - - def test_backend_init(self): - expected = ['/usr/sbin/rndc', '-s', '192.0.2.4', '-p', '953', - '-c', '/etc/rndc.conf', '-k', '/etc/rndc.key'] - self.assertEqual(expected, self.backend._rndc_call_base) - - def test_backend_init_using_defaults(self): - target = objects.PoolTarget.from_dict({ - 'id': '4588652b-50e7-46b9-b688-a9bad40a873e', - 'type': 'bind9', - 'masters': [{'host': '192.0.2.1', 'port': 53}, - {'host': '192.0.2.2', 'port': 35}], - 'options': [] - }) - backend = Bind9Backend(target) - expected = ['rndc', '-s', '127.0.0.1', '-p', '953'] - self.assertEqual(expected, backend._rndc_call_base) - - @mock.patch('designate.utils.execute') - def test_create_zone(self, mock_exe): - context = self.get_context() - self.backend.create_zone(context, self.zone) - self.assertEqual(1, mock_exe.call_count) - args = mock_exe.call_args[0] - self.assertEqual(( - '/usr/sbin/rndc', '-s', '192.0.2.4', '-p', '953', - '-c', '/etc/rndc.conf', '-k', '/etc/rndc.key', 'addzone', - ), args[:10]) - - e1 = 'example.com { type slave; masters { 192.0.2.1 port 53; 192.0.2.2 port 35;}; file "slave.example.com.cca7908b-dad4-4c50-adba-fb67d4c556e8"; };' # noqa - e2 = 'example.com { type slave; masters { 192.0.2.2 port 35; 192.0.2.1 port 53;}; file "slave.example.com.cca7908b-dad4-4c50-adba-fb67d4c556e8"; };' # noqa - self.assertTrue(args[-1] == e1 or args[-1] == e2) - - @mock.patch('designate.utils.execute') - def test_delete_zone(self, mock_exe): - context = self.get_context() - self.backend.delete_zone(context, self.zone) - mock_exe.assert_called_with( - '/usr/sbin/rndc', '-s', '192.0.2.4', '-p', '953', - '-c', '/etc/rndc.conf', '-k', '/etc/rndc.key', - 'delzone', '-clean', 'example.com ' - ) - - -class Bind9BackendFunctionalTestCase(BackendTestCase): - - # Run the real rndc, if available - - def setUp(self): - super(Bind9BackendFunctionalTestCase, self).setUp() - - self.CONF.set_override('root_helper', ' ') # disable rootwrap - self._conf_fn = tempfile.mkstemp(prefix='rndc-', suffix='.conf')[1] - self._key_fn = tempfile.mkstemp(prefix='rndc-', suffix='.key')[1] - with open(self._key_fn, 'w') as f: - f.write(""" -key "rndc-key" { - algorithm hmac-md5; - secret "iNeLyEHGbOrogTw+nB/KwQ=="; -}; -""") - with open(self._conf_fn, 'w') as f: - f.write(""" -key "rndc-key" { - algorithm hmac-md5; - secret "iNeLyEHGbOrogTw+nB/KwQ=="; -}; - -options { - default-key "rndc-key"; - default-server 127.0.0.1; - default-port 953; -}; -""") - self.zone = objects.Zone(id='cca7908b-dad4-4c50-adba-fb67d4c556e8', - name='example.com.', - email='example@example.com') - target = objects.PoolTarget.from_dict({ - 'id': '4588652b-50e7-46b9-b688-a9bad40a873e', - 'type': 'bind9', - 'masters': [{'host': '127.0.0.1', 'port': 33353}], - 'options': [{'key': 'host', 'value': '127.0.0.1'}, - {'key': 'port', 'value': 33353}, - {'key': 'rndc_host', 'value': '127.0.0.1'}, - {'key': 'rndc_port', 'value': 33953}, - {'key': 'rndc_bin_path', 'value': RNDC_BIN_PATH}, - {'key': 'rndc_config_file', 'value': self._conf_fn}, - {'key': 'rndc_key_file', 'value': self._key_fn}, - {'key': 'clean_zonefile', 'value': 'true'}], - }) - - self.backend = Bind9Backend(target) - - @unittest.skipIf(RNDC_NOT_AVAILABLE, "rndc binary not installed") - def test_create_zone_call_rndc_connection_refused(self): - # Run rndc againts a closed port. Albeit this does not perform a - # successful rndc run, it is enough to test the argument parsing - context = self.get_context() - exp_msg = 'rndc: connect failed: 127.0.0.1#33953: connection refused' - try: - self.backend.create_zone(context, self.zone) - unittest.fail("Did not raise an exception") - except exceptions.Backend as e: - self.assertTrue(exp_msg in str(e)) diff --git a/designate/tests/unit/backend/test_bind9.py b/designate/tests/unit/backend/test_bind9.py new file mode 100644 index 000000000..6934bec11 --- /dev/null +++ b/designate/tests/unit/backend/test_bind9.py @@ -0,0 +1,225 @@ +# Copyright 2015 FUJITSU LIMITED +# +# 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 + +import designate.tests +from designate import exceptions +from designate import objects +from designate import utils +from designate.backend import impl_bind9 +from designate.tests import fixtures + + +class Bind9BackendTestCase(designate.tests.TestCase): + def setUp(self): + super(Bind9BackendTestCase, self).setUp() + self.zone = objects.Zone( + id='cca7908b-dad4-4c50-adba-fb67d4c556e8', + name='example.com.', + email='example@example.com' + ) + + self.target = { + 'id': '4588652b-50e7-46b9-b688-a9bad40a873e', + 'type': 'bind9', + 'masters': [ + {'host': '192.168.1.1', 'port': 53}, + {'host': '192.168.1.2', 'port': 35} + ], + 'options': [ + {'key': 'host', 'value': '192.168.2.3'}, + {'key': 'port', 'value': '53'}, + {'key': 'rndc_host', 'value': '192.168.2.4'}, + {'key': 'rndc_port', 'value': '953'}, + {'key': 'rndc_bin_path', 'value': '/usr/sbin/rndc'}, + {'key': 'rndc_config_file', 'value': '/etc/rndc.conf'}, + {'key': 'rndc_key_file', 'value': '/etc/rndc.key'}, + {'key': 'clean_zonefile', 'value': 'true'} + ], + } + + self.backend = impl_bind9.Bind9Backend( + objects.PoolTarget.from_dict(self.target) + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_create_zone(self, mock_execute): + with fixtures.random_seed(0): + self.backend.create_zone(self.admin_context, self.zone) + + mock_execute.assert_called_with( + [ + 'addzone', + 'example.com { type slave; masters { 192.168.1.1 port 53; 192.168.1.2 port 35;}; file "slave.example.com.cca7908b-dad4-4c50-adba-fb67d4c556e8"; };' # noqa + ] + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_create_zone_with_view(self, mock_execute): + self.target['options'].append( + {'key': 'view', 'value': 'guest'}, + ) + + backend = impl_bind9.Bind9Backend( + objects.PoolTarget.from_dict(self.target) + ) + + with fixtures.random_seed(1): + backend.create_zone(self.admin_context, self.zone) + + mock_execute.assert_called_with( + [ + 'addzone', + 'example.com in guest { type slave; masters { 192.168.1.2 port 35; 192.168.1.1 port 53;}; file "slave.example.com.cca7908b-dad4-4c50-adba-fb67d4c556e8"; };' # noqa + ] + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_create_zone_raises_on_exception(self, mock_execute): + mock_execute.side_effect = exceptions.Backend('badop') + self.assertRaises( + exceptions.Backend, + self.backend.create_zone, self.admin_context, self.zone + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_create_zone_already_exists(self, mock_execute): + mock_execute.side_effect = exceptions.Backend('already exists') + + self.backend.create_zone(self.admin_context, self.zone) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_delete_zone(self, mock_execute): + self.backend.delete_zone(self.admin_context, self.zone) + + mock_execute.assert_called_with( + ['delzone', '-clean', 'example.com '] + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_delete_zone_with_view(self, mock_execute): + self.target['options'].append( + {'key': 'view', 'value': 'guest'}, + ) + + backend = impl_bind9.Bind9Backend( + objects.PoolTarget.from_dict(self.target) + ) + + backend.delete_zone(self.admin_context, self.zone) + + mock_execute.assert_called_with( + ['delzone', '-clean', 'example.com in guest'] + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_delete_zone_without_clean_zonefile(self, mock_execute): + self.target['options'] = [ + {'key': 'clean_zonefile', 'value': 'false'} + ] + + backend = impl_bind9.Bind9Backend( + objects.PoolTarget.from_dict(self.target) + ) + + backend.delete_zone(self.admin_context, self.zone) + + mock_execute.assert_called_with( + ['delzone', 'example.com '] + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_delete_zone_raises_on_exception(self, mock_execute): + mock_execute.side_effect = exceptions.Backend('badop') + self.assertRaises( + exceptions.Backend, + self.backend.delete_zone, self.admin_context, self.zone + ) + + @mock.patch.object(impl_bind9.Bind9Backend, '_execute_rndc') + def test_delete_zone_already_deleted(self, mock_execute): + mock_execute.side_effect = exceptions.Backend('not found') + + self.backend.delete_zone(self.admin_context, self.zone) + + def test_generate_rndc_base_call(self): + self.assertEqual( + [ + '/usr/sbin/rndc', '-s', '192.168.2.4', '-p', '953', + '-c', '/etc/rndc.conf', '-k', '/etc/rndc.key' + ], + self.backend._generate_rndc_base_call() + ) + + def test_generate_rndc_base_call_without_config_file(self): + self.target['options'] = [ + {'key': 'rndc_host', 'value': '192.168.4.4'}, + {'key': 'rndc_port', 'value': '953'}, + {'key': 'rndc_bin_path', 'value': '/usr/sbin/rndc'}, + {'key': 'rndc_key_file', 'value': '/etc/rndc.key'}, + ] + + backend = impl_bind9.Bind9Backend( + objects.PoolTarget.from_dict(self.target) + ) + + self.assertEqual( + [ + '/usr/sbin/rndc', '-s', '192.168.4.4', '-p', '953', + '-k', '/etc/rndc.key' + ], + backend._generate_rndc_base_call() + ) + + def test_generate_rndc_base_call_without_key_file(self): + self.target['options'] = [ + {'key': 'rndc_host', 'value': '192.168.3.4'}, + {'key': 'rndc_port', 'value': '953'}, + {'key': 'rndc_bin_path', 'value': '/usr/sbin/rndc'}, + {'key': 'rndc_config_file', 'value': '/etc/rndc.conf'}, + ] + + backend = impl_bind9.Bind9Backend( + objects.PoolTarget.from_dict(self.target) + ) + + self.assertEqual( + [ + '/usr/sbin/rndc', '-s', '192.168.3.4', '-p', '953', + '-c', '/etc/rndc.conf' + ], + backend._generate_rndc_base_call() + ) + + @mock.patch('designate.utils.execute') + def test_execute_rndc(self, mock_execute): + rndc_op = ['delzone', 'example.com '] + + self.backend._execute_rndc(rndc_op) + + mock_execute.assert_called_with( + '/usr/sbin/rndc', '-s', '192.168.2.4', '-p', '953', + '-c', '/etc/rndc.conf', '-k', '/etc/rndc.key', + 'delzone', 'example.com ' + ) + + @mock.patch('designate.utils.execute') + def test_execute_rndc_raises_on_exception(self, mock_execute): + mock_execute.side_effect = utils.processutils.ProcessExecutionError() + rndc_op = ['badop', 'example.com '] + + self.assertRaises( + exceptions.Backend, + self.backend._execute_rndc, rndc_op + ) diff --git a/designate/tests/unit/backend/test_dynect.py b/designate/tests/unit/backend/test_dynect.py index 4eacfabf1..353772598 100644 --- a/designate/tests/unit/backend/test_dynect.py +++ b/designate/tests/unit/backend/test_dynect.py @@ -15,8 +15,8 @@ # under the License. import requests_mock +import designate.tests from designate import objects -from designate import tests from designate.backend import impl_dynect MASTERS = ["10.0.0.1"] @@ -110,7 +110,7 @@ ACTIVATE_SUCCESS = { } -class DynECTTestsCase(tests.TestCase): +class DynECTTestsCase(designate.tests.TestCase): def setUp(self): super(DynECTTestsCase, self).setUp() diff --git a/designate/tests/unit/backend/test_infoblox.py b/designate/tests/unit/backend/test_infoblox.py index 45f8dbf4a..e34b14b74 100644 --- a/designate/tests/unit/backend/test_infoblox.py +++ b/designate/tests/unit/backend/test_infoblox.py @@ -15,15 +15,15 @@ import mock import requests_mock +import designate.tests from designate import exceptions from designate import objects -from designate import tests from designate.backend import impl_infoblox from designate.backend.impl_infoblox import ibexceptions from designate.mdns import rpcapi as mdns_rpcapi -class InfobloxBackendTestCase(tests.TestCase): +class InfobloxBackendTestCase(designate.tests.TestCase): def setUp(self): super(InfobloxBackendTestCase, self).setUp() self.base_address = 'https://localhost/wapi' diff --git a/designate/tests/unit/backend/test_nsd4.py b/designate/tests/unit/backend/test_nsd4.py index 2896abb96..bfc087eee 100644 --- a/designate/tests/unit/backend/test_nsd4.py +++ b/designate/tests/unit/backend/test_nsd4.py @@ -19,13 +19,13 @@ import ssl import eventlet import mock +import designate.tests from designate import exceptions from designate import objects -from designate import tests from designate.backend import impl_nsd4 -class NSD4BackendTestCase(tests.TestCase): +class NSD4BackendTestCase(designate.tests.TestCase): def setUp(self): super(NSD4BackendTestCase, self).setUp() diff --git a/designate/tests/unit/backend/test_pdns4.py b/designate/tests/unit/backend/test_pdns4.py index 570abbd74..595bd88d2 100644 --- a/designate/tests/unit/backend/test_pdns4.py +++ b/designate/tests/unit/backend/test_pdns4.py @@ -12,15 +12,15 @@ import mock import requests_mock +import designate.tests from designate import exceptions from designate import objects -from designate import tests from designate.backend import impl_pdns4 from designate.mdns import rpcapi as mdns_rpcapi from designate.tests import fixtures -class PDNS4BackendTestCase(tests.TestCase): +class PDNS4BackendTestCase(designate.tests.TestCase): def setUp(self): super(PDNS4BackendTestCase, self).setUp() self.stdlog = fixtures.StandardLogging()