2013-03-18 01:06:52 +04:00
#
2013-10-28 00:59:46 +04:00
# Copyright 2009, 2013 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
# Cole Robinson <crobinso@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
2013-10-28 00:59:47 +04:00
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2013-03-18 01:06:52 +04:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
2013-08-09 04:47:17 +04:00
from virtinst import VirtualDevice
2013-07-14 02:56:09 +04:00
from virtinst . xmlbuilder import XMLProperty
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-07-16 17:14:37 +04:00
class _VirtualCharDevice ( VirtualDevice ) :
2013-03-18 01:06:52 +04:00
"""
Base class for all character devices . Shouldn ' t be instantiated
directly .
"""
2013-07-16 17:14:37 +04:00
TYPE_PTY = " pty "
TYPE_DEV = " dev "
TYPE_STDIO = " stdio "
TYPE_PIPE = " pipe "
TYPE_FILE = " file "
TYPE_VC = " vc "
TYPE_NULL = " null "
TYPE_TCP = " tcp "
TYPE_UDP = " udp "
TYPE_UNIX = " unix "
TYPE_SPICEVMC = " spicevmc "
2014-03-25 18:42:33 +04:00
TYPE_SPICEPORT = " spiceport "
2013-10-05 19:07:32 +04:00
# We don't list the non-UI friendly types here
_TYPES_FOR_ALL = [ TYPE_PTY , TYPE_DEV , TYPE_FILE ,
TYPE_TCP , TYPE_UDP , TYPE_UNIX ]
2014-03-25 18:42:33 +04:00
_TYPES_FOR_CHANNEL = [ TYPE_SPICEVMC , TYPE_SPICEPORT ]
2013-08-08 03:04:18 +04:00
TYPES = _TYPES_FOR_ALL
2013-07-16 17:14:37 +04:00
MODE_CONNECT = " connect "
MODE_BIND = " bind "
MODES = [ MODE_CONNECT , MODE_BIND ]
PROTOCOL_RAW = " raw "
PROTOCOL_TELNET = " telnet "
PROTOCOLS = [ PROTOCOL_RAW , PROTOCOL_TELNET ]
CHANNEL_TARGET_GUESTFWD = " guestfwd "
CHANNEL_TARGET_VIRTIO = " virtio "
CHANNEL_TARGETS = [ CHANNEL_TARGET_GUESTFWD ,
CHANNEL_TARGET_VIRTIO ]
CONSOLE_TARGET_SERIAL = " serial "
CONSOLE_TARGET_UML = " uml "
CONSOLE_TARGET_XEN = " xen "
CONSOLE_TARGET_VIRTIO = " virtio "
CONSOLE_TARGETS = [ CONSOLE_TARGET_SERIAL , CONSOLE_TARGET_UML ,
CONSOLE_TARGET_XEN , CONSOLE_TARGET_VIRTIO ]
2013-10-05 21:27:11 +04:00
CHANNEL_NAME_SPICE = " com.redhat.spice.0 "
CHANNEL_NAME_QEMUGA = " org.qemu.guest_agent.0 "
CHANNEL_NAME_LIBGUESTFS = " org.libguestfs.channel.0 "
2014-03-25 18:42:33 +04:00
CHANNEL_NAME_SPICE_WEBDAV = " org.spice-space.webdav.0 "
2013-10-05 21:27:11 +04:00
CHANNEL_NAMES = [ CHANNEL_NAME_SPICE ,
CHANNEL_NAME_QEMUGA ,
2014-03-25 18:42:33 +04:00
CHANNEL_NAME_LIBGUESTFS ,
CHANNEL_NAME_SPICE_WEBDAV ]
2013-10-05 21:27:11 +04:00
2013-10-05 22:04:49 +04:00
@staticmethod
def pretty_channel_name ( val ) :
if val == _VirtualCharDevice . CHANNEL_NAME_SPICE :
return " spice "
if val == _VirtualCharDevice . CHANNEL_NAME_QEMUGA :
return " qemu-ga "
if val == _VirtualCharDevice . CHANNEL_NAME_LIBGUESTFS :
return " libguestfs "
2014-03-25 18:42:33 +04:00
if val == _VirtualCharDevice . CHANNEL_NAME_SPICE_WEBDAV :
return " spice-webdav "
2013-10-05 22:04:49 +04:00
return None
2013-07-16 17:14:37 +04:00
@staticmethod
def pretty_type ( ctype ) :
2013-03-18 01:06:52 +04:00
"""
Return a human readable description of the passed char type
"""
desc = " "
2013-07-16 17:14:37 +04:00
if ctype == _VirtualCharDevice . TYPE_PTY :
2013-03-18 01:06:52 +04:00
desc = _ ( " Pseudo TTY " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_DEV :
2013-03-18 01:06:52 +04:00
desc = _ ( " Physical host character device " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_STDIO :
2013-03-18 01:06:52 +04:00
desc = _ ( " Standard input/output " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_PIPE :
2013-03-18 01:06:52 +04:00
desc = _ ( " Named pipe " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_FILE :
2013-03-18 01:06:52 +04:00
desc = _ ( " Output to a file " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_VC :
2013-03-18 01:06:52 +04:00
desc = _ ( " Virtual console " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_NULL :
2013-03-18 01:06:52 +04:00
desc = _ ( " Null device " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_TCP :
2013-03-18 01:06:52 +04:00
desc = _ ( " TCP net console " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_UDP :
2013-03-18 01:06:52 +04:00
desc = _ ( " UDP net console " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_UNIX :
2013-03-18 01:06:52 +04:00
desc = _ ( " Unix socket " )
2013-07-16 17:14:37 +04:00
elif ctype == _VirtualCharDevice . TYPE_SPICEVMC :
2013-03-18 01:06:52 +04:00
desc = _ ( " Spice agent " )
2014-03-25 18:42:33 +04:00
elif ctype == _VirtualCharDevice . TYPE_SPICEPORT :
desc = _ ( " Spice port " )
2013-03-18 01:06:52 +04:00
return desc
2013-07-16 17:14:37 +04:00
@staticmethod
def pretty_mode ( char_mode ) :
2013-03-18 01:06:52 +04:00
"""
Return a human readable description of the passed char type
"""
desc = " "
2013-07-16 17:14:37 +04:00
if char_mode == _VirtualCharDevice . MODE_CONNECT :
2013-03-18 01:06:52 +04:00
desc = _ ( " Client mode " )
2013-07-16 17:14:37 +04:00
elif char_mode == _VirtualCharDevice . MODE_BIND :
2013-03-18 01:06:52 +04:00
desc = _ ( " Server mode " )
return desc
def supports_property ( self , propname , ro = False ) :
"""
Whether the character dev type supports the passed property name
"""
users = {
2013-07-16 17:14:37 +04:00
" source_path " : [ self . TYPE_FILE , self . TYPE_UNIX ,
self . TYPE_DEV , self . TYPE_PIPE ] ,
" source_mode " : [ self . TYPE_UNIX , self . TYPE_TCP ] ,
" source_host " : [ self . TYPE_TCP , self . TYPE_UDP ] ,
" source_port " : [ self . TYPE_TCP , self . TYPE_UDP ] ,
2014-03-25 18:42:33 +04:00
" source_channel " : [ self . TYPE_SPICEPORT ] ,
2013-07-16 17:14:37 +04:00
" protocol " : [ self . TYPE_TCP ] ,
" bind_host " : [ self . TYPE_UDP ] ,
" bind_port " : [ self . TYPE_UDP ] ,
2013-10-05 19:28:41 +04:00
}
2013-03-18 01:06:52 +04:00
if ro :
2013-07-16 17:14:37 +04:00
users [ " source_path " ] + = [ self . TYPE_PTY ]
2013-03-18 01:06:52 +04:00
if users . get ( propname ) :
2013-07-16 17:14:37 +04:00
return self . type in users [ propname ]
2013-03-18 01:06:52 +04:00
return hasattr ( self , propname )
2014-01-19 22:56:06 +04:00
def _set_host_helper ( self , hostparam , portparam , val ) :
def parse_host ( val ) :
host , ignore , port = ( val or " " ) . partition ( " : " )
return host or None , port or None
host , port = parse_host ( val )
if host :
setattr ( self , hostparam , host )
if port :
setattr ( self , portparam , port )
def set_friendly_source ( self , val ) :
self . _set_host_helper ( " source_host " , " source_port " , val )
def set_friendly_bind ( self , val ) :
self . _set_host_helper ( " bind_host " , " bind_port " , val )
def set_friendly_target ( self , val ) :
self . _set_host_helper ( " target_address " , " target_port " , val )
2013-07-16 17:14:37 +04:00
2013-07-24 22:37:07 +04:00
_XML_PROP_ORDER = [ " type " , " _has_mode_bind " , " _has_mode_connect " ,
2013-07-16 17:14:37 +04:00
" bind_host " , " bind_port " ,
2014-03-25 18:42:32 +04:00
" source_mode " , " _source_path " , " source_channel " ,
2013-07-16 17:14:37 +04:00
" source_host " , " source_port " ,
" target_type " , " target_name " ]
type = XMLProperty (
2013-03-18 01:06:52 +04:00
doc = _ ( " Method used to expose character device in the host. " ) ,
xpath = " ./@type " )
2013-09-24 17:25:05 +04:00
_tty = XMLProperty ( " ./@tty " )
_source_path = XMLProperty ( xpath = " ./source/@path " ,
doc = _ ( " Host input path to attach to the guest. " ) )
def _get_source_path ( self ) :
source = self . _source_path
if source is None and self . _tty :
return self . _tty
return source
def _set_source_path ( self , val ) :
self . _source_path = val
source_path = property ( _get_source_path , _set_source_path )
2013-07-16 17:14:37 +04:00
2014-03-25 18:42:32 +04:00
source_channel = XMLProperty ( xpath = " ./source/@channel " ,
doc = _ ( " Source channel name. " ) )
2013-07-16 17:14:37 +04:00
def _get_default_source_mode ( self ) :
if self . type == self . TYPE_UDP :
return self . MODE_CONNECT
if not self . supports_property ( " source_mode " ) :
return None
return self . MODE_BIND
2013-09-24 17:25:05 +04:00
def _make_sourcemode_xpath ( self ) :
2013-07-16 17:14:37 +04:00
if self . type == self . TYPE_UDP :
2013-03-18 01:06:52 +04:00
return " ./source[@mode= ' connect ' ]/@mode "
return " ./source/@mode "
2013-07-16 17:14:37 +04:00
source_mode = XMLProperty ( name = " char sourcemode " ,
doc = _ ( " Target connect/listen mode. " ) ,
2013-09-24 17:25:05 +04:00
make_xpath_cb = _make_sourcemode_xpath ,
2013-07-16 17:14:37 +04:00
default_cb = _get_default_source_mode )
def _get_default_sourcehost ( self ) :
if not self . supports_property ( " source_host " ) :
return None
return " 127.0.0.1 "
def _set_source_validate ( self , val ) :
if val is None or self . type != self . TYPE_UDP :
return val
if not self . _has_mode_connect :
self . _has_mode_connect = self . MODE_CONNECT
return val
2013-09-24 17:25:05 +04:00
def _make_sourcehost_xpath ( self ) :
2013-07-16 17:14:37 +04:00
mode = self . source_mode
if self . type == self . TYPE_UDP :
mode = " connect "
return " ./source[@mode= ' %s ' ]/@host " % mode
source_host = XMLProperty ( name = " char sourcehost " ,
doc = _ ( " Address to connect/listen to. " ) ,
2013-09-24 17:25:05 +04:00
make_xpath_cb = _make_sourcehost_xpath ,
2013-07-16 17:14:37 +04:00
default_cb = _get_default_sourcehost ,
set_converter = _set_source_validate )
2013-09-24 17:25:05 +04:00
def _make_sourceport_xpath ( self ) :
2013-03-18 01:06:52 +04:00
return " ./source[@mode= ' %s ' ]/@service " % self . source_mode
2013-07-16 17:14:37 +04:00
source_port = XMLProperty ( name = " char sourceport " ,
doc = _ ( " Port on target host to connect/listen to. " ) ,
2013-09-24 17:25:05 +04:00
make_xpath_cb = _make_sourceport_xpath ,
2013-07-17 17:57:15 +04:00
set_converter = _set_source_validate , is_int = True )
2013-07-16 17:14:37 +04:00
2013-09-19 21:27:30 +04:00
_has_mode_connect = XMLProperty ( " ./source[@mode= ' connect ' ]/@mode " )
_has_mode_bind = XMLProperty ( " ./source[@mode= ' bind ' ]/@mode " )
2013-07-16 17:14:37 +04:00
def _set_bind_validate ( self , val ) :
if val is None :
return None
if not self . _has_mode_bind :
self . _has_mode_bind = self . MODE_BIND
return val
2013-09-19 21:27:30 +04:00
bind_host = XMLProperty ( " ./source[@mode= ' bind ' ]/@host " ,
2013-10-24 17:07:06 +04:00
doc = _ ( " Host address to bind to. " ) ,
2013-07-16 17:14:37 +04:00
set_converter = _set_bind_validate )
2013-09-19 21:27:30 +04:00
bind_port = XMLProperty ( " ./source[@mode= ' bind ' ]/@service " ,
2013-07-16 17:14:37 +04:00
doc = _ ( " Host port to bind to. " ) ,
2013-07-17 17:57:15 +04:00
set_converter = _set_bind_validate , is_int = True )
2013-07-16 17:14:37 +04:00
def _get_default_protocol ( self ) :
if not self . supports_property ( " protocol " ) :
return None
return self . PROTOCOL_RAW
2013-09-19 21:27:30 +04:00
protocol = XMLProperty ( " ./protocol/@type " ,
2013-07-16 17:14:37 +04:00
doc = _ ( " Format used when sending data. " ) ,
default_cb = _get_default_protocol )
def _get_default_target_type ( self ) :
2013-08-08 03:04:18 +04:00
if self . virtual_device_type == " channel " :
2013-07-16 17:14:37 +04:00
return self . CHANNEL_TARGET_VIRTIO
return None
2013-09-19 21:27:30 +04:00
target_type = XMLProperty ( " ./target/@type " ,
2013-07-16 17:14:37 +04:00
doc = _ ( " Channel type as exposed in the guest. " ) ,
default_cb = _get_default_target_type )
2013-09-19 21:27:30 +04:00
target_address = XMLProperty ( " ./target/@address " ,
2013-07-16 17:14:37 +04:00
doc = _ ( " Guest forward channel address in the guest. " ) )
2013-09-19 21:27:30 +04:00
target_port = XMLProperty ( " ./target/@port " , is_int = True ,
2013-07-16 17:14:37 +04:00
doc = _ ( " Guest forward channel port in the guest. " ) )
def _default_target_name ( self ) :
if self . type == self . TYPE_SPICEVMC :
2013-10-05 21:27:11 +04:00
return self . CHANNEL_NAME_SPICE
2013-07-16 17:14:37 +04:00
return None
2013-09-19 21:27:30 +04:00
target_name = XMLProperty ( " ./target/@name " ,
2013-03-18 01:06:52 +04:00
doc = _ ( " Sysfs name of virtio port in the guest " ) ,
2013-07-16 17:14:37 +04:00
default_cb = _default_target_name )
2013-04-13 22:34:52 +04:00
2013-07-16 17:14:37 +04:00
class VirtualConsoleDevice ( _VirtualCharDevice ) :
virtual_device_type = " console "
2013-10-05 19:28:41 +04:00
TYPES = [ _VirtualCharDevice . TYPE_PTY ]
2013-04-13 22:34:52 +04:00
2013-07-16 17:14:37 +04:00
class VirtualSerialDevice ( _VirtualCharDevice ) :
virtual_device_type = " serial "
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-07-16 17:14:37 +04:00
class VirtualParallelDevice ( _VirtualCharDevice ) :
virtual_device_type = " parallel "
2013-04-13 22:34:52 +04:00
2013-07-16 17:14:37 +04:00
class VirtualChannelDevice ( _VirtualCharDevice ) :
virtual_device_type = " channel "
2013-10-05 19:07:32 +04:00
TYPES = ( _VirtualCharDevice . _TYPES_FOR_CHANNEL +
_VirtualCharDevice . _TYPES_FOR_ALL )
2013-07-24 16:46:55 +04:00
VirtualConsoleDevice . register_type ( )
VirtualSerialDevice . register_type ( )
VirtualParallelDevice . register_type ( )
VirtualChannelDevice . register_type ( )