VirtualCharDevice: Convert to new style XML props, rework API

This commit is contained in:
Cole Robinson 2013-07-16 09:14:37 -04:00
parent 9f37f58804
commit e802eae07b
28 changed files with 325 additions and 690 deletions

View File

@ -25,7 +25,8 @@ from virtinst import VirtualDisk
from virtinst import VirtualAudio
from virtinst import VirtualNetworkInterface
from virtinst import VirtualHostDevice
from virtinst import VirtualCharDevice
from virtinst import (VirtualChannelDevice, VirtualConsoleDevice,
VirtualParallelDevice, VirtualSerialDevice)
from virtinst import VirtualVideoDevice
from virtinst import VirtualController
from virtinst import VirtualWatchdog
@ -313,9 +314,8 @@ class TestXMLConfig(unittest.TestCase):
g.add_device(utils.get_filedisk())
inp = VirtualInputDevice(g.conn)
cons = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_CONSOLE,
VirtualCharDevice.CHAR_PTY)
cons = VirtualConsoleDevice(g.conn)
cons.type = "pty"
g.add_device(inp)
g.add_device(cons)
@ -679,46 +679,38 @@ class TestXMLConfig(unittest.TestCase):
i = utils.make_pxe_installer()
g = utils.get_basic_fullyvirt_guest(installer=i)
dev1 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_SERIAL,
VirtualCharDevice.CHAR_NULL)
dev2 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_PARALLEL,
VirtualCharDevice.CHAR_UNIX)
dev1 = VirtualSerialDevice(g.conn)
dev1.type = "null"
dev2 = VirtualParallelDevice(g.conn)
dev2.type = "unix"
dev2.source_path = "/tmp/foobar"
dev3 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_SERIAL,
VirtualCharDevice.CHAR_TCP)
dev3 = VirtualSerialDevice(g.conn)
dev3.type = "tcp"
dev3.protocol = "telnet"
dev3.source_host = "my.source.host"
dev3.source_port = "1234"
dev4 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_PARALLEL,
VirtualCharDevice.CHAR_UDP)
dev4 = VirtualParallelDevice(g.conn)
dev4.type = "udp"
dev4.bind_host = "my.bind.host"
dev4.bind_port = "1111"
dev4.source_host = "my.source.host"
dev4.source_port = "2222"
dev5 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_CHANNEL,
VirtualCharDevice.CHAR_PTY)
dev5.target_type = dev5.CHAR_CHANNEL_TARGET_VIRTIO
dev5 = VirtualChannelDevice(g.conn)
dev5.type = "pty"
dev5.target_type = dev5.CHANNEL_TARGET_VIRTIO
dev5.target_name = "foo.bar.frob"
dev6 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_CONSOLE,
VirtualCharDevice.CHAR_PTY)
dev6 = VirtualConsoleDevice(g.conn)
dev6.type = "pty"
dev7 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_CONSOLE,
VirtualCharDevice.CHAR_PTY)
dev7.target_type = dev5.CHAR_CONSOLE_TARGET_VIRTIO
dev7 = VirtualConsoleDevice(g.conn)
dev7.type = "pty"
dev7.target_type = dev7.CONSOLE_TARGET_VIRTIO
dev8 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_CHANNEL,
VirtualCharDevice.CHAR_PTY)
dev8.target_type = dev5.CHAR_CHANNEL_TARGET_GUESTFWD
dev8 = VirtualChannelDevice(g.conn)
dev8.type = "pty"
dev8.target_type = dev8.CHANNEL_TARGET_GUESTFWD
dev8.target_address = "1.2.3.4"
dev8.target_port = "4567"
@ -811,16 +803,13 @@ class TestXMLConfig(unittest.TestCase):
g.add_device(net3)
# Character devices
cdev1 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_SERIAL,
VirtualCharDevice.CHAR_NULL)
cdev2 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_PARALLEL,
VirtualCharDevice.CHAR_UNIX)
cdev1 = VirtualSerialDevice(g.conn)
cdev1.type = "null"
cdev2 = VirtualParallelDevice(g.conn)
cdev2.type = "unix"
cdev2.source_path = "/tmp/foobar"
cdev3 = VirtualCharDevice.get_dev_instance(g.conn,
VirtualCharDevice.DEV_CHANNEL,
VirtualCharDevice.CHAR_SPICEVMC)
cdev3 = VirtualChannelDevice(g.conn)
cdev3.type = "spicevmc"
g.add_device(cdev1)
g.add_device(cdev2)
g.add_device(cdev3)

View File

@ -20,7 +20,10 @@
<emulator>/usr/lib/xen/bin/qemu-dm</emulator>
<input type="mouse" bus="ps2"/>
<graphics type="sdl" display=":3.4" xauth="/tmp/.Xauthority"/>
<serial type="null"/>
<serial type="udp">
<source mode="bind" host="example.com" service="66"/>
<source mode="connect" host="example.com.uk" service="77"/>
</serial>
<serial type="tcp">
<source mode="connect" host="my.source.host" service="1234"/>
<protocol type="raw"/>

View File

@ -312,46 +312,50 @@ class XMLParseTest(unittest.TestCase):
channel2 = guest.get_devices("channel")[1]
check = self._make_checker(serial1)
check("char_type", "null")
check("type", "null", "udp")
check("bind_host", None, "example.com")
check("bind_port", None, 66)
check("source_host", None, "example.com.uk")
check("source_port", None, 77)
check = self._make_checker(serial2)
check("char_type", "tcp")
check("type", "tcp")
check("protocol", "telnet", "raw")
check("source_mode", "bind", "connect")
check = self._make_checker(parallel1)
check("source_mode", "bind")
check("source_path", "/tmp/foobar", None)
check("char_type", "unix", "pty")
check("type", "unix", "pty")
check = self._make_checker(parallel2)
check("char_type", "udp")
check("bind_port", "1111", "1357")
check("type", "udp")
check("bind_port", 1111, 1357)
check("bind_host", "my.bind.host", "my.foo.host")
check("source_mode", "connect")
check("source_port", "2222", "7777")
check("source_port", 2222, 7777)
check("source_host", "my.source.host", "source.foo.host")
check = self._make_checker(console1)
check("char_type", "pty")
check("type", "pty")
check("target_type", None)
check = self._make_checker(console2)
check("char_type", "file")
check("type", "file")
check("source_path", "/tmp/foo.img", None)
check("source_path", None, "/root/foo")
check("target_type", "virtio")
check = self._make_checker(channel1)
check("char_type", "pty")
check("target_type", "virtio")
check("type", "pty")
check("target_type", "virtio", "bar", "virtio")
check("target_name", "foo.bar.frob", "test.changed")
check = self._make_checker(channel2)
check("char_type", "unix")
check("type", "unix", "foo", "unix")
check("target_type", "guestfwd")
check("target_address", "1.2.3.4", "5.6.7.8")
check("target_port", "4567", "1199")
check("target_port", 4567, 1199)
self._alter_compare(guest.get_xml_config(), outfile)

View File

