Adds get_console_connect_info API
Implements: blueprint hyper-v-rdp-console Currently graphical console access to Nova instances is limited to clients which are part of Nova itself (novnc, xvpvnc, spice-html5). The mentioned clients verify the validity of a console access token with the following private API: nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token The usage of a private API precludes the possibility of employing external graphical console clients, including FreeRDP-WebConnect, used to connect to Hyper-V instances via RDP. This change adds a public API method that wraps the aforementioned check_token private API. This allows external clients to obtain the necessary protocol connection information by providing a token previously obtained with calls to get_vnc_console, get_spice_console or get_rdp_console. Includes V2 and V3 API implementations. Change-Id: Idd1e4f57b16bd1488f3b72bb064cef51321a7c79
This commit is contained in:
parent
efc49f656c
commit
630a349bc3
@ -639,6 +639,14 @@
|
||||
"name": "ExtendedServicesDelete",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/extended_services_delete/api/v2",
|
||||
"updated": "2013-12-10T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-console-auth-tokens",
|
||||
"description": "Console token authentication support.",
|
||||
"links": [],
|
||||
"name": "ConsoleAuthTokens",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/consoles-auth-tokens/api/v2",
|
||||
"updated": "2013-08-13T00:00:00+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -260,4 +260,7 @@
|
||||
<extension alias="os-extended-services-delete" updated="2013-12-10T00:00:00" namespace="http://docs.openstack.org/compute/ext/extended_services_delete/api/v2" name="ExtendedServicesDelete">
|
||||
<description>Services deletion support.</description>
|
||||
</extension>
|
||||
<extension alias="os-console-auth-tokens" updated="2013-08-13T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/consoles-auth-tokens/api/v2" name="ConsoleAuthTokens">
|
||||
<description>Console token authentication support.</description>
|
||||
</extension>
|
||||
</extensions>
|
||||
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"console": {
|
||||
"instance_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13",
|
||||
"host": "localhost",
|
||||
"port": 5900,
|
||||
"internal_access_path": "51af38c3-555e-4884-a314-6c8cdde37444"
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<console>
|
||||
<instance_uuid>b48316c5-71e8-45e4-9884-6c78055b9b13</instance_uuid>
|
||||
<host>localhost</host>
|
||||
<port>5900</port>
|
||||
<internal_access_path>51af38c3-555e-4884-a314-6c8cdde37444</internal_access_path>
|
||||
</console>
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"os-getRDPConsole": {
|
||||
"type": "rdp-html5"
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<os-getRDPConsole type="rdp-html5" />
|
16
doc/api_samples/os-console-auth-tokens/server-post-req.json
Normal file
16
doc/api_samples/os-console-auth-tokens/server-post-req.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"flavorRef" : "http://openstack.example.com/openstack/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
19
doc/api_samples/os-console-auth-tokens/server-post-req.xml
Normal file
19
doc/api_samples/os-console-auth-tokens/server-post-req.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b" flavorRef="http://openstack.example.com/openstack/flavors/1" name="new-server-test">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</server>
|
16
doc/api_samples/os-console-auth-tokens/server-post-resp.json
Normal file
16
doc/api_samples/os-console-auth-tokens/server-post-resp.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "MVk5HPrazHcG",
|
||||
"id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/openstack/servers/5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/openstack/servers/5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="5bbcc3c4-1da2-4437-a48a-66f15b1b13f9" adminPass="MVk5HPrazHcG">
|
||||
<metadata/>
|
||||
<atom:link href="http://openstack.example.com/v2/openstack/servers/5bbcc3c4-1da2-4437-a48a-66f15b1b13f9" rel="self"/>
|
||||
<atom:link href="http://openstack.example.com/openstack/servers/5bbcc3c4-1da2-4437-a48a-66f15b1b13f9" rel="bookmark"/>
|
||||
</server>
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"console": {
|
||||
"instance_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13",
|
||||
"host": "localhost",
|
||||
"port": 5900,
|
||||
"internal_access_path": "51af38c3-555e-4884-a314-6c8cdde37444"
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"get_rdp_console": {
|
||||
"type": "rdp-html5"
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"image_ref" : "http://glance.openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||
"flavor_ref" : "http://openstack.example.com/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"admin_password": "Kwg5tff6KiUU",
|
||||
"id": "8619225c-67c8-424f-9b46-cec5bad137a2",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v3/servers/8619225c-67c8-424f-9b46-cec5bad137a2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/servers/8619225c-67c8-424f-9b46-cec5bad137a2",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -256,6 +256,8 @@
|
||||
"compute_extension:v3:os-migrations:discoverable": "",
|
||||
"compute_extension:os-assisted-volume-snapshots:create": "rule:admin_api",
|
||||
"compute_extension:os-assisted-volume-snapshots:delete": "rule:admin_api",
|
||||
"compute_extension:console_auth_tokens": "rule:admin_api",
|
||||
"compute_extension:v3:os-console-auth-tokens": "rule:admin_api",
|
||||
|
||||
|
||||
"volume:create": "",
|
||||
|
68
nova/api/openstack/compute/contrib/console_auth_tokens.py
Normal file
68
nova/api/openstack/compute/contrib/console_auth_tokens.py
Normal file
@ -0,0 +1,68 @@
|
||||
# Copyright 2013 Cloudbase Solutions Srl
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.consoleauth import rpcapi as consoleauth_rpcapi
|
||||
from nova.openstack.common.gettextutils import _
|
||||
|
||||
|
||||
authorize = extensions.extension_authorizer('compute', 'console_auth_tokens')
|
||||
|
||||
|
||||
class ConsoleAuthTokensController(wsgi.Controller):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
|
||||
super(ConsoleAuthTokensController, self).__init__(*args, **kwargs)
|
||||
|
||||
def show(self, req, id):
|
||||
"""Checks a console auth token and returns the related connect info."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
token = id
|
||||
connect_info = self._consoleauth_rpcapi.check_token(context, token)
|
||||
if not connect_info:
|
||||
raise webob.exc.HTTPNotFound(explanation=_("Token not found"))
|
||||
|
||||
console_type = connect_info.get('console_type')
|
||||
# This is currently required only for RDP consoles
|
||||
if console_type != "rdp-html5":
|
||||
raise webob.exc.HTTPUnauthorized(
|
||||
explanation=_("The requested console type details are not "
|
||||
"accessible"))
|
||||
|
||||
return {'console':
|
||||
dict([(i, connect_info[i])
|
||||
for i in ['instance_uuid', 'host', 'port',
|
||||
'internal_access_path']
|
||||
if i in connect_info])}
|
||||
|
||||
|
||||
class Console_auth_tokens(extensions.ExtensionDescriptor):
|
||||
"""Console token authentication support."""
|
||||
name = "ConsoleAuthTokens"
|
||||
alias = "os-console-auth-tokens"
|
||||
namespace = ("http://docs.openstack.org/compute/ext/"
|
||||
"consoles-auth-tokens/api/v2")
|
||||
updated = "2013-08-13T00:00:00+00:00"
|
||||
|
||||
def get_resources(self):
|
||||
controller = ConsoleAuthTokensController()
|
||||
ext = extensions.ResourceExtension('os-console-auth-tokens',
|
||||
controller)
|
||||
return [ext]
|
75
nova/api/openstack/compute/plugins/v3/console_auth_tokens.py
Normal file
75
nova/api/openstack/compute/plugins/v3/console_auth_tokens.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Copyright 2013 Cloudbase Solutions Srl
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.consoleauth import rpcapi as consoleauth_rpcapi
|
||||
from nova.openstack.common.gettextutils import _
|
||||
|
||||
ALIAS = "os-console-auth-tokens"
|
||||
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
|
||||
|
||||
|
||||
class ConsoleAuthTokensController(wsgi.Controller):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
|
||||
super(ConsoleAuthTokensController, self).__init__(*args, **kwargs)
|
||||
|
||||
@extensions.expected_errors((400, 401, 404))
|
||||
def show(self, req, id):
|
||||
"""Checks a console auth token and returns the related connect info."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
token = id
|
||||
if not token:
|
||||
msg = _("token not provided")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
connect_info = self._consoleauth_rpcapi.check_token(context, token)
|
||||
if not connect_info:
|
||||
raise webob.exc.HTTPNotFound(explanation=_("Token not found"))
|
||||
|
||||
console_type = connect_info.get('console_type')
|
||||
# This is currently required only for RDP consoles
|
||||
if console_type != "rdp-html5":
|
||||
raise webob.exc.HTTPUnauthorized(
|
||||
explanation=_("The requested console type details are not "
|
||||
"accessible"))
|
||||
|
||||
return {'console':
|
||||
dict([(i, connect_info[i])
|
||||
for i in ['instance_uuid', 'host', 'port',
|
||||
'internal_access_path']
|
||||
if i in connect_info])}
|
||||
|
||||
|
||||
class ConsoleAuthTokens(extensions.V3APIExtensionBase):
|
||||
"""Console token authentication support."""
|
||||
name = "ConsoleAuthTokens"
|
||||
alias = ALIAS
|
||||
namespace = "http://docs.openstack.org/compute/ext/%s/api/v3" % ALIAS
|
||||
version = 1
|
||||
|
||||
def get_resources(self):
|
||||
controller = ConsoleAuthTokensController()
|
||||
ext = extensions.ResourceExtension('os-console-auth-tokens',
|
||||
controller)
|
||||
return [ext]
|
||||
|
||||
def get_controller_extensions(self):
|
||||
return []
|
@ -0,0 +1,104 @@
|
||||
# Copyright 2013 Cloudbase Solutions Srl
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import webob
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.consoleauth import rpcapi as consoleauth_rpcapi
|
||||
from nova import context
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import fakes
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('osapi_compute_ext_list', 'nova.api.openstack.compute.contrib')
|
||||
|
||||
_FAKE_CONNECT_INFO = {'instance_uuid': 'fake_instance_uuid',
|
||||
'host': 'fake_host',
|
||||
'port': 'fake_port',
|
||||
'internal_access_path': 'fake_access_path',
|
||||
'console_type': 'rdp-html5'}
|
||||
|
||||
|
||||
def _fake_check_token(self, context, token):
|
||||
return _FAKE_CONNECT_INFO
|
||||
|
||||
|
||||
def _fake_check_token_not_found(self, context, token):
|
||||
return None
|
||||
|
||||
|
||||
def _fake_check_token_unauthorized(self, context, token):
|
||||
connect_info = _FAKE_CONNECT_INFO
|
||||
connect_info['console_type'] = 'unauthorized_console_type'
|
||||
return connect_info
|
||||
|
||||
|
||||
class ConsoleAuthTokensExtensionTest(test.TestCase):
|
||||
|
||||
_FAKE_URL = '/v2/fake/os-console-auth-tokens/1'
|
||||
|
||||
_EXPECTED_OUTPUT = {'console': {'instance_uuid': 'fake_instance_uuid',
|
||||
'host': 'fake_host',
|
||||
'port': 'fake_port',
|
||||
'internal_access_path':
|
||||
'fake_access_path'}}
|
||||
|
||||
def setUp(self):
|
||||
super(ConsoleAuthTokensExtensionTest, self).setUp()
|
||||
self.stubs.Set(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
|
||||
_fake_check_token)
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
osapi_compute_ext_list=['Console_auth_tokens'])
|
||||
|
||||
ctxt = self._get_admin_context()
|
||||
self.app = fakes.wsgi_app(init_only=('os-console-auth-tokens',),
|
||||
fake_auth_context=ctxt)
|
||||
|
||||
def _get_admin_context(self):
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt.user_id = 'fake'
|
||||
ctxt.project_id = 'fake'
|
||||
return ctxt
|
||||
|
||||
def _create_request(self):
|
||||
req = webob.Request.blank(self._FAKE_URL)
|
||||
req.method = "GET"
|
||||
req.headers["content-type"] = "application/json"
|
||||
return req
|
||||
|
||||
def test_get_console_connect_info(self):
|
||||
req = self._create_request()
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(200, res.status_int)
|
||||
output = jsonutils.loads(res.body)
|
||||
self.assertEqual(self._EXPECTED_OUTPUT, output)
|
||||
|
||||
def test_get_console_connect_info_token_not_found(self):
|
||||
self.stubs.Set(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
|
||||
_fake_check_token_not_found)
|
||||
req = self._create_request()
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(404, res.status_int)
|
||||
|
||||
def test_get_console_connect_info_unauthorized_console_type(self):
|
||||
self.stubs.Set(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
|
||||
_fake_check_token_unauthorized)
|
||||
req = self._create_request()
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(401, res.status_int)
|
@ -0,0 +1,94 @@
|
||||
# Copyright 2013 Cloudbase Solutions Srl
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.consoleauth import rpcapi as consoleauth_rpcapi
|
||||
from nova import context
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import fakes
|
||||
|
||||
|
||||
_FAKE_CONNECT_INFO = {'instance_uuid': 'fake_instance_uuid',
|
||||
'host': 'fake_host',
|
||||
'port': 'fake_port',
|
||||
'internal_access_path': 'fake_access_path',
|
||||
'console_type': 'rdp-html5'}
|
||||
|
||||
|
||||
def _fake_check_token(self, context, token):
|
||||
return _FAKE_CONNECT_INFO
|
||||
|
||||
|
||||
def _fake_check_token_not_found(self, context, token):
|
||||
return None
|
||||
|
||||
|
||||
def _fake_check_token_unauthorized(self, context, token):
|
||||
connect_info = _FAKE_CONNECT_INFO
|
||||
connect_info['console_type'] = 'unauthorized_console_type'
|
||||
return connect_info
|
||||
|
||||
|
||||
class ConsoleAuthTokensExtensionTest(test.TestCase):
|
||||
|
||||
_FAKE_URL = '/v3/os-console-auth-tokens/1'
|
||||
|
||||
_EXPECTED_OUTPUT = {'console': {'instance_uuid': 'fake_instance_uuid',
|
||||
'host': 'fake_host',
|
||||
'port': 'fake_port',
|
||||
'internal_access_path':
|
||||
'fake_access_path'}}
|
||||
|
||||
def setUp(self):
|
||||
super(ConsoleAuthTokensExtensionTest, self).setUp()
|
||||
self.stubs.Set(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
|
||||
_fake_check_token)
|
||||
|
||||
ctxt = self._get_admin_context()
|
||||
self.app = fakes.wsgi_app_v3(init_only=('os-console-auth-tokens'),
|
||||
fake_auth_context=ctxt)
|
||||
|
||||
def _get_admin_context(self):
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt.user_id = 'fake'
|
||||
ctxt.project_id = 'fake'
|
||||
return ctxt
|
||||
|
||||
def _create_request(self):
|
||||
req = fakes.HTTPRequestV3.blank(self._FAKE_URL)
|
||||
req.method = "GET"
|
||||
req.headers["content-type"] = "application/json"
|
||||
return req
|
||||
|
||||
def test_get_console_connect_info(self):
|
||||
req = self._create_request()
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(200, res.status_int)
|
||||
output = jsonutils.loads(res.body)
|
||||
self.assertEqual(self._EXPECTED_OUTPUT, output)
|
||||
|
||||
def test_get_console_connect_info_token_not_found(self):
|
||||
self.stubs.Set(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
|
||||
_fake_check_token_not_found)
|
||||
req = self._create_request()
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(404, res.status_int)
|
||||
|
||||
def test_get_console_connect_info_unauthorized_console_type(self):
|
||||
self.stubs.Set(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
|
||||
_fake_check_token_unauthorized)
|
||||
req = self._create_request()
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(401, res.status_int)
|
@ -294,6 +294,8 @@ policy_data = """
|
||||
"compute_extension:v3:os-migrations:index": "is_admin:True",
|
||||
"compute_extension:os-assisted-volume-snapshots:create": "",
|
||||
"compute_extension:os-assisted-volume-snapshots:delete": "",
|
||||
"compute_extension:console_auth_tokens": "is_admin:True",
|
||||
"compute_extension:v3:os-console-auth-tokens": "is_admin:True",
|
||||
|
||||
"volume:create": "",
|
||||
"volume:get": "",
|
||||
|
@ -104,6 +104,14 @@
|
||||
"namespace": "http://docs.openstack.org/compute/ext/server_usage/api/v1.1",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "os-console-auth-tokens",
|
||||
"description": "%(text)s",
|
||||
"links": [],
|
||||
"name": "ConsoleAuthTokens",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/consoles-auth-tokens/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "OS-SCH-HNT",
|
||||
"description": "%(text)s",
|
||||
|
@ -239,4 +239,7 @@
|
||||
<extension alias="os-extended-services-delete" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_services_delete/api/v2" name="ExtendedServicesDelete">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
<extension alias="os-console-auth-tokens" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/consoles-auth-tokens/api/v2" name="ConsoleAuthTokens">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
</extensions>
|
||||
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"console": {
|
||||
"instance_uuid": "%(id)s",
|
||||
"host": "%(host)s",
|
||||
"port": %(port)s,
|
||||
"internal_access_path": "%(internal_access_path)s"
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<console>
|
||||
<instance_uuid>%(id)s</instance_uuid>
|
||||
<host>%(host)s</host>
|
||||
<port>%(port)s</port>
|
||||
<internal_access_path>%(internal_access_path)s</internal_access_path>
|
||||
</console>
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"os-getRDPConsole": {
|
||||
"type": "rdp-html5"
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<os-getRDPConsole>
|
||||
<type>rdp-html5</type>
|
||||
</os-getRDPConsole>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"imageRef" : "%(host)s/openstack/images/%(image_id)s",
|
||||
"flavorRef" : "%(host)s/openstack/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
},
|
||||
"personality" : [
|
||||
{
|
||||
"path" : "/etc/banner.txt",
|
||||
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test">
|
||||
<metadata>
|
||||
<meta key="My Server Name">Apache1</meta>
|
||||
</metadata>
|
||||
<personality>
|
||||
<file path="/etc/banner.txt">
|
||||
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||
</file>
|
||||
</personality>
|
||||
</server>
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"adminPass": "%(password)s",
|
||||
"id": "%(id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2/openstack/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/openstack/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s">
|
||||
<metadata/>
|
||||
<atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/>
|
||||
<atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/>
|
||||
</server>
|
@ -19,6 +19,7 @@ import datetime
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import urllib
|
||||
import uuid as uuid_lib
|
||||
|
||||
@ -2037,6 +2038,46 @@ class ConsolesSampleXmlTests(ConsolesSampleJsonTests):
|
||||
ctype = 'xml'
|
||||
|
||||
|
||||
class ConsoleAuthTokensSampleJsonTests(ServersSampleBase):
|
||||
extends_name = ("nova.api.openstack.compute.contrib.consoles.Consoles")
|
||||
extension_name = ("nova.api.openstack.compute.contrib.console_auth_tokens."
|
||||
"Console_auth_tokens")
|
||||
|
||||
def _get_console_url(self, data):
|
||||
return json.loads(data)["console"]["url"]
|
||||
|
||||
def _get_console_token(self, uuid):
|
||||
response = self._do_post('servers/%s/action' % uuid,
|
||||
'get-rdp-console-post-req',
|
||||
{'action': 'os-getRDPConsole'})
|
||||
|
||||
url = self._get_console_url(response.read())
|
||||
return re.match('.+?token=([^&]+)', url).groups()[0]
|
||||
|
||||
def test_get_console_connect_info(self):
|
||||
self.flags(enabled=True, group='rdp')
|
||||
|
||||
uuid = self._post_server()
|
||||
token = self._get_console_token(uuid)
|
||||
|
||||
response = self._do_get('os-console-auth-tokens/%s' % token)
|
||||
|
||||
subs = self._get_regexes()
|
||||
subs["uuid"] = uuid
|
||||
subs["host"] = r"[\w\.\-]+"
|
||||
subs["port"] = "[0-9]+"
|
||||
subs["internal_access_path"] = ".*"
|
||||
self._verify_response('get-console-connect-info-get-resp', subs,
|
||||
response, 200)
|
||||
|
||||
|
||||
class ConsoleAuthTokensSampleXmlTests(ConsoleAuthTokensSampleJsonTests):
|
||||
ctype = 'xml'
|
||||
|
||||
def _get_console_url(self, data):
|
||||
return etree.fromstring(data).find('url').text
|
||||
|
||||
|
||||
class DeferredDeleteSampleJsonTests(ServersSampleBase):
|
||||
extension_name = ("nova.api.openstack.compute.contrib"
|
||||
".deferred_delete.Deferred_delete")
|
||||
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"console": {
|
||||
"instance_uuid": "%(id)s",
|
||||
"host": "%(host)s",
|
||||
"port": %(port)s,
|
||||
"internal_access_path": "%(internal_access_path)s"
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"get_rdp_console": {
|
||||
"type": "rdp-html5"
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"server" : {
|
||||
"name" : "new-server-test",
|
||||
"image_ref" : "%(glance_host)s/images/%(image_id)s",
|
||||
"flavor_ref" : "%(host)s/flavors/1",
|
||||
"metadata" : {
|
||||
"My Server Name" : "Apache1"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"server": {
|
||||
"admin_password": "%(password)s",
|
||||
"id": "%(id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v3/servers/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/servers/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
50
nova/tests/integrated/v3/test_console_auth_tokens.py
Normal file
50
nova/tests/integrated/v3/test_console_auth_tokens.py
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright 2013 Cloudbase Solutions Srl
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
from nova.tests.integrated.v3 import test_servers
|
||||
|
||||
|
||||
class ConsoleAuthTokensSampleJsonTests(test_servers.ServersSampleBase):
|
||||
extension_name = "os-console-auth-tokens"
|
||||
extra_extensions_to_load = ["os-remote-consoles"]
|
||||
|
||||
def _get_console_url(self, data):
|
||||
return json.loads(data)["console"]["url"]
|
||||
|
||||
def _get_console_token(self, uuid):
|
||||
response = self._do_post('servers/%s/action' % uuid,
|
||||
'get-rdp-console-post-req',
|
||||
{'action': 'os-getRDPConsole'})
|
||||
|
||||
url = self._get_console_url(response.read())
|
||||
return re.match('.+?token=([^&]+)', url).groups()[0]
|
||||
|
||||
def test_get_console_connect_info(self):
|
||||
self.flags(enabled=True, group='rdp')
|
||||
|
||||
uuid = self._post_server()
|
||||
token = self._get_console_token(uuid)
|
||||
|
||||
response = self._do_get('os-console-auth-tokens/%s' % token)
|
||||
|
||||
subs = self._get_regexes()
|
||||
subs["uuid"] = uuid
|
||||
subs["host"] = r"[\w\.\-]+"
|
||||
subs["port"] = "[0-9]+"
|
||||
subs["internal_access_path"] = ".*"
|
||||
self._verify_response('get-console-connect-info-get-resp', subs,
|
||||
response, 200)
|
@ -67,6 +67,7 @@ nova.api.v3.extensions =
|
||||
cells = nova.api.openstack.compute.plugins.v3.cells:Cells
|
||||
certificates = nova.api.openstack.compute.plugins.v3.certificates:Certificates
|
||||
config_drive = nova.api.openstack.compute.plugins.v3.config_drive:ConfigDrive
|
||||
console_auth_tokens = nova.api.openstack.compute.plugins.v3.console_auth_tokens:ConsoleAuthTokens
|
||||
console_output = nova.api.openstack.compute.plugins.v3.console_output:ConsoleOutput
|
||||
consoles = nova.api.openstack.compute.plugins.v3.consoles:Consoles
|
||||
deferred_delete = nova.api.openstack.compute.plugins.v3.deferred_delete:DeferredDelete
|
||||
|
Loading…
Reference in New Issue
Block a user