From 4a68c5e4ab92daa31d8af47a91a2d8e45c185817 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Fri, 8 Feb 2013 21:32:20 -0500 Subject: More conductor support for resizes This patch adds more support for resizes to conductor, which apparently are not getting tested in the "full" tempest gate. This adds network_migrate_instance_{start,finish}() calls to conductor, which offloads the network_api calls of similar name over RPC for components that can't take the DB hit of calling network_api directly. Also, in quota, the commit and rollback calls hit the database, so export those from conductor as well. This is likely the source of the failures in bug 1119817 Change-Id: I56bb65b0e168e36e138cf6bf125d6e83bf71f50b --- nova/compute/manager.py | 38 ++++++++++++++++++++-------------- nova/conductor/api.py | 32 ++++++++++++++++++++++++++++ nova/conductor/manager.py | 28 +++++++++++++++++++++++-- nova/conductor/rpcapi.py | 27 ++++++++++++++++++++++++ nova/tests/compute/test_compute.py | 22 +++++++++++--------- nova/tests/conductor/test_conductor.py | 34 ++++++++++++++++++++++++++++++ 6 files changed, 153 insertions(+), 28 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index bb4af94a6..a2b42c7c3 100755 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1840,8 +1840,9 @@ class ComputeManager(manager.SchedulerDependentManager): self.network_api.setup_networks_on_host(context, instance, teardown=True) - self.network_api.migrate_instance_start(context, instance, - migration) + self.conductor_api.network_migrate_instance_start(context, + instance, + migration) network_info = self._get_instance_nw_info(context, instance) block_device_info = self._get_instance_volume_block_device_info( @@ -1920,8 +1921,9 @@ class ComputeManager(manager.SchedulerDependentManager): instance['uuid'], launched_at=timeutils.utcnow(), expected_task_state=task_states.RESIZE_REVERTING) - self.network_api.migrate_instance_finish(context, instance, - migration) + self.conductor_api.network_migrate_instance_finish(context, + instance, + migration) instance = self._instance_update(context, instance['uuid'], vm_state=vm_states.ACTIVE, task_state=None) @@ -1934,15 +1936,13 @@ class ComputeManager(manager.SchedulerDependentManager): self._quota_commit(context, reservations) - @staticmethod - def _quota_commit(context, reservations): + def _quota_commit(self, context, reservations): if reservations: - QUOTAS.commit(context, reservations) + self.conductor_api.quota_commit(context, reservations) - @staticmethod - def _quota_rollback(context, reservations): + def _quota_rollback(self, context, reservations): if reservations: - QUOTAS.rollback(context, reservations) + self.conductor_api.quota_rollback(context, reservations) def _prep_resize(self, context, image, instance, instance_type, reservations, request_spec, filter_properties, node): @@ -2096,8 +2096,9 @@ class ComputeManager(manager.SchedulerDependentManager): self._terminate_volume_connections(context, instance) - self.network_api.migrate_instance_start(context, instance, - migration) + self.conductor_api.network_migrate_instance_start(context, + instance, + migration) migration = self.conductor_api.migration_update(context, migration, 'post-migrating') @@ -2156,8 +2157,9 @@ class ComputeManager(manager.SchedulerDependentManager): self.network_api.setup_networks_on_host(context, instance, migration['dest_compute']) - self.network_api.migrate_instance_finish(context, instance, - migration) + self.conductor_api.network_migrate_instance_finish(context, + instance, + migration) network_info = self._get_instance_nw_info(context, instance) @@ -2864,7 +2866,9 @@ class ComputeManager(manager.SchedulerDependentManager): migration = {'source_compute': self.host, 'dest_compute': dest, } - self.network_api.migrate_instance_start(ctxt, instance_ref, migration) + self.conductor_api.network_migrate_instance_start(ctxt, + instance_ref, + migration) # Define domain at destination host, without doing it, # pause/suspend/terminate do not work. @@ -2919,7 +2923,9 @@ class ComputeManager(manager.SchedulerDependentManager): self.host) migration = {'source_compute': instance['host'], 'dest_compute': self.host, } - self.network_api.migrate_instance_finish(context, instance, migration) + self.conductor_api.network_migrate_instance_finish(context, + instance, + migration) network_info = self._get_instance_nw_info(context, instance) block_device_info = self._get_instance_volume_block_device_info( diff --git a/nova/conductor/api.py b/nova/conductor/api.py index 3b193fff8..50f59d9d6 100644 --- a/nova/conductor/api.py +++ b/nova/conductor/api.py @@ -303,6 +303,22 @@ class LocalAPI(object): return self._manager.security_groups_trigger_members_refresh(context, group_ids) + def network_migrate_instance_start(self, context, instance, migration): + return self._manager.network_migrate_instance_start(context, + instance, + migration) + + def network_migrate_instance_finish(self, context, instance, migration): + return self._manager.network_migrate_instance_finish(context, + instance, + migration) + + def quota_commit(self, context, reservations): + return self._manager.quota_commit(context, reservations) + + def quota_rollback(self, context, reservations): + return self._manager.quota_rollback(context, reservations) + class API(object): """Conductor API that does updates via RPC to the ConductorManager.""" @@ -604,3 +620,19 @@ class API(object): def security_groups_trigger_members_refresh(self, context, group_ids): return self.conductor_rpcapi.security_groups_trigger_members_refresh( context, group_ids) + + def network_migrate_instance_start(self, context, instance, migration): + return self.conductor_rpcapi.network_migrate_instance_start(context, + instance, + migration) + + def network_migrate_instance_finish(self, context, instance, migration): + return self.conductor_rpcapi.network_migrate_instance_finish(context, + instance, + migration) + + def quota_commit(self, context, reservations): + return self.conductor_rpcapi.quota_commit(context, reservations) + + def quota_rollback(self, context, reservations): + return self.conductor_rpcapi.quota_rollback(context, reservations) diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py index 0d2031a4a..905d2e2cd 100644 --- a/nova/conductor/manager.py +++ b/nova/conductor/manager.py @@ -18,12 +18,13 @@ from nova.compute import api as compute_api from nova.compute import utils as compute_utils from nova import exception from nova import manager +from nova import network from nova import notifications from nova.openstack.common import jsonutils from nova.openstack.common import log as logging from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils - +from nova import quota LOG = logging.getLogger(__name__) @@ -46,12 +47,23 @@ datetime_fields = ['launched_at', 'terminated_at'] class ConductorManager(manager.SchedulerDependentManager): """Mission: TBD.""" - RPC_API_VERSION = '1.40' + RPC_API_VERSION = '1.41' def __init__(self, *args, **kwargs): super(ConductorManager, self).__init__(service_name='conductor', *args, **kwargs) self.security_group_api = compute_api.SecurityGroupAPI() + self._network_api = None + self.quotas = quota.QUOTAS + + @property + def network_api(self): + # NOTE(danms): We need to instantiate our network_api on first use + # to avoid the circular dependency that exists between our init + # and network_api's + if self._network_api is None: + self._network_api = network.API() + return self._network_api def ping(self, context, arg): return jsonutils.to_primitive({'service': 'conductor', 'arg': arg}) @@ -360,3 +372,15 @@ class ConductorManager(manager.SchedulerDependentManager): def security_groups_trigger_members_refresh(self, context, group_ids): self.security_group_api.trigger_members_refresh(context, group_ids) + + def network_migrate_instance_start(self, context, instance, migration): + self.network_api.migrate_instance_start(context, instance, migration) + + def network_migrate_instance_finish(self, context, instance, migration): + self.network_api.migrate_instance_finish(context, instance, migration) + + def quota_commit(self, context, reservations): + quota.QUOTAS.commit(context, reservations) + + def quota_rollback(self, context, reservations): + quota.QUOTAS.rollback(context, reservations) diff --git a/nova/conductor/rpcapi.py b/nova/conductor/rpcapi.py index f5ce0b4cb..58613e59a 100644 --- a/nova/conductor/rpcapi.py +++ b/nova/conductor/rpcapi.py @@ -75,6 +75,9 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy): 1.40 - Added security_groups_trigger_handler and security_groups_trigger_members_refresh Remove instance_get_active_by_window + 1.41 - Added fixed_ip_get_by_instance, network_get, + instance_floating_address_get_all, quota_commit, + quota_rollback """ BASE_RPC_API_VERSION = '1.0' @@ -382,3 +385,27 @@ class ConductorAPI(nova.openstack.common.rpc.proxy.RpcProxy): msg = self.make_msg('security_groups_trigger_members_refresh', group_ids=group_ids) return self.call(context, msg, version='1.40') + + def network_migrate_instance_start(self, context, instance, migration): + instance_p = jsonutils.to_primitive(instance) + migration_p = jsonutils.to_primitive(migration) + msg = self.make_msg('network_migrate_instance_start', + instance=instance_p, migration=migration_p) + return self.call(context, msg, version='1.41') + + def network_migrate_instance_finish(self, context, instance, migration): + instance_p = jsonutils.to_primitive(instance) + migration_p = jsonutils.to_primitive(migration) + msg = self.make_msg('network_migrate_instance_finish', + instance=instance_p, migration=migration_p) + return self.call(context, msg, version='1.41') + + def quota_commit(self, context, reservations): + reservations_p = jsonutils.to_primitive(reservations) + msg = self.make_msg('quota_commit', reservations=reservations_p) + return self.call(context, msg, version='1.41') + + def quota_rollback(self, context, reservations): + reservations_p = jsonutils.to_primitive(reservations) + msg = self.make_msg('quota_rollback', reservations=reservations_p) + return self.call(context, msg, version='1.41') diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 442832553..1ec626d1a 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -2640,10 +2640,11 @@ class ComputeTestCase(BaseTestCase): # creating mocks self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance') self.compute.driver.unfilter_instance(inst_ref, []) - self.mox.StubOutWithMock(self.compute.network_api, - 'migrate_instance_start') + self.mox.StubOutWithMock(self.compute.conductor_api, + 'network_migrate_instance_start') migration = {'source_compute': srchost, 'dest_compute': dest, } - self.compute.network_api.migrate_instance_start(c, inst_ref, migration) + self.compute.conductor_api.network_migrate_instance_start(c, inst_ref, + migration) self.mox.StubOutWithMock(rpc, 'call') rpc.call(c, rpc.queue_get_for(c, CONF.compute_topic, dest), {"method": "post_live_migration_at_destination", @@ -2684,11 +2685,12 @@ class ComputeTestCase(BaseTestCase): # creating mocks self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance') self.compute.driver.unfilter_instance(inst_ref, []) - self.mox.StubOutWithMock(self.compute.network_api, - 'migrate_instance_start') + self.mox.StubOutWithMock(self.compute.conductor_api, + 'network_migrate_instance_start') migration = {'source_compute': srchost, 'dest_compute': dest, } - self.compute.network_api.migrate_instance_start(c, inst_ref, migration) + self.compute.conductor_api.network_migrate_instance_start(c, inst_ref, + migration) self.mox.StubOutWithMock(rpc, 'call') rpc.call(c, rpc.queue_get_for(c, CONF.compute_topic, dest), {"method": "post_live_migration_at_destination", @@ -2710,8 +2712,8 @@ class ComputeTestCase(BaseTestCase): def test_post_live_migration_at_destination(self): self.mox.StubOutWithMock(self.compute.network_api, 'setup_networks_on_host') - self.mox.StubOutWithMock(self.compute.network_api, - 'migrate_instance_finish') + self.mox.StubOutWithMock(self.compute.conductor_api, + 'network_migrate_instance_finish') self.mox.StubOutWithMock(self.compute, '_get_power_state') self.mox.StubOutWithMock(self.compute, '_instance_update') @@ -2726,8 +2728,8 @@ class ComputeTestCase(BaseTestCase): self.compute.host) migration = {'source_compute': instance['host'], 'dest_compute': self.compute.host, } - self.compute.network_api.migrate_instance_finish(admin_ctxt, - instance, migration) + self.compute.conductor_api.network_migrate_instance_finish(admin_ctxt, + instance, migration) fake_net_info = [] fake_block_dev_info = {'foo': 'bar'} self.compute.driver.post_live_migration_at_destination(admin_ctxt, diff --git a/nova/tests/conductor/test_conductor.py b/nova/tests/conductor/test_conductor.py index bd73328e8..5c9ce9e5f 100644 --- a/nova/tests/conductor/test_conductor.py +++ b/nova/tests/conductor/test_conductor.py @@ -31,6 +31,7 @@ from nova import notifications from nova.openstack.common import jsonutils from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils +from nova import quota from nova import test @@ -503,6 +504,39 @@ class _BaseTestCase(object): self.conductor.security_groups_trigger_members_refresh(self.context, [1, 2, 3]) + def test_network_migrate_instance_start(self): + self.mox.StubOutWithMock(self.conductor_manager.network_api, + 'migrate_instance_start') + self.conductor_manager.network_api.migrate_instance_start(self.context, + 'instance', + 'migration') + self.mox.ReplayAll() + self.conductor.network_migrate_instance_start(self.context, + 'instance', + 'migration') + + def test_network_migrate_instance_finish(self): + self.mox.StubOutWithMock(self.conductor_manager.network_api, + 'migrate_instance_finish') + self.conductor_manager.network_api.migrate_instance_finish( + self.context, 'instance', 'migration') + self.mox.ReplayAll() + self.conductor.network_migrate_instance_finish(self.context, + 'instance', + 'migration') + + def test_quota_commit(self): + self.mox.StubOutWithMock(quota.QUOTAS, 'commit') + quota.QUOTAS.commit(self.context, 'reservations') + self.mox.ReplayAll() + self.conductor.quota_commit(self.context, 'reservations') + + def test_quota_commit(self): + self.mox.StubOutWithMock(quota.QUOTAS, 'rollback') + quota.QUOTAS.rollback(self.context, 'reservations') + self.mox.ReplayAll() + self.conductor.quota_rollback(self.context, 'reservations') + class ConductorTestCase(_BaseTestCase, test.TestCase): """Conductor Manager Tests.""" -- cgit