[Kimchi-devel] [PATCH] [Kimchi 3/6] Implement the backend to support web serial console
Aline Manera
alinefm at linux.vnet.ibm.com
Fri Feb 5 16:27:04 UTC 2016
On 02/04/2016 05:47 PM, Jose Ricardo Ziviani wrote:
> - This commit implements kimchi backend necessary to receive a web
> request to open the serial console for a particular guest, add
> the security token and starts the server.
>
> Signed-off-by: Jose Ricardo Ziviani <joserz at linux.vnet.ibm.com>
> ---
> control/vms.py | 3 ++-
> i18n.py | 4 +++-
> model/vms.py | 37 ++++++++++++++++++++++++++++++++++++-
> websocket.py | 34 ++++++++++++++++++++++++++++++++--
> 4 files changed, 73 insertions(+), 5 deletions(-)
>
> diff --git a/control/vms.py b/control/vms.py
> index 96bdb20..e9f01e1 100644
> --- a/control/vms.py
> +++ b/control/vms.py
> @@ -1,7 +1,7 @@
> #
> # Project Kimchi
> #
> -# Copyright IBM, Corp. 2013-2015
> +# Copyright IBM, Corp. 2013-2016
> #
> # This library is free software; you can redistribute it and/or
> # modify it under the terms of the GNU Lesser General Public
> @@ -55,6 +55,7 @@ class VM(Resource):
> 'password'])
> self.suspend = self.generate_action_handler('suspend')
> self.resume = self.generate_action_handler('resume')
> + self.serial = self.generate_action_handler('serial')
>
> @property
> def data(self):
> diff --git a/i18n.py b/i18n.py
> index a575922..f84e12c 100644
> --- a/i18n.py
> +++ b/i18n.py
> @@ -1,7 +1,7 @@
> #
> # Project Kimchi
> #
> -# Copyright IBM, Corp. 2014-2015
> +# Copyright IBM, Corp. 2014-2016
> #
> # This library is free software; you can redistribute it and/or
> # modify it under the terms of the GNU Lesser General Public
> @@ -131,6 +131,8 @@ messages = {
> "KCHVM0073E": _("Unable to update the following parameters while the VM is offline: %(params)s"),
> "KCHVM0074E": _("Unable to update the following parameters while the VM is online: %(params)s"),
> "KCHVM0075E": _("Cannot change VCPU value because '%(vm)s' has a topology defined - sockets: %(sockets)s, cores: %(cores)s, threads: %(threads)s."),
> + "KCHVM0076E": _("VM %(name)s must have serial and console defined to open a web serial console"),
> + "KCHVM0077E": _("Impossible to get the serial console of %(name)s"),
>
> "KCHVMHDEV0001E": _("VM %(vmid)s does not contain directly assigned host device %(dev_name)s."),
> "KCHVMHDEV0002E": _("The host device %(dev_name)s is not allowed to directly assign to VM."),
> diff --git a/model/vms.py b/model/vms.py
> index c76641c..26b5cfb 100644
> --- a/model/vms.py
> +++ b/model/vms.py
> @@ -1,7 +1,7 @@
> #
> # Project Kimchi
> #
> -# Copyright IBM, Corp. 2014-2015
> +# Copyright IBM, Corp. 2014-2016
> #
> # This library is free software; you can redistribute it and/or
> # modify it under the terms of the GNU Lesser General Public
> @@ -46,6 +46,7 @@ from wok.xmlutils.utils import dictize
>
> from wok.plugins.kimchi import model
> from wok.plugins.kimchi import websocket
> +from wok.plugins.kimchi import serial_console
> from wok.plugins.kimchi.config import READONLY_POOL_TYPE, get_kimchi_version
> from wok.plugins.kimchi.kvmusertests import UserTests
> from wok.plugins.kimchi.model.config import CapabilitiesModel
> @@ -245,6 +246,7 @@ class VMModel(object):
> cls = import_class('plugins.kimchi.model.vmsnapshots.VMSnapshotsModel')
> self.vmsnapshots = cls(**kargs)
> self.stats = {}
> + self._serial_procs = []
>
> def has_topology(self, dom):
> xml = dom.XMLDesc(0)
> @@ -1175,6 +1177,12 @@ class VMModel(object):
> else:
> memory = info[2] >> 10
>
> + # assure there is no zombie process left
> + for proc in self._serial_procs[:]:
> + if not proc.is_alive():
> + proc.join(1)
> + self._serial_procs.remove(proc)
> +
> return {'name': name,
> 'state': state,
> 'stats': res,
> @@ -1359,6 +1367,20 @@ class VMModel(object):
> raise OperationFailed("KCHVM0022E",
> {'name': name, 'err': e.get_error_message()})
>
> + def _vm_check_serial(self, name):
> + dom = self.get_vm(name, self.conn)
> + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
> +
> + expr = "/domain/devices/serial/@type"
> + if not xpath_get_text(xml, expr):
> + return False
> +
> + expr = "/domain/devices/console/@type"
> + if not xpath_get_text(xml, expr):
> + return False
> +
> + return True
> +
> def _vm_get_graphics(self, name):
> dom = self.get_vm(name, self.conn)
> xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
> @@ -1390,6 +1412,19 @@ class VMModel(object):
> return (graphics_type, graphics_listen, graphics_port,
> graphics_passwd, graphics_passwdValidTo)
>
> + def serial(self, name):
> + if not self._vm_check_serial(name):
> + raise OperationFailed("KCHVM0076E", {'name': name})
> +
> + websocket.add_proxy_token(name.encode('utf-8')+'-console',
> + '/tmp/%s' % name.encode('utf-8'))
> +
> + try:
> + self._serial_procs.append(
> + serial_console.main(name.encode('utf-8')))
> + except:
> + raise OperationFailed("KCHVM0077E", {'name': name})
> +
> def connect(self, name):
> # (type, listen, port, passwd, passwdValidTo)
> graphics_port = self._vm_get_graphics(name)[2]
> diff --git a/websocket.py b/websocket.py
> index 4f94ab2..ab3ffb4 100644
> --- a/websocket.py
> +++ b/websocket.py
> @@ -34,10 +34,32 @@ try:
> except ImportError:
> tokenFile = False
>
> +try:
> + from websockify import ProxyRequestHandler as request_proxy
> +except:
> + from websockify import WebSocketProxy as request_proxy
> +
>
> WS_TOKENS_DIR = os.path.join(PluginPaths('kimchi').state_dir, 'vnc-tokens')
>
>
> +class custom_handler(request_proxy):
> +
> +
CustomHandler
> def get_target(self, target_plugin, path):
> + target = super(custom_handler, self).get_target(target_plugin, path)
> + if target[0] == 'unix_socket':
> + try:
> + self.server.unix_target = target[1]
> + except:
> + self.unix_target = target[1]
> + else:
> + try:
> + self.server.unix_target = None
> + except:
> + self.unix_target = None
> + return target
> +
> +
> def new_ws_proxy():
> try:
> os.makedirs(WS_TOKENS_DIR, mode=0755)
> @@ -64,7 +86,12 @@ def new_ws_proxy():
> params['token_plugin'] = TokenFile(src=WS_TOKENS_DIR)
>
> def start_proxy():
> - server = WebSocketProxy(**params)
> + try:
> + server = WebSocketProxy(RequestHandlerClass=custom_handler,
> + **params)
> + except TypeError:
> + server = custom_handler(**params)
> +
> server.start_server()
>
> proc = Process(target=start_proxy)
> @@ -82,7 +109,10 @@ def add_proxy_token(name, port):
> So remove it when needed as base64 can work well without it.
> """
> name = base64.urlsafe_b64encode(name).rstrip('=')
> - f.write('%s: localhost:%s' % (name.encode('utf-8'), port))
> + if type(port) == str:
> + f.write('%s: unix_socket:%s' % (name.encode('utf-8'), port))
> + else:
> + f.write('%s: localhost:%s' % (name.encode('utf-8'), port))
It is dangerous to trust the variable type to determine the connection type.
I'd suggest to use a new variable to indicate that. So the developer can
really know what is going on.
>
> def remove_proxy_token(name):
More information about the Kimchi-devel
mailing list