# Copyright 2013 New Dream Network, LLC (DreamHost) # Copyright 2015 Rackspace # # 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 neutron import context from neutron.extensions import portbindings from neutron.openstack.common import uuidutils from neutron.plugins.common import constants from neutron.tests.unit import testlib_api from six import moves from neutron_lbaas.db.loadbalancer import loadbalancer_dbv2 as ldb from neutron_lbaas.db.loadbalancer import models as db_models from neutron_lbaas.drivers.common import agent_callbacks from neutron_lbaas.extensions import loadbalancerv2 from neutron_lbaas.services.loadbalancer import constants as lb_const from neutron_lbaas.services.loadbalancer import data_models from neutron_lbaas.tests.unit.drivers.common import test_agent_driver_base class TestLoadBalancerCallbacks( test_agent_driver_base.TestLoadBalancerPluginBase): def setUp(self): super(TestLoadBalancerCallbacks, self).setUp() self.callbacks = agent_callbacks.LoadBalancerCallbacks( self.plugin_instance ) get_lbaas_agents_patcher = mock.patch( 'neutron_lbaas.agent_scheduler.LbaasAgentSchedulerDbMixin.' 'get_lbaas_agents') get_lbaas_agents_patcher.start() def test_get_ready_devices(self): with self.loadbalancer() as loadbalancer: lb_id = loadbalancer['loadbalancer']['id'] self.plugin_instance.db.update_loadbalancer_provisioning_status( context.get_admin_context(), loadbalancer['loadbalancer']['id']) with mock.patch( 'neutron_lbaas.agent_scheduler.LbaasAgentSchedulerDbMixin.' 'list_loadbalancers_on_lbaas_agent') as mock_agent_lbs: mock_agent_lbs.return_value = [ data_models.LoadBalancer(id=lb_id)] ready = self.callbacks.get_ready_devices( context.get_admin_context(), ) self.assertEqual(ready, [lb_id]) def test_get_ready_devices_multiple_listeners_and_loadbalancers(self): ctx = context.get_admin_context() # add 3 load balancers and 2 listeners directly to DB # to create 2 "ready" devices and one load balancer without listener loadbalancers = [] for i in moves.xrange(3): loadbalancers.append(ldb.models.LoadBalancer( id=uuidutils.generate_uuid(), vip_subnet_id=self._subnet_id, provisioning_status=constants.ACTIVE, admin_state_up=True, operating_status=constants.ACTIVE)) ctx.session.add(loadbalancers[i]) listener0 = ldb.models.Listener( id=uuidutils.generate_uuid(), protocol="HTTP", loadbalancer_id=loadbalancers[0].id, provisioning_status=constants.ACTIVE, admin_state_up=True, connection_limit=3, protocol_port=80, operating_status=constants.ACTIVE) ctx.session.add(listener0) loadbalancers[0].listener_id = listener0.id listener1 = ldb.models.Listener( id=uuidutils.generate_uuid(), protocol="HTTP", loadbalancer_id=loadbalancers[1].id, provisioning_status=constants.ACTIVE, admin_state_up=True, connection_limit=3, protocol_port=80, operating_status=constants.ACTIVE) ctx.session.add(listener1) loadbalancers[1].listener_id = listener1.id ctx.session.flush() self.assertEqual(ctx.session.query(ldb.models.LoadBalancer).count(), 3) self.assertEqual(ctx.session.query(ldb.models.Listener).count(), 2) with mock.patch( 'neutron_lbaas.agent_scheduler.LbaasAgentSchedulerDbMixin' '.list_loadbalancers_on_lbaas_agent') as mock_agent_lbs: mock_agent_lbs.return_value = loadbalancers ready = self.callbacks.get_ready_devices(ctx) self.assertEqual(len(ready), 3) self.assertIn(loadbalancers[0].id, ready) self.assertIn(loadbalancers[1].id, ready) self.assertIn(loadbalancers[2].id, ready) # cleanup ctx.session.query(ldb.models.Listener).delete() ctx.session.query(ldb.models.LoadBalancer).delete() def test_get_ready_devices_inactive_loadbalancer(self): with self.loadbalancer() as loadbalancer: lb_id = loadbalancer['loadbalancer']['id'] self.plugin_instance.db.update_loadbalancer_provisioning_status( context.get_admin_context(), loadbalancer['loadbalancer']['id']) # set the loadbalancer inactive need to use plugin directly since # status is not tenant mutable self.plugin_instance.db.update_loadbalancer( context.get_admin_context(), loadbalancer['loadbalancer']['id'], {'loadbalancer': {'provisioning_status': constants.INACTIVE}} ) with mock.patch( 'neutron_lbaas.agent_scheduler.LbaasAgentSchedulerDbMixin.' 'list_loadbalancers_on_lbaas_agent') as mock_agent_lbs: mock_agent_lbs.return_value = [ data_models.LoadBalancer(id=lb_id)] ready = self.callbacks.get_ready_devices( context.get_admin_context(), ) self.assertEqual([loadbalancer['loadbalancer']['id']], ready) def test_get_loadbalancer_active(self): with self.loadbalancer() as loadbalancer: ctx = context.get_admin_context() # activate objects self.plugin_instance.db.update_status( ctx, db_models.LoadBalancer, loadbalancer['loadbalancer']['id'], 'ACTIVE') lb = self.plugin_instance.db.get_loadbalancer( ctx, loadbalancer['loadbalancer']['id'] ) load_balancer = self.callbacks.get_loadbalancer( ctx, loadbalancer['loadbalancer']['id'] ) expected_lb = lb.to_dict() expected_lb['provider']['device_driver'] = 'dummy' subnet = self.plugin_instance.db._core_plugin.get_subnet( ctx, expected_lb['vip_subnet_id']) expected_lb['vip_port']['fixed_ips'][0]['subnet'] = subnet del expected_lb['stats'] self.assertEqual(expected_lb, load_balancer) def _update_port_test_helper(self, expected, func, **kwargs): core = self.plugin_instance.db._core_plugin with self.loadbalancer() as loadbalancer: lb_id = loadbalancer['loadbalancer']['id'] if 'device_id' not in expected: expected['device_id'] = lb_id self.plugin_instance.db.update_loadbalancer_provisioning_status( context.get_admin_context(), loadbalancer['loadbalancer']['id']) ctx = context.get_admin_context() db_lb = self.plugin_instance.db.get_loadbalancer(ctx, lb_id) func(ctx, port_id=db_lb.vip_port_id, **kwargs) db_port = core.get_port(ctx, db_lb.vip_port_id) for k, v in expected.iteritems(): self.assertEqual(db_port[k], v) def test_plug_vip_port(self): exp = { 'admin_state_up': True } self._update_port_test_helper( exp, self.callbacks.plug_vip_port, host='host' ) def test_plug_vip_port_mock_with_host(self): exp = { 'admin_state_up': True, portbindings.HOST_ID: 'host' } with mock.patch.object( self.plugin.db._core_plugin, 'update_port') as mock_update_port: with self.loadbalancer() as loadbalancer: lb_id = loadbalancer['loadbalancer']['id'] ctx = context.get_admin_context() self.callbacks.update_status(ctx, 'loadbalancer', lb_id, constants.ACTIVE) (self.plugin_instance.db .update_loadbalancer_provisioning_status(ctx, lb_id)) db_lb = self.plugin_instance.db.get_loadbalancer(ctx, lb_id) self.callbacks.plug_vip_port(ctx, port_id=db_lb.vip_port_id, host='host') mock_update_port.assert_called_once_with( ctx, db_lb.vip_port_id, {'port': testlib_api.SubDictMatch(exp)}) def test_unplug_vip_port(self): exp = { 'device_owner': '', 'device_id': '', 'admin_state_up': False } self._update_port_test_helper( exp, self.callbacks.unplug_vip_port, host='host' ) def test_loadbalancer_deployed(self): with self.loadbalancer() as loadbalancer: ctx = context.get_admin_context() l = self.plugin_instance.db.get_loadbalancer( ctx, loadbalancer['loadbalancer']['id']) self.assertEqual('PENDING_CREATE', l.provisioning_status) self.callbacks.loadbalancer_deployed( ctx, loadbalancer['loadbalancer']['id']) l = self.plugin_instance.db.get_loadbalancer( ctx, loadbalancer['loadbalancer']['id']) self.assertEqual('ACTIVE', l.provisioning_status) def test_listener_deployed(self): with self.loadbalancer(no_delete=True) as loadbalancer: self.plugin_instance.db.update_loadbalancer_provisioning_status( context.get_admin_context(), loadbalancer['loadbalancer']['id']) with self.listener( loadbalancer_id=loadbalancer[ 'loadbalancer']['id']) as listener: ctx = context.get_admin_context() l = self.plugin_instance.db.get_loadbalancer( ctx, loadbalancer['loadbalancer']['id']) self.assertEqual('PENDING_UPDATE', l.provisioning_status) ll = self.plugin_instance.db.get_listener( ctx, listener['listener']['id']) self.assertEqual('PENDING_CREATE', ll.provisioning_status) self.callbacks.loadbalancer_deployed( ctx, loadbalancer['loadbalancer']['id']) l = self.plugin_instance.db.get_loadbalancer( ctx, loadbalancer['loadbalancer']['id']) self.assertEqual('ACTIVE', l.provisioning_status) ll = self.plugin_instance.db.get_listener( ctx, listener['listener']['id']) self.assertEqual('ACTIVE', ll.provisioning_status) def test_update_status_loadbalancer(self): with self.loadbalancer() as loadbalancer: loadbalancer_id = loadbalancer['loadbalancer']['id'] ctx = context.get_admin_context() l = self.plugin_instance.db.get_loadbalancer(ctx, loadbalancer_id) self.assertEqual('PENDING_CREATE', l.provisioning_status) self.callbacks.update_status(ctx, 'loadbalancer', loadbalancer_id, provisioning_status=constants.ACTIVE, operating_status=lb_const.ONLINE) l = self.plugin_instance.db.get_loadbalancer(ctx, loadbalancer_id) self.assertEqual(constants.ACTIVE, l.provisioning_status) self.assertEqual(lb_const.ONLINE, l.operating_status) def test_update_status_loadbalancer_deleted_already(self): with mock.patch.object(agent_callbacks, 'LOG') as mock_log: loadbalancer_id = 'deleted_lb' ctx = context.get_admin_context() self.assertRaises(loadbalancerv2.EntityNotFound, self.plugin_instance.get_loadbalancer, ctx, loadbalancer_id) self.callbacks.update_status(ctx, 'loadbalancer', loadbalancer_id, provisioning_status=constants.ACTIVE) self.assertTrue(mock_log.warning.called)