# 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.""" import socket from oslo.config import cfg from oslo import messaging from nova.compute import rpcapi as compute_rpcapi from nova import exception from nova import manager from nova.openstack.common import importutils from nova.openstack.common import log as logging from nova import utils console_manager_opts = [ cfg.StrOpt('console_driver', default='nova.console.xvp.XVPConsoleProxy', help='Driver to use for the console proxy'), cfg.BoolOpt('stub_compute', default=False, help='Stub calls to compute worker for tests'), cfg.StrOpt('console_public_hostname', default=socket.gethostname(), help='Publicly visible name for this console host'), ] CONF = cfg.CONF CONF.register_opts(console_manager_opts) 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, console_driver=None, *args, **kwargs): if not console_driver: console_driver = CONF.console_driver self.driver = importutils.import_object(console_driver) super(ConsoleProxyManager, self).__init__(service_name='console', *args, **kwargs) self.driver.host = self.host self.compute_rpcapi = compute_rpcapi.ComputeAPI() def init_host(self): self.driver.init_host() def add_console(self, context, instance_id): instance = self.db.instance_get(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 ned to ask. if CONF.stub_compute: pool_info = {'address': '127.0.0.1', 'username': 'test', 'password': '1234pass'} else: pool_info = self.compute_rpcapi.get_console_pool_info(context, console_type, instance_host) pool_info['password'] = self.driver.fix_pool_password( pool_info['password']) pool_info['host'] = self.host pool_info['public_hostname'] = CONF.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