2fa3558c40
Replace agent based driver files from haproxy driver dir Same for unit tests files Finalizes blueprint lbaas-common-agent-driver Change-Id: Ibff85a9c2e1f1c59d72616836d56a697dce72c59
370 lines
16 KiB
Python
370 lines
16 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
#
|
|
# Copyright 2013 New Dream Network, LLC (DreamHost)
|
|
#
|
|
# 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.
|
|
#
|
|
# @author: Mark McClain, DreamHost
|
|
|
|
import contextlib
|
|
|
|
import mock
|
|
|
|
from neutron.plugins.common import constants
|
|
from neutron.services.loadbalancer.agent import agent_manager as manager
|
|
from neutron.tests import base
|
|
|
|
|
|
class TestManager(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(TestManager, self).setUp()
|
|
self.addCleanup(mock.patch.stopall)
|
|
|
|
mock_conf = mock.Mock()
|
|
mock_conf.device_driver = ['devdriver']
|
|
|
|
self.mock_importer = mock.patch.object(manager, 'importutils').start()
|
|
|
|
rpc_mock_cls = mock.patch(
|
|
'neutron.services.loadbalancer.agent.agent_api.LbaasAgentApi'
|
|
).start()
|
|
|
|
self.mgr = manager.LbaasAgentManager(mock_conf)
|
|
self.rpc_mock = rpc_mock_cls.return_value
|
|
self.log = mock.patch.object(manager, 'LOG').start()
|
|
self.driver_mock = mock.Mock()
|
|
self.mgr.device_drivers = {'devdriver': self.driver_mock}
|
|
self.mgr.instance_mapping = {'1': 'devdriver', '2': 'devdriver'}
|
|
self.mgr.needs_resync = False
|
|
|
|
def test_initialize_service_hook(self):
|
|
with mock.patch.object(self.mgr, 'sync_state') as sync:
|
|
self.mgr.initialize_service_hook(mock.Mock())
|
|
sync.assert_called_once_with()
|
|
|
|
def test_periodic_resync_needs_sync(self):
|
|
with mock.patch.object(self.mgr, 'sync_state') as sync:
|
|
self.mgr.needs_resync = True
|
|
self.mgr.periodic_resync(mock.Mock())
|
|
sync.assert_called_once_with()
|
|
|
|
def test_periodic_resync_no_sync(self):
|
|
with mock.patch.object(self.mgr, 'sync_state') as sync:
|
|
self.mgr.needs_resync = False
|
|
self.mgr.periodic_resync(mock.Mock())
|
|
self.assertFalse(sync.called)
|
|
|
|
def test_collect_stats(self):
|
|
self.mgr.collect_stats(mock.Mock())
|
|
self.rpc_mock.update_pool_stats.assert_has_calls([
|
|
mock.call('1', mock.ANY),
|
|
mock.call('2', mock.ANY)
|
|
])
|
|
|
|
def test_collect_stats_exception(self):
|
|
self.driver_mock.get_stats.side_effect = Exception
|
|
|
|
self.mgr.collect_stats(mock.Mock())
|
|
|
|
self.assertFalse(self.rpc_mock.called)
|
|
self.assertTrue(self.mgr.needs_resync)
|
|
self.assertTrue(self.log.exception.called)
|
|
|
|
def _sync_state_helper(self, ready, reloaded, destroyed):
|
|
with contextlib.nested(
|
|
mock.patch.object(self.mgr, '_reload_pool'),
|
|
mock.patch.object(self.mgr, '_destroy_pool')
|
|
) as (reload, destroy):
|
|
|
|
self.rpc_mock.get_ready_devices.return_value = ready
|
|
|
|
self.mgr.sync_state()
|
|
|
|
self.assertEqual(len(reloaded), len(reload.mock_calls))
|
|
self.assertEqual(len(destroyed), len(destroy.mock_calls))
|
|
|
|
reload.assert_has_calls([mock.call(i) for i in reloaded])
|
|
destroy.assert_has_calls([mock.call(i) for i in destroyed])
|
|
self.assertFalse(self.mgr.needs_resync)
|
|
|
|
def test_sync_state_all_known(self):
|
|
self._sync_state_helper(['1', '2'], ['1', '2'], [])
|
|
|
|
def test_sync_state_all_unknown(self):
|
|
self.mgr.instance_mapping = {}
|
|
self._sync_state_helper(['1', '2'], ['1', '2'], [])
|
|
|
|
def test_sync_state_destroy_all(self):
|
|
self._sync_state_helper([], [], ['1', '2'])
|
|
|
|
def test_sync_state_both(self):
|
|
self.mgr.instance_mapping = {'1': 'devdriver'}
|
|
self._sync_state_helper(['2'], ['2'], ['1'])
|
|
|
|
def test_sync_state_exception(self):
|
|
self.rpc_mock.get_ready_devices.side_effect = Exception
|
|
|
|
self.mgr.sync_state()
|
|
|
|
self.assertTrue(self.log.exception.called)
|
|
self.assertTrue(self.mgr.needs_resync)
|
|
|
|
def test_reload_pool(self):
|
|
config = {'driver': 'devdriver'}
|
|
self.rpc_mock.get_logical_device.return_value = config
|
|
pool_id = 'new_id'
|
|
self.assertNotIn(pool_id, self.mgr.instance_mapping)
|
|
|
|
self.mgr._reload_pool(pool_id)
|
|
|
|
self.driver_mock.deploy_instance.assert_called_once_with(config)
|
|
self.assertIn(pool_id, self.mgr.instance_mapping)
|
|
self.rpc_mock.pool_deployed.assert_called_once_with(pool_id)
|
|
|
|
def test_reload_pool_driver_not_found(self):
|
|
config = {'driver': 'unknown_driver'}
|
|
self.rpc_mock.get_logical_device.return_value = config
|
|
pool_id = 'new_id'
|
|
self.assertNotIn(pool_id, self.mgr.instance_mapping)
|
|
|
|
self.mgr._reload_pool(pool_id)
|
|
|
|
self.assertTrue(self.log.error.called)
|
|
self.assertFalse(self.driver_mock.deploy_instance.called)
|
|
self.assertNotIn(pool_id, self.mgr.instance_mapping)
|
|
self.assertFalse(self.rpc_mock.pool_deployed.called)
|
|
|
|
def test_reload_pool_exception_on_driver(self):
|
|
config = {'driver': 'devdriver'}
|
|
self.rpc_mock.get_logical_device.return_value = config
|
|
self.driver_mock.deploy_instance.side_effect = Exception
|
|
pool_id = 'new_id'
|
|
self.assertNotIn(pool_id, self.mgr.instance_mapping)
|
|
|
|
self.mgr._reload_pool(pool_id)
|
|
|
|
self.driver_mock.deploy_instance.assert_called_once_with(config)
|
|
self.assertNotIn(pool_id, self.mgr.instance_mapping)
|
|
self.assertFalse(self.rpc_mock.pool_deployed.called)
|
|
self.assertTrue(self.log.exception.called)
|
|
self.assertTrue(self.mgr.needs_resync)
|
|
|
|
def test_destroy_pool(self):
|
|
pool_id = '1'
|
|
self.assertIn(pool_id, self.mgr.instance_mapping)
|
|
|
|
self.mgr._destroy_pool(pool_id)
|
|
|
|
self.driver_mock.undeploy_instance.assert_called_once_with(pool_id)
|
|
self.assertNotIn(pool_id, self.mgr.instance_mapping)
|
|
self.rpc_mock.pool_destroyed.assert_called_once_with(pool_id)
|
|
self.assertFalse(self.mgr.needs_resync)
|
|
|
|
def test_destroy_pool_exception_on_driver(self):
|
|
pool_id = '1'
|
|
self.assertIn(pool_id, self.mgr.instance_mapping)
|
|
self.driver_mock.undeploy_instance.side_effect = Exception
|
|
|
|
self.mgr._destroy_pool(pool_id)
|
|
|
|
self.driver_mock.undeploy_instance.assert_called_once_with(pool_id)
|
|
self.assertIn(pool_id, self.mgr.instance_mapping)
|
|
self.assertFalse(self.rpc_mock.pool_destroyed.called)
|
|
self.assertTrue(self.log.exception.called)
|
|
self.assertTrue(self.mgr.needs_resync)
|
|
|
|
def test_get_driver_unknown_device(self):
|
|
self.assertRaises(manager.DeviceNotFoundOnAgent,
|
|
self.mgr._get_driver, 'unknown')
|
|
|
|
def test_remove_orphans(self):
|
|
self.mgr.remove_orphans()
|
|
self.driver_mock.remove_orphans.assert_called_once_with(['1', '2'])
|
|
|
|
def test_create_vip(self):
|
|
vip = {'id': 'id1', 'pool_id': '1'}
|
|
self.mgr.create_vip(mock.Mock(), vip)
|
|
self.driver_mock.create_vip.assert_called_once_with(vip)
|
|
self.rpc_mock.update_status.assert_called_once_with('vip', vip['id'],
|
|
constants.ACTIVE)
|
|
|
|
def test_create_vip_failed(self):
|
|
vip = {'id': 'id1', 'pool_id': '1'}
|
|
self.driver_mock.create_vip.side_effect = Exception
|
|
self.mgr.create_vip(mock.Mock(), vip)
|
|
self.driver_mock.create_vip.assert_called_once_with(vip)
|
|
self.rpc_mock.update_status.assert_called_once_with('vip', vip['id'],
|
|
constants.ERROR)
|
|
|
|
def test_update_vip(self):
|
|
old_vip = {'id': 'id1'}
|
|
vip = {'id': 'id1', 'pool_id': '1'}
|
|
self.mgr.update_vip(mock.Mock(), old_vip, vip)
|
|
self.driver_mock.update_vip.assert_called_once_with(old_vip, vip)
|
|
self.rpc_mock.update_status.assert_called_once_with('vip', vip['id'],
|
|
constants.ACTIVE)
|
|
|
|
def test_update_vip_failed(self):
|
|
old_vip = {'id': 'id1'}
|
|
vip = {'id': 'id1', 'pool_id': '1'}
|
|
self.driver_mock.update_vip.side_effect = Exception
|
|
self.mgr.update_vip(mock.Mock(), old_vip, vip)
|
|
self.driver_mock.update_vip.assert_called_once_with(old_vip, vip)
|
|
self.rpc_mock.update_status.assert_called_once_with('vip', vip['id'],
|
|
constants.ERROR)
|
|
|
|
def test_delete_vip(self):
|
|
vip = {'id': 'id1', 'pool_id': '1'}
|
|
self.mgr.delete_vip(mock.Mock(), vip)
|
|
self.driver_mock.delete_vip.assert_called_once_with(vip)
|
|
|
|
def test_create_pool(self):
|
|
pool = {'id': 'id1'}
|
|
self.assertNotIn(pool['id'], self.mgr.instance_mapping)
|
|
self.mgr.create_pool(mock.Mock(), pool, 'devdriver')
|
|
self.driver_mock.create_pool.assert_called_once_with(pool)
|
|
self.rpc_mock.update_status.assert_called_once_with('pool', pool['id'],
|
|
constants.ACTIVE)
|
|
self.assertIn(pool['id'], self.mgr.instance_mapping)
|
|
|
|
def test_create_pool_failed(self):
|
|
pool = {'id': 'id1'}
|
|
self.assertNotIn(pool['id'], self.mgr.instance_mapping)
|
|
self.driver_mock.create_pool.side_effect = Exception
|
|
self.mgr.create_pool(mock.Mock(), pool, 'devdriver')
|
|
self.driver_mock.create_pool.assert_called_once_with(pool)
|
|
self.rpc_mock.update_status.assert_called_once_with('pool', pool['id'],
|
|
constants.ERROR)
|
|
self.assertNotIn(pool['id'], self.mgr.instance_mapping)
|
|
|
|
def test_update_pool(self):
|
|
old_pool = {'id': '1'}
|
|
pool = {'id': '1'}
|
|
self.mgr.update_pool(mock.Mock(), old_pool, pool)
|
|
self.driver_mock.update_pool.assert_called_once_with(old_pool, pool)
|
|
self.rpc_mock.update_status.assert_called_once_with('pool', pool['id'],
|
|
constants.ACTIVE)
|
|
|
|
def test_update_pool_failed(self):
|
|
old_pool = {'id': '1'}
|
|
pool = {'id': '1'}
|
|
self.driver_mock.update_pool.side_effect = Exception
|
|
self.mgr.update_pool(mock.Mock(), old_pool, pool)
|
|
self.driver_mock.update_pool.assert_called_once_with(old_pool, pool)
|
|
self.rpc_mock.update_status.assert_called_once_with('pool', pool['id'],
|
|
constants.ERROR)
|
|
|
|
def test_delete_pool(self):
|
|
pool = {'id': '1'}
|
|
self.assertIn(pool['id'], self.mgr.instance_mapping)
|
|
self.mgr.delete_pool(mock.Mock(), pool)
|
|
self.driver_mock.delete_pool.assert_called_once_with(pool)
|
|
self.assertNotIn(pool['id'], self.mgr.instance_mapping)
|
|
|
|
def test_create_member(self):
|
|
member = {'id': 'id1', 'pool_id': '1'}
|
|
self.mgr.create_member(mock.Mock(), member)
|
|
self.driver_mock.create_member.assert_called_once_with(member)
|
|
self.rpc_mock.update_status.assert_called_once_with('member',
|
|
member['id'],
|
|
constants.ACTIVE)
|
|
|
|
def test_create_member_failed(self):
|
|
member = {'id': 'id1', 'pool_id': '1'}
|
|
self.driver_mock.create_member.side_effect = Exception
|
|
self.mgr.create_member(mock.Mock(), member)
|
|
self.driver_mock.create_member.assert_called_once_with(member)
|
|
self.rpc_mock.update_status.assert_called_once_with('member',
|
|
member['id'],
|
|
constants.ERROR)
|
|
|
|
def test_update_member(self):
|
|
old_member = {'id': 'id1'}
|
|
member = {'id': 'id1', 'pool_id': '1'}
|
|
self.mgr.update_member(mock.Mock(), old_member, member)
|
|
self.driver_mock.update_member.assert_called_once_with(old_member,
|
|
member)
|
|
self.rpc_mock.update_status.assert_called_once_with('member',
|
|
member['id'],
|
|
constants.ACTIVE)
|
|
|
|
def test_update_member_failed(self):
|
|
old_member = {'id': 'id1'}
|
|
member = {'id': 'id1', 'pool_id': '1'}
|
|
self.driver_mock.update_member.side_effect = Exception
|
|
self.mgr.update_member(mock.Mock(), old_member, member)
|
|
self.driver_mock.update_member.assert_called_once_with(old_member,
|
|
member)
|
|
self.rpc_mock.update_status.assert_called_once_with('member',
|
|
member['id'],
|
|
constants.ERROR)
|
|
|
|
def test_delete_member(self):
|
|
member = {'id': 'id1', 'pool_id': '1'}
|
|
self.mgr.delete_member(mock.Mock(), member)
|
|
self.driver_mock.delete_member.assert_called_once_with(member)
|
|
|
|
def test_create_monitor(self):
|
|
monitor = {'id': 'id1'}
|
|
assoc_id = {'monitor_id': monitor['id'], 'pool_id': '1'}
|
|
self.mgr.create_pool_health_monitor(mock.Mock(), monitor, '1')
|
|
self.driver_mock.create_pool_health_monitor.assert_called_once_with(
|
|
monitor, '1')
|
|
self.rpc_mock.update_status.assert_called_once_with('health_monitor',
|
|
assoc_id,
|
|
constants.ACTIVE)
|
|
|
|
def test_create_monitor_failed(self):
|
|
monitor = {'id': 'id1'}
|
|
assoc_id = {'monitor_id': monitor['id'], 'pool_id': '1'}
|
|
self.driver_mock.create_pool_health_monitor.side_effect = Exception
|
|
self.mgr.create_pool_health_monitor(mock.Mock(), monitor, '1')
|
|
self.driver_mock.create_pool_health_monitor.assert_called_once_with(
|
|
monitor, '1')
|
|
self.rpc_mock.update_status.assert_called_once_with('health_monitor',
|
|
assoc_id,
|
|
constants.ERROR)
|
|
|
|
def test_update_monitor(self):
|
|
monitor = {'id': 'id1'}
|
|
assoc_id = {'monitor_id': monitor['id'], 'pool_id': '1'}
|
|
self.mgr.update_pool_health_monitor(mock.Mock(), monitor, monitor, '1')
|
|
self.driver_mock.update_pool_health_monitor.assert_called_once_with(
|
|
monitor, monitor, '1')
|
|
self.rpc_mock.update_status.assert_called_once_with('health_monitor',
|
|
assoc_id,
|
|
constants.ACTIVE)
|
|
|
|
def test_update_monitor_failed(self):
|
|
monitor = {'id': 'id1'}
|
|
assoc_id = {'monitor_id': monitor['id'], 'pool_id': '1'}
|
|
self.driver_mock.update_pool_health_monitor.side_effect = Exception
|
|
self.mgr.update_pool_health_monitor(mock.Mock(), monitor, monitor, '1')
|
|
self.driver_mock.update_pool_health_monitor.assert_called_once_with(
|
|
monitor, monitor, '1')
|
|
self.rpc_mock.update_status.assert_called_once_with('health_monitor',
|
|
assoc_id,
|
|
constants.ERROR)
|
|
|
|
def test_delete_monitor(self):
|
|
monitor = {'id': 'id1'}
|
|
self.mgr.delete_pool_health_monitor(mock.Mock(), monitor, '1')
|
|
self.driver_mock.delete_pool_health_monitor.assert_called_once_with(
|
|
monitor, '1')
|
|
|
|
def test_agent_disabled(self):
|
|
payload = {'admin_state_up': False}
|
|
self.mgr.agent_updated(mock.Mock(), payload)
|
|
self.driver_mock.undeploy_instance.assert_has_calls(
|
|
[mock.call('1'), mock.call('2')])
|