api: add serial console API calls v2

Adds a new REST APIv2 to call service serial console

Co-Authored-By: Ian Wells <iawells@cisco.com>
Co-Authored-By: Sushma Korati <sushma_korati@persistent.co.in>
Co-Authored-By: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>

Patial-Implements: blueprint serial-ports
Change-Id: I35d94c1924caa9cbc0fcdd9c637d28e95ff31ab2
This commit is contained in:
Vladan Popovic 2014-08-11 19:05:36 +01:00 committed by Sahid Orentino Ferdjaoui
parent 9364cdaa3e
commit e89eaf9a7d
11 changed files with 217 additions and 0 deletions

View File

@ -0,0 +1,5 @@
{
"os-getSerialConsole": {
"type": "serial"
}
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<os-getSerialConsole type="serial" />

View File

@ -0,0 +1,6 @@
{
"console": {
"type": "serial",
"url":"http://127.0.0.1:6083/?token=f9906a48-b71e-4f18-baca-c987da3ebdb3"
}
}

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<console>
<type>serial</type>
<url>http://127.0.0.1:6083/?token=f9906a48-b71e-4f18-baca-c987da3ebdb3</url>
</console>

View File

@ -107,6 +107,30 @@ class ConsolesController(wsgi.Controller):
return {'console': {'type': console_type, 'url': output['url']}}
@wsgi.action('os-getSerialConsole')
def get_serial_console(self, req, id, body):
"""Get connection to a serial console."""
context = req.environ['nova.context']
authorize(context)
# If type is not supplied or unknown get_serial_console below will cope
console_type = body['os-getSerialConsole'].get('type')
try:
instance = self.compute_api.get(context, id, want_objects=True)
output = self.compute_api.get_serial_console(context,
instance,
console_type)
except exception.InstanceNotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.format_message())
except exception.InstanceNotReady as e:
raise webob.exc.HTTPConflict(explanation=e.format_message())
except NotImplementedError:
msg = _("Unable to get serial console, "
"functionality not implemented")
raise webob.exc.HTTPNotImplemented(explanation=msg)
return {'console': {'type': console_type, 'url': output['url']}}
class Consoles(extensions.ExtensionDescriptor):
"""Interactive Console support."""

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import webob
from nova.compute import api as compute_api
@ -34,6 +35,10 @@ def fake_get_rdp_console(self, _context, _instance, _console_type):
return {'url': 'http://fake'}
def fake_get_serial_console(self, _context, _instance, _console_type):
return {'url': 'http://fake'}
def fake_get_vnc_console_invalid_type(self, _context,
_instance, _console_type):
raise exception.ConsoleTypeInvalid(console_type=_console_type)
@ -113,6 +118,8 @@ class ConsolesExtensionTestV21(test.NoDBTestCase):
fake_get_spice_console)
self.stubs.Set(compute_api.API, 'get_rdp_console',
fake_get_rdp_console)
self.stubs.Set(compute_api.API, 'get_serial_console',
fake_get_serial_console)
self.stubs.Set(compute_api.API, 'get', fake_get)
self._setup_wsgi()
@ -443,3 +450,139 @@ class ConsolesExtensionTestV2(ConsolesExtensionTestV21):
def test_get_rdp_console_with_undefined_param(self):
pass
def test_get_serial_console(self):
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(self.app)
output = jsonutils.loads(res.body)
self.assertEqual(200, res.status_int)
self.assertEqual({u'console': {u'url': u'http://fake',
u'type': u'serial'}},
output)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_not_enable(self, get_serial_console):
get_serial_console.side_effect = exception.ConsoleTypeUnavailable(
console_type="serial")
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
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, 400)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_invalid_type(self, get_serial_console):
get_serial_console.side_effect = (
exception.ConsoleTypeInvalid(console_type='invalid'))
body = {'os-getSerialConsole': {'type': 'invalid'}}
req = webob.Request.blank(self.url)
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, 400)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_no_type(self, get_serial_console):
get_serial_console.side_effect = (
exception.ConsoleTypeInvalid(console_type=''))
body = {'os-getSerialConsole': {}}
req = webob.Request.blank(self.url)
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, 400)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_no_instance(self, get_serial_console):
get_serial_console.side_effect = (
exception.InstanceNotFound(instance_id='xxx'))
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
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, 404)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_instance_not_ready(self, get_serial_console):
get_serial_console.side_effect = (
exception.InstanceNotReady(instance_id='xxx'))
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
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)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_socket_exhausted(self, get_serial_console):
get_serial_console.side_effect = (
exception.SocketPortRangeExhaustedException(
host='127.0.0.1'))
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
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, 500)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_image_nport_invalid(self, get_serial_console):
get_serial_console.side_effect = (
exception.ImageSerialPortNumberInvalid(
num_ports='x', property="hw_serial_port_count"))
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
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, 400)
self.assertTrue(get_serial_console.called)
@mock.patch.object(compute_api.API, 'get_serial_console')
def test_get_serial_console_image_nport_exceed(self, get_serial_console):
get_serial_console.side_effect = (
exception.ImageSerialPortNumberExceedFlavorValue())
body = {'os-getSerialConsole': {'type': 'serial'}}
req = webob.Request.blank(self.url)
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, 400)
self.assertTrue(get_serial_console.called)

View File

@ -0,0 +1,5 @@
{
"os-getSerialConsole": {
"type": "serial"
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<os-getSerialConsole>
<type>serial</type>
</os-getSerialConsole>

View File

@ -0,0 +1,6 @@
{
"console": {
"type": "serial",
"url":"%(url)s"
}
}

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<console>
<type>serial</type>
<url>%(url)s</url>
</console>

View File

@ -2086,6 +2086,7 @@ class ConsolesSampleJsonTests(ServersSampleBase):
self.flags(vnc_enabled=True)
self.flags(enabled=True, group='spice')
self.flags(enabled=True, group='rdp')
self.flags(enabled=True, group='serial_console')
def test_get_vnc_console(self):
uuid = self._post_server()
@ -2119,6 +2120,17 @@ class ConsolesSampleJsonTests(ServersSampleBase):
self._verify_response('get-rdp-console-post-resp', subs,
response, 200)
def test_get_serial_console(self):
uuid = self._post_server()
response = self._do_post('servers/%s/action' % uuid,
'get-serial-console-post-req',
{'action': 'os-getSerialConsole'})
subs = self._get_regexes()
subs["url"] = \
"((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)"
self._verify_response('get-serial-console-post-resp', subs,
response, 200)
class ConsolesSampleXmlTests(ConsolesSampleJsonTests):
ctype = 'xml'