summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Kearney <josh@jk0.org>2011-07-08 22:36:22 +0000
committerTarmac <>2011-07-08 22:36:22 +0000
commita5dc12c586f34fd92c7846ce7ec8ec2b86cc09de (patch)
tree4cbf11f40f5cb9ae715d37c9d3c6ff800f3ee5c3
parent282ac84e652d807a3927012192b5f79cc74d6426 (diff)
parent93fe8b7844561f3872aa5afa5e85e7baf25f3ff4 (diff)
downloadnova-a5dc12c586f34fd92c7846ce7ec8ec2b86cc09de.tar.gz
nova-a5dc12c586f34fd92c7846ce7ec8ec2b86cc09de.tar.xz
nova-a5dc12c586f34fd92c7846ce7ec8ec2b86cc09de.zip
Make the instance migration calls available via the API.
-rw-r--r--nova/api/openstack/servers.py10
-rw-r--r--nova/compute/api.py24
-rw-r--r--nova/tests/api/openstack/test_servers.py17
-rw-r--r--nova/tests/test_compute.py8
4 files changed, 52 insertions, 7 deletions
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index fc1ab8d46..eacc2109f 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -176,7 +176,7 @@ class Controller(object):
'confirmResize': self._action_confirm_resize,
'revertResize': self._action_revert_resize,
'rebuild': self._action_rebuild,
- }
+ 'migrate': self._action_migrate}
for key in actions.keys():
if key in body:
@@ -220,6 +220,14 @@ class Controller(object):
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()
+ def _action_migrate(self, input_dict, req, id):
+ try:
+ self.compute_api.resize(req.environ['nova.context'], id)
+ except Exception, e:
+ LOG.exception(_("Error in migrate %s"), e)
+ return faults.Fault(exc.HTTPBadRequest())
+ return exc.HTTPAccepted()
+
@scheduler_api.redirect_handler
def lock(self, req, id):
"""
diff --git a/nova/compute/api.py b/nova/compute/api.py
index b0eedcd64..edd1a4d64 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -855,13 +855,24 @@ class API(base.Base):
self.db.instance_update(context, instance_id,
{'host': migration_ref['dest_compute'], })
- def resize(self, context, instance_id, flavor_id):
- """Resize a running instance."""
+ def resize(self, context, instance_id, flavor_id=None):
+ """Resize (ie, migrate) a running instance.
+
+ If flavor_id is None, the process is considered a migration, keeping
+ the original flavor_id. If flavor_id is not None, the instance should
+ be migrated to a new host and resized to the new flavor_id.
+ """
instance = self.db.instance_get(context, instance_id)
current_instance_type = instance['instance_type']
- new_instance_type = self.db.instance_type_get_by_flavor_id(
- context, flavor_id)
+ # If flavor_id is not provided, only migrate the instance.
+ if not flavor_id:
+ LOG.debug(_("flavor_id is None. Assuming migration."))
+ new_instance_type = current_instance_type
+ else:
+ new_instance_type = self.db.instance_type_get_by_flavor_id(
+ context, flavor_id)
+
current_instance_type_name = current_instance_type['name']
new_instance_type_name = new_instance_type['name']
LOG.debug(_("Old instance type %(current_instance_type_name)s, "
@@ -875,7 +886,8 @@ class API(base.Base):
if current_memory_mb > new_memory_mb:
raise exception.ApiError(_("Invalid flavor: cannot downsize"
"instances"))
- if current_memory_mb == new_memory_mb:
+
+ if (current_memory_mb == new_memory_mb) and flavor_id:
raise exception.ApiError(_("Invalid flavor: cannot use"
"the same flavor. "))
@@ -883,7 +895,7 @@ class API(base.Base):
{"method": "prep_resize",
"args": {"topic": FLAGS.compute_topic,
"instance_id": instance_id,
- "flavor_id": flavor_id}})
+ "flavor_id": new_instance_type['id']}})
@scheduler_api.reroute_compute("add_fixed_ip")
def add_fixed_ip(self, context, instance_id, network_id):
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 0cb16b4c0..1f369c4c8 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -1557,6 +1557,23 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_migrate_server(self):
+ """This is basically the same as resize, only we provide the `migrate`
+ attribute in the body's dict.
+ """
+ req = self.webreq('/1/action', 'POST', dict(migrate=None))
+
+ self.resize_called = False
+
+ def resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.resize_called, True)
+
def test_shutdown_status(self):
new_server = return_server_with_power_state(power_state.SHUTDOWN)
self.stubs.Set(nova.db.api, 'instance_get', new_server)
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 45cd2f764..04bb194d5 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -532,6 +532,14 @@ class ComputeTestCase(test.TestCase):
self.context, instance_id, 1)
self.compute.terminate_instance(self.context, instance_id)
+ def test_migrate(self):
+ context = self.context.elevated()
+ instance_id = self._create_instance()
+ self.compute.run_instance(self.context, instance_id)
+ # Migrate simply calls resize() without a flavor_id.
+ self.compute_api.resize(context, instance_id, None)
+ self.compute.terminate_instance(context, instance_id)
+
def _setup_other_managers(self):
self.volume_manager = utils.import_object(FLAGS.volume_manager)
self.network_manager = utils.import_object(FLAGS.network_manager)