summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/compute/contrib/consoles.py2
-rw-r--r--nova/exception.py4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_consoles.py17
-rw-r--r--nova/virt/xenapi/vmops.py17
4 files changed, 39 insertions, 1 deletions
diff --git a/nova/api/openstack/compute/contrib/consoles.py b/nova/api/openstack/compute/contrib/consoles.py
index ef61d3966..4f88d033c 100644
--- a/nova/api/openstack/compute/contrib/consoles.py
+++ b/nova/api/openstack/compute/contrib/consoles.py
@@ -48,6 +48,8 @@ class ConsolesController(wsgi.Controller):
console_type)
except exception.InstanceNotFound as e:
raise webob.exc.HTTPNotFound(explanation=unicode(e))
+ except exception.InstanceNotReady as e:
+ raise webob.exc.HTTPConflict(explanation=unicode(e))
return {'console': {'type': console_type, 'url': output['url']}}
diff --git a/nova/exception.py b/nova/exception.py
index 9c579322b..7e3976d0f 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -327,6 +327,10 @@ class InstanceNotInRescueMode(Invalid):
message = _("Instance %(instance_id)s is not in rescue mode")
+class InstanceNotReady(Invalid):
+ message = _("Instance %(instance_id)s is not ready")
+
+
class InstanceSuspendFailure(Invalid):
message = _("Failed to suspend instance") + ": %(reason)s"
diff --git a/nova/tests/api/openstack/compute/contrib/test_consoles.py b/nova/tests/api/openstack/compute/contrib/test_consoles.py
index 8d727a556..887092806 100644
--- a/nova/tests/api/openstack/compute/contrib/test_consoles.py
+++ b/nova/tests/api/openstack/compute/contrib/test_consoles.py
@@ -31,6 +31,10 @@ def fake_get_vnc_console_invalid_type(self, _context,
raise exception.ConsoleTypeInvalid(console_type=_console_type)
+def fake_get_vnc_console_not_ready(self, _context, instance, _console_type):
+ raise exception.InstanceNotReady(instance_id=instance["uuid"])
+
+
def fake_get_vnc_console_not_found(self, _context, instance, _console_type):
raise exception.InstanceNotFound(instance_id=instance["uuid"])
@@ -64,6 +68,19 @@ class ConsolesExtensionTest(test.TestCase):
self.assertEqual(output,
{u'console': {u'url': u'http://fake', u'type': u'novnc'}})
+ def test_get_vnc_console_not_ready(self):
+ self.stubs.Set(compute.API, 'get_vnc_console',
+ fake_get_vnc_console_not_ready)
+ body = {'os-getVNCConsole': {'type': 'novnc'}}
+ 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(fakes.wsgi_app())
+ output = jsonutils.loads(res.body)
+ self.assertEqual(res.status_int, 409)
+
def test_get_vnc_console_no_type(self):
self.stubs.Set(compute.API, 'get', fake_get)
self.stubs.Set(compute.API, 'get_vnc_console',
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 8d443f498..05b2b1579 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -30,6 +30,7 @@ import netaddr
from nova.compute import api as compute
from nova.compute import power_state
from nova.compute import vm_mode
+from nova.compute import vm_states
from nova import context as nova_context
from nova import db
from nova import exception
@@ -1230,7 +1231,21 @@ class VMOps(object):
def get_vnc_console(self, instance):
"""Return connection info for a vnc console."""
- vm_ref = self._get_vm_opaque_ref(instance)
+ # NOTE(johannes): This can fail if the VM object hasn't been created
+ # yet on the dom0. Since that step happens fairly late in the build
+ # process, there's a potential for a race condition here. Until the
+ # VM object is created, return back a 409 error instead of a 404
+ # error.
+ try:
+ vm_ref = self._get_vm_opaque_ref(instance)
+ except exception.NotFound:
+ if instance['vm_state'] != vm_states.BUILDING:
+ raise
+
+ LOG.info(_('Fetching VM ref while BUILDING failed'),
+ instance=instance)
+ raise exception.InstanceNotReady(instance_id=instance['uuid'])
+
session_id = self._session.get_session_id()
path = "/console?ref=%s&session_id=%s" % (str(vm_ref), session_id)