summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-11-28 15:27:57 +0000
committerGerrit Code Review <review@openstack.org>2012-11-28 15:27:57 +0000
commite2c0174a76b7cdc9471a35a8a5d26cc6479b13e2 (patch)
tree6ad9f308831c1a7b172e0a0d8665cddf3b024dd1
parentb424512f9f5a7b74103b68c21a48f2ad6b9aa79e (diff)
parent8a3c7d30914c7cd1f85583316980ece3c33ed3d1 (diff)
downloadnova-e2c0174a76b7cdc9471a35a8a5d26cc6479b13e2.tar.gz
nova-e2c0174a76b7cdc9471a35a8a5d26cc6479b13e2.tar.xz
nova-e2c0174a76b7cdc9471a35a8a5d26cc6479b13e2.zip
Merge "Make resize and multi-node work properly together"
-rw-r--r--nova/compute/manager.py16
-rw-r--r--nova/compute/resource_tracker.py17
-rw-r--r--nova/compute/rpcapi.py8
-rw-r--r--nova/conductor/manager.py2
-rw-r--r--nova/db/api.py8
-rw-r--r--nova/db/sqlalchemy/api.py9
-rw-r--r--nova/scheduler/filter_scheduler.py3
-rw-r--r--nova/tests/compute/test_resource_tracker.py11
-rw-r--r--nova/tests/compute/test_rpcapi.py3
-rw-r--r--nova/tests/scheduler/test_filter_scheduler.py2
-rw-r--r--nova/tests/test_db_api.py32
11 files changed, 71 insertions, 40 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index a0835d107..7d793ad8c 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -307,7 +307,7 @@ class ComputeVirtAPI(virtapi.VirtAPI):
class ComputeManager(manager.SchedulerDependentManager):
"""Manages the running instances from creation to destruction."""
- RPC_API_VERSION = '2.19'
+ RPC_API_VERSION = '2.20'
def __init__(self, compute_driver=None, *args, **kwargs):
"""Load configuration options and connect to the hypervisor."""
@@ -1770,7 +1770,7 @@ class ComputeManager(manager.SchedulerDependentManager):
QUOTAS.rollback(context, reservations)
def _prep_resize(self, context, image, instance, instance_type,
- reservations, request_spec, filter_properties):
+ reservations, request_spec, filter_properties, node):
if not filter_properties:
filter_properties = {}
@@ -1787,7 +1787,7 @@ class ComputeManager(manager.SchedulerDependentManager):
raise exception.MigrationError(msg)
limits = filter_properties.get('limits', {})
- rt = self._get_resource_tracker(instance.get('node'))
+ rt = self._get_resource_tracker(node)
with rt.resize_claim(context, instance, instance_type, limits=limits) \
as claim:
migration_ref = claim.migration
@@ -1802,12 +1802,17 @@ class ComputeManager(manager.SchedulerDependentManager):
@wrap_instance_fault
def prep_resize(self, context, image, instance, instance_type,
reservations=None, request_spec=None,
- filter_properties=None):
+ filter_properties=None, node=None):
"""Initiates the process of moving a running instance to another host.
Possibly changes the RAM and disk size in the process.
"""
+ if node is None:
+ node = self.driver.get_available_nodes()[0]
+ LOG.debug(_("No node specified, defaulting to %(node)s") %
+ locals())
+
with self._error_out_instance_on_exception(context, instance['uuid'],
reservations):
compute_utils.notify_usage_exists(
@@ -1816,7 +1821,7 @@ class ComputeManager(manager.SchedulerDependentManager):
context, instance, "resize.prep.start")
try:
self._prep_resize(context, image, instance, instance_type,
- reservations, request_spec, filter_properties)
+ reservations, request_spec, filter_properties, node)
except Exception:
# try to re-schedule the resize elsewhere:
self._reschedule_resize_or_reraise(context, image, instance,
@@ -1911,6 +1916,7 @@ class ComputeManager(manager.SchedulerDependentManager):
instance = self._instance_update(context, instance['uuid'],
host=migration['dest_compute'],
+ node=migration['dest_node'],
task_state=task_states.RESIZE_MIGRATED,
expected_task_state=task_states.
RESIZE_MIGRATING)
diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py
index ac46f31da..b3e9538bd 100644
--- a/nova/compute/resource_tracker.py
+++ b/nova/compute/resource_tracker.py
@@ -167,7 +167,9 @@ class ResourceTracker(object):
return db.migration_create(context.elevated(),
{'instance_uuid': instance['uuid'],
'source_compute': instance['host'],
+ 'source_node': instance['node'],
'dest_compute': self.host,
+ 'dest_node': self.nodename,
'dest_host': self.driver.get_host_ip_addr(),
'old_instance_type_id': old_instance_type['id'],
'new_instance_type_id': instance_type['id'],
@@ -258,7 +260,8 @@ class ResourceTracker(object):
self._update_usage_from_instances(resources, instances)
# Grab all in-progress migrations:
- migrations = db.migration_get_in_progress_by_host(context, self.host)
+ migrations = db.migration_get_in_progress_by_host_and_node(context,
+ self.host, self.nodename)
self._update_usage_from_migrations(resources, migrations)
@@ -377,15 +380,17 @@ class ResourceTracker(object):
uuid = migration['instance_uuid']
LOG.audit(_("Updating from migration %s") % uuid)
- incoming = (migration['dest_compute'] == self.host)
- outbound = (migration['source_compute'] == self.host)
- same_host = (incoming and outbound)
+ incoming = (migration['dest_compute'] == self.host and
+ migration['dest_node'] == self.nodename)
+ outbound = (migration['source_compute'] == self.host and
+ migration['source_node'] == self.nodename)
+ same_node = (incoming and outbound)
instance = self.tracked_instances.get(uuid, None)
itype = None
- if same_host:
- # same host resize. record usage for whichever instance type the
+ if same_node:
+ # same node resize. record usage for whichever instance type the
# instance is *not* in:
if (instance['instance_type_id'] ==
migration['old_instance_type_id']):
diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py
index 6f69a3cd8..bdb2c4d2d 100644
--- a/nova/compute/rpcapi.py
+++ b/nova/compute/rpcapi.py
@@ -147,6 +147,7 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
2.17 - Add get_backdoor_port()
2.18 - Add bdms to rebuild_instance
2.19 - Add node to run_instance
+ 2.20 - Add node to prep_resize
'''
#
@@ -357,16 +358,17 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
def prep_resize(self, ctxt, image, instance, instance_type, host,
reservations=None, request_spec=None,
- filter_properties=None):
+ filter_properties=None, node=None):
instance_p = jsonutils.to_primitive(instance)
instance_type_p = jsonutils.to_primitive(instance_type)
self.cast(ctxt, self.make_msg('prep_resize',
instance=instance_p, instance_type=instance_type_p,
image=image, reservations=reservations,
request_spec=request_spec,
- filter_properties=filter_properties),
+ filter_properties=filter_properties,
+ node=node),
_compute_topic(self.topic, ctxt, host, None),
- version='2.10')
+ version='2.20')
def reboot_instance(self, ctxt, instance,
block_device_info, network_info, reboot_type):
diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py
index 6270fb241..4cb6672f4 100644
--- a/nova/conductor/manager.py
+++ b/nova/conductor/manager.py
@@ -24,7 +24,7 @@ LOG = logging.getLogger(__name__)
allowed_updates = ['task_state', 'vm_state', 'expected_task_state',
'power_state', 'access_ip_v4', 'access_ip_v6',
- 'launched_at', 'terminated_at', 'host',
+ 'launched_at', 'terminated_at', 'host', 'node',
'memory_mb', 'vcpus', 'root_gb', 'ephemeral_gb',
'instance_type_id', 'root_device_name', 'host',
'progress', 'vm_mode', 'default_ephemeral_device',
diff --git a/nova/db/api.py b/nova/db/api.py
index ebad6ffae..b496e4bd0 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -404,11 +404,11 @@ def migration_get_unconfirmed_by_dest_compute(context, confirm_window,
confirm_window, dest_compute)
-def migration_get_in_progress_by_host(context, host):
- """Finds all migrations for the given host that are not yet confirmed or
- reverted.
+def migration_get_in_progress_by_host_and_node(context, host, node):
+ """Finds all migrations for the given host + node that are not yet
+ confirmed or reverted.
"""
- return IMPL.migration_get_in_progress_by_host(context, host)
+ return IMPL.migration_get_in_progress_by_host_and_node(context, host, node)
####################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 96666079a..cf5561d8b 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -3394,11 +3394,14 @@ def migration_get_unconfirmed_by_dest_compute(context, confirm_window,
@require_admin_context
-def migration_get_in_progress_by_host(context, host, session=None):
+def migration_get_in_progress_by_host_and_node(context, host, node,
+ session=None):
return model_query(context, models.Migration, session=session).\
- filter(or_(models.Migration.source_compute == host,
- models.Migration.dest_compute == host)).\
+ filter(or_(and_(models.Migration.source_compute == host,
+ models.Migration.source_node == node),
+ and_(models.Migration.dest_compute == host,
+ models.Migration.dest_node == node))).\
filter(~models.Migration.status.in_(['confirmed', 'reverted'])).\
options(joinedload('instance')).\
all()
diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py
index 7e158765a..03fd9cd1a 100644
--- a/nova/scheduler/filter_scheduler.py
+++ b/nova/scheduler/filter_scheduler.py
@@ -117,7 +117,8 @@ class FilterScheduler(driver.Scheduler):
# Forward off to the host
self.compute_rpcapi.prep_resize(context, image, instance,
instance_type, weighed_host.obj.host, reservations,
- request_spec=request_spec, filter_properties=filter_properties)
+ request_spec=request_spec, filter_properties=filter_properties,
+ node=weighed_host.obj.nodename)
def _provision_resource(self, context, weighed_host, request_spec,
filter_properties, requested_networks, injected_files,
diff --git a/nova/tests/compute/test_resource_tracker.py b/nova/tests/compute/test_resource_tracker.py
index 85d6c3dd6..ac18e9505 100644
--- a/nova/tests/compute/test_resource_tracker.py
+++ b/nova/tests/compute/test_resource_tracker.py
@@ -321,8 +321,8 @@ class BaseTrackerTestCase(BaseTestCase):
self._fake_compute_node_update)
self.stubs.Set(db, 'migration_update',
self._fake_migration_update)
- self.stubs.Set(db, 'migration_get_in_progress_by_host',
- self._fake_migration_get_in_progress_by_host)
+ self.stubs.Set(db, 'migration_get_in_progress_by_host_and_node',
+ self._fake_migration_get_in_progress_by_host_and_node)
self.tracker.update_available_resource(self.context)
self.limits = self._limits()
@@ -352,7 +352,8 @@ class BaseTrackerTestCase(BaseTestCase):
self.compute.update(values)
return self.compute
- def _fake_migration_get_in_progress_by_host(self, ctxt, host):
+ def _fake_migration_get_in_progress_by_host_and_node(self, ctxt, host,
+ node):
status = ['confirmed', 'reverted']
migrations = []
@@ -615,7 +616,9 @@ class ResizeClaimTestCase(BaseTrackerTestCase):
migration = {
'id': 1,
'source_compute': 'host1',
+ 'source_node': 'fakenode',
'dest_compute': 'host2',
+ 'dest_node': 'fakenode',
'dest_host': '127.0.0.1',
'old_instance_type_id': 1,
'new_instance_type_id': 2,
@@ -722,7 +725,7 @@ class ResizeClaimTestCase(BaseTrackerTestCase):
def test_revert_reserve_source(self):
# if a revert has started at the API and audit runs on
# the source compute before the instance flips back to source,
- # resources should still be help at the source based on the
+ # resources should still be held at the source based on the
# migration:
dest = "desthost"
dest_tracker = self._tracker(host=dest)
diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py
index d0796a27d..54d8d47c7 100644
--- a/nova/tests/compute/test_rpcapi.py
+++ b/nova/tests/compute/test_rpcapi.py
@@ -228,7 +228,8 @@ class ComputeRpcAPITestCase(test.TestCase):
reservations=list('fake_res'),
request_spec='fake_spec',
filter_properties={'fakeprop': 'fakeval'},
- version='2.10')
+ node='node',
+ version='2.20')
def test_reboot_instance(self):
self.maxDiff = None
diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py
index e9412ba60..d44c79b72 100644
--- a/nova/tests/scheduler/test_filter_scheduler.py
+++ b/nova/tests/scheduler/test_filter_scheduler.py
@@ -329,7 +329,7 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
[instance['uuid']]).AndReturn(weighed_hosts)
sched.compute_rpcapi.prep_resize(self.context, image, instance,
instance_type, 'host', reservations, request_spec=request_spec,
- filter_properties=filter_properties)
+ filter_properties=filter_properties, node='node')
self.mox.ReplayAll()
sched.schedule_prep_resize(self.context, image, request_spec,
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index 21e37d609..7f28c9397 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -1164,19 +1164,20 @@ class MigrationTestCase(test.TestCase):
self._create()
self._create(status='reverted')
self._create(status='confirmed')
- self._create(source_compute='host2', dest_compute='host1')
+ self._create(source_compute='host2', source_node='b',
+ dest_compute='host1', dest_node='a')
self._create(source_compute='host2', dest_compute='host3')
self._create(source_compute='host3', dest_compute='host4')
def _create(self, status='migrating', source_compute='host1',
- dest_compute='host2'):
+ source_node='a', dest_compute='host2', dest_node='b'):
values = {'host': source_compute}
instance = db.instance_create(self.ctxt, values)
values = {'status': status, 'source_compute': source_compute,
- 'dest_compute': dest_compute,
- 'instance_uuid': instance['uuid']}
+ 'source_node': source_node, 'dest_compute': dest_compute,
+ 'dest_node': dest_node, 'instance_uuid': instance['uuid']}
db.migration_create(self.ctxt, values)
def _assert_in_progress(self, migrations):
@@ -1184,20 +1185,29 @@ class MigrationTestCase(test.TestCase):
self.assertNotEqual('confirmed', migration.status)
self.assertNotEqual('reverted', migration.status)
- def test_in_progress_host1(self):
- migrations = db.migration_get_in_progress_by_host(self.ctxt, 'host1')
+ def test_in_progress_host1_nodea(self):
+ migrations = db.migration_get_in_progress_by_host_and_node(self.ctxt,
+ 'host1', 'a')
# 2 as source + 1 as dest
self.assertEqual(3, len(migrations))
self._assert_in_progress(migrations)
- def test_in_progress_host2(self):
- migrations = db.migration_get_in_progress_by_host(self.ctxt, 'host2')
- # 2 as dest, 2 as source
- self.assertEqual(4, len(migrations))
+ def test_in_progress_host1_nodeb(self):
+ migrations = db.migration_get_in_progress_by_host_and_node(self.ctxt,
+ 'host1', 'b')
+ # some migrations are to/from host1, but none with a node 'b'
+ self.assertEqual(0, len(migrations))
+
+ def test_in_progress_host2_nodeb(self):
+ migrations = db.migration_get_in_progress_by_host_and_node(self.ctxt,
+ 'host2', 'b')
+ # 2 as dest, 1 as source
+ self.assertEqual(3, len(migrations))
self._assert_in_progress(migrations)
def test_instance_join(self):
- migrations = db.migration_get_in_progress_by_host(self.ctxt, 'host2')
+ migrations = db.migration_get_in_progress_by_host_and_node(self.ctxt,
+ 'host2', 'b')
for migration in migrations:
instance = migration['instance']
self.assertEqual(migration['instance_uuid'], instance['uuid'])