summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhou ShaoYu <hzzhoushaoyu@corp.netease.com>2013-02-05 14:42:53 +0800
committerZhou ShaoYu <hzzhoushaoyu@corp.netease.com>2013-02-05 15:48:10 +0800
commit702fdf2fc1acc32b5ccd9e0830e574c42770ab5d (patch)
tree28abec1117b15e2b206fd403ef40585358b63cfc
parent81da7771aaa6eec79f6b3fd91ce315cd5c5b7e7a (diff)
downloadnova-702fdf2fc1acc32b5ccd9e0830e574c42770ab5d.tar.gz
nova-702fdf2fc1acc32b5ccd9e0830e574c42770ab5d.tar.xz
nova-702fdf2fc1acc32b5ccd9e0830e574c42770ab5d.zip
Fix check instance host for instance action
When instance has no host, actions such as get_console_output, start_stop_instance cause HTTP 500 response. Here change to HTTPConflict when action called before host set. Fix LP# 1116012 Change-Id: I6153a03f449d9fad8d0d8fb7295bdea4d2b2c2b1
-rw-r--r--nova/api/openstack/compute/contrib/console_output.py2
-rw-r--r--nova/api/openstack/compute/contrib/server_start_stop.py10
-rw-r--r--nova/compute/api.py26
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_console_output.py16
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_server_start_stop.py21
-rw-r--r--nova/tests/compute/test_compute.py27
6 files changed, 90 insertions, 12 deletions
diff --git a/nova/api/openstack/compute/contrib/console_output.py b/nova/api/openstack/compute/contrib/console_output.py
index 953459d38..b734cbd13 100644
--- a/nova/api/openstack/compute/contrib/console_output.py
+++ b/nova/api/openstack/compute/contrib/console_output.py
@@ -65,6 +65,8 @@ class ConsoleOutputController(wsgi.Controller):
length)
except exception.NotFound:
raise webob.exc.HTTPNotFound(_('Unable to get console'))
+ except exception.InstanceNotReady as e:
+ raise webob.exc.HTTPConflict(explanation=unicode(e))
# XML output is not correctly escaped, so remove invalid characters
remove_re = re.compile('[\x00-\x08\x0B-\x0C\x0E-\x1F]')
diff --git a/nova/api/openstack/compute/contrib/server_start_stop.py b/nova/api/openstack/compute/contrib/server_start_stop.py
index 733972083..a13aabb05 100644
--- a/nova/api/openstack/compute/contrib/server_start_stop.py
+++ b/nova/api/openstack/compute/contrib/server_start_stop.py
@@ -44,7 +44,10 @@ class ServerStartStopActionController(wsgi.Controller):
context = req.environ['nova.context']
instance = self._get_instance(context, id)
LOG.debug(_('start instance'), instance=instance)
- self.compute_api.start(context, instance)
+ try:
+ self.compute_api.start(context, instance)
+ except exception.InstanceNotReady as e:
+ raise webob.exc.HTTPConflict(explanation=unicode(e))
return webob.Response(status_int=202)
@wsgi.action('os-stop')
@@ -53,7 +56,10 @@ class ServerStartStopActionController(wsgi.Controller):
context = req.environ['nova.context']
instance = self._get_instance(context, id)
LOG.debug(_('stop instance'), instance=instance)
- self.compute_api.stop(context, instance)
+ try:
+ self.compute_api.stop(context, instance)
+ except exception.InstanceNotReady as e:
+ raise webob.exc.HTTPConflict(explanation=unicode(e))
return webob.Response(status_int=202)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 23024ba29..dca91ac2b 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -131,6 +131,15 @@ def check_instance_state(vm_state=None, task_state=(None,)):
return outer
+def check_instance_host(function):
+ @functools.wraps(function)
+ def wrapped(self, context, instance, *args, **kwargs):
+ if not instance['host']:
+ raise exception.InstanceNotReady(instance_id=instance['uuid'])
+ return function(self, context, instance, *args, **kwargs)
+ return wrapped
+
+
def check_instance_lock(function):
@functools.wraps(function)
def inner(self, context, instance, *args, **kwargs):
@@ -1213,6 +1222,7 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
+ @check_instance_host
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED,
vm_states.ERROR, vm_states.STOPPED],
task_state=[None])
@@ -1231,6 +1241,7 @@ class API(base.Base):
@wrap_check_policy
@check_instance_lock
+ @check_instance_host
@check_instance_state(vm_state=[vm_states.STOPPED])
def start(self, context, instance):
"""Start an instance."""
@@ -2135,11 +2146,9 @@ class API(base.Base):
file_contents=file_contents)
@wrap_check_policy
+ @check_instance_host
def get_vnc_console(self, context, instance, console_type):
"""Get a url to an instance Console."""
- if not instance['host']:
- raise exception.InstanceNotReady(instance_id=instance['uuid'])
-
connect_info = self.compute_rpcapi.get_vnc_console(context,
instance=instance, console_type=console_type)
@@ -2149,20 +2158,17 @@ class API(base.Base):
return {'url': connect_info['access_url']}
+ @check_instance_host
def get_vnc_connect_info(self, context, instance, console_type):
"""Used in a child cell to get console info."""
- if not instance['host']:
- raise exception.InstanceNotReady(instance_id=instance['uuid'])
connect_info = self.compute_rpcapi.get_vnc_console(context,
instance=instance, console_type=console_type)
return connect_info
@wrap_check_policy
+ @check_instance_host
def get_spice_console(self, context, instance, console_type):
"""Get a url to an instance Console."""
- if not instance['host']:
- raise exception.InstanceNotReady(instance_id=instance['uuid'])
-
connect_info = self.compute_rpcapi.get_spice_console(context,
instance=instance, console_type=console_type)
@@ -2172,15 +2178,15 @@ class API(base.Base):
return {'url': connect_info['access_url']}
+ @check_instance_host
def get_spice_connect_info(self, context, instance, console_type):
"""Used in a child cell to get console info."""
- if not instance['host']:
- raise exception.InstanceNotReady(instance_id=instance['uuid'])
connect_info = self.compute_rpcapi.get_spice_console(context,
instance=instance, console_type=console_type)
return connect_info
@wrap_check_policy
+ @check_instance_host
def get_console_output(self, context, instance, tail_length=None):
"""Get console output for an instance."""
return self.compute_rpcapi.get_console_output(context,
diff --git a/nova/tests/api/openstack/compute/contrib/test_console_output.py b/nova/tests/api/openstack/compute/contrib/test_console_output.py
index d3f80b655..14b61abb7 100644
--- a/nova/tests/api/openstack/compute/contrib/test_console_output.py
+++ b/nova/tests/api/openstack/compute/contrib/test_console_output.py
@@ -35,6 +35,10 @@ def fake_get_console_output(self, _context, _instance, tail_length):
return '\n'.join(fixture)
+def fake_get_console_output_not_ready(self, _context, _instance, tail_length):
+ raise exception.InstanceNotReady(instance_id=_instance["uuid"])
+
+
def fake_get(self, context, instance_uuid):
return {'uuid': instance_uuid}
@@ -133,3 +137,15 @@ class ConsoleOutputExtensionTest(test.TestCase):
res = req.get_response(self.app)
self.assertEqual(res.status_int, 400)
+
+ def test_get_console_output_not_ready(self):
+ self.stubs.Set(compute_api.API, 'get_console_output',
+ fake_get_console_output_not_ready)
+ body = {'os-getConsoleOutput': {'length': 3}}
+ req = webob.Request.blank('/v2/fake/servers/1/action')
+ req.method = "POST"
+ req.body = jsonutils.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ res = req.get_response(self.app)
+ self.assertEqual(res.status_int, 409)
diff --git a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
index 554379e74..eb708a574 100644
--- a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
+++ b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
@@ -17,6 +17,7 @@ import webob
from nova.api.openstack.compute.contrib import server_start_stop
from nova.compute import api as compute_api
+from nova import exception
from nova import test
from nova.tests.api.openstack import fakes
@@ -25,6 +26,10 @@ def fake_compute_api_get(self, context, instance_id):
return {'id': 1, 'uuid': instance_id}
+def fake_start_stop_not_ready(self, context, instance):
+ raise exception.InstanceNotReady(instance_id=instance["uuid"])
+
+
class ServerStartStopTest(test.TestCase):
def setUp(self):
@@ -41,6 +46,14 @@ class ServerStartStopTest(test.TestCase):
body = dict(start="")
self.controller._start_server(req, 'test_inst', body)
+ def test_start_not_ready(self):
+ self.stubs.Set(compute_api.API, 'get', fake_compute_api_get)
+ self.stubs.Set(compute_api.API, 'start', fake_start_stop_not_ready)
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
+ body = dict(start="")
+ self.assertRaises(webob.exc.HTTPConflict,
+ self.controller._start_server, req, 'test_inst', body)
+
def test_stop(self):
self.stubs.Set(compute_api.API, 'get', fake_compute_api_get)
self.mox.StubOutWithMock(compute_api.API, 'stop')
@@ -51,6 +64,14 @@ class ServerStartStopTest(test.TestCase):
body = dict(stop="")
self.controller._stop_server(req, 'test_inst', body)
+ def test_stop_not_ready(self):
+ self.stubs.Set(compute_api.API, 'get', fake_compute_api_get)
+ self.stubs.Set(compute_api.API, 'stop', fake_start_stop_not_ready)
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
+ body = dict(start="")
+ self.assertRaises(webob.exc.HTTPConflict,
+ self.controller._stop_server, req, 'test_inst', body)
+
def test_start_with_bogus_id(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
body = dict(start="")
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 8b38b51f2..d70114313 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -3783,6 +3783,15 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(self.context, instance['uuid'])
+ def test_start_no_host(self):
+ instance = self._create_fake_instance(params={'host': ''})
+
+ self.assertRaises(exception.InstanceNotReady,
+ self.compute_api.start,
+ self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_stop(self):
instance = jsonutils.to_primitive(self._create_fake_instance())
instance_uuid = instance['uuid']
@@ -3798,6 +3807,15 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(self.context, instance['uuid'])
+ def test_stop_no_host(self):
+ instance = self._create_fake_instance(params={'host': ''})
+
+ self.assertRaises(exception.InstanceNotReady,
+ self.compute_api.stop,
+ self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_start_shutdown(self):
def check_state(instance_uuid, power_state_, vm_state_, task_state_):
instance = db.instance_get_by_uuid(self.context, instance_uuid)
@@ -5636,6 +5654,15 @@ class ComputeAPITestCase(BaseTestCase):
fake_instance, tail_length=fake_tail_length)
self.assertEqual(output, fake_console_output)
+ def test_console_output_no_host(self):
+ instance = self._create_fake_instance(params={'host': ''})
+
+ self.assertRaises(exception.InstanceNotReady,
+ self.compute_api.get_console_output,
+ self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_attach_volume(self):
# Ensure instance can be soft rebooted.