@ -33,11 +33,9 @@ import urlgrabber.progress as progress
import virtinst
import virtinst.cli as cli
import virtinst.util as util
from virtinst import VirtualCharDevice
from virtinst.cli import fail, print_stdout, print_stderr
##############################
# Validation utility helpers #
##############################
@ -529,14 +527,10 @@ def build_guest_instance(conn, options):
get_watchdog(options.watchdog, guest)
get_filesystems(options.filesystems, guest)
cli.get_sound(options.sound, options.soundhw, guest)
get_chardevs(VirtualCharDevice.VIRTUAL_DEV_SERIAL, options.serials,
guest, cli.parse_serial)
get_chardevs(VirtualCharDevice.VIRTUAL_DEV_PARALLEL, options.parallels,
guest, cli.parse_parallel)
get_chardevs(VirtualCharDevice.VIRTUAL_DEV_CHANNEL, options.channels,
guest, cli.parse_channel)
get_chardevs(VirtualCharDevice.VIRTUAL_DEV_CONSOLE, options.consoles,
guest, cli.parse_console)
get_chardevs("serial", options.serials, guest, cli.parse_serial)
get_chardevs("parallel", options.parallels, guest, cli.parse_parallel)
get_chardevs("channel", options.channels, guest, cli.parse_channel)
get_chardevs("console", options.consoles, guest, cli.parse_console)
cli.get_hostdevs(options.hostdevs, guest)
cli.get_smartcard(guest, options.smartcard)
cli.get_tpm(guest, options.tpm)

View File

