Merge "Remove 'nova-console' service, 'console' RPC API"
This commit is contained in:
commit
a3499027f0
|
@ -31,7 +31,6 @@ redirectmatch 301 ^/nova/([^/]+)/man/nova-cells.html$ /nova/$1/cli/nova-cells.ht
|
||||||
# this is gone and never coming back, indicate that to the end users
|
# this is gone and never coming back, indicate that to the end users
|
||||||
redirectmatch 301 ^/nova/([^/]+)/man/nova-compute.html$ /nova/$1/cli/nova-compute.html
|
redirectmatch 301 ^/nova/([^/]+)/man/nova-compute.html$ /nova/$1/cli/nova-compute.html
|
||||||
redirectmatch 301 ^/nova/([^/]+)/man/nova-conductor.html$ /nova/$1/cli/nova-conductor.html
|
redirectmatch 301 ^/nova/([^/]+)/man/nova-conductor.html$ /nova/$1/cli/nova-conductor.html
|
||||||
redirectmatch 301 ^/nova/([^/]+)/man/nova-console.html$ /nova/$1/cli/nova-console.html
|
|
||||||
redirectmatch 301 ^/nova/([^/]+)/man/nova-dhcpbridge.html$ /nova/$1/cli/nova-dhcpbridge.html
|
redirectmatch 301 ^/nova/([^/]+)/man/nova-dhcpbridge.html$ /nova/$1/cli/nova-dhcpbridge.html
|
||||||
redirectmatch 301 ^/nova/([^/]+)/man/nova-manage.html$ /nova/$1/cli/nova-manage.html
|
redirectmatch 301 ^/nova/([^/]+)/man/nova-manage.html$ /nova/$1/cli/nova-manage.html
|
||||||
redirectmatch 301 ^/nova/([^/]+)/man/nova-network.html$ /nova/$1/cli/nova-network.html
|
redirectmatch 301 ^/nova/([^/]+)/man/nova-network.html$ /nova/$1/cli/nova-network.html
|
||||||
|
|
|
@ -87,5 +87,4 @@ deployments, but are documented for existing ones.
|
||||||
|
|
||||||
nova-dhcpbridge
|
nova-dhcpbridge
|
||||||
nova-network
|
nova-network
|
||||||
nova-console
|
|
||||||
nova-xvpvncproxy
|
nova-xvpvncproxy
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
============
|
|
||||||
nova-console
|
|
||||||
============
|
|
||||||
|
|
||||||
-------------------
|
|
||||||
Nova Console Server
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
:Author: openstack@lists.openstack.org
|
|
||||||
:Copyright: OpenStack Foundation
|
|
||||||
:Manual section: 1
|
|
||||||
:Manual group: cloud computing
|
|
||||||
|
|
||||||
Synopsis
|
|
||||||
========
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
nova-console [options]
|
|
||||||
|
|
||||||
Description
|
|
||||||
===========
|
|
||||||
|
|
||||||
:program:`nova-console` is a server daemon that serves the Nova Console
|
|
||||||
service, which is a console proxy to set up multi-tenant VM console access,
|
|
||||||
e.g. with *XVP*.
|
|
||||||
|
|
||||||
.. deprecated:: 19.0.0
|
|
||||||
|
|
||||||
:program:`nova-console` is deprecated since 19.0.0 (Stein) and will be
|
|
||||||
removed in an upcoming release.
|
|
||||||
|
|
||||||
Options
|
|
||||||
=======
|
|
||||||
|
|
||||||
**General options**
|
|
||||||
|
|
||||||
Files
|
|
||||||
=====
|
|
||||||
|
|
||||||
* ``/etc/nova/nova.conf``
|
|
||||||
* ``/etc/nova/policy.json``
|
|
||||||
* ``/etc/nova/rootwrap.conf``
|
|
||||||
* ``/etc/nova/rootwrap.d/``
|
|
||||||
|
|
||||||
See Also
|
|
||||||
========
|
|
||||||
|
|
||||||
* :nova-doc:`OpenStack Nova <>`
|
|
||||||
|
|
||||||
Bugs
|
|
||||||
====
|
|
||||||
|
|
||||||
* Nova bugs are managed at `Launchpad <https://bugs.launchpad.net/nova>`__
|
|
|
@ -86,7 +86,6 @@ _man_pages = [
|
||||||
('nova-api-os-compute', u'Cloud controller fabric'),
|
('nova-api-os-compute', u'Cloud controller fabric'),
|
||||||
('nova-compute', u'Cloud controller fabric'),
|
('nova-compute', u'Cloud controller fabric'),
|
||||||
('nova-conductor', u'Cloud controller fabric'),
|
('nova-conductor', u'Cloud controller fabric'),
|
||||||
('nova-console', u'Cloud controller fabric'),
|
|
||||||
('nova-dhcpbridge', u'Cloud controller fabric'),
|
('nova-dhcpbridge', u'Cloud controller fabric'),
|
||||||
('nova-manage', u'Cloud controller fabric'),
|
('nova-manage', u'Cloud controller fabric'),
|
||||||
('nova-network', u'Cloud controller fabric'),
|
('nova-network', u'Cloud controller fabric'),
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
/nova/latest/man/nova-cells.html 301 /nova/latest/cli/nova-cells.html
|
/nova/latest/man/nova-cells.html 301 /nova/latest/cli/nova-cells.html
|
||||||
/nova/latest/man/nova-compute.html 301 /nova/latest/cli/nova-compute.html
|
/nova/latest/man/nova-compute.html 301 /nova/latest/cli/nova-compute.html
|
||||||
/nova/latest/man/nova-conductor.html 301 /nova/latest/cli/nova-conductor.html
|
/nova/latest/man/nova-conductor.html 301 /nova/latest/cli/nova-conductor.html
|
||||||
/nova/latest/man/nova-console.html 301 /nova/latest/cli/nova-console.html
|
|
||||||
/nova/latest/man/nova-dhcpbridge.html 301 /nova/latest/cli/nova-dhcpbridge.html
|
/nova/latest/man/nova-dhcpbridge.html 301 /nova/latest/cli/nova-dhcpbridge.html
|
||||||
/nova/latest/man/nova-manage.html 301 /nova/latest/cli/nova-manage.html
|
/nova/latest/man/nova-manage.html 301 /nova/latest/cli/nova-manage.html
|
||||||
/nova/latest/man/nova-network.html 301 /nova/latest/cli/nova-network.html
|
/nova/latest/man/nova-network.html 301 /nova/latest/cli/nova-network.html
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
# Copyright (c) 2010 OpenStack Foundation
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Starter script for Nova Console Proxy."""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
|
||||||
from oslo_reports import guru_meditation_report as gmr
|
|
||||||
from oslo_reports import opts as gmr_opts
|
|
||||||
|
|
||||||
from nova import config
|
|
||||||
from nova.console import rpcapi as console_rpcapi
|
|
||||||
from nova import objects
|
|
||||||
from nova import service
|
|
||||||
from nova import version
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
LOG = logging.getLogger('nova.console')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
config.parse_args(sys.argv)
|
|
||||||
logging.setup(CONF, "nova")
|
|
||||||
objects.register_all()
|
|
||||||
gmr_opts.set_defaults(CONF)
|
|
||||||
|
|
||||||
gmr.TextGuruMeditation.setup_autorun(version, conf=CONF)
|
|
||||||
|
|
||||||
LOG.warning('The nova-console service is deprecated as it is Xen '
|
|
||||||
'specific, does not function properly in a multi-cell '
|
|
||||||
'environment, and has effectively been replaced by noVNC '
|
|
||||||
'and the nova-novncproxy service.')
|
|
||||||
|
|
||||||
server = service.Service.create(binary='nova-console',
|
|
||||||
topic=console_rpcapi.RPC_TOPIC)
|
|
||||||
service.serve(server)
|
|
||||||
service.wait()
|
|
|
@ -69,7 +69,6 @@ from nova.compute.utils import wrap_instance_event
|
||||||
from nova.compute import vm_states
|
from nova.compute import vm_states
|
||||||
from nova import conductor
|
from nova import conductor
|
||||||
import nova.conf
|
import nova.conf
|
||||||
from nova.console import rpcapi as console_rpcapi
|
|
||||||
import nova.context
|
import nova.context
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import exception_wrapper
|
from nova import exception_wrapper
|
||||||
|
@ -1522,6 +1521,7 @@ class ComputeManager(manager.Manager):
|
||||||
except exception.InstanceNotFound:
|
except exception.InstanceNotFound:
|
||||||
return power_state.NOSTATE
|
return power_state.NOSTATE
|
||||||
|
|
||||||
|
# TODO(stephenfin): Remove this once we bump the compute API to v6.0
|
||||||
def get_console_topic(self, context):
|
def get_console_topic(self, context):
|
||||||
"""Retrieves the console host for a project on this host.
|
"""Retrieves the console host for a project on this host.
|
||||||
|
|
||||||
|
@ -1529,7 +1529,7 @@ class ComputeManager(manager.Manager):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO(mdragon): perhaps make this variable by console_type?
|
# TODO(mdragon): perhaps make this variable by console_type?
|
||||||
return '%s.%s' % (console_rpcapi.RPC_TOPIC, CONF.console_host)
|
return 'console.%s' % CONF.console_host
|
||||||
|
|
||||||
@wrap_exception()
|
@wrap_exception()
|
||||||
def get_console_pool_info(self, context, console_type):
|
def get_console_pool_info(self, context, console_type):
|
||||||
|
|
|
@ -709,6 +709,7 @@ class ComputeAPI(object):
|
||||||
return cctxt.call(ctxt, 'get_console_pool_info',
|
return cctxt.call(ctxt, 'get_console_pool_info',
|
||||||
console_type=console_type)
|
console_type=console_type)
|
||||||
|
|
||||||
|
# TODO(stephenfin): This is no longer used and can be removed in v6.0
|
||||||
def get_console_topic(self, ctxt, host):
|
def get_console_topic(self, ctxt, host):
|
||||||
version = '5.0'
|
version = '5.0'
|
||||||
cctxt = self.router.client(ctxt).prepare(
|
cctxt = self.router.client(ctxt).prepare(
|
||||||
|
|
|
@ -96,18 +96,6 @@ Conductor RPC API version cap.
|
||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
|
|
||||||
* By default send the latest version the client knows about
|
|
||||||
* A string representing a version number in the format 'N.N';
|
|
||||||
for example, possible values might be '1.12' or '2.0'.
|
|
||||||
* An OpenStack release name, in lower case, such as 'mitaka' or
|
|
||||||
'liberty'.
|
|
||||||
"""),
|
|
||||||
cfg.StrOpt('console',
|
|
||||||
help="""
|
|
||||||
Console RPC API version cap.
|
|
||||||
|
|
||||||
Possible values:
|
|
||||||
|
|
||||||
* By default send the latest version the client knows about
|
* By default send the latest version the client knows about
|
||||||
* A string representing a version number in the format 'N.N';
|
* A string representing a version number in the format 'N.N';
|
||||||
for example, possible values might be '1.12' or '2.0'.
|
for example, possible values might be '1.12' or '2.0'.
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
# Copyright (c) 2010 OpenStack Foundation
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Handles ConsoleProxy API requests."""
|
|
||||||
|
|
||||||
|
|
||||||
from nova.compute import rpcapi as compute_rpcapi
|
|
||||||
from nova.console import rpcapi as console_rpcapi
|
|
||||||
from nova.db import base
|
|
||||||
from nova import objects
|
|
||||||
|
|
||||||
|
|
||||||
class API(base.Base):
|
|
||||||
"""API for spinning up or down console proxy connections."""
|
|
||||||
def get_consoles(self, context, instance_uuid):
|
|
||||||
return self.db.console_get_all_by_instance(context, instance_uuid,
|
|
||||||
columns_to_join=['pool'])
|
|
||||||
|
|
||||||
def get_console(self, context, instance_uuid, console_uuid):
|
|
||||||
return self.db.console_get(context, console_uuid, instance_uuid)
|
|
||||||
|
|
||||||
def delete_console(self, context, instance_uuid, console_uuid):
|
|
||||||
console = self.db.console_get(context, console_uuid, instance_uuid)
|
|
||||||
rpcapi = console_rpcapi.ConsoleAPI(topic=console_rpcapi.RPC_TOPIC,
|
|
||||||
server=console['pool']['host'])
|
|
||||||
rpcapi.remove_console(context, console['id'])
|
|
||||||
|
|
||||||
def create_console(self, context, instance_uuid):
|
|
||||||
# NOTE(mdragon): If we wanted to return this the console info
|
|
||||||
# here, as we would need to do a call.
|
|
||||||
# They can just do an index later to fetch
|
|
||||||
# console info. I am not sure which is better
|
|
||||||
# here.
|
|
||||||
instance = objects.Instance.get_by_uuid(context, instance_uuid)
|
|
||||||
topic = self._get_console_topic(context, instance.host)
|
|
||||||
server = None
|
|
||||||
if '.' in topic:
|
|
||||||
topic, server = topic.split('.', 1)
|
|
||||||
rpcapi = console_rpcapi.ConsoleAPI(topic=topic, server=server)
|
|
||||||
rpcapi.add_console(context, instance.id)
|
|
||||||
|
|
||||||
def _get_console_topic(self, context, instance_host):
|
|
||||||
rpcapi = compute_rpcapi.ComputeAPI()
|
|
||||||
return rpcapi.get_console_topic(context, instance_host)
|
|
|
@ -1,115 +0,0 @@
|
||||||
# Copyright (c) 2010 OpenStack Foundation
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Console Proxy Service."""
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
|
||||||
import oslo_messaging as messaging
|
|
||||||
|
|
||||||
from nova.compute import rpcapi as compute_rpcapi
|
|
||||||
import nova.conf
|
|
||||||
from nova.console import xvp
|
|
||||||
from nova import exception
|
|
||||||
from nova import manager
|
|
||||||
from nova import objects
|
|
||||||
from nova import utils
|
|
||||||
|
|
||||||
|
|
||||||
CONF = nova.conf.CONF
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleProxyManager(manager.Manager):
|
|
||||||
"""Sets up and tears down any console proxy connections.
|
|
||||||
|
|
||||||
Needed for accessing instance consoles securely.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
target = messaging.Target(version='2.0')
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.driver = xvp.XVPConsoleProxy()
|
|
||||||
super(ConsoleProxyManager, self).__init__(service_name='console',
|
|
||||||
*args, **kwargs)
|
|
||||||
self.driver.host = self.host
|
|
||||||
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
LOG.info('Reloading compute RPC API')
|
|
||||||
compute_rpcapi.LAST_VERSION = None
|
|
||||||
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
|
|
||||||
|
|
||||||
def init_host(self):
|
|
||||||
self.driver.init_host()
|
|
||||||
|
|
||||||
def add_console(self, context, instance_id):
|
|
||||||
instance = objects.Instance.get_by_id(context, instance_id)
|
|
||||||
host = instance.host
|
|
||||||
name = instance.name
|
|
||||||
pool = self._get_pool_for_instance_host(context, host)
|
|
||||||
try:
|
|
||||||
console = self.db.console_get_by_pool_instance(context,
|
|
||||||
pool['id'],
|
|
||||||
instance.uuid)
|
|
||||||
except exception.NotFound:
|
|
||||||
LOG.debug('Adding console', instance=instance)
|
|
||||||
password = utils.generate_password(8)
|
|
||||||
port = self.driver.get_port(context)
|
|
||||||
console_data = {'instance_name': name,
|
|
||||||
'instance_uuid': instance.uuid,
|
|
||||||
'password': password,
|
|
||||||
'pool_id': pool['id']}
|
|
||||||
if port:
|
|
||||||
console_data['port'] = port
|
|
||||||
console = self.db.console_create(context, console_data)
|
|
||||||
self.driver.setup_console(context, console)
|
|
||||||
|
|
||||||
return console['id']
|
|
||||||
|
|
||||||
def remove_console(self, context, console_id):
|
|
||||||
try:
|
|
||||||
console = self.db.console_get(context, console_id)
|
|
||||||
except exception.NotFound:
|
|
||||||
LOG.debug('Tried to remove non-existent console '
|
|
||||||
'%(console_id)s.',
|
|
||||||
{'console_id': console_id})
|
|
||||||
return
|
|
||||||
self.db.console_delete(context, console_id)
|
|
||||||
self.driver.teardown_console(context, console)
|
|
||||||
|
|
||||||
def _get_pool_for_instance_host(self, context, instance_host):
|
|
||||||
context = context.elevated()
|
|
||||||
console_type = self.driver.console_type
|
|
||||||
try:
|
|
||||||
pool = self.db.console_pool_get_by_host_type(context,
|
|
||||||
instance_host,
|
|
||||||
self.host,
|
|
||||||
console_type)
|
|
||||||
except exception.NotFound:
|
|
||||||
# NOTE(mdragon): Right now, the only place this info exists is the
|
|
||||||
# compute worker's flagfile, at least for
|
|
||||||
# xenserver. Thus we need to ask.
|
|
||||||
pool_info = self.compute_rpcapi.get_console_pool_info(context,
|
|
||||||
instance_host, console_type)
|
|
||||||
pool_info['password'] = self.driver.fix_pool_password(
|
|
||||||
pool_info['password'])
|
|
||||||
pool_info['host'] = self.host
|
|
||||||
pool_info['public_hostname'] = \
|
|
||||||
CONF.xenserver.console_public_hostname
|
|
||||||
pool_info['console_type'] = self.driver.console_type
|
|
||||||
pool_info['compute_host'] = instance_host
|
|
||||||
pool = self.db.console_pool_create(context, pool_info)
|
|
||||||
return pool
|
|
|
@ -1,77 +0,0 @@
|
||||||
# Copyright 2013 Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Client side of the console RPC API.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import oslo_messaging as messaging
|
|
||||||
|
|
||||||
import nova.conf
|
|
||||||
from nova import profiler
|
|
||||||
from nova import rpc
|
|
||||||
|
|
||||||
CONF = nova.conf.CONF
|
|
||||||
RPC_TOPIC = "console"
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace_cls("rpc")
|
|
||||||
class ConsoleAPI(object):
|
|
||||||
'''Client side of the console rpc API.
|
|
||||||
|
|
||||||
API version history:
|
|
||||||
|
|
||||||
1.0 - Initial version.
|
|
||||||
1.1 - Added get_backdoor_port()
|
|
||||||
|
|
||||||
... Grizzly and Havana support message version 1.1. So, any changes to
|
|
||||||
existing methods in 1.x after that point should be done such that they
|
|
||||||
can handle the version_cap being set to 1.1.
|
|
||||||
|
|
||||||
2.0 - Major API rev for Icehouse
|
|
||||||
|
|
||||||
... Icehouse, Juno, Kilo, Liberty, Mitaka, Newton, and Ocata support
|
|
||||||
message version 2.0. So, any changes to existing methods in 2.x after
|
|
||||||
that point should be done such that they can handle the version_cap
|
|
||||||
being set to 2.0.
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
VERSION_ALIASES = {
|
|
||||||
'grizzly': '1.1',
|
|
||||||
'havana': '1.1',
|
|
||||||
'icehouse': '2.0',
|
|
||||||
'juno': '2.0',
|
|
||||||
'kilo': '2.0',
|
|
||||||
'liberty': '2.0',
|
|
||||||
'mitaka': '2.0',
|
|
||||||
'newton': '2.0',
|
|
||||||
'ocata': '2.0',
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, topic=None, server=None):
|
|
||||||
super(ConsoleAPI, self).__init__()
|
|
||||||
topic = topic if topic else RPC_TOPIC
|
|
||||||
target = messaging.Target(topic=topic, server=server, version='2.0')
|
|
||||||
version_cap = self.VERSION_ALIASES.get(CONF.upgrade_levels.console,
|
|
||||||
CONF.upgrade_levels.console)
|
|
||||||
self.client = rpc.get_client(target, version_cap=version_cap)
|
|
||||||
|
|
||||||
def add_console(self, ctxt, instance_id):
|
|
||||||
cctxt = self.client.prepare()
|
|
||||||
cctxt.cast(ctxt, 'add_console', instance_id=instance_id)
|
|
||||||
|
|
||||||
def remove_console(self, ctxt, console_id):
|
|
||||||
cctxt = self.client.prepare()
|
|
||||||
cctxt.cast(ctxt, 'remove_console', console_id=console_id)
|
|
|
@ -1413,21 +1413,7 @@ def project_get_networks(context, project_id, associate=True):
|
||||||
return IMPL.project_get_networks(context, project_id, associate)
|
return IMPL.project_get_networks(context, project_id, associate)
|
||||||
|
|
||||||
|
|
||||||
###################
|
##################
|
||||||
|
|
||||||
|
|
||||||
def console_pool_create(context, values):
|
|
||||||
"""Create console pool."""
|
|
||||||
return IMPL.console_pool_create(context, values)
|
|
||||||
|
|
||||||
|
|
||||||
def console_pool_get_by_host_type(context, compute_host, proxy_host,
|
|
||||||
console_type):
|
|
||||||
"""Fetch a console pool for a given proxy host, compute host, and type."""
|
|
||||||
return IMPL.console_pool_get_by_host_type(context,
|
|
||||||
compute_host,
|
|
||||||
proxy_host,
|
|
||||||
console_type)
|
|
||||||
|
|
||||||
|
|
||||||
def console_pool_get_all_by_host_type(context, host, console_type):
|
def console_pool_get_all_by_host_type(context, host, console_type):
|
||||||
|
@ -1437,31 +1423,6 @@ def console_pool_get_all_by_host_type(context, host, console_type):
|
||||||
console_type)
|
console_type)
|
||||||
|
|
||||||
|
|
||||||
def console_create(context, values):
|
|
||||||
"""Create a console."""
|
|
||||||
return IMPL.console_create(context, values)
|
|
||||||
|
|
||||||
|
|
||||||
def console_delete(context, console_id):
|
|
||||||
"""Delete a console."""
|
|
||||||
return IMPL.console_delete(context, console_id)
|
|
||||||
|
|
||||||
|
|
||||||
def console_get_by_pool_instance(context, pool_id, instance_uuid):
|
|
||||||
"""Get console entry for a given instance and pool."""
|
|
||||||
return IMPL.console_get_by_pool_instance(context, pool_id, instance_uuid)
|
|
||||||
|
|
||||||
|
|
||||||
def console_get_all_by_instance(context, instance_uuid, columns_to_join=None):
|
|
||||||
"""Get consoles for a given instance."""
|
|
||||||
return IMPL.console_get_all_by_instance(context, instance_uuid,
|
|
||||||
columns_to_join)
|
|
||||||
|
|
||||||
|
|
||||||
def console_get(context, console_id, instance_uuid=None):
|
|
||||||
"""Get a specific console (possibly on a given instance)."""
|
|
||||||
return IMPL.console_get(context, console_id, instance_uuid)
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4487,40 +4487,6 @@ def migration_migrate_to_uuid(context, count):
|
||||||
##################
|
##################
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_writer
|
|
||||||
def console_pool_create(context, values):
|
|
||||||
pool = models.ConsolePool()
|
|
||||||
pool.update(values)
|
|
||||||
try:
|
|
||||||
pool.save(context.session)
|
|
||||||
except db_exc.DBDuplicateEntry:
|
|
||||||
raise exception.ConsolePoolExists(
|
|
||||||
host=values["host"],
|
|
||||||
console_type=values["console_type"],
|
|
||||||
compute_host=values["compute_host"],
|
|
||||||
)
|
|
||||||
return pool
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_reader
|
|
||||||
def console_pool_get_by_host_type(context, compute_host, host,
|
|
||||||
console_type):
|
|
||||||
|
|
||||||
result = model_query(context, models.ConsolePool, read_deleted="no").\
|
|
||||||
filter_by(host=host).\
|
|
||||||
filter_by(console_type=console_type).\
|
|
||||||
filter_by(compute_host=compute_host).\
|
|
||||||
options(joinedload('consoles')).\
|
|
||||||
first()
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
raise exception.ConsolePoolNotFoundForHostType(
|
|
||||||
host=host, console_type=console_type,
|
|
||||||
compute_host=compute_host)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_reader
|
@pick_context_manager_reader
|
||||||
def console_pool_get_all_by_host_type(context, host, console_type):
|
def console_pool_get_all_by_host_type(context, host, console_type):
|
||||||
return model_query(context, models.ConsolePool, read_deleted="no").\
|
return model_query(context, models.ConsolePool, read_deleted="no").\
|
||||||
|
@ -4530,71 +4496,6 @@ def console_pool_get_all_by_host_type(context, host, console_type):
|
||||||
all()
|
all()
|
||||||
|
|
||||||
|
|
||||||
##################
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_writer
|
|
||||||
def console_create(context, values):
|
|
||||||
console = models.Console()
|
|
||||||
console.update(values)
|
|
||||||
console.save(context.session)
|
|
||||||
return console
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_writer
|
|
||||||
def console_delete(context, console_id):
|
|
||||||
# NOTE(mdragon): consoles are meant to be transient.
|
|
||||||
context.session.query(models.Console).\
|
|
||||||
filter_by(id=console_id).\
|
|
||||||
delete()
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_reader
|
|
||||||
def console_get_by_pool_instance(context, pool_id, instance_uuid):
|
|
||||||
result = model_query(context, models.Console, read_deleted="yes").\
|
|
||||||
filter_by(pool_id=pool_id).\
|
|
||||||
filter_by(instance_uuid=instance_uuid).\
|
|
||||||
options(joinedload('pool')).\
|
|
||||||
first()
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
raise exception.ConsoleNotFoundInPoolForInstance(
|
|
||||||
pool_id=pool_id, instance_uuid=instance_uuid)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_reader
|
|
||||||
def console_get_all_by_instance(context, instance_uuid, columns_to_join=None):
|
|
||||||
query = model_query(context, models.Console, read_deleted="yes").\
|
|
||||||
filter_by(instance_uuid=instance_uuid)
|
|
||||||
if columns_to_join:
|
|
||||||
for column in columns_to_join:
|
|
||||||
query = query.options(joinedload(column))
|
|
||||||
return query.all()
|
|
||||||
|
|
||||||
|
|
||||||
@pick_context_manager_reader
|
|
||||||
def console_get(context, console_id, instance_uuid=None):
|
|
||||||
query = model_query(context, models.Console, read_deleted="yes").\
|
|
||||||
filter_by(id=console_id).\
|
|
||||||
options(joinedload('pool'))
|
|
||||||
|
|
||||||
if instance_uuid is not None:
|
|
||||||
query = query.filter_by(instance_uuid=instance_uuid)
|
|
||||||
|
|
||||||
result = query.first()
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
if instance_uuid:
|
|
||||||
raise exception.ConsoleNotFoundForInstance(
|
|
||||||
instance_uuid=instance_uuid)
|
|
||||||
else:
|
|
||||||
raise exception.ConsoleNotFound(console_id=console_id)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
########################
|
########################
|
||||||
# User-provided metadata
|
# User-provided metadata
|
||||||
|
|
||||||
|
|
|
@ -1001,6 +1001,7 @@ class ConsolePool(BASE, NovaBase, models.SoftDeleteMixin):
|
||||||
compute_host = Column(String(255))
|
compute_host = Column(String(255))
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(stephenfin): Remove in V or later
|
||||||
class Console(BASE, NovaBase, models.SoftDeleteMixin):
|
class Console(BASE, NovaBase, models.SoftDeleteMixin):
|
||||||
"""Represents a console session for an instance."""
|
"""Represents a console session for an instance."""
|
||||||
__tablename__ = 'consoles'
|
__tablename__ = 'consoles'
|
||||||
|
|
|
@ -1203,35 +1203,10 @@ class ConsoleLogOutputException(NovaException):
|
||||||
"%(instance_id)s. Reason: %(reason)s")
|
"%(instance_id)s. Reason: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
class ConsolePoolExists(NovaException):
|
|
||||||
msg_fmt = _("Console pool with host %(host)s, console_type "
|
|
||||||
"%(console_type)s and compute_host %(compute_host)s "
|
|
||||||
"already exists.")
|
|
||||||
|
|
||||||
|
|
||||||
class ConsolePoolNotFoundForHostType(NotFound):
|
|
||||||
msg_fmt = _("Console pool of type %(console_type)s "
|
|
||||||
"for compute host %(compute_host)s "
|
|
||||||
"on proxy host %(host)s not found.")
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleNotFound(NotFound):
|
|
||||||
msg_fmt = _("Console %(console_id)s could not be found.")
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleNotFoundForInstance(ConsoleNotFound):
|
|
||||||
msg_fmt = _("Console for instance %(instance_uuid)s could not be found.")
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleNotAvailable(NotFound):
|
class ConsoleNotAvailable(NotFound):
|
||||||
msg_fmt = _("Guest does not have a console available.")
|
msg_fmt = _("Guest does not have a console available.")
|
||||||
|
|
||||||
|
|
||||||
class ConsoleNotFoundInPoolForInstance(ConsoleNotFound):
|
|
||||||
msg_fmt = _("Console for instance %(instance_uuid)s "
|
|
||||||
"in pool %(pool_id)s could not be found.")
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleTypeInvalid(Invalid):
|
class ConsoleTypeInvalid(Invalid):
|
||||||
msg_fmt = _("Invalid console type %(console_type)s")
|
msg_fmt = _("Invalid console type %(console_type)s")
|
||||||
|
|
||||||
|
|
|
@ -796,6 +796,8 @@ class NotificationSource(BaseNovaEnum):
|
||||||
# TODO(stephenfin): Remove when 'NotificationPublisher' object version is
|
# TODO(stephenfin): Remove when 'NotificationPublisher' object version is
|
||||||
# bumped to 3.0
|
# bumped to 3.0
|
||||||
CELLS = 'nova-cells'
|
CELLS = 'nova-cells'
|
||||||
|
# TODO(stephenfin): Remove when 'NotificationPublisher' object version is
|
||||||
|
# bumped to 3.0
|
||||||
CONSOLE = 'nova-console'
|
CONSOLE = 'nova-console'
|
||||||
METADATA = 'nova-metadata'
|
METADATA = 'nova-metadata'
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,6 @@ CONF = nova.conf.CONF
|
||||||
|
|
||||||
SERVICE_MANAGERS = {
|
SERVICE_MANAGERS = {
|
||||||
'nova-compute': 'nova.compute.manager.ComputeManager',
|
'nova-compute': 'nova.compute.manager.ComputeManager',
|
||||||
'nova-console': 'nova.console.manager.ConsoleProxyManager',
|
|
||||||
'nova-conductor': 'nova.conductor.manager.ConductorManager',
|
'nova-conductor': 'nova.conductor.manager.ConductorManager',
|
||||||
'nova-metadata': 'nova.api.manager.MetadataManager',
|
'nova-metadata': 'nova.api.manager.MetadataManager',
|
||||||
'nova-scheduler': 'nova.scheduler.manager.SchedulerManager',
|
'nova-scheduler': 'nova.scheduler.manager.SchedulerManager',
|
||||||
|
|
|
@ -1,199 +0,0 @@
|
||||||
# Copyright (c) 2010 OpenStack Foundation
|
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Tests For Console proxy."""
|
|
||||||
|
|
||||||
import fixtures
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from nova.compute import rpcapi as compute_rpcapi
|
|
||||||
from nova.console import api as console_api
|
|
||||||
from nova.console import manager as console_manager
|
|
||||||
from nova import context
|
|
||||||
from nova.db import api as db
|
|
||||||
from nova import exception
|
|
||||||
from nova import objects
|
|
||||||
from nova import test
|
|
||||||
from nova.tests.unit import fake_instance
|
|
||||||
from nova.tests.unit import fake_xvp_console_proxy
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleTestCase(test.TestCase):
|
|
||||||
"""Test case for console proxy manager."""
|
|
||||||
def setUp(self):
|
|
||||||
super(ConsoleTestCase, self).setUp()
|
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
|
||||||
'nova.console.manager.xvp.XVPConsoleProxy',
|
|
||||||
fake_xvp_console_proxy.FakeConsoleProxy))
|
|
||||||
self.console = console_manager.ConsoleProxyManager()
|
|
||||||
self.user_id = 'fake'
|
|
||||||
self.project_id = 'fake'
|
|
||||||
self.context = context.RequestContext(self.user_id, self.project_id)
|
|
||||||
self.host = 'test_compute_host'
|
|
||||||
self.pool_info = {'address': '127.0.0.1',
|
|
||||||
'username': 'test',
|
|
||||||
'password': '1234pass'}
|
|
||||||
|
|
||||||
def test_reset(self):
|
|
||||||
with mock.patch('nova.compute.rpcapi.ComputeAPI') as mock_rpc:
|
|
||||||
old_rpcapi = self.console.compute_rpcapi
|
|
||||||
self.console.reset()
|
|
||||||
mock_rpc.assert_called_once_with()
|
|
||||||
self.assertNotEqual(old_rpcapi,
|
|
||||||
self.console.compute_rpcapi)
|
|
||||||
|
|
||||||
def _create_instance(self):
|
|
||||||
"""Create a test instance."""
|
|
||||||
inst = {}
|
|
||||||
inst['image_id'] = 1
|
|
||||||
inst['reservation_id'] = 'r-fakeres'
|
|
||||||
inst['user_id'] = self.user_id
|
|
||||||
inst['project_id'] = self.project_id
|
|
||||||
inst['instance_type_id'] = 1
|
|
||||||
inst['ami_launch_index'] = 0
|
|
||||||
return fake_instance.fake_instance_obj(self.context, **inst)
|
|
||||||
|
|
||||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info')
|
|
||||||
def test_get_pool_for_instance_host(self, mock_get):
|
|
||||||
mock_get.return_value = self.pool_info
|
|
||||||
pool = self.console._get_pool_for_instance_host(self.context,
|
|
||||||
self.host)
|
|
||||||
self.assertEqual(pool['compute_host'], self.host)
|
|
||||||
|
|
||||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info')
|
|
||||||
def test_get_pool_creates_new_pool_if_needed(self, mock_get):
|
|
||||||
mock_get.return_value = self.pool_info
|
|
||||||
self.assertRaises(exception.NotFound,
|
|
||||||
db.console_pool_get_by_host_type,
|
|
||||||
self.context,
|
|
||||||
self.host,
|
|
||||||
self.console.host,
|
|
||||||
self.console.driver.console_type)
|
|
||||||
pool = self.console._get_pool_for_instance_host(self.context,
|
|
||||||
self.host)
|
|
||||||
pool2 = db.console_pool_get_by_host_type(self.context,
|
|
||||||
self.host,
|
|
||||||
self.console.host,
|
|
||||||
self.console.driver.console_type)
|
|
||||||
self.assertEqual(pool['id'], pool2['id'])
|
|
||||||
|
|
||||||
def test_get_pool_does_not_create_new_pool_if_exists(self):
|
|
||||||
pool_info = {'address': '127.0.0.1',
|
|
||||||
'username': 'test',
|
|
||||||
'password': '1234pass',
|
|
||||||
'host': self.console.host,
|
|
||||||
'console_type': self.console.driver.console_type,
|
|
||||||
'compute_host': 'sometesthostname'}
|
|
||||||
new_pool = db.console_pool_create(self.context, pool_info)
|
|
||||||
pool = self.console._get_pool_for_instance_host(self.context,
|
|
||||||
'sometesthostname')
|
|
||||||
self.assertEqual(pool['id'], new_pool['id'])
|
|
||||||
|
|
||||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info')
|
|
||||||
@mock.patch('nova.objects.instance.Instance.get_by_id')
|
|
||||||
def test_add_console(self, mock_id, mock_get):
|
|
||||||
mock_get.return_value = self.pool_info
|
|
||||||
|
|
||||||
instance = self._create_instance()
|
|
||||||
mock_id.return_value = instance
|
|
||||||
self.console.add_console(self.context, instance.id)
|
|
||||||
pool = db.console_pool_get_by_host_type(self.context,
|
|
||||||
instance.host, self.console.host,
|
|
||||||
self.console.driver.console_type)
|
|
||||||
|
|
||||||
console_instances = [con['instance_uuid'] for con in pool['consoles']]
|
|
||||||
self.assertIn(instance.uuid, console_instances)
|
|
||||||
|
|
||||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info')
|
|
||||||
@mock.patch('nova.objects.instance.Instance.get_by_id')
|
|
||||||
def test_add_console_does_not_duplicate(self, mock_id, mock_get):
|
|
||||||
mock_get.return_value = self.pool_info
|
|
||||||
|
|
||||||
instance = self._create_instance()
|
|
||||||
mock_id.return_value = instance
|
|
||||||
cons1 = self.console.add_console(self.context, instance.id)
|
|
||||||
cons2 = self.console.add_console(self.context, instance.id)
|
|
||||||
self.assertEqual(cons1, cons2)
|
|
||||||
|
|
||||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info')
|
|
||||||
@mock.patch('nova.objects.instance.Instance.get_by_id')
|
|
||||||
def test_remove_console(self, mock_id, mock_get):
|
|
||||||
mock_get.return_value = self.pool_info
|
|
||||||
|
|
||||||
instance = self._create_instance()
|
|
||||||
mock_id.return_value = instance
|
|
||||||
console_id = self.console.add_console(self.context, instance.id)
|
|
||||||
self.console.remove_console(self.context, console_id)
|
|
||||||
|
|
||||||
self.assertRaises(exception.NotFound,
|
|
||||||
db.console_get,
|
|
||||||
self.context,
|
|
||||||
console_id)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleAPITestCase(test.NoDBTestCase):
|
|
||||||
"""Test case for console API."""
|
|
||||||
def setUp(self):
|
|
||||||
super(ConsoleAPITestCase, self).setUp()
|
|
||||||
|
|
||||||
self.context = context.RequestContext('fake', 'fake')
|
|
||||||
self.console_api = console_api.API()
|
|
||||||
self.fake_uuid = '00000000-aaaa-bbbb-cccc-000000000000'
|
|
||||||
self.fake_instance = {
|
|
||||||
'id': 1,
|
|
||||||
'uuid': self.fake_uuid,
|
|
||||||
'host': 'fake_host'
|
|
||||||
}
|
|
||||||
self.fake_console = {
|
|
||||||
'pool': {'host': 'fake_host'},
|
|
||||||
'id': 'fake_id'
|
|
||||||
}
|
|
||||||
|
|
||||||
def _fake_db_console_get(_ctxt, _console_uuid, _instance_uuid):
|
|
||||||
return self.fake_console
|
|
||||||
self.stub_out('nova.db.api.console_get', _fake_db_console_get)
|
|
||||||
|
|
||||||
def _fake_db_console_get_all_by_instance(_ctxt, _instance_uuid,
|
|
||||||
columns_to_join):
|
|
||||||
return [self.fake_console]
|
|
||||||
self.stub_out('nova.db.api.console_get_all_by_instance',
|
|
||||||
_fake_db_console_get_all_by_instance)
|
|
||||||
|
|
||||||
def test_get_consoles(self):
|
|
||||||
console = self.console_api.get_consoles(self.context, self.fake_uuid)
|
|
||||||
self.assertEqual(console, [self.fake_console])
|
|
||||||
|
|
||||||
def test_get_console(self):
|
|
||||||
console = self.console_api.get_console(self.context, self.fake_uuid,
|
|
||||||
'fake_id')
|
|
||||||
self.assertEqual(console, self.fake_console)
|
|
||||||
|
|
||||||
@mock.patch('nova.console.rpcapi.ConsoleAPI.remove_console')
|
|
||||||
def test_delete_console(self, mock_remove):
|
|
||||||
self.console_api.delete_console(self.context, self.fake_uuid,
|
|
||||||
'fake_id')
|
|
||||||
mock_remove.assert_called_once_with(self.context, 'fake_id')
|
|
||||||
|
|
||||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_topic',
|
|
||||||
return_value='compute.fake_host')
|
|
||||||
@mock.patch.object(objects.Instance, 'get_by_uuid')
|
|
||||||
def test_create_console(self, mock_get_instance_by_uuid,
|
|
||||||
mock_get_console_topic):
|
|
||||||
mock_get_instance_by_uuid.return_value = objects.Instance(
|
|
||||||
**self.fake_instance)
|
|
||||||
self.console_api.create_console(self.context, self.fake_uuid)
|
|
||||||
mock_get_console_topic.assert_called_once_with(self.context,
|
|
||||||
'fake_host')
|
|
|
@ -1,61 +0,0 @@
|
||||||
# Copyright 2012, Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Unit Tests for nova.console.rpcapi
|
|
||||||
"""
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from nova.console import rpcapi as console_rpcapi
|
|
||||||
from nova import context
|
|
||||||
from nova import test
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleRpcAPITestCase(test.NoDBTestCase):
|
|
||||||
def _test_console_api(self, method, rpc_method, **kwargs):
|
|
||||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
|
||||||
|
|
||||||
rpcapi = console_rpcapi.ConsoleAPI()
|
|
||||||
self.assertIsNotNone(rpcapi.client)
|
|
||||||
self.assertEqual(rpcapi.client.target.topic,
|
|
||||||
console_rpcapi.RPC_TOPIC)
|
|
||||||
|
|
||||||
orig_prepare = rpcapi.client.prepare
|
|
||||||
|
|
||||||
with test.nested(
|
|
||||||
mock.patch.object(rpcapi.client, rpc_method),
|
|
||||||
mock.patch.object(rpcapi.client, 'prepare'),
|
|
||||||
mock.patch.object(rpcapi.client, 'can_send_version'),
|
|
||||||
) as (
|
|
||||||
rpc_mock, prepare_mock, csv_mock
|
|
||||||
):
|
|
||||||
prepare_mock.return_value = rpcapi.client
|
|
||||||
rpc_mock.return_value = 'foo' if rpc_method == 'call' else None
|
|
||||||
csv_mock.side_effect = (
|
|
||||||
lambda v: orig_prepare().can_send_version())
|
|
||||||
|
|
||||||
retval = getattr(rpcapi, method)(ctxt, **kwargs)
|
|
||||||
self.assertEqual(retval, rpc_mock.return_value)
|
|
||||||
|
|
||||||
prepare_mock.assert_called_once_with()
|
|
||||||
rpc_mock.assert_called_once_with(ctxt, method, **kwargs)
|
|
||||||
|
|
||||||
def test_add_console(self):
|
|
||||||
self._test_console_api('add_console', instance_id='i',
|
|
||||||
rpc_method='cast')
|
|
||||||
|
|
||||||
def test_remove_console(self):
|
|
||||||
self._test_console_api('remove_console', console_id='i',
|
|
||||||
rpc_method='cast')
|
|
|
@ -3210,25 +3210,6 @@ class InstanceTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
|
|
||||||
db.virtual_interface_create(ctxt, {'instance_uuid': uuid})
|
db.virtual_interface_create(ctxt, {'instance_uuid': uuid})
|
||||||
|
|
||||||
pool_values = {
|
|
||||||
'address': '192.168.10.10',
|
|
||||||
'username': 'user1',
|
|
||||||
'password': 'passwd1',
|
|
||||||
'console_type': 'type1',
|
|
||||||
'public_hostname': 'public_host1',
|
|
||||||
'host': 'host1',
|
|
||||||
'compute_host': 'compute_host1',
|
|
||||||
}
|
|
||||||
console_pool = db.console_pool_create(ctxt, pool_values)
|
|
||||||
console_values = {
|
|
||||||
'instance_name': instance['name'],
|
|
||||||
'instance_uuid': uuid,
|
|
||||||
'password': 'pass',
|
|
||||||
'port': 7878,
|
|
||||||
'pool_id': console_pool['id']
|
|
||||||
}
|
|
||||||
db.console_create(self.ctxt, console_values)
|
|
||||||
|
|
||||||
# Hard delete the instance
|
# Hard delete the instance
|
||||||
db.instance_destroy(ctxt, uuid, hard_delete=True)
|
db.instance_destroy(ctxt, uuid, hard_delete=True)
|
||||||
|
|
||||||
|
@ -3260,10 +3241,7 @@ class InstanceTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
_assert_instance_id_mapping(ctxt, self, uuid)
|
_assert_instance_id_mapping(ctxt, self, uuid)
|
||||||
self.assertRaises(exception.InstanceNotFound,
|
self.assertRaises(exception.InstanceNotFound,
|
||||||
db.instance_destroy, ctxt, uuid)
|
db.instance_destroy, ctxt, uuid)
|
||||||
# NOTE(ttsiouts): Should these also be valid?
|
# NOTE(ttsiouts): FixedIp has the instance_uuid as a foreign key
|
||||||
# instance_consoles = db.console_get_all_by_instance(ctxt, uuid)
|
|
||||||
# self.assertEqual(0, len(instance_consoles))
|
|
||||||
# Also FixedIp has the instance_uuid as a foreign key
|
|
||||||
|
|
||||||
def test_check_instance_exists(self):
|
def test_check_instance_exists(self):
|
||||||
instance = self.create_instance_with_args()
|
instance = self.create_instance_with_args()
|
||||||
|
@ -7916,207 +7894,6 @@ class CertificateTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
self._assertEqualObjects(self.created[1], cert[0])
|
self._assertEqualObjects(self.created[1], cert[0])
|
||||||
|
|
||||||
|
|
||||||
class ConsoleTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(ConsoleTestCase, self).setUp()
|
|
||||||
self.ctxt = context.get_admin_context()
|
|
||||||
pools_data = [
|
|
||||||
{'address': '192.168.10.10',
|
|
||||||
'username': 'user1',
|
|
||||||
'password': 'passwd1',
|
|
||||||
'console_type': 'type1',
|
|
||||||
'public_hostname': 'public_host1',
|
|
||||||
'host': 'host1',
|
|
||||||
'compute_host': 'compute_host1',
|
|
||||||
},
|
|
||||||
{'address': '192.168.10.11',
|
|
||||||
'username': 'user2',
|
|
||||||
'password': 'passwd2',
|
|
||||||
'console_type': 'type2',
|
|
||||||
'public_hostname': 'public_host2',
|
|
||||||
'host': 'host2',
|
|
||||||
'compute_host': 'compute_host2',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
self.console_pools = [db.console_pool_create(self.ctxt, val)
|
|
||||||
for val in pools_data]
|
|
||||||
instance_uuid = uuidsentinel.uuid1
|
|
||||||
db.instance_create(self.ctxt, {'uuid': instance_uuid})
|
|
||||||
self.console_data = [{'instance_name': 'name' + str(x),
|
|
||||||
'instance_uuid': instance_uuid,
|
|
||||||
'password': 'pass' + str(x),
|
|
||||||
'port': 7878 + x,
|
|
||||||
'pool_id': self.console_pools[x]['id']}
|
|
||||||
for x in range(len(pools_data))]
|
|
||||||
self.consoles = [db.console_create(self.ctxt, val)
|
|
||||||
for val in self.console_data]
|
|
||||||
|
|
||||||
def test_console_create(self):
|
|
||||||
ignored_keys = ['id', 'deleted', 'deleted_at', 'created_at',
|
|
||||||
'updated_at']
|
|
||||||
for console in self.consoles:
|
|
||||||
self.assertIsNotNone(console['id'])
|
|
||||||
self._assertEqualListsOfObjects(self.console_data, self.consoles,
|
|
||||||
ignored_keys=ignored_keys)
|
|
||||||
|
|
||||||
def test_console_get_by_id(self):
|
|
||||||
console = self.consoles[0]
|
|
||||||
console_get = db.console_get(self.ctxt, console['id'])
|
|
||||||
self._assertEqualObjects(console, console_get,
|
|
||||||
ignored_keys=['pool'])
|
|
||||||
|
|
||||||
def test_console_get_by_id_uuid(self):
|
|
||||||
console = self.consoles[0]
|
|
||||||
console_get = db.console_get(self.ctxt, console['id'],
|
|
||||||
console['instance_uuid'])
|
|
||||||
self._assertEqualObjects(console, console_get,
|
|
||||||
ignored_keys=['pool'])
|
|
||||||
|
|
||||||
def test_console_get_by_pool_instance(self):
|
|
||||||
console = self.consoles[0]
|
|
||||||
console_get = db.console_get_by_pool_instance(self.ctxt,
|
|
||||||
console['pool_id'], console['instance_uuid'])
|
|
||||||
self._assertEqualObjects(console, console_get,
|
|
||||||
ignored_keys=['pool'])
|
|
||||||
|
|
||||||
def test_console_get_all_by_instance(self):
|
|
||||||
instance_uuid = self.consoles[0]['instance_uuid']
|
|
||||||
consoles_get = db.console_get_all_by_instance(self.ctxt, instance_uuid)
|
|
||||||
self._assertEqualListsOfObjects(self.consoles, consoles_get)
|
|
||||||
|
|
||||||
def test_console_get_all_by_instance_with_pool(self):
|
|
||||||
instance_uuid = self.consoles[0]['instance_uuid']
|
|
||||||
consoles_get = db.console_get_all_by_instance(self.ctxt, instance_uuid,
|
|
||||||
columns_to_join=['pool'])
|
|
||||||
self._assertEqualListsOfObjects(self.consoles, consoles_get,
|
|
||||||
ignored_keys=['pool'])
|
|
||||||
self._assertEqualListsOfObjects([pool for pool in self.console_pools],
|
|
||||||
[c['pool'] for c in consoles_get])
|
|
||||||
|
|
||||||
def test_console_get_all_by_instance_empty(self):
|
|
||||||
consoles_get = db.console_get_all_by_instance(self.ctxt,
|
|
||||||
uuidsentinel.uuid2)
|
|
||||||
self.assertEqual(consoles_get, [])
|
|
||||||
|
|
||||||
def test_console_delete(self):
|
|
||||||
console_id = self.consoles[0]['id']
|
|
||||||
db.console_delete(self.ctxt, console_id)
|
|
||||||
self.assertRaises(exception.ConsoleNotFound, db.console_get,
|
|
||||||
self.ctxt, console_id)
|
|
||||||
|
|
||||||
def test_console_get_by_pool_instance_not_found(self):
|
|
||||||
self.assertRaises(exception.ConsoleNotFoundInPoolForInstance,
|
|
||||||
db.console_get_by_pool_instance, self.ctxt,
|
|
||||||
self.consoles[0]['pool_id'],
|
|
||||||
uuidsentinel.uuid2)
|
|
||||||
|
|
||||||
def test_console_get_not_found(self):
|
|
||||||
self.assertRaises(exception.ConsoleNotFound, db.console_get,
|
|
||||||
self.ctxt, 100500)
|
|
||||||
|
|
||||||
def test_console_get_not_found_instance(self):
|
|
||||||
self.assertRaises(exception.ConsoleNotFoundForInstance, db.console_get,
|
|
||||||
self.ctxt, self.consoles[0]['id'],
|
|
||||||
uuidsentinel.uuid2)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsolePoolTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
|
||||||
def setUp(self):
|
|
||||||
super(ConsolePoolTestCase, self).setUp()
|
|
||||||
|
|
||||||
self.ctxt = context.get_admin_context()
|
|
||||||
self.test_console_pool_1 = {
|
|
||||||
'address': '192.168.2.10',
|
|
||||||
'username': 'user_1',
|
|
||||||
'password': 'secret_123',
|
|
||||||
'console_type': 'type_1',
|
|
||||||
'public_hostname': 'public_hostname_123',
|
|
||||||
'host': 'localhost',
|
|
||||||
'compute_host': '127.0.0.1',
|
|
||||||
}
|
|
||||||
self.test_console_pool_2 = {
|
|
||||||
'address': '192.168.2.11',
|
|
||||||
'username': 'user_2',
|
|
||||||
'password': 'secret_1234',
|
|
||||||
'console_type': 'type_2',
|
|
||||||
'public_hostname': 'public_hostname_1234',
|
|
||||||
'host': '127.0.0.1',
|
|
||||||
'compute_host': 'localhost',
|
|
||||||
}
|
|
||||||
self.test_console_pool_3 = {
|
|
||||||
'address': '192.168.2.12',
|
|
||||||
'username': 'user_3',
|
|
||||||
'password': 'secret_12345',
|
|
||||||
'console_type': 'type_2',
|
|
||||||
'public_hostname': 'public_hostname_12345',
|
|
||||||
'host': '127.0.0.1',
|
|
||||||
'compute_host': '192.168.1.1',
|
|
||||||
}
|
|
||||||
|
|
||||||
def test_console_pool_create(self):
|
|
||||||
console_pool = db.console_pool_create(
|
|
||||||
self.ctxt, self.test_console_pool_1)
|
|
||||||
self.assertIsNotNone(console_pool.get('id'))
|
|
||||||
ignored_keys = ['deleted', 'created_at', 'updated_at',
|
|
||||||
'deleted_at', 'id']
|
|
||||||
self._assertEqualObjects(
|
|
||||||
console_pool, self.test_console_pool_1, ignored_keys)
|
|
||||||
|
|
||||||
def test_console_pool_create_duplicate(self):
|
|
||||||
db.console_pool_create(self.ctxt, self.test_console_pool_1)
|
|
||||||
self.assertRaises(exception.ConsolePoolExists, db.console_pool_create,
|
|
||||||
self.ctxt, self.test_console_pool_1)
|
|
||||||
|
|
||||||
def test_console_pool_get_by_host_type(self):
|
|
||||||
params = [
|
|
||||||
self.test_console_pool_1,
|
|
||||||
self.test_console_pool_2,
|
|
||||||
]
|
|
||||||
|
|
||||||
for p in params:
|
|
||||||
db.console_pool_create(self.ctxt, p)
|
|
||||||
|
|
||||||
ignored_keys = ['deleted', 'created_at', 'updated_at',
|
|
||||||
'deleted_at', 'id', 'consoles']
|
|
||||||
|
|
||||||
cp = self.test_console_pool_1
|
|
||||||
db_cp = db.console_pool_get_by_host_type(
|
|
||||||
self.ctxt, cp['compute_host'], cp['host'], cp['console_type']
|
|
||||||
)
|
|
||||||
self._assertEqualObjects(cp, db_cp, ignored_keys)
|
|
||||||
|
|
||||||
def test_console_pool_get_by_host_type_no_resuls(self):
|
|
||||||
self.assertRaises(
|
|
||||||
exception.ConsolePoolNotFoundForHostType,
|
|
||||||
db.console_pool_get_by_host_type, self.ctxt, 'compute_host',
|
|
||||||
'host', 'console_type')
|
|
||||||
|
|
||||||
def test_console_pool_get_all_by_host_type(self):
|
|
||||||
params = [
|
|
||||||
self.test_console_pool_1,
|
|
||||||
self.test_console_pool_2,
|
|
||||||
self.test_console_pool_3,
|
|
||||||
]
|
|
||||||
for p in params:
|
|
||||||
db.console_pool_create(self.ctxt, p)
|
|
||||||
ignored_keys = ['deleted', 'created_at', 'updated_at',
|
|
||||||
'deleted_at', 'id', 'consoles']
|
|
||||||
|
|
||||||
cp = self.test_console_pool_2
|
|
||||||
db_cp = db.console_pool_get_all_by_host_type(
|
|
||||||
self.ctxt, cp['host'], cp['console_type'])
|
|
||||||
|
|
||||||
self._assertEqualListsOfObjects(
|
|
||||||
db_cp, [self.test_console_pool_2, self.test_console_pool_3],
|
|
||||||
ignored_keys)
|
|
||||||
|
|
||||||
def test_console_pool_get_all_by_host_type_no_results(self):
|
|
||||||
res = db.console_pool_get_all_by_host_type(
|
|
||||||
self.ctxt, 'cp_host', 'cp_console_type')
|
|
||||||
self.assertEqual([], res)
|
|
||||||
|
|
||||||
|
|
||||||
class DnsdomainTestCase(test.TestCase):
|
class DnsdomainTestCase(test.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -8455,9 +8232,6 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
self.dns_domains = models.DNSDomain.__table__
|
self.dns_domains = models.DNSDomain.__table__
|
||||||
self.shadow_dns_domains = sqlalchemyutils.get_table(
|
self.shadow_dns_domains = sqlalchemyutils.get_table(
|
||||||
self.engine, "shadow_dns_domains")
|
self.engine, "shadow_dns_domains")
|
||||||
self.consoles = models.Console.__table__
|
|
||||||
self.shadow_consoles = sqlalchemyutils.get_table(
|
|
||||||
self.engine, "shadow_consoles")
|
|
||||||
self.console_pools = models.ConsolePool.__table__
|
self.console_pools = models.ConsolePool.__table__
|
||||||
self.shadow_console_pools = sqlalchemyutils.get_table(
|
self.shadow_console_pools = sqlalchemyutils.get_table(
|
||||||
self.engine, "shadow_console_pools")
|
self.engine, "shadow_console_pools")
|
||||||
|
@ -8813,41 +8587,6 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin):
|
||||||
'sqlite version too old for reliable SQLA foreign_keys')
|
'sqlite version too old for reliable SQLA foreign_keys')
|
||||||
self.conn.execute("PRAGMA foreign_keys = ON")
|
self.conn.execute("PRAGMA foreign_keys = ON")
|
||||||
|
|
||||||
def test_archive_deleted_rows_fk_constraint(self):
|
|
||||||
# consoles.pool_id depends on console_pools.id
|
|
||||||
self._check_sqlite_version_less_than_3_7()
|
|
||||||
ins_stmt = self.console_pools.insert().values(deleted=1,
|
|
||||||
deleted_at=timeutils.utcnow())
|
|
||||||
result = self.conn.execute(ins_stmt)
|
|
||||||
id1 = result.inserted_primary_key[0]
|
|
||||||
ins_stmt = self.consoles.insert().values(deleted=1,
|
|
||||||
deleted_at=timeutils.utcnow(),
|
|
||||||
pool_id=id1)
|
|
||||||
result = self.conn.execute(ins_stmt)
|
|
||||||
result.inserted_primary_key[0]
|
|
||||||
# The first try to archive console_pools should fail, due to FK.
|
|
||||||
num = sqlalchemy_api._archive_deleted_rows_for_table(self.metadata,
|
|
||||||
"console_pools",
|
|
||||||
max_rows=None,
|
|
||||||
before=None)
|
|
||||||
self.assertEqual(num[0], 0)
|
|
||||||
# Then archiving consoles should work.
|
|
||||||
num = sqlalchemy_api._archive_deleted_rows_for_table(self.metadata,
|
|
||||||
"consoles",
|
|
||||||
max_rows=None,
|
|
||||||
before=None)
|
|
||||||
self.assertEqual(num[0], 1)
|
|
||||||
# Then archiving console_pools should work.
|
|
||||||
num = sqlalchemy_api._archive_deleted_rows_for_table(self.metadata,
|
|
||||||
"console_pools",
|
|
||||||
max_rows=None,
|
|
||||||
before=None)
|
|
||||||
self.assertEqual(num[0], 1)
|
|
||||||
self._assert_shadow_tables_empty_except(
|
|
||||||
'shadow_console_pools',
|
|
||||||
'shadow_consoles'
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_archive_deleted_rows_for_migrations(self):
|
def test_archive_deleted_rows_for_migrations(self):
|
||||||
# migrations.instance_uuid depends on instances.uuid
|
# migrations.instance_uuid depends on instances.uuid
|
||||||
self._check_sqlite_version_less_than_3_7()
|
self._check_sqlite_version_less_than_3_7()
|
||||||
|
|
|
@ -55,8 +55,6 @@ class TestProfiler(test.NoDBTestCase):
|
||||||
'nova.conductor.manager.ConductorManager',
|
'nova.conductor.manager.ConductorManager',
|
||||||
'nova.conductor.rpcapi.ComputeTaskAPI',
|
'nova.conductor.rpcapi.ComputeTaskAPI',
|
||||||
'nova.conductor.rpcapi.ConductorAPI',
|
'nova.conductor.rpcapi.ConductorAPI',
|
||||||
'nova.console.manager.ConsoleProxyManager',
|
|
||||||
'nova.console.rpcapi.ConsoleAPI',
|
|
||||||
'nova.image.api.API',
|
'nova.image.api.API',
|
||||||
'nova.network.api.API',
|
'nova.network.api.API',
|
||||||
'nova.network.manager.FlatDHCPManager',
|
'nova.network.manager.FlatDHCPManager',
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
---
|
---
|
||||||
upgrade:
|
upgrade:
|
||||||
- |
|
- |
|
||||||
The following APIs have been removed. Calling these APIs will
|
The ``nova-console`` service has been deprecated since the 19.0.0 Stein
|
||||||
|
release and has now been removed. The following configuration options are
|
||||||
|
therefore removed.
|
||||||
|
|
||||||
|
* ``[upgrade_levels] console``
|
||||||
|
|
||||||
|
In addition, the following APIs have been removed. Calling these APIs will
|
||||||
now result in a ``410 HTTPGone`` error response:
|
now result in a ``410 HTTPGone`` error response:
|
||||||
|
|
||||||
* ``POST /servers/{server_id}/consoles``
|
* ``POST /servers/{server_id}/consoles``
|
||||||
|
@ -9,7 +15,7 @@ upgrade:
|
||||||
* ``GET /servers/{server_id}/consoles/{console_id}``
|
* ``GET /servers/{server_id}/consoles/{console_id}``
|
||||||
* ``DELETE /servers/{server_id}/consoles/{console_id}``
|
* ``DELETE /servers/{server_id}/consoles/{console_id}``
|
||||||
|
|
||||||
In addition, the following policies are removed. These were related to the
|
Finally, the following policies are removed. These were related to the
|
||||||
removed APIs listed above and no longer had any effect:
|
removed APIs listed above and no longer had any effect:
|
||||||
|
|
||||||
* ``os_compute_api:os-consoles:index``
|
* ``os_compute_api:os-consoles:index``
|
||||||
|
|
|
@ -66,7 +66,6 @@ console_scripts =
|
||||||
nova-api-os-compute = nova.cmd.api_os_compute:main
|
nova-api-os-compute = nova.cmd.api_os_compute:main
|
||||||
nova-compute = nova.cmd.compute:main
|
nova-compute = nova.cmd.compute:main
|
||||||
nova-conductor = nova.cmd.conductor:main
|
nova-conductor = nova.cmd.conductor:main
|
||||||
nova-console = nova.cmd.console:main
|
|
||||||
nova-dhcpbridge = nova.cmd.dhcpbridge:main
|
nova-dhcpbridge = nova.cmd.dhcpbridge:main
|
||||||
nova-manage = nova.cmd.manage:main
|
nova-manage = nova.cmd.manage:main
|
||||||
nova-network = nova.cmd.network:main
|
nova-network = nova.cmd.network:main
|
||||||
|
|
Loading…
Reference in New Issue