summaryrefslogtreecommitdiff
path: root/designate/tests/test_pool_manager/test_service.py
diff options
context:
space:
mode:
Diffstat (limited to 'designate/tests/test_pool_manager/test_service.py')
-rw-r--r--designate/tests/test_pool_manager/test_service.py480
1 files changed, 0 insertions, 480 deletions
diff --git a/designate/tests/test_pool_manager/test_service.py b/designate/tests/test_pool_manager/test_service.py
deleted file mode 100644
index 2610ebb8..00000000
--- a/designate/tests/test_pool_manager/test_service.py
+++ /dev/null
@@ -1,480 +0,0 @@
-# Copyright 2014 eBay Inc.
-#
-# Author: Ron Rickard <rrickard@ebaysf.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_log import log
-import oslo_messaging as messaging
-from mock import call
-from mock import Mock
-from mock import patch
-
-from designate import exceptions
-from designate import objects
-from designate.utils import generate_uuid
-from designate.backend import impl_fake
-from designate.central import rpcapi as central_rpcapi
-from designate.mdns import rpcapi as mdns_rpcapi
-from designate.storage.impl_sqlalchemy import tables
-from designate.tests.test_pool_manager import PoolManagerTestCase
-from designate.tests.test_pool_manager import POOL_DICT
-import designate.pool_manager.service as pm_module
-
-LOG = log.getLogger(__name__)
-
-
-class PoolManagerServiceNoopTest(PoolManagerTestCase):
-
- def setUp(self):
- super(PoolManagerServiceNoopTest, self).setUp()
-
- self.config(
- threshold_percentage=100,
- enable_recovery_timer=False,
- enable_sync_timer=False,
- poll_retry_interval=0,
- poll_max_retries=1,
- cache_driver='noop',
- group='service:pool_manager')
-
- # TODO(kiall): Rework all this pool config etc into a fixture..
- # Configure the Pool ID
- self.config(
- pool_id='794ccc2c-d751-44fe-b57f-8894c9f5c842',
- group='service:pool_manager')
-
- # Start the Service
- with patch.object(
- central_rpcapi.CentralAPI,
- 'get_pool',
- return_value=objects.Pool.from_dict(POOL_DICT)):
- self.service = self.start_service('pool_manager')
- self.cache = self.service.cache
-
- @staticmethod
- def _build_zone(name, action, status, id=None):
- zid = id or '75ea1626-eea7-46b5-acb7-41e5897c2d40'
- values = {
- 'id': zid,
- 'name': name,
- 'pool_id': '794ccc2c-d751-44fe-b57f-8894c9f5c842',
- 'action': action,
- 'serial': 1422062497,
- 'status': status
- }
- return objects.Zone.from_dict(values)
-
- def _build_zones(self, n, action, status):
- return [
- self._build_zone("zone%02X.example." % cnt, action,
- status, id=generate_uuid())
- for cnt in range(n)
- ]
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(mdns_rpcapi.MdnsAPI, 'poll_for_serial_number')
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_create_zone(
- self, mock_update_status, mock_notify_zone_changed,
- mock_poll_for_serial_number, _):
- zone = self._build_zone('example.org.', 'CREATE', 'PENDING')
-
- self.service.create_zone(self.admin_context, zone)
-
- create_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'CREATE')
- # Even though _retrieve_statuses tries to get from mdns, mdns does
- # not return any status
- self.assertEqual(0, len(create_statuses))
-
- # Ensure poll_for_serial_number was called for each nameserver.
- self.assertEqual(2, mock_poll_for_serial_number.call_count)
- self.assertEqual(
- [call(self.admin_context, zone,
- self.service.pool.nameservers[0], 30, 0, 1, 5),
- call(self.admin_context, zone,
- self.service.pool.nameservers[1], 30, 0, 1, 5)],
- mock_poll_for_serial_number.call_args_list)
-
- # Pool manager needs to call into mdns to calculate consensus as
- # there is no cache. So update_status is never called.
- self.assertFalse(mock_update_status.called)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(impl_fake.FakeBackend, 'create_zone')
- @patch.object(mdns_rpcapi.MdnsAPI, 'poll_for_serial_number')
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_create_zone_target_both_failure(
- self, mock_update_status, mock_notify_zone_changed,
- mock_poll_for_serial_number, mock_create_zone, _):
- zone = self._build_zone('example.org.', 'CREATE', 'PENDING')
-
- mock_create_zone.side_effect = exceptions.Backend
-
- self.service.create_zone(self.admin_context, zone)
-
- create_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'CREATE')
- self.assertEqual(0, len(create_statuses))
-
- # Since consensus is not reached this early, we immediately call
- # central's update_status.
- self.assertTrue(mock_update_status.called)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(impl_fake.FakeBackend, 'create_zone')
- @patch.object(mdns_rpcapi.MdnsAPI, 'poll_for_serial_number')
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_create_zone_target_one_failure(
- self, mock_update_status, mock_notify_zone_changed,
- mock_poll_for_serial_number, mock_create_zone, _):
-
- zone = self._build_zone('example.org.', 'CREATE', 'PENDING')
-
- mock_create_zone.side_effect = [exceptions.Backend, None]
-
- self.service.create_zone(self.admin_context, zone)
-
- create_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'CREATE')
- self.assertEqual(0, len(create_statuses))
-
- # Since consensus is not reached this early, we immediately call
- # central's update_status.
- self.assertTrue(mock_update_status.called)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(impl_fake.FakeBackend, 'create_zone')
- @patch.object(mdns_rpcapi.MdnsAPI, 'poll_for_serial_number')
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_create_zone_target_one_failure_consensus(
- self, mock_update_status, mock_notify_zone_changed,
- mock_poll_for_serial_number, mock_create_zone, _):
-
- self.service.stop()
- self.config(
- threshold_percentage=50,
- group='service:pool_manager')
- with patch.object(
- central_rpcapi.CentralAPI,
- 'get_pool',
- return_value=objects.Pool.from_dict(POOL_DICT)):
- self.service = self.start_service('pool_manager')
-
- zone = self._build_zone('example.org.', 'CREATE', 'PENDING')
-
- mock_create_zone.side_effect = [None, exceptions.Backend]
-
- self.service.create_zone(self.admin_context, zone)
-
- create_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'CREATE')
- self.assertEqual(0, len(create_statuses))
-
- # Ensure poll_for_serial_number was called for each nameserver.
- self.assertFalse(mock_update_status.called)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_update_status(self, mock_update_status, _):
-
- zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[0],
- 'SUCCESS', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- # Ensure update_status was not called.
- self.assertFalse(mock_update_status.called)
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[1],
- 'SUCCESS', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- # Ensure update_status was not called.
- self.assertFalse(mock_update_status.called)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_update_status_both_failure(self, mock_update_status, _):
- zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[0],
- 'ERROR', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- mock_update_status.assert_called_once_with(
- self.admin_context, zone.id, 'ERROR', 0)
-
- # Reset the mock call attributes.
- mock_update_status.reset_mock()
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[1],
- 'ERROR', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- mock_update_status.assert_called_once_with(
- self.admin_context, zone.id, 'ERROR', 0)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_update_status_one_failure(self, mock_update_status, _):
- zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[0],
- 'SUCCESS', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- # Ensure update_status was not called.
- self.assertFalse(mock_update_status.called)
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[1],
- 'ERROR', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- mock_update_status.assert_called_once_with(
- self.admin_context, zone.id, 'ERROR', 0)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'get_serial_number',
- side_effect=messaging.MessagingException)
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_update_status_one_failure_consensus(self, mock_update_status, _):
-
- self.service.stop()
- self.config(
- threshold_percentage=50,
- group='service:pool_manager')
- with patch.object(
- central_rpcapi.CentralAPI,
- 'get_pool',
- return_value=objects.Pool.from_dict(POOL_DICT)):
- self.service = self.start_service('pool_manager')
-
- zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[0],
- 'SUCCESS', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- # Ensure update_status was not called.
- self.assertFalse(mock_update_status.called)
-
- # Reset the mock call attributes.
- mock_update_status.reset_mock()
-
- self.service.update_status(self.admin_context, zone,
- self.service.pool.nameservers[1],
- 'ERROR', zone.serial)
-
- update_statuses = self.service._retrieve_statuses(
- self.admin_context, zone, 'UPDATE')
- self.assertEqual(0, len(update_statuses))
-
- mock_update_status.assert_called_once_with(
- self.admin_context, zone.id, 'ERROR', 0)
-
- @patch.object(central_rpcapi.CentralAPI, 'find_zones')
- def test_periodic_sync_not_leader(self, mock_find_zones):
- self.service._update_zone_on_target = Mock(return_value=False)
- self.service._pool_election = Mock()
- self.service._pool_election.is_leader = False
- self.service.update_zone = Mock()
-
- self.service.periodic_sync()
- self.assertFalse(mock_find_zones.called)
-
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- def test_update_zone_no_consensus(self, mock_cent_update_status):
- zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
- self.service._update_zone_on_target = Mock(return_value=True)
- self.service._exceed_or_meet_threshold = Mock(return_value=False)
-
- ret = self.service.update_zone(self.admin_context, zone)
- self.assertFalse(ret)
-
- self.assertEqual(2, self.service._update_zone_on_target.call_count)
- self.assertEqual(1, mock_cent_update_status.call_count)
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'poll_for_serial_number')
- def test_update_zone(self, mock_mdns_poll):
- zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
- self.service._update_zone_on_target = Mock(return_value=True)
- self.service._update_zone_on_also_notify = Mock()
- self.service.pool.also_notifies = objects.PoolAlsoNotifyList(
- objects=[objects.PoolAlsoNotify(host='1.0.0.0', port=1)]
- )
- self.service._exceed_or_meet_threshold = Mock(return_value=True)
-
- # cache.retrieve will throw exceptions.PoolManagerStatusNotFound
- # mdns_api.poll_for_serial_number will be called twice
- ret = self.service.update_zone(self.admin_context, zone)
- self.assertTrue(ret)
-
- self.assertEqual(2, self.service._update_zone_on_target.call_count)
- self.assertEqual(1, self.service._update_zone_on_also_notify.call_count) # noqa
- self.assertEqual(2, mock_mdns_poll.call_count)
-
- # Periodic sync
-
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- @patch.object(central_rpcapi.CentralAPI, 'find_zones')
- def test_periodic_sync(self, mock_find_zones,
- mock_cent_update_status, *a):
- self.service.update_zone = Mock()
- mock_find_zones.return_value = self._build_zones(2, 'UPDATE',
- 'PENDING')
- self.service.periodic_sync()
-
- self.assertEqual(1, mock_find_zones.call_count)
- criterion = mock_find_zones.call_args_list[0][0][1]
- self.assertEqual('!ERROR', criterion['status'])
- self.assertEqual(2, self.service.update_zone.call_count)
- self.assertEqual(0, mock_cent_update_status.call_count)
-
- @patch.object(pm_module.time, 'sleep')
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- @patch.object(central_rpcapi.CentralAPI, 'find_zones')
- def test_periodic_sync_with_failing_update(
- self, mock_find_zones, mock_cent_update_status, *mocks):
- self.service.update_zone = Mock(return_value=False) # fail update
- mock_find_zones.return_value = self._build_zones(3, 'UPDATE',
- 'PENDING')
- self.service.periodic_sync()
-
- self.assertEqual(1, mock_find_zones.call_count)
- criterion = mock_find_zones.call_args_list[0][0][1]
- self.assertEqual('!ERROR', criterion['status'])
-
- # 3 zones, all failing, with 3 attempts: 9 calls
- self.assertEqual(9, self.service.update_zone.call_count)
-
- # the zones have been put in ERROR status
- self.assertEqual(3, mock_cent_update_status.call_count)
-
- @patch.object(pm_module.time, 'sleep')
- @patch.object(mdns_rpcapi.MdnsAPI, 'notify_zone_changed')
- @patch.object(central_rpcapi.CentralAPI, 'update_status')
- @patch.object(central_rpcapi.CentralAPI, 'find_zones')
- def test_periodic_sync_with_failing_update_with_exception(
- self, mock_find_zones, mock_cent_update_status, *mocks):
- self.service.update_zone = Mock(side_effect=Exception)
- mock_find_zones.return_value = self._build_zones(3, 'UPDATE',
- 'PENDING')
- self.service.periodic_sync()
-
- self.assertEqual(1, mock_find_zones.call_count)
- criterion = mock_find_zones.call_args_list[0][0][1]
- self.assertEqual('!ERROR', criterion['status'])
-
- # 3 zones, all failing, with 3 attempts: 9 calls
- self.assertEqual(9, self.service.update_zone.call_count)
-
- # the zones have been put in ERROR status
- self.assertEqual(3, mock_cent_update_status.call_count)
-
-
-class PoolManagerServiceEndToEndTest(PoolManagerServiceNoopTest):
-
- def setUp(self):
- super(PoolManagerServiceEndToEndTest, self).setUp()
-
- def _fetch_all_zones(self):
- """Fetch all zones including deleted ones
- """
- query = tables.zones.select()
- return self.storage.session.execute(query).fetchall()
-
- def _log_all_zones(self, zones, msg=None):
- """Log out a summary of zones
- """
- if msg:
- LOG.debug("--- %s ---" % msg)
- cols = ('name', 'status', 'action', 'deleted', 'deleted_at',
- 'parent_zone_id')
- tpl = "%-35s | %-11s | %-11s | %-32s | %-20s | %s"
- LOG.debug(tpl % cols)
- for z in zones:
- LOG.debug(tpl % tuple(z[k] for k in cols))
-
- def _assert_count_all_zones(self, n):
- """Assert count ALL zones including deleted ones
- """
- zones = self._fetch_all_zones()
- if len(zones) == n:
- return
-
- msg = "failed: %d zones expected, %d found" % (n, len(zones))
- self._log_all_zones(zones, msg=msg)
- raise Exception("Unexpected number of zones")
-
- def _assert_num_failed_zones(self, action, n):
- zones = self.service._get_failed_zones(
- self.admin_context, action)
- if len(zones) != n:
- LOG.error("Expected %d failed zones, got %d", n, len(zones))
- self._log_all_zones(zones, msg='listing zones')
- self.assertEqual(n, len(zones))
-
- def _assert_num_healthy_zones(self, action, n):
- criterion = {
- 'action': action,
- 'pool_id': pm_module.CONF['service:pool_manager'].pool_id,
- 'status': '!%s' % pm_module.ERROR_STATUS
- }
- zones = self.service.central_api.find_zones(self.admin_context,
- criterion)
- if len(zones) != n:
- LOG.error("Expected %d healthy zones, got %d", n, len(zones))
- self._log_all_zones(zones, msg='listing zones')
- self.assertEqual(n, len(zones))