48e94bf75c
When using serial console we are expecting using a plain websocket so we should to return the 'ws://' scheme as the default one, also it makes no sense to handle webserving content since currently nothing has been implemented in favor of this case. DocImpact: The 'base_url' option serial_console has been updated Closes-Bug: #1373950 Change-Id: I0d0e4f7060febec5e0a357cd3e8c05486f2afaa5
116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
# 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.
|
|
|
|
"""Serial consoles module."""
|
|
|
|
import socket
|
|
|
|
from oslo.config import cfg
|
|
import six.moves
|
|
|
|
from nova import exception
|
|
from nova.i18n import _LW
|
|
from nova.openstack.common import log as logging
|
|
from nova import utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
ALLOCATED_PORTS = set() # in-memory set of already allocated ports
|
|
SERIAL_LOCK = 'serial-lock'
|
|
DEFAULT_PORT_RANGE = '10000:20000'
|
|
|
|
serial_opts = [
|
|
cfg.BoolOpt('enabled',
|
|
default=False,
|
|
help='Enable serial console related features'),
|
|
cfg.StrOpt('port_range',
|
|
default=DEFAULT_PORT_RANGE,
|
|
help='Range of TCP ports to use for serial ports '
|
|
'on compute hosts'),
|
|
cfg.StrOpt('base_url',
|
|
default='ws://127.0.0.1:6083/',
|
|
help='Location of serial console proxy.'),
|
|
cfg.StrOpt('listen',
|
|
default='127.0.0.1',
|
|
help=('IP address on which instance serial console '
|
|
'should listen')),
|
|
cfg.StrOpt('proxyclient_address',
|
|
default='127.0.0.1',
|
|
help=('The address to which proxy clients '
|
|
'(like nova-serialproxy) should connect')),
|
|
]
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_opts(serial_opts, group='serial_console')
|
|
|
|
# TODO(sahid): Add a method to initialize ALOCATED_PORTS with the
|
|
# already binded TPC port(s). (cf from danpb: list all running guests and
|
|
# query the XML in libvirt driver to find out the TCP port(s) it uses).
|
|
|
|
|
|
@utils.synchronized(SERIAL_LOCK)
|
|
def acquire_port(host):
|
|
"""Returns a free TCP port on host.
|
|
|
|
Find and returns a free TCP port on 'host' in the range
|
|
of 'CONF.serial_console.port_range'.
|
|
"""
|
|
|
|
start, stop = _get_port_range()
|
|
|
|
for port in six.moves.range(start, stop):
|
|
if (host, port) in ALLOCATED_PORTS:
|
|
continue
|
|
try:
|
|
_verify_port(host, port)
|
|
ALLOCATED_PORTS.add((host, port))
|
|
return port
|
|
except exception.SocketPortInUseException as e:
|
|
LOG.warn(e)
|
|
|
|
raise exception.SocketPortRangeExhaustedException(host=host)
|
|
|
|
|
|
@utils.synchronized(SERIAL_LOCK)
|
|
def release_port(host, port):
|
|
"""Release TCP port to be used next time."""
|
|
ALLOCATED_PORTS.discard((host, port))
|
|
|
|
|
|
def _get_port_range():
|
|
config_range = CONF.serial_console.port_range
|
|
try:
|
|
start, stop = map(int, config_range.split(':'))
|
|
if start >= stop:
|
|
raise ValueError
|
|
except ValueError:
|
|
LOG.warn(_LW("serial_console.port_range should be <num>:<num>. "
|
|
"Given value %(port_range)s could not be parsed. "
|
|
"Taking the default port range %(default)s."),
|
|
{'port_range': config_range,
|
|
'default': DEFAULT_PORT_RANGE})
|
|
start, stop = map(int, DEFAULT_PORT_RANGE.split(':'))
|
|
return start, stop
|
|
|
|
|
|
def _verify_port(host, port):
|
|
s = socket.socket()
|
|
try:
|
|
s.bind((host, port))
|
|
except socket.error as e:
|
|
raise exception.SocketPortInUseException(
|
|
host=host, port=port, error=e)
|
|
finally:
|
|
s.close()
|