@ -27,7 +27,8 @@ from gi.repository import Gdk
# pylint: enable=E0611
import virtinst
from virtinst import (VirtualCharDevice,
from virtinst import (VirtualChannelDevice, VirtualParallelDevice,
VirtualSerialDevice,
VirtualVideoDevice, VirtualWatchdog,
VirtualFilesystem, VirtualSmartCardDevice,
VirtualRedirDevice, VirtualTPMDevice)
@ -132,7 +133,7 @@ class vmmAddHardware(vmmGObjectUI):
self.widget("char-info").set_markup(doc)
def update_doc_char_type(self, *ignore):
return self._update_doc("char_type")
return self._update_doc("type")
def update_doc_char_source_path(self, *ignore):
return self._update_doc("source_path")
def update_doc_char_source_mode(self, *ignore):
@ -147,18 +148,17 @@ class vmmAddHardware(vmmGObjectUI):
return self._update_doc("target_name")
def _build_doc_str(self, param, docstr=None):
doc = ""
doctmpl = "<i>%s</i>"
if docstr:
doc = doctmpl % (docstr)
elif self._dev:
devclass = self._dev.__class__
paramdoc = getattr(devclass, param).__doc__
if paramdoc:
doc = doctmpl % paramdoc
return doctmpl % (docstr)
elif not self._dev:
return ""
return doc
propdoc = getattr(self._dev.all_xml_props()[param], "__doc__")
if propdoc:
return doctmpl % propdoc
return ""
def show(self, parent):
logging.debug("Showing addhw")
@ -303,8 +303,8 @@ class vmmAddHardware(vmmGObjectUI):
char_mode.pack_start(text, True)
char_mode.add_attribute(text, 'text', 1)
char_mode_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
for t in VirtualCharDevice.char_modes:
desc = VirtualCharDevice.get_char_mode_desc(t)
for t in VirtualSerialDevice.MODES:
desc = VirtualSerialDevice.pretty_mode(t)
char_mode_model.append([t, desc + " (%s)" % t])
self.widget("char-info-box").modify_bg(Gtk.StateType.NORMAL,
@ -833,7 +833,8 @@ class vmmAddHardware(vmmGObjectUI):
# Char device type
char_devtype = self.widget("char-device-type")
dev_type = self.get_char_type()
char_class = self.get_char_type()
# Type name, desc
char_devtype_model = Gtk.ListStore(str, str)
char_devtype.clear()
@ -842,12 +843,12 @@ class vmmAddHardware(vmmGObjectUI):
char_devtype.pack_start(text, True)
char_devtype.add_attribute(text, 'text', 1)
for t in VirtualCharDevice.char_types_for_dev_type[dev_type]:
for t in char_class.TYPES:
if (t in rhel6_blacklist and
not self.vm.rhel6_defaults()):
continue
desc = VirtualCharDevice.get_char_type_desc(t)
desc = char_class.pretty_type(t)
row = [t, desc + " (%s)" % t]
char_devtype_model.append(row)
char_devtype.set_active(0)
@ -988,10 +989,10 @@ class vmmAddHardware(vmmGObjectUI):
label = row[5]
if label == "parallel":
return VirtualCharDevice.VIRTUAL_DEV_PARALLEL
return VirtualParallelDevice
elif label == "channel":
return VirtualCharDevice.VIRTUAL_DEV_CHANNEL
return VirtualCharDevice.VIRTUAL_DEV_SERIAL
return VirtualChannelDevice
return VirtualSerialDevice
def dev_to_title(self, page):
if page == PAGE_ERROR:
@ -1020,7 +1021,8 @@ class vmmAddHardware(vmmGObjectUI):
return _("TPM")
if page == PAGE_CHAR:
return self.get_char_type().capitalize() + " Device"
char_class = self.get_char_type()
return char_class.virtual_device_type.capitalize() + " Device"
if page == PAGE_HOSTDEV:
return self.get_config_host_device_type_info()[0]
@ -1056,16 +1058,17 @@ class vmmAddHardware(vmmGObjectUI):
self.widget("tpm-param-box").set_property("visible", show_something)
def change_char_device_type(self, src):
self._update_doc("char_type")
self._update_doc("type")
idx = src.get_active()
if idx < 0:
return
chartype = self.get_char_type()
char_class = self.get_char_type()
devtype = src.get_model()[src.get_active()][0]
conn = self.conn.get_backend()
self._dev = VirtualCharDevice.get_dev_instance(conn, chartype, devtype)
self._dev = char_class(conn)
self._dev.type = devtype
show_something = False
for param_name, widget_name in char_widget_mappings.items():
@ -1472,13 +1475,14 @@ class vmmAddHardware(vmmGObjectUI):
return self.err.val_err(_("Host device parameter error"), e)
def validate_page_char(self):
chartype = self.get_char_type()
charclass = self.get_char_type()
modebox = self.widget("char-mode")
devbox = self.widget("char-device-type")
devtype = devbox.get_model()[devbox.get_active()][0]
conn = self.conn.get_backend()
devclass = VirtualCharDevice.get_dev_instance(conn, chartype, devtype)
devclass = charclass(conn)
devclass.type = devtype
source_path = self.widget("char-path").get_text()
source_mode = modebox.get_model()[modebox.get_active()][0]
@ -1489,9 +1493,9 @@ class vmmAddHardware(vmmGObjectUI):
target_name = self.widget("char-target-name").get_text()
if self.widget("char-use-telnet").get_active():
protocol = VirtualCharDevice.CHAR_PROTOCOL_TELNET
protocol = VirtualSerialDevice.PROTOCOL_TELNET
else:
protocol = VirtualCharDevice.CHAR_PROTOCOL_RAW
protocol = VirtualSerialDevice.PROTOCOL_RAW
value_mappings = {
"source_path" : source_path,
@ -1514,8 +1518,9 @@ class vmmAddHardware(vmmGObjectUI):
# Dump XML for sanity checking
self._dev.get_xml_config()
except Exception, e:
return self.err.val_err(_("%s device parameter error") %
chartype.capitalize(), e)
return self.err.val_err(
_("%s device parameter error") %
charclass.virtual_device_type.capitalize(), e)
def validate_page_video(self):
conn = self.conn.get_backend()

View File

@ -2417,8 +2417,8 @@ class vmmDetails(vmmGObjectUI):
has_multi_spice = (len([d for d in self.vm.get_graphics_devices() if
d.type == d.TYPE_SPICE]) > 1)
has_spicevmc = bool([d for d in self.vm.get_char_devices() if
(d.dev_type == d.DEV_CHANNEL and
d.char_type == d.CHAR_SPICEVMC)])
(d.virtual_device_type == "channel" and
d.type == "spicevmc")])
fromspice = (gdev.type == "spice")
tospice = (newgtype == "spice")
@ -3234,8 +3234,8 @@ class vmmDetails(vmmGObjectUI):
if not chardev:
return
show_target_type = not (chardev.dev_type in
[chardev.DEV_SERIAL, chardev.DEV_PARALLEL])
show_target_type = not (chardev.virtual_device_type in
["serial", "parallel"])
def show_ui(param, val=None):
widgetname = "char-" + param.replace("_", "-")
@ -3268,7 +3268,7 @@ class vmmDetails(vmmGObjectUI):
char_type = chardev.virtual_device_type.capitalize()
target_port = chardev.target_port
dev_type = chardev.char_type or "pty"
dev_type = chardev.type or "pty"
primary = hasattr(chardev, "virtmanager_console_dup")
typelabel = ""

View File

@ -28,7 +28,6 @@ import threading
import libvirt
import virtinst
from virtinst.VirtualCharDevice import VirtualCharSpicevmcDevice
from virtManager import util
from virtManager.libvirtobject import vmmLibvirtObject
@ -45,12 +44,12 @@ def compare_device(origdev, newdev, idx):
"hostdev" : ["type", "managed", "vmmindex",
"product", "vendor",
"function", "domain", "slot"],
"serial" : ["char_type", "target_port"],
"parallel" : ["char_type", "target_port"],
"console" : ["char_type", "target_type", "target_port"],
"serial" : ["type", "target_port"],
"parallel" : ["type", "target_port"],
"console" : ["type", "target_type", "target_port"],
"graphics" : ["type", "vmmindex"],
"controller" : ["type", "index"],
"channel" : ["char_type", "target_name"],
"channel" : ["type", "target_name"],
"filesystem" : ["target" , "vmmindex"],
"smartcard" : ["mode" , "vmmindex"],
"redirdev" : ["bus" , "type", "vmmindex"],
@ -740,12 +739,13 @@ class vmmDomain(vmmLibvirtObject):
is_spice = (newval == virtinst.VirtualGraphics.TYPE_SPICE)
if is_spice:
guest.add_device(VirtualCharSpicevmcDevice(guest.conn))
dev = virtinst.VirtualChannelDevice(guest.conn)
dev.type = dev.TYPE_SPICEVMC
guest.add_device(dev)
else:
channels = guest.get_devices("channel")
channels = [x for x in channels if
(x.char_type ==
virtinst.VirtualCharDevice.CHAR_SPICEVMC)]
channels = [x for x in guest.get_devices("channel")
if x.type == "spicevmc"]
for dev in channels:
guest.remove_device(dev)
@ -1109,7 +1109,7 @@ class vmmDomain(vmmLibvirtObject):
con = consoles[0]
ser = serials[0]
if (con.char_type == ser.char_type and
if (con.type == ser.type and
con.target_type is None or con.target_type == "serial"):
ser.virtmanager_console_dup = con
devs.remove(con)

View File

@ -264,7 +264,7 @@ class vmmSerialConsole(vmmGObject):
"""
usable_types = ["pty"]
ctype = dev.char_type
ctype = dev.type
path = dev.source_path
is_remote = vm.conn.is_remote()
support_tunnel = vmmSerialConsole.support_remote_console(vm)

View File

@ -35,7 +35,6 @@ from virtinst.xmlbuilder import XMLBuilder, XMLProperty
from virtinst.VirtualDevice import VirtualDevice
from virtinst.VirtualDisk import VirtualDisk
from virtinst.VirtualInputDevice import VirtualInputDevice
from virtinst.VirtualCharDevice import VirtualCharDevice
from virtinst.VirtualController import VirtualController
from virtinst.Clock import Clock
from virtinst.Seclabel import Seclabel
@ -626,10 +625,10 @@ class Guest(XMLBuilder):
"sound" : virtinst.VirtualAudio,
"hostdev" : virtinst.VirtualHostDevice,
"input" : virtinst.VirtualInputDevice,
"serial" : virtinst.VirtualCharDevice,
"parallel" : virtinst.VirtualCharDevice,
"console" : virtinst.VirtualCharDevice,
"channel" : virtinst.VirtualCharDevice,
"serial" : virtinst.VirtualSerialDevice,
"parallel" : virtinst.VirtualParallelDevice,
"console" : virtinst.VirtualConsoleDevice,
"channel" : virtinst.VirtualChannelDevice,
"graphics" : virtinst.VirtualGraphics,
"video" : virtinst.VirtualVideoDevice,
"watchdog" : virtinst.VirtualWatchdog,
@ -653,11 +652,7 @@ class Guest(XMLBuilder):
devnode.virtinst_root_doc = self._xml_root_doc
objclass = device_mappings.get(devnode.name)
if objclass == virtinst.VirtualCharDevice:
dev = objclass(self.conn, devnode.name,
parsexmlnode=devnode)
else:
dev = objclass(self.conn, parsexmlnode=devnode)
dev = objclass(self.conn, parsexmlnode=devnode)
self._add_device(dev)
self._xml_node.virtinst_root_doc = self._xml_root_doc
@ -681,9 +676,8 @@ class Guest(XMLBuilder):
return dev
def _get_default_console_device(self):
dev = VirtualCharDevice.get_dev_instance(self.conn,
VirtualCharDevice.DEV_CONSOLE,
VirtualCharDevice.CHAR_PTY)
dev = virtinst.VirtualConsoleDevice(self.conn)
dev.type = dev.TYPE_PTY
return dev
def _get_device_xml(self, devs, install=True):
@ -1383,16 +1377,15 @@ class Guest(XMLBuilder):
# Spice agent channel (only if we use spice)
def has_spice_agent():
for chn in devlist_func(channeltype):
if chn.char_type == chn.CHAR_SPICEVMC:
if chn.type == chn.TYPE_SPICEVMC:
return True
if (has_spice() and
not has_spice_agent() and
self.conn.check_conn_support(
self.conn.SUPPORT_CONN_HV_CHAR_SPICEVMC)):
agentdev = VirtualCharDevice.get_dev_instance(self.conn,
VirtualCharDevice.DEV_CHANNEL,
VirtualCharDevice.CHAR_SPICEVMC)
agentdev = virtinst.VirtualChannelDevice(self.conn)
agentdev.type = agentdev.TYPE_SPICEVMC
self.add_device(agentdev)
# Generate UUID

View File

@ -22,7 +22,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualAudio(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_AUDIO
virtual_device_type = VirtualDevice.VIRTUAL_DEV_AUDIO
MODEL_DEFAULT = "default"
MODELS = ["es1370", "sb16", "pcspk", "ac97", "ich6", MODEL_DEFAULT]

View File

@ -18,617 +18,262 @@
# MA 02110-1301 USA.
from virtinst.VirtualDevice import VirtualDevice
from virtinst.util import xml_escape
from virtinst.xmlbuilder import XMLProperty
class VirtualCharDevice(VirtualDevice):
class _VirtualCharDevice(VirtualDevice):
"""
Base class for all character devices. Shouldn't be instantiated
directly.
"""
DEV_SERIAL = "serial"
DEV_PARALLEL = "parallel"
DEV_CONSOLE = "console"
DEV_CHANNEL = "channel"
dev_types = [DEV_SERIAL, DEV_PARALLEL, DEV_CONSOLE, DEV_CHANNEL]
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"
TYPES = [TYPE_PTY, TYPE_DEV, TYPE_STDIO, TYPE_FILE, TYPE_VC,
TYPE_PIPE, TYPE_NULL, TYPE_TCP, TYPE_UDP, TYPE_UNIX,
TYPE_SPICEVMC]
CHAR_PTY = "pty"
CHAR_DEV = "dev"
CHAR_STDIO = "stdio"
CHAR_PIPE = "pipe"
CHAR_FILE = "file"
CHAR_VC = "vc"
CHAR_NULL = "null"
CHAR_TCP = "tcp"
CHAR_UDP = "udp"
CHAR_UNIX = "unix"
CHAR_SPICEVMC = "spicevmc"
char_types = [CHAR_PTY, CHAR_DEV, CHAR_STDIO, CHAR_FILE, CHAR_VC,
CHAR_PIPE, CHAR_NULL, CHAR_TCP, CHAR_UDP, CHAR_UNIX,
CHAR_SPICEVMC]
MODE_CONNECT = "connect"
MODE_BIND = "bind"
MODES = [MODE_CONNECT, MODE_BIND]
_non_channel_types = char_types[:]
_non_channel_types.remove(CHAR_SPICEVMC)
PROTOCOL_RAW = "raw"
PROTOCOL_TELNET = "telnet"
PROTOCOLS = [PROTOCOL_RAW, PROTOCOL_TELNET]
char_types_for_dev_type = {
DEV_SERIAL: _non_channel_types,
DEV_PARALLEL: _non_channel_types,
DEV_CONSOLE: _non_channel_types,
DEV_CHANNEL: [CHAR_SPICEVMC],
}
CHANNEL_TARGET_GUESTFWD = "guestfwd"
CHANNEL_TARGET_VIRTIO = "virtio"
CHANNEL_TARGETS = [CHANNEL_TARGET_GUESTFWD,
CHANNEL_TARGET_VIRTIO]
CHAR_MODE_CONNECT = "connect"
CHAR_MODE_BIND = "bind"
char_modes = [CHAR_MODE_CONNECT, CHAR_MODE_BIND]
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]
CHAR_PROTOCOL_RAW = "raw"
CHAR_PROTOCOL_TELNET = "telnet"
char_protocols = [CHAR_PROTOCOL_RAW, CHAR_PROTOCOL_TELNET]
CHAR_CHANNEL_TARGET_GUESTFWD = "guestfwd"
CHAR_CHANNEL_TARGET_VIRTIO = "virtio"
target_types = [CHAR_CHANNEL_TARGET_GUESTFWD,
CHAR_CHANNEL_TARGET_VIRTIO]
CHAR_CHANNEL_ADDRESS_VIRTIO_SERIAL = "virtio-serial"
address_types = [CHAR_CHANNEL_ADDRESS_VIRTIO_SERIAL]
CHAR_CONSOLE_TARGET_SERIAL = "serial"
CHAR_CONSOLE_TARGET_UML = "uml"
CHAR_CONSOLE_TARGET_XEN = "xen"
CHAR_CONSOLE_TARGET_VIRTIO = "virtio"
has_target = False
def get_char_type_desc(char_type):
@staticmethod
def pretty_type(ctype):
"""
Return a human readable description of the passed char type
"""
desc = ""
if char_type == VirtualCharDevice.CHAR_PTY:
if ctype == _VirtualCharDevice.TYPE_PTY:
desc = _("Pseudo TTY")
elif char_type == VirtualCharDevice.CHAR_DEV:
elif ctype == _VirtualCharDevice.TYPE_DEV:
desc = _("Physical host character device")
elif char_type == VirtualCharDevice.CHAR_STDIO:
elif ctype == _VirtualCharDevice.TYPE_STDIO:
desc = _("Standard input/output")
elif char_type == VirtualCharDevice.CHAR_PIPE:
elif ctype == _VirtualCharDevice.TYPE_PIPE:
desc = _("Named pipe")
elif char_type == VirtualCharDevice.CHAR_FILE:
elif ctype == _VirtualCharDevice.TYPE_FILE:
desc = _("Output to a file")
elif char_type == VirtualCharDevice.CHAR_VC:
elif ctype == _VirtualCharDevice.TYPE_VC:
desc = _("Virtual console")
elif char_type == VirtualCharDevice.CHAR_NULL:
elif ctype == _VirtualCharDevice.TYPE_NULL:
desc = _("Null device")
elif char_type == VirtualCharDevice.CHAR_TCP:
elif ctype == _VirtualCharDevice.TYPE_TCP:
desc = _("TCP net console")
elif char_type == VirtualCharDevice.CHAR_UDP:
elif ctype == _VirtualCharDevice.TYPE_UDP:
desc = _("UDP net console")
elif char_type == VirtualCharDevice.CHAR_UNIX:
elif ctype == _VirtualCharDevice.TYPE_UNIX:
desc = _("Unix socket")
elif char_type == VirtualCharDevice.CHAR_SPICEVMC:
elif ctype == _VirtualCharDevice.TYPE_SPICEVMC:
desc = _("Spice agent")
return desc
get_char_type_desc = staticmethod(get_char_type_desc)
def get_char_mode_desc(char_mode):
@staticmethod
def pretty_mode(char_mode):
"""
Return a human readable description of the passed char type
"""
desc = ""
if char_mode == VirtualCharDevice.CHAR_MODE_CONNECT:
if char_mode == _VirtualCharDevice.MODE_CONNECT:
desc = _("Client mode")
elif char_mode == VirtualCharDevice.CHAR_MODE_BIND:
elif char_mode == _VirtualCharDevice.MODE_BIND:
desc = _("Server mode")
return desc
get_char_mode_desc = staticmethod(get_char_mode_desc)
# 'char_type' of class (must be properly set in subclass)
_char_type = None
def get_dev_instance(conn, dev_type, char_type):
"""
Set up the class attributes for the passed char_type
"""
# By default, all the possible parameters are enabled for the
# device class. We go through here and del() all the ones that
# don't apply. This is kind of whacky, but it's nice to to
# allow an API user to just use hasattr(obj, paramname) to see
# what parameters apply, instead of having to hardcode all that
# information.
if char_type == VirtualCharDevice.CHAR_PTY:
c = VirtualCharPtyDevice
elif char_type == VirtualCharDevice.CHAR_STDIO:
c = VirtualCharStdioDevice
elif char_type == VirtualCharDevice.CHAR_NULL:
c = VirtualCharNullDevice
elif char_type == VirtualCharDevice.CHAR_VC:
c = VirtualCharVcDevice
elif char_type == VirtualCharDevice.CHAR_DEV:
c = VirtualCharDevDevice
elif char_type == VirtualCharDevice.CHAR_FILE:
c = VirtualCharFileDevice
elif char_type == VirtualCharDevice.CHAR_PIPE:
c = VirtualCharPipeDevice
elif char_type == VirtualCharDevice.CHAR_TCP:
c = VirtualCharTcpDevice
elif char_type == VirtualCharDevice.CHAR_UNIX:
c = VirtualCharUnixDevice
elif char_type == VirtualCharDevice.CHAR_UDP:
c = VirtualCharUdpDevice
elif char_type == VirtualCharDevice.CHAR_SPICEVMC:
c = VirtualCharSpicevmcDevice
else:
raise ValueError(_("Unknown character device type '%s'.") %
char_type)
if dev_type == VirtualCharDevice.DEV_CONSOLE:
return VirtualConsoleDevice(conn)
return c(conn, dev_type)
get_dev_instance = staticmethod(get_dev_instance)
def __init__(self, conn, dev_type, parsexml=None, parsexmlnode=None):
if dev_type not in self.dev_types:
raise ValueError(_("Unknown character device type '%s'") % dev_type)
self._dev_type = dev_type
self._virtual_device_type = self._dev_type
VirtualDevice.__init__(self, conn, parsexml, parsexmlnode)
# Init
self._source_path = None
self._source_mode = self.CHAR_MODE_BIND
self._source_host = "127.0.0.1"
self._source_port = None
self._target_type = None
self._target_address = None
self._target_port = None
self._target_name = None
self._bind_host = None
self._bind_port = None
self._protocol = self.CHAR_PROTOCOL_RAW
self._address_type = None
if self.char_type == self.CHAR_UDP:
self._source_mode = self.CHAR_MODE_CONNECT
if self._is_parse():
return
if not self._char_type:
raise ValueError("Must be instantiated through a subclass.")
self.char_type = self._char_type
def supports_property(self, propname, ro=False):
"""
Whether the character dev type supports the passed property name
"""
users = {
"source_path" : [self.CHAR_FILE, self.CHAR_UNIX,
self.CHAR_DEV, self.CHAR_PIPE],
"source_mode" : [self.CHAR_UNIX, self.CHAR_TCP],
"source_host" : [self.CHAR_TCP, self.CHAR_UDP],
"source_port" : [self.CHAR_TCP, self.CHAR_UDP],
"protocol" : [self.CHAR_TCP],
"bind_host" : [self.CHAR_UDP],
"bind_port" : [self.CHAR_UDP],
"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],
"protocol" : [self.TYPE_TCP],
"bind_host" : [self.TYPE_UDP],
"bind_port" : [self.TYPE_UDP],
}
if ro:
users["source_path"] += [self.CHAR_PTY]
users["source_path"] += [self.TYPE_PTY]
channel_users = {
"target_name" : [self.CHAR_CHANNEL_TARGET_VIRTIO],
"target_name" : [self.CHANNEL_TARGET_VIRTIO],
}
if users.get(propname):
return self.char_type in users[propname]
return self.type in users[propname]
if channel_users.get(propname):
return (self.dev_type == self.DEV_CHANNEL and
return (self.virtual_device_type == "channel" and
self.target_type in channel_users[propname])
return hasattr(self, propname)
# Properties
def get_dev_type(self):
return self._dev_type
dev_type = property(get_dev_type)
def get_char_type(self):
return self._char_type
def set_char_type(self, val):
if val not in self.char_types:
raise ValueError(_("Unknown character device type '%s'")
% val)
self._char_type = val
char_type = XMLProperty(get_char_type, set_char_type,
_XML_PROP_ORDER = ["type",
"bind_host", "bind_port",
"source_mode", "source_path",
"source_host", "source_port",
"target_type", "target_name"]
type = XMLProperty(
doc=_("Method used to expose character device in the host."),
xpath="./@type")
# Properties functions used by the various subclasses
def get_source_path(self):
return self._source_path
def set_source_path(self, val):
self._source_path = val
def _sourcepath_get_xpath(self):
return "./source/@path | ./@tty"
source_path = XMLProperty(get_source_path, set_source_path,
xml_get_xpath=_sourcepath_get_xpath,
xpath="./source/@path")
source_path = XMLProperty(xml_get_xpath=_sourcepath_get_xpath,
doc=_("Host input path to attach to the guest."),
xpath="./source/@path")
def get_source_mode(self):
return self._source_mode
def set_source_mode(self, val):
if val not in self.char_modes:
raise ValueError(_("Unknown character mode '%s'.") % val)
self._source_mode = val
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
def _sourcemode_xpath(self):
if self.char_type == self.CHAR_UDP:
if self.type == self.TYPE_UDP:
return "./source[@mode='connect']/@mode"
return "./source/@mode"
source_mode = XMLProperty(get_source_mode, set_source_mode,
name="char sourcemode",
xml_get_xpath=_sourcemode_xpath,
xml_set_xpath=_sourcemode_xpath)
source_mode = XMLProperty(name="char sourcemode",
doc=_("Target connect/listen mode."),
xml_get_xpath=_sourcemode_xpath,
xml_set_xpath=_sourcemode_xpath,
default_cb=_get_default_source_mode)
def get_source_host(self):
return self._source_host
def set_source_host(self, val):
self._source_host = val
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
def _sourcehost_xpath(self):
return "./source[@mode='%s']/@host" % self.source_mode
source_host = XMLProperty(get_source_host, set_source_host,
name="char sourcehost",
xml_get_xpath=_sourcehost_xpath,
xml_set_xpath=_sourcehost_xpath)
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."),
xml_get_xpath=_sourcehost_xpath,
xml_set_xpath=_sourcehost_xpath,
default_cb=_get_default_sourcehost,
set_converter=_set_source_validate)
def get_source_port(self):
return self._source_port
def set_source_port(self, val):
self._source_port = int(val)
def _sourceport_xpath(self):
return "./source[@mode='%s']/@service" % self.source_mode
source_port = XMLProperty(get_source_port, set_source_port,
name="char sourceport",
xml_get_xpath=_sourceport_xpath,
xml_set_xpath=_sourceport_xpath)
def _get_sourceport_convert(self, val):
if val is None:
return None
return int(val)
def _set_sourceport_convert(self, val):
return self._get_sourceport_convert(self._set_source_validate(val))
source_port = XMLProperty(name="char sourceport",
doc=_("Port on target host to connect/listen to."),
xml_get_xpath=_sourceport_xpath,
xml_set_xpath=_sourceport_xpath,
set_converter=_set_sourceport_convert,
get_converter=_get_sourceport_convert)
def get_bind_host(self):
return self._bind_host
def set_bind_host(self, val):
self._bind_host = val
bind_host = XMLProperty(get_bind_host, set_bind_host,
xpath="./source[@mode='bind']/@host")
_has_mode_connect = XMLProperty(xpath="./source[@mode='connect']/@mode")
_has_mode_bind = XMLProperty(xpath="./source[@mode='bind']/@mode")
def get_bind_port(self):
return self._bind_port
def set_bind_port(self, val):
self._bind_port = int(val)
bind_port = XMLProperty(get_bind_port, set_bind_port,
xpath="./source[@mode='bind']/@service")
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
bind_host = XMLProperty(xpath="./source[@mode='bind']/@host",
doc=_("Host addresss to bind to."),
set_converter=_set_bind_validate)
def _get_bindport_convert(self, val):
if val is None:
return None
return int(val)
def _set_bindport_convert(self, val):
return self._get_bindport_convert(self._set_bind_validate(val))
bind_port = XMLProperty(xpath="./source[@mode='bind']/@service",
doc=_("Host port to bind to."),
get_converter=_get_bindport_convert,
set_converter=_set_bindport_convert)
def get_protocol(self):
return self._protocol
def set_protocol(self, val):
if val not in self.char_protocols:
raise ValueError(_("Unknown protocol '%s'.") % val)
self._protocol = val
protocol = XMLProperty(get_protocol, set_protocol,
xpath="./protocol/@type")
def _get_default_protocol(self):
if not self.supports_property("protocol"):
return None
return self.PROTOCOL_RAW
protocol = XMLProperty(xpath="./protocol/@type",
doc=_("Format used when sending data."),
default_cb=_get_default_protocol)
# GuestFWD target properties
def get_target_type(self):
return self._target_type
def set_target_type(self, val):
if val not in self.target_types:
raise ValueError(_("Unknown target type '%s'. Must be in: ") % val,
self.target_types)
self._target_type = val
target_type = XMLProperty(get_target_type, set_target_type,
doc=_("Channel type as exposed in the guest."),
xpath="./target/@type")
def _get_default_target_type(self):
if self.type == self.TYPE_SPICEVMC:
return self.CHANNEL_TARGET_VIRTIO
return None
target_type = XMLProperty(xpath="./target/@type",
doc=_("Channel type as exposed in the guest."),
default_cb=_get_default_target_type)
def set_target_address(self, val):
self._target_address = val
def get_target_address(self):
return self._target_address
target_address = XMLProperty(get_target_address, set_target_address,
doc=_("Guest forward channel address in the guest."),
xpath="./target/@address")
target_address = XMLProperty(xpath="./target/@address",
doc=_("Guest forward channel address in the guest."))
def set_target_port(self, val):
self._target_port = val
def get_target_port(self):
return self._target_port
target_port = XMLProperty(get_target_port, set_target_port,
doc=_("Guest forward channel port in the guest."),
xpath="./target/@port")
target_port = XMLProperty(xpath="./target/@port", is_int=True,
doc=_("Guest forward channel port in the guest."))
def set_target_name(self, val):
self._target_name = val
def get_target_name(self):
return self._target_name
target_name = XMLProperty(get_target_name, set_target_name,
def _default_target_name(self):
if self.type == self.TYPE_SPICEVMC:
return "com.redhat.spice.0"
return None
target_name = XMLProperty(xpath="./target/@name",
doc=_("Sysfs name of virtio port in the guest"),
xpath="./target/@name")
def get_address_type(self):
return self._address_type
def set_address_type(self, val):
if val not in self.address_types:
raise ValueError(_("Unknown address type '%s'. Must be in: ") % val,
self.address_types)
self._address_type = val
address_type = XMLProperty(get_address_type, set_address_type,
doc=_("Channel type as exposed in the guest."),
xpath="./address/@type")
# XML building helpers
def _char_empty_xml(self):
"""
Provide source xml for devices with no params (null, stdio, ...)
"""
return ""
def _char_file_xml(self):
"""
Provide source xml for devs that require only a path (dev, pipe)
"""
file_xml = ""
mode_xml = ""
if self.source_path:
file_xml = " path='%s'" % xml_escape(self.source_path)
else:
raise ValueError(_("A source path is required for character "
"device type '%s'" % self.char_type))
if self.supports_property("source_mode") and self.source_mode:
mode_xml = " mode='%s'" % xml_escape(self.source_mode)
xml = " <source%s%s/>\n" % (mode_xml, file_xml)
return xml
def _char_xml(self):
pass
def _get_target_xml(self):
xml = ""
if not self.target_type:
return xml
xml = " <target type='%s'" % self.target_type
if self._dev_type == self.DEV_CHANNEL:
if self.target_type == self.CHAR_CHANNEL_TARGET_GUESTFWD:
if not self.target_address and not self.target_port:
raise RuntimeError("A target address and port must be "
"specified for '%s'" % self.target_type)
xml += " address='%s'" % self.target_address
xml += " port='%s'" % self.target_port
elif self.target_type == self.CHAR_CHANNEL_TARGET_VIRTIO:
if self.target_name:
xml += " name='%s'" % self.target_name
default_cb=_default_target_name)
xml += "/>\n"
return xml
def _get_address_xml(self):
xml = ""
if not self.address_type:
return xml
xml = " <address type='%s'" % self.address_type
xml += "/>\n"
return xml
class VirtualConsoleDevice(_VirtualCharDevice):
virtual_device_type = "console"
def _get_xml_config(self):
xml = " <%s type='%s'" % (self._dev_type, self._char_type)
char_xml = self._char_xml()
target_xml = self._get_target_xml()
has_target = (self._dev_type == self.DEV_CHANNEL or
self._dev_type == self.DEV_CONSOLE or
self.has_target)
if target_xml and not has_target:
raise RuntimeError(
"Target parameters not used with '%s' devices, only '%s'" %
(self._dev_type, self.DEV_CHANNEL))
address_xml = self._get_address_xml()
has_address = self._target_type == self.CHAR_CHANNEL_TARGET_VIRTIO
if address_xml and not has_address:
raise RuntimeError(
"Address parameters not used with '%s' target, only '%s'" %
(self._target_type, self.CHAR_CHANNEL_TARGET_VIRTIO))
if char_xml or target_xml or address_xml:
xml += ">"
if char_xml:
xml += "\n%s" % char_xml
if target_xml:
xml += "\n%s" % target_xml
if address_xml:
xml += "\n%s" % target_xml
xml += " </%s>" % self._dev_type
else:
xml += "/>"
return xml
# Back compat class for building a simple PTY 'console' element
class VirtualSerialDevice(_VirtualCharDevice):
virtual_device_type = "serial"
class VirtualConsoleDevice(VirtualCharDevice):
_char_xml = VirtualCharDevice._char_empty_xml
_char_type = VirtualCharDevice.CHAR_PTY
def __init__(self, conn, parsexml=None, parsexmlnode=None):
VirtualCharDevice.__init__(self, conn, VirtualCharDevice.DEV_CONSOLE,
parsexml, parsexmlnode)
self.target_types = [self.CHAR_CONSOLE_TARGET_SERIAL,
self.CHAR_CONSOLE_TARGET_VIRTIO,
self.CHAR_CONSOLE_TARGET_XEN,
self.CHAR_CONSOLE_TARGET_UML]
# Classes for each device 'type'
class VirtualParallelDevice(_VirtualCharDevice):
virtual_device_type = "parallel"
class VirtualCharPtyDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_PTY
_char_xml = VirtualCharDevice._char_empty_xml
source_path = property(VirtualCharDevice.get_source_path,
VirtualCharDevice.set_source_path,
doc=_("PTY allocated to the guest."))
class VirtualCharStdioDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_STDIO
_char_xml = VirtualCharDevice._char_empty_xml
class VirtualCharNullDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_NULL
_char_xml = VirtualCharDevice._char_empty_xml
class VirtualCharVcDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_VC
_char_xml = VirtualCharDevice._char_empty_xml
class VirtualCharDevDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_DEV
_char_xml = VirtualCharDevice._char_file_xml
source_path = property(VirtualCharDevice.get_source_path,
VirtualCharDevice.set_source_path,
doc=_("Host character device to attach to guest."))
class VirtualCharPipeDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_PIPE
_char_xml = VirtualCharDevice._char_file_xml
source_path = property(VirtualCharDevice.get_source_path,
VirtualCharDevice.set_source_path,
doc=_("Named pipe to use for input and output."))
class VirtualCharFileDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_FILE
_char_xml = VirtualCharDevice._char_file_xml
source_path = property(VirtualCharDevice.get_source_path,
VirtualCharDevice.set_source_path,
doc=_("File path to record device output."))
class VirtualCharUnixDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_UNIX
_char_xml = VirtualCharDevice._char_file_xml
source_mode = property(VirtualCharDevice.get_source_mode,
VirtualCharDevice.set_source_mode,
doc=_("Target connect/listen mode."))
source_path = property(VirtualCharDevice.get_source_path,
VirtualCharDevice.set_source_path,
doc=_("Unix socket path."))
class VirtualCharTcpDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_TCP
source_mode = property(VirtualCharDevice.get_source_mode,
VirtualCharDevice.set_source_mode,
doc=_("Target connect/listen mode."))
source_host = property(VirtualCharDevice.get_source_host,
VirtualCharDevice.set_source_host,
doc=_("Address to connect/listen to."))
source_port = property(VirtualCharDevice.get_source_port,
VirtualCharDevice.set_source_port,
doc=_("Port on target host to connect/listen to."))
protocol = property(VirtualCharDevice.get_protocol,
VirtualCharDevice.set_protocol,
doc=_("Format used when sending data."))
def _char_xml(self):
if not self.source_host and not self.source_port:
raise ValueError(_("A host and port must be specified."))
xml = (" <source mode='%s' host='%s' service='%s'/>\n" %
(self.source_mode, self.source_host, self.source_port))
xml += " <protocol type='%s'/>\n" % self.protocol
return xml
class VirtualCharUdpDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_UDP
bind_host = property(VirtualCharDevice.get_bind_host,
VirtualCharDevice.set_bind_host,
doc=_("Host address to bind to."))
bind_port = property(VirtualCharDevice.get_bind_port,
VirtualCharDevice.set_bind_port,
doc=_("Host port to bind to."))
source_host = property(VirtualCharDevice.get_source_host,
VirtualCharDevice.set_source_host,
doc=_("Host address to send output to."))
source_port = property(VirtualCharDevice.get_source_port,
VirtualCharDevice.set_source_port,
doc=_("Host port to send output to."))
# XXX: UDP: Only source _connect_ port required?
def _char_xml(self):
if not self.source_port:
raise ValueError(_("A connection port must be specified."))
xml = ""
bind_xml = ""
bind_host_xml = ""
bind_port_xml = ""
source_host_xml = ""
if self.bind_port:
bind_port_xml = " service='%s'" % self.bind_port
if not self.bind_host:
self.bind_host = "127.0.0.1"
if self.bind_host:
bind_host_xml = " host='%s'" % self.bind_host
if self.source_host:
source_host_xml = " host='%s'" % self.source_host
if self.bind_host or self.bind_port:
bind_xml = (" <source mode='bind'%s%s/>\n" %
(bind_host_xml, bind_port_xml))
xml += bind_xml
xml += (" <source mode='connect'%s service='%s'/>\n" %
(source_host_xml, self.source_port))
return xml
class VirtualCharSpicevmcDevice(VirtualCharDevice):
_char_type = VirtualCharDevice.CHAR_SPICEVMC
_char_xml = VirtualCharDevice._char_empty_xml
target_types = [VirtualCharDevice.CHAR_CHANNEL_TARGET_VIRTIO]
has_target = True
def __init__(self, conn, dev_type=VirtualCharDevice.DEV_CHANNEL,
parsexml=None, parsexmlnode=None):
VirtualCharDevice.__init__(self, conn, dev_type,
parsexml, parsexmlnode)
self._target_type = VirtualCharDevice.CHAR_CHANNEL_TARGET_VIRTIO
self._target_name = "com.redhat.spice.0"
class VirtualChannelDevice(_VirtualCharDevice):
virtual_device_type = "channel"
TYPES = [_VirtualCharDevice.TYPE_SPICEVMC]

View File

@ -22,7 +22,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualController(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_CONTROLLER
virtual_device_type = VirtualDevice.VIRTUAL_DEV_CONTROLLER
TYPE_IDE = "ide"
TYPE_FDC = "fdc"

View File

@ -69,7 +69,7 @@ class VirtualDevice(XMLBuilder):
VIRTUAL_DEV_TPM]
# General device type (disk, interface, etc.)
_virtual_device_type = None
virtual_device_type = None
_XML_INDENT = 4
def __init__(self, conn, parsexml=None, parsexmlnode=None):
@ -79,24 +79,20 @@ class VirtualDevice(XMLBuilder):
@param conn: libvirt connection to validate device against
"""
XMLBuilder.__init__(self, conn, parsexml, parsexmlnode)
self._XML_ROOT_NAME = self._virtual_device_type
self._XML_ROOT_NAME = self.virtual_device_type
self.alias = VirtualDeviceAlias(conn, parsexmlnode=parsexmlnode)
self.address = VirtualDeviceAddress(conn, parsexmlnode=parsexmlnode)
self._XML_SUB_ELEMENTS = ["alias", "address"]
if not self._virtual_device_type:
if not self.virtual_device_type:
raise ValueError(_("Virtual device type must be set in subclass."))
if self._virtual_device_type not in self.virtual_device_types:
if self.virtual_device_type not in self.virtual_device_types:
raise ValueError(_("Unknown virtual device type '%s'.") %
self._virtual_device_type)
self.virtual_device_type)
def get_virtual_device_type(self):
return self._virtual_device_type
virtual_device_type = property(get_virtual_device_type)
def setup(self, meter=None):
"""
Perform potentially hazardous device initialization, like

View File

@ -142,7 +142,7 @@ class VirtualDisk(VirtualDevice):
# pylint: disable=W0622
# Redefining built-in 'type', but it matches the XML so keep it
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_DISK
virtual_device_type = VirtualDevice.VIRTUAL_DEV_DISK
DRIVER_FILE = "file"
DRIVER_PHY = "phy"

View File

@ -24,7 +24,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualFilesystem(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_FILESYSTEM
virtual_device_type = VirtualDevice.VIRTUAL_DEV_FILESYSTEM
_target_props = ["dir", "name", "file", "dev"]

View File

@ -58,7 +58,7 @@ def _yes_bool(val):
class VirtualGraphics(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_GRAPHICS
virtual_device_type = VirtualDevice.VIRTUAL_DEV_GRAPHICS
TYPE_SDL = "sdl"
TYPE_VNC = "vnc"

View File

@ -23,7 +23,7 @@ from virtinst import NodeDeviceParser
class VirtualHostDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_HOSTDEV
virtual_device_type = VirtualDevice.VIRTUAL_DEV_HOSTDEV
@staticmethod
def device_from_node(conn, name=None, nodedev=None, is_dup=False,

View File

@ -22,7 +22,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualInputDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_INPUT
virtual_device_type = VirtualDevice.VIRTUAL_DEV_INPUT
TYPE_MOUSE = "mouse"
TYPE_TABLET = "tablet"

View File

@ -22,7 +22,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualMemballoon(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_MEMBALLOON
virtual_device_type = VirtualDevice.VIRTUAL_DEV_MEMBALLOON
MODEL_DEFAULT = "virtio"
MODELS = ["xen", "none", MODEL_DEFAULT]

View File

@ -66,7 +66,7 @@ class VirtualPort(XMLBuilder):
class VirtualNetworkInterface(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_NET
virtual_device_type = VirtualDevice.VIRTUAL_DEV_NET
TYPE_BRIDGE = "bridge"
TYPE_VIRTUAL = "network"

View File

@ -26,7 +26,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualRedirDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_REDIRDEV
virtual_device_type = VirtualDevice.VIRTUAL_DEV_REDIRDEV
BUS_DEFAULT = "default"
BUSES = ["usb"]

View File

@ -25,7 +25,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualSmartCardDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_SMARTCARD
virtual_device_type = VirtualDevice.VIRTUAL_DEV_SMARTCARD
# Default models list
MODE_DEFAULT = "default"

View File

@ -28,7 +28,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualTPMDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_TPM
virtual_device_type = VirtualDevice.VIRTUAL_DEV_TPM
TYPE_PASSTHROUGH = "passthrough"
TYPE_DEFAULT = "default"

View File

@ -23,7 +23,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualVideoDevice(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_VIDEO
virtual_device_type = VirtualDevice.VIRTUAL_DEV_VIDEO
# Default models list
MODEL_DEFAULT = "default"

View File

@ -23,7 +23,7 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualWatchdog(VirtualDevice):
_virtual_device_type = VirtualDevice.VIRTUAL_DEV_WATCHDOG
virtual_device_type = VirtualDevice.VIRTUAL_DEV_WATCHDOG
MODEL_I6300 = "i6300esb"
MODEL_IB700 = "ib700"

View File

@ -28,7 +28,10 @@ from virtinst.VirtualAudio import VirtualAudio
from virtinst.VirtualInputDevice import VirtualInputDevice
from virtinst.VirtualDisk import VirtualDisk
from virtinst.VirtualHostDevice import VirtualHostDevice
from virtinst.VirtualCharDevice import VirtualCharDevice
from virtinst.VirtualCharDevice import (VirtualChannelDevice,
VirtualConsoleDevice,
VirtualParallelDevice,
VirtualSerialDevice)
from virtinst.VirtualVideoDevice import VirtualVideoDevice
from virtinst.VirtualController import VirtualController
from virtinst.VirtualWatchdog import VirtualWatchdog

View File

@ -42,7 +42,6 @@ from virtinst import VirtualNetworkInterface
from virtinst import VirtualGraphics
from virtinst import VirtualAudio
from virtinst import VirtualDisk
from virtinst import VirtualCharDevice
DEFAULT_POOL_PATH = "/var/lib/libvirt/images"
@ -1813,32 +1812,36 @@ def parse_memballoon(guest, optstring, dev=None):
######################################################
def parse_serial(guest, optstring, dev=None):
return _parse_char(guest, optstring, "serial", dev)
if not dev:
dev = virtinst.VirtualSerialDevice(guest.conn)
return _parse_char(optstring, "serial", dev)
def parse_parallel(guest, optstring, dev=None):
return _parse_char(guest, optstring, "parallel", dev)
if not dev:
dev = virtinst.VirtualParallelDevice(guest.conn)
return _parse_char(optstring, "parallel", dev)
def parse_console(guest, optstring, dev=None):
return _parse_char(guest, optstring, "console", dev)
if not dev:
dev = virtinst.VirtualConsoleDevice(guest.conn)
return _parse_char(optstring, "console", dev)
def parse_channel(guest, optstring, dev=None):
return _parse_char(guest, optstring, "channel", dev)
if not dev:
dev = virtinst.VirtualChannelDevice(guest.conn)
return _parse_char(optstring, "channel", dev)
def _parse_char(guest, optstring, dev_type, dev=None):
def _parse_char(optstring, dev_type, dev=None):
"""
Helper to parse --serial/--parallel options
"""
# Peel the char type off the front
opts = parse_optstr(optstring, remove_first="char_type")
char_type = opts.get("char_type")
if not dev:
dev = VirtualCharDevice.get_dev_instance(guest.conn,
dev_type, char_type)
ctype = opts.get("char_type")
def set_param(paramname, dictname, val=None):
val = get_opt_param(opts, dictname, val)
@ -1848,7 +1851,7 @@ def _parse_char(guest, optstring, dev_type, dev=None):
if not dev.supports_property(paramname):
raise ValueError(_("%(devtype)s type '%(chartype)s' does not "
"support '%(optname)s' option.") %
{"devtype" : dev_type, "chartype": char_type,
{"devtype" : dev_type, "chartype": ctype,
"optname" : dictname})
setattr(dev, paramname, val)
@ -1863,7 +1866,7 @@ def _parse_char(guest, optstring, dev_type, dev=None):
bind_host, bind_port = parse_host("bind_host")
target_addr, target_port = parse_host("target_address")
set_param("char_type", "char_type")
set_param("type", "char_type")
set_param("source_path", "path")
set_param("source_mode", "mode")
set_param("protocol", "protocol")

View File

@ -313,8 +313,8 @@ class XMLProperty(property):
raise RuntimeError("Can't set default_cb for old style XML "
"prop.")
property.__init__(self, fget=self.new_getter, fset=self.new_setter,
doc=doc)
property.__init__(self, fget=self.new_getter, fset=self.new_setter)
self.__doc__ = doc
##################
@ -344,7 +344,7 @@ class XMLProperty(property):
Map the raw property() instance to the param name it's exposed
as in the XMLBuilder class. This is just for debug purposes.
"""
for key, val in xmlbuilder._all_xml_props().items():
for key, val in xmlbuilder.all_xml_props().items():
if val is self:
return key
raise RuntimeError("Didn't find expected property")
@ -703,7 +703,7 @@ class XMLBuilder(object):
Refresh the XML for the passed class propname. Used to adjust
the XML when an interdependent property changes.
"""
self._all_xml_props()[propname].refresh_xml(self)
self.all_xml_props()[propname].refresh_xml(self)
###################
@ -772,7 +772,7 @@ class XMLBuilder(object):
self._set_xml_context()
def _all_xml_props(self):
def all_xml_props(self):
ret = {}
for c in reversed(type.mro(self.__class__)[:-1]):
for key, val in c.__dict__.items():
@ -782,7 +782,7 @@ class XMLBuilder(object):
def _do_add_parse_bits(self, xml):
# Find all properties that have default callbacks
xmlprops = self._all_xml_props()
xmlprops = self.all_xml_props()
defaultprops = [v for v in xmlprops.values() if v.has_default_value()]
for prop in defaultprops:
prop.set_default(self)