virtinst: move UI only functions into virtManager

These throw off code coverage testing. They are mostly:

* pretty* device helpers
* network + snapshot validation + creation routines
This commit is contained in:
Cole Robinson 2019-06-09 15:29:44 -04:00
parent c9233aa6c3
commit b5a664bd1b
27 changed files with 526 additions and 637 deletions

View File

@ -48,7 +48,6 @@ class TestNodeDev(unittest.TestCase):
dev = NodeDevice(self.conn, funky_chars_xml) dev = NodeDevice(self.conn, funky_chars_xml)
self.assertEqual(dev.name, "L3B2616") self.assertEqual(dev.name, "L3B2616")
self.assertEqual(dev.device_type, "LENOVO") self.assertEqual(dev.device_type, "LENOVO")
self.assertEqual(dev.pretty_name(), dev.name)
def testNetDevice(self): def testNetDevice(self):
devname = "net_00_1c_25_10_b1_e4" devname = "net_00_1c_25_10_b1_e4"
@ -57,19 +56,8 @@ class TestNodeDev(unittest.TestCase):
self.assertEqual(dev.parent, "pci_8086_1049") self.assertEqual(dev.parent, "pci_8086_1049")
self.assertEqual(dev.device_type, "net") self.assertEqual(dev.device_type, "net")
self.assertEqual(dev.interface, "eth0") self.assertEqual(dev.interface, "eth0")
self.assertEqual(dev.pretty_name(), "Interface eth0")
def testPCIDevice(self): def testPCIDevice(self):
devname = "pci_1180_592"
dev = self._nodeDevFromName(devname)
self.assertEqual(dev.pretty_name(),
"0000:15:00:4 Ricoh Co Ltd R5C592 Memory Stick Bus Host Adapter")
devname = "pci_8086_1049"
dev = self._nodeDevFromName(devname)
self.assertEqual(dev.pretty_name(),
"0000:00:19:0 Intel Corporation 82566MM Gigabit Network Connection")
nodename = "pci_8086_10fb" nodename = "pci_8086_10fb"
obj = self._nodeDevFromName(nodename) obj = self._nodeDevFromName(nodename)
self.assertEqual(obj.is_pci_sriov(), True) self.assertEqual(obj.is_pci_sriov(), True)
@ -81,13 +69,8 @@ class TestNodeDev(unittest.TestCase):
def testUSBDevDevice(self): def testUSBDevDevice(self):
devname = "usb_device_781_5151_2004453082054CA1BEEE" devname = "usb_device_781_5151_2004453082054CA1BEEE"
dev = self._nodeDevFromName(devname) dev = self._nodeDevFromName(devname)
self.assertEqual(dev.pretty_name(), self.assertEqual(dev.vendor_name, "SanDisk Corp.")
"001:004 SanDisk Corp. Cruzer Micro 256/512MB Flash Drive") self.assertEqual(dev.product_name, "Cruzer Micro 256/512MB Flash Drive")
devname = "usb_device_483_2016_noserial"
dev = self._nodeDevFromName(devname)
self.assertEqual(dev.pretty_name(),
"003:002 SGS Thomson Microelectronics Fingerprint Reader")
devname = "usb_device_1d6b_1_0000_00_1a_0" devname = "usb_device_1d6b_1_0000_00_1a_0"
dev = self._nodeDevFromName(devname) dev = self._nodeDevFromName(devname)
@ -126,8 +109,6 @@ class TestNodeDev(unittest.TestCase):
"/dev/dri/by-path/pci-0000:00:02.0-render") "/dev/dri/by-path/pci-0000:00:02.0-render")
self.assertEqual(dev.devnodes[1].node_type, "link") self.assertEqual(dev.devnodes[1].node_type, "link")
self.assertEqual(dev.is_drm_render(), True) self.assertEqual(dev.is_drm_render(), True)
self.assertEqual(dev.pretty_name(),
"0000:00:02:0 Intel Corporation HD Graphics 530 (render)")
# NodeDevice 2 Device XML tests # NodeDevice 2 Device XML tests

View File

@ -280,7 +280,7 @@ class vmmAddHardware(vmmGObjectUI):
True, None) True, None)
add_hw_option(_("RNG"), "system-run", PAGE_RNG, True, None) add_hw_option(_("RNG"), "system-run", PAGE_RNG, True, None)
add_hw_option(_("Panic Notifier"), "system-run", PAGE_PANIC, add_hw_option(_("Panic Notifier"), "system-run", PAGE_PANIC,
bool(DevicePanic.get_models(self.vm.get_xmlobj().os)), bool(DevicePanic.get_models(self.vm.get_xmlobj())),
_("Not supported for this hypervisor/libvirt/arch combination.")) _("Not supported for this hypervisor/libvirt/arch combination."))
add_hw_option(_("Virtio VSOCK"), "network-idle", PAGE_VSOCK, add_hw_option(_("Virtio VSOCK"), "network-idle", PAGE_VSOCK,
self.vm.is_hvm(), self.vm.is_hvm(),
@ -403,6 +403,295 @@ class vmmAddHardware(vmmGObjectUI):
return True return True
#####################
# Pretty UI helpers #
#####################
@staticmethod
def char_recommended_types(char_class):
if char_class.XML_NAME == "console":
return [DeviceSerial.TYPE_PTY]
ret = [DeviceSerial.TYPE_PTY,
DeviceSerial.TYPE_FILE,
DeviceSerial.TYPE_UNIX]
if char_class.XML_NAME == "channel":
ret = [DeviceSerial.TYPE_SPICEVMC,
DeviceSerial.TYPE_SPICEPORT] + ret
return ret
@staticmethod
def char_pretty_channel_name(val):
if val == DeviceChannel.CHANNEL_NAME_SPICE:
return "spice"
if val == DeviceChannel.CHANNEL_NAME_QEMUGA:
return "qemu-ga"
if val == DeviceChannel.CHANNEL_NAME_LIBGUESTFS:
return "libguestfs"
if val == DeviceChannel.CHANNEL_NAME_SPICE_WEBDAV:
return "spice-webdav"
return None
@staticmethod
def char_pretty_type(ctype):
"""
Return a human readable description of the passed char type
"""
if ctype == DeviceSerial.TYPE_PTY:
return _("Pseudo TTY")
elif ctype == DeviceSerial.TYPE_FILE:
return _("Output to a file")
elif ctype == DeviceSerial.TYPE_TCP:
return _("TCP net console")
elif ctype == DeviceSerial.TYPE_UDP:
return _("UDP net console")
elif ctype == DeviceSerial.TYPE_UNIX:
return _("Unix socket")
elif ctype == DeviceSerial.TYPE_SPICEVMC:
return _("Spice agent")
elif ctype == DeviceSerial.TYPE_SPICEPORT:
return _("Spice port")
return ctype
@staticmethod
def controller_recommended_types():
return [DeviceController.TYPE_SCSI,
DeviceController.TYPE_USB,
DeviceController.TYPE_VIRTIOSERIAL,
DeviceController.TYPE_CCID]
@staticmethod
def controller_pretty_type(ctype):
pretty_mappings = {
DeviceController.TYPE_IDE: "IDE",
DeviceController.TYPE_FDC: _("Floppy"),
DeviceController.TYPE_SCSI: "SCSI",
DeviceController.TYPE_SATA: "SATA",
DeviceController.TYPE_VIRTIOSERIAL: "VirtIO Serial",
DeviceController.TYPE_USB: "USB",
DeviceController.TYPE_PCI: "PCI",
DeviceController.TYPE_CCID: "CCID",
DeviceController.TYPE_XENBUS: "xenbus",
}
if ctype not in pretty_mappings:
return ctype
return pretty_mappings[ctype]
@staticmethod
def controller_pretty_desc(dev):
ret = vmmAddHardware.controller_pretty_type(dev.type)
if dev.type == "scsi":
if dev.model == "virtio-scsi":
ret = "Virtio " + ret
elif dev.address.type == "spapr-vio":
ret = "sPAPR " + ret
if dev.type == "pci" and dev.model == "pcie-root":
ret = "PCIe"
return ret
@staticmethod
def disk_old_recommended_buses(guest):
ret = []
if guest.os.is_hvm() or guest.conn.is_test():
if not guest.os.is_q35():
ret.append("ide")
ret.append("sata")
ret.append("fdc")
ret.append("scsi")
ret.append("usb")
if guest.type in ["qemu", "kvm", "test"]:
ret.append("sd")
ret.append("virtio")
if "scsi" not in ret:
ret.append("scsi")
if guest.conn.is_xen() or guest.conn.is_test():
ret.append("xen")
return ret
@staticmethod
def disk_recommended_buses(guest, domcaps, devtype):
# try to get supported disk bus types from domain capabilities
if "bus" in domcaps.devices.disk.enum_names():
buses = domcaps.devices.disk.get_enum("bus").get_values()
else:
buses = vmmAddHardware.disk_old_recommended_buses(guest)
bus_map = {
"disk": ["ide", "sata", "scsi", "sd", "usb", "virtio", "xen"],
"floppy": ["fdc"],
"cdrom": ["ide", "sata", "scsi"],
"lun": ["scsi"],
}
return [bus for bus in buses if bus in bus_map.get(devtype, [])]
@staticmethod
def disk_pretty_bus(bus):
if bus in ["ide", "sata", "scsi", "usb", "sd"]:
return bus.upper()
if bus in ["xen"]:
return bus.capitalize()
if bus == "virtio":
return "VirtIO"
return bus
@staticmethod
def tpm_pretty_type(tpm_type):
if tpm_type == DeviceTpm.TYPE_PASSTHROUGH:
return _("Passthrough device")
if tpm_type == DeviceTpm.TYPE_EMULATOR:
return _("Emulated device")
return tpm_type
@staticmethod
def tpm_pretty_model(tpm_model):
if tpm_model == DeviceTpm.MODEL_TIS:
return _("TIS")
if tpm_model == DeviceTpm.MODEL_CRB:
return _("CRB")
return tpm_model
@staticmethod
def panic_pretty_model(panic_model):
if panic_model == DevicePanic.MODEL_ISA:
return _("ISA")
elif panic_model == DevicePanic.MODEL_PSERIES:
return _("pSeries")
elif panic_model == DevicePanic.MODEL_HYPERV:
return _("Hyper-V")
elif panic_model == DevicePanic.MODEL_S390:
return _("s390")
return panic_model
@staticmethod
def rng_pretty_type(rng_type):
if rng_type == DeviceRng.TYPE_RANDOM:
return _("Random")
if rng_type == DeviceRng.TYPE_EGD:
return _("Entropy Gathering Daemon")
return rng_type
@staticmethod
def rng_pretty_backend_type(backend_type):
return {"udp": "UDP",
"tcp": "TCP"}.get(backend_type) or backend_type
@staticmethod
def rng_pretty_mode(mode):
return {"bind": _("Bind"),
"connect": _("Connect")}.get(mode) or mode
@staticmethod
def sound_recommended_models(_guest):
return ["ich6", "ich9", "ac97"]
@staticmethod
def sound_pretty_model(model):
ret = model.upper()
if model in ["ich6", "ich9"]:
ret = "HDA (%s)" % model.upper()
return ret
@staticmethod
def watchdog_pretty_action(action):
if action == DeviceWatchdog.ACTION_RESET:
return _("Forcefully reset the guest")
if action == DeviceWatchdog.ACTION_SHUTDOWN:
return _("Gracefully shutdown the guest")
if action == DeviceWatchdog.ACTION_POWEROFF:
return _("Forcefully power off the guest")
if action == DeviceWatchdog.ACTION_PAUSE:
return _("Pause the guest")
if action == DeviceWatchdog.ACTION_NONE:
return _("No action")
if action == DeviceWatchdog.ACTION_DUMP:
return _("Dump guest memory core")
return action
@staticmethod
def input_pretty_name(typ, bus):
if typ == "tablet" and bus == "usb":
return _("EvTouch USB Graphics Tablet")
if bus in ["usb", "ps2"]:
return _("Generic") + (" %s %s" %
(bus.upper(), str(typ).capitalize()))
return "%s %s" % (str(bus).capitalize(), str(typ).capitalize())
@staticmethod
def interface_recommended_models(guest):
if not guest.os.is_hvm():
return []
ret = []
if guest.type in ["kvm", "qemu", "vz", "test"]:
ret.append("virtio")
if guest.os.is_x86():
if guest.os.is_q35():
ret.append("e1000e")
else:
ret.append("rtl8139")
ret.append("e1000")
if guest.type in ["xen", "test"]:
ret.append("netfront")
ret.sort()
return ret
@staticmethod
def redirdev_pretty_type(typ):
if typ == "tcp":
return "TCP"
if typ == "spicevmc":
return "SpiceVMC"
return typ and typ.capitalize()
@staticmethod
def video_recommended_models(guest):
if guest.conn.is_xen():
return ["xen", "vga"]
if guest.conn.is_qemu() or guest.conn.is_test():
return ["vga", "qxl", "virtio"]
return []
@staticmethod
def video_pretty_model(model):
if model in ["qxl", "vmvga", "vga"]:
return model.upper()
return model.capitalize()
@staticmethod
def hostdev_pretty_name(hostdev):
def dehex(val):
if val.startswith("0x"):
val = val[2:]
return val
def safeint(val, fmt="%.3d"):
try:
int(val)
except Exception:
return str(val)
return fmt % int(val)
label = hostdev.type.upper()
if hostdev.vendor and hostdev.product:
label += " %s:%s" % (dehex(hostdev.vendor), dehex(hostdev.product))
elif hostdev.bus and hostdev.device:
label += " %s:%s" % (safeint(hostdev.bus), safeint(hostdev.device))
elif (hostdev.bus and hostdev.slot and
hostdev.function and hostdev.domain):
label += (" %s:%s:%s.%s" %
(dehex(hostdev.domain), dehex(hostdev.bus),
dehex(hostdev.slot), dehex(hostdev.function)))
return label
######################### #########################
# UI init/reset helpers # # UI init/reset helpers #
@ -467,11 +756,11 @@ class vmmAddHardware(vmmGObjectUI):
@staticmethod @staticmethod
def populate_disk_bus_combo(vm, devtype, model): def populate_disk_bus_combo(vm, devtype, model):
domcaps = vm.get_domain_capabilities() domcaps = vm.get_domain_capabilities()
buses = DeviceDisk.get_recommended_buses(vm.xmlobj, domcaps, devtype) buses = vmmAddHardware.disk_recommended_buses(vm.xmlobj, domcaps, devtype)
model.clear() model.clear()
for bus in buses: for bus in buses:
model.append([bus, DeviceDisk.pretty_disk_bus(bus)]) model.append([bus, vmmAddHardware.disk_pretty_bus(bus)])
@staticmethod @staticmethod
@ -481,7 +770,7 @@ class vmmAddHardware(vmmGObjectUI):
# [xml value, label] # [xml value, label]
model.append([None, _("Hypervisor default")]) model.append([None, _("Hypervisor default")])
for netmodel in DeviceInterface.get_models(vm.xmlobj): for netmodel in vmmAddHardware.interface_recommended_models(vm.xmlobj):
model.append([netmodel, netmodel]) model.append([netmodel, netmodel])
uiutil.set_list_selection( uiutil.set_list_selection(
@ -502,15 +791,16 @@ class vmmAddHardware(vmmGObjectUI):
(DeviceInput.TYPE_TABLET, DeviceInput.BUS_VIRTIO), (DeviceInput.TYPE_TABLET, DeviceInput.BUS_VIRTIO),
] ]
cvals = [((t, b), DeviceInput.pretty_name(t, b)) for t, b in devices] cvals = [((t, b), vmmAddHardware.input_pretty_name(t, b))
for t, b in devices]
_build_combo(self.widget("input-type"), cvals) _build_combo(self.widget("input-type"), cvals)
@staticmethod @staticmethod
def build_sound_combo(vm, combo): def build_sound_combo(vm, combo):
values = [] values = []
for m in DeviceSound.get_recommended_models(vm.xmlobj): for m in vmmAddHardware.sound_recommended_models(vm.xmlobj):
values.append([m, DeviceSound.pretty_model(m)]) values.append([m, vmmAddHardware.sound_pretty_model(m)])
default = DeviceSound.default_model(vm.xmlobj) default = DeviceSound.default_model(vm.xmlobj)
_build_combo(combo, values, default_value=default) _build_combo(combo, values, default_value=default)
@ -540,12 +830,12 @@ class vmmAddHardware(vmmGObjectUI):
continue continue
if dev.xmlobj.is_pci_bridge(): if dev.xmlobj.is_pci_bridge():
continue continue
prettyname = dev.xmlobj.pretty_name() prettyname = dev.pretty_name()
if devtype == "pci": if devtype == "pci":
for subdev in netdevs: for subdev in netdevs:
if dev.xmlobj.name == subdev.xmlobj.parent: if dev.xmlobj.name == subdev.xmlobj.parent:
prettyname += " (%s)" % subdev.xmlobj.pretty_name() prettyname += " (%s)" % subdev.pretty_name()
model.append([dev.xmlobj, prettyname]) model.append([dev.xmlobj, prettyname])
@ -557,8 +847,8 @@ class vmmAddHardware(vmmGObjectUI):
@staticmethod @staticmethod
def build_video_combo(vm, combo): def build_video_combo(vm, combo):
values = [] values = []
for m in DeviceVideo.get_recommended_models(vm.xmlobj): for m in vmmAddHardware.video_recommended_models(vm.xmlobj):
values.append([m, DeviceVideo.pretty_model(m)]) values.append([m, vmmAddHardware.video_pretty_model(m)])
if not values: if not values:
values.append([None, _("Hypervisor default")]) values.append([None, _("Hypervisor default")])
default = DeviceVideo.default_model(vm.xmlobj) default = DeviceVideo.default_model(vm.xmlobj)
@ -584,8 +874,8 @@ class vmmAddHardware(vmmGObjectUI):
model = self.widget("char-device-type").get_model() model = self.widget("char-device-type").get_model()
model.clear() model.clear()
for t in char_class.get_recommended_types(self.vm.xmlobj): for t in vmmAddHardware.char_recommended_types(char_class):
model.append([t, char_class.pretty_type(t) + " (%s)" % t]) model.append([t, vmmAddHardware.char_pretty_type(t) + " (%s)" % t])
uiutil.set_list_selection(self.widget("char-device-type"), "pty") uiutil.set_list_selection(self.widget("char-device-type"), "pty")
@ -600,7 +890,7 @@ class vmmAddHardware(vmmGObjectUI):
def build_watchdogaction_combo(_vm, combo): def build_watchdogaction_combo(_vm, combo):
values = [] values = []
for m in DeviceWatchdog.ACTIONS: for m in DeviceWatchdog.ACTIONS:
values.append([m, DeviceWatchdog.get_action_desc(m)]) values.append([m, vmmAddHardware.watchdog_pretty_action(m)])
_build_combo(combo, values, default_value=DeviceWatchdog.ACTION_RESET) _build_combo(combo, values, default_value=DeviceWatchdog.ACTION_RESET)
@ -621,11 +911,11 @@ class vmmAddHardware(vmmGObjectUI):
def _build_tpm_type_combo(self): def _build_tpm_type_combo(self):
values = [] values = []
for t in DeviceTpm.TYPES: for t in DeviceTpm.TYPES:
values.append([t, DeviceTpm.get_pretty_type(t)]) values.append([t, vmmAddHardware.tpm_pretty_type(t)])
_build_combo(self.widget("tpm-type"), values) _build_combo(self.widget("tpm-type"), values)
values = [] values = []
for t in DeviceTpm.MODELS: for t in DeviceTpm.MODELS:
values.append([t, DeviceTpm.get_pretty_model(t)]) values.append([t, vmmAddHardware.tpm_pretty_model(t)])
_build_combo(self.widget("tpm-model"), values) _build_combo(self.widget("tpm-model"), values)
values = [] values = []
for t in DeviceTpm.VERSIONS: for t in DeviceTpm.VERSIONS:
@ -650,7 +940,7 @@ class vmmAddHardware(vmmGObjectUI):
mod_list = vmmAddHardware._get_tpm_model_list(vm, tpmversion) mod_list = vmmAddHardware._get_tpm_model_list(vm, tpmversion)
for m in mod_list: for m in mod_list:
model.append([m, DeviceTpm.get_pretty_model(m)]) model.append([m, vmmAddHardware.tpm_pretty_model(m)])
combo.set_active(0) combo.set_active(0)
@staticmethod @staticmethod
@ -661,8 +951,8 @@ class vmmAddHardware(vmmGObjectUI):
def _build_panic_model_combo(self): def _build_panic_model_combo(self):
values = [] values = []
for m in DevicePanic.get_models(self.vm.get_xmlobj().os): for m in DevicePanic.get_models(self.vm.get_xmlobj()):
values.append([m, DevicePanic.get_pretty_model(m)]) values.append([m, vmmAddHardware.panic_pretty_model(m)])
default = DevicePanic.get_default_model(self.vm.get_xmlobj()) default = DevicePanic.get_default_model(self.vm.get_xmlobj())
_build_combo(self.widget("panic-model"), values, default_value=default) _build_combo(self.widget("panic-model"), values, default_value=default)
@ -670,8 +960,8 @@ class vmmAddHardware(vmmGObjectUI):
def _build_controller_type_combo(self): def _build_controller_type_combo(self):
values = [] values = []
for t in DeviceController.get_recommended_types(self.vm.xmlobj): for t in vmmAddHardware.controller_recommended_types():
values.append([t, DeviceController.pretty_type(t)]) values.append([t, vmmAddHardware.controller_pretty_type(t)])
_build_combo(self.widget("controller-type"), values, _build_combo(self.widget("controller-type"), values,
default_value=DeviceController.TYPE_SCSI) default_value=DeviceController.TYPE_SCSI)

View File

@ -11,6 +11,9 @@ from gi.repository import Gtk
from gi.repository import Gdk from gi.repository import Gdk
from gi.repository import Pango from gi.repository import Pango
import libvirt
from virtinst import generatename
from virtinst import Network from virtinst import Network
from . import uiutil from . import uiutil
@ -110,8 +113,9 @@ class vmmCreateNetwork(vmmGObjectUI):
mode_model.append(["hostdev", _("SR-IOV pool")]) mode_model.append(["hostdev", _("SR-IOV pool")])
def reset_state(self): def reset_state(self):
default_name = Network.find_free_name( basename = "network"
self.conn.get_backend(), "network") default_name = generatename.generate_name(
basename, self.conn.get_backend().networkLookupByName)
self.widget("net-name").set_text(default_name) self.widget("net-name").set_text(default_name)
self.widget("net-dns-use-netname").set_active(True) self.widget("net-dns-use-netname").set_active(True)
@ -161,7 +165,7 @@ class vmmCreateNetwork(vmmGObjectUI):
for pcidev in self.conn.filter_nodedevs("pci"): for pcidev in self.conn.filter_nodedevs("pci"):
if not pcidev.xmlobj.is_pci_sriov(): if not pcidev.xmlobj.is_pci_sriov():
continue continue
devdesc = pcidev.xmlobj.pretty_name() devdesc = pcidev.pretty_name()
for netdev in self.conn.filter_nodedevs("net"): for netdev in self.conn.filter_nodedevs("net"):
if pcidev.xmlobj.name != netdev.xmlobj.parent: if pcidev.xmlobj.name != netdev.xmlobj.parent:
continue continue
@ -353,6 +357,15 @@ class vmmCreateNetwork(vmmGObjectUI):
# XML build and install # # XML build and install #
######################### #########################
def _validate(self, net):
net.validate_generic_name(_("Network"), net.name)
try:
net.conn.networkLookupByName(net.name)
except libvirt.libvirtError:
return
raise ValueError(_("Name '%s' already in use by another network." %
net.name))
def _build_xmlobj(self): def _build_xmlobj(self):
net = Network(self.conn.get_backend()) net = Network(self.conn.get_backend())
@ -418,12 +431,22 @@ class vmmCreateNetwork(vmmGObjectUI):
def _async_net_create(self, asyncjob, net): def _async_net_create(self, asyncjob, net):
ignore = asyncjob ignore = asyncjob
net.install() xml = net.get_xml()
logging.debug("Creating virtual network '%s' with xml:\n%s",
net.name, xml)
netobj = self.conn.get_backend().networkDefineXML(xml)
try:
netobj.create()
netobj.setAutostart(True)
except Exception:
netobj.undefine()
raise
def finish(self, ignore): def finish(self, ignore):
try: try:
net = self._build_xmlobj() net = self._build_xmlobj()
net.validate() self._validate(net)
except Exception as e: except Exception as e:
self.err.show_err(_("Error generating network xml: %s") % str(e)) self.err.show_err(_("Error generating network xml: %s") % str(e))
return return

View File

@ -173,7 +173,7 @@ def _label_for_device(dev):
devtype = dev.DEVICE_TYPE devtype = dev.DEVICE_TYPE
if devtype == "disk": if devtype == "disk":
busstr = virtinst.DeviceDisk.pretty_disk_bus(dev.bus) or "" busstr = vmmAddHardware.disk_pretty_bus(dev.bus) or ""
if dev.device == "floppy": if dev.device == "floppy":
devstr = _("Floppy") devstr = _("Floppy")
@ -220,28 +220,30 @@ def _label_for_device(dev):
if devtype == "channel": if devtype == "channel":
label = _("Channel") label = _("Channel")
name = dev.pretty_channel_name(dev.target_name) name = vmmAddHardware.char_pretty_channel_name(dev.target_name)
if not name: if not name:
name = dev.pretty_type(dev.type) name = vmmAddHardware.char_pretty_type(dev.type)
if name: if name:
label += " %s" % name label += " %s" % name
return label return label
if devtype == "graphics": if devtype == "graphics":
return _("Display %s") % dev.pretty_type_simple(dev.type) pretty = vmmGraphicsDetails.graphics_pretty_type_simple(dev.type)
return _("Display %s") % pretty
if devtype == "redirdev": if devtype == "redirdev":
return _("%s Redirector %s") % (dev.bus.upper(), return _("%s Redirector %s") % (dev.bus.upper(),
dev.get_xml_idx() + 1) dev.get_xml_idx() + 1)
if devtype == "hostdev": if devtype == "hostdev":
return dev.pretty_name() return vmmAddHardware.hostdev_pretty_name(dev)
if devtype == "sound": if devtype == "sound":
return _("Sound %s") % dev.model return _("Sound %s") % dev.model
if devtype == "video": if devtype == "video":
return _("Video %s") % dev.pretty_model(dev.model) return _("Video %s") % vmmAddHardware.video_pretty_model(dev.model)
if devtype == "filesystem": if devtype == "filesystem":
return _("Filesystem %s") % dev.target[:8] return _("Filesystem %s") % dev.target[:8]
if devtype == "controller": if devtype == "controller":
return _("Controller %s %s") % (dev.pretty_desc(), dev.index) return _("Controller %s %s") % (
vmmAddHardware.controller_pretty_desc(dev), dev.index)
if devtype == "rng": if devtype == "rng":
label = _("RNG") label = _("RNG")
if dev.device: if dev.device:
@ -2269,7 +2271,7 @@ class vmmDetails(vmmGObjectUI):
self.netlist.set_dev(net) self.netlist.set_dev(net)
def refresh_input_page(self, inp): def refresh_input_page(self, inp):
dev = inp.pretty_name(inp.type, inp.bus) dev = vmmAddHardware.input_pretty_name(inp.type, inp.bus)
mode = None mode = None
if inp.type == "tablet": if inp.type == "tablet":
@ -2302,7 +2304,8 @@ class vmmDetails(vmmGObjectUI):
address = _("%s:%s") % (rd.source.host, rd.source.service) address = _("%s:%s") % (rd.source.host, rd.source.service)
self.widget("redir-title").set_markup(_label_for_device(rd)) self.widget("redir-title").set_markup(_label_for_device(rd))
self.widget("redir-type").set_text(rd.pretty_type(rd.type)) self.widget("redir-type").set_text(
vmmAddHardware.redirdev_pretty_type(rd.type))
self.widget("redir-address").set_text(address or "") self.widget("redir-address").set_text(address or "")
uiutil.set_grid_row_visible( uiutil.set_grid_row_visible(
@ -2316,7 +2319,7 @@ class vmmDetails(vmmGObjectUI):
dev_type = tpmdev.type dev_type = tpmdev.type
self.widget("tpm-dev-type").set_text( self.widget("tpm-dev-type").set_text(
virtinst.DeviceTpm.get_pretty_type(dev_type)) vmmAddHardware.tpm_pretty_type(dev_type))
vmmAddHardware.populate_tpm_model_combo( vmmAddHardware.populate_tpm_model_combo(
self.vm, self.widget("tpm-model"), tpmdev.version) self.vm, self.widget("tpm-model"), tpmdev.version)
@ -2328,7 +2331,7 @@ class vmmDetails(vmmGObjectUI):
def refresh_panic_page(self, dev): def refresh_panic_page(self, dev):
model = dev.model or "isa" model = dev.model or "isa"
pmodel = virtinst.DevicePanic.get_pretty_model(model) pmodel = vmmAddHardware.panic_pretty_model(model)
self.widget("panic-model").set_text(pmodel) self.widget("panic-model").set_text(pmodel)
def refresh_rng_page(self, dev): def refresh_rng_page(self, dev):
@ -2336,7 +2339,7 @@ class vmmDetails(vmmGObjectUI):
uiutil.set_grid_row_visible(self.widget("rng-device"), is_random) uiutil.set_grid_row_visible(self.widget("rng-device"), is_random)
self.widget("rng-type").set_text( self.widget("rng-type").set_text(
dev.get_pretty_type(dev.backend_model)) vmmAddHardware.rng_pretty_type(dev.backend_model))
self.widget("rng-device").set_text(dev.device or "") self.widget("rng-device").set_text(dev.device or "")
def refresh_vsock_page(self, dev): def refresh_vsock_page(self, dev):
@ -2413,13 +2416,13 @@ class vmmDetails(vmmGObjectUI):
nodedev = None nodedev = None
for trydev in self.vm.conn.filter_nodedevs(devtype): for trydev in self.vm.conn.filter_nodedevs(devtype):
if trydev.xmlobj.compare_to_hostdev(hostdev): if trydev.xmlobj.compare_to_hostdev(hostdev):
nodedev = trydev.xmlobj nodedev = trydev
pretty_name = None pretty_name = None
if nodedev: if nodedev:
pretty_name = nodedev.pretty_name() pretty_name = nodedev.pretty_name()
if not pretty_name: if not pretty_name:
pretty_name = hostdev.pretty_name() pretty_name = vmmAddHardware.hostdev_pretty_name(hostdev)
uiutil.set_grid_row_visible( uiutil.set_grid_row_visible(
self.widget("hostdev-rombar"), hostdev.type == "pci") self.widget("hostdev-rombar"), hostdev.type == "pci")
@ -2499,7 +2502,7 @@ class vmmDetails(vmmGObjectUI):
_("Cannot remove controller while devices are attached.")) _("Cannot remove controller while devices are attached."))
break break
type_label = controller.pretty_desc() type_label = vmmAddHardware.controller_pretty_desc(controller)
self.widget("controller-type").set_text(type_label) self.widget("controller-type").set_text(type_label)
combo = self.widget("controller-model") combo = self.widget("controller-model")

View File

@ -131,11 +131,28 @@ class vmmDomainSnapshot(vmmLibvirtObject):
ignore = force ignore = force
self._backend.delete() self._backend.delete()
def _state_str_to_int(self):
state = self.get_xmlobj().state
statemap = {
"nostate": libvirt.VIR_DOMAIN_NOSTATE,
"running": libvirt.VIR_DOMAIN_RUNNING,
"blocked": libvirt.VIR_DOMAIN_BLOCKED,
"paused": libvirt.VIR_DOMAIN_PAUSED,
"shutdown": libvirt.VIR_DOMAIN_SHUTDOWN,
"shutoff": libvirt.VIR_DOMAIN_SHUTOFF,
"crashed": libvirt.VIR_DOMAIN_CRASHED,
"pmsuspended": getattr(libvirt, "VIR_DOMAIN_PMSUSPENDED", 7)
}
if state == "disk-snapshot" or state not in statemap:
state = "shutoff"
return statemap.get(state, libvirt.VIR_DOMAIN_NOSTATE)
def run_status(self): def run_status(self):
status = DomainSnapshot.state_str_to_int(self.get_xmlobj().state) status = self._state_str_to_int()
return LibvirtEnumMap.pretty_run_status(status, False) return LibvirtEnumMap.pretty_run_status(status, False)
def run_status_icon_name(self): def run_status_icon_name(self):
status = DomainSnapshot.state_str_to_int(self.get_xmlobj().state) status = self._state_str_to_int()
if status not in LibvirtEnumMap.VM_STATUS_ICONS: if status not in LibvirtEnumMap.VM_STATUS_ICONS:
logging.debug("Unknown status %d, using NOSTATE", status) logging.debug("Unknown status %d, using NOSTATE", status)
status = libvirt.VIR_DOMAIN_NOSTATE status = libvirt.VIR_DOMAIN_NOSTATE

View File

@ -55,6 +55,20 @@ class vmmGraphicsDetails(vmmGObjectUI):
self.vm = None self.vm = None
self.conn = None self.conn = None
#####################
# Pretty UI helpers #
#####################
@staticmethod
def graphics_pretty_type_simple(gtype):
if (gtype in [virtinst.DeviceGraphics.TYPE_VNC,
virtinst.DeviceGraphics.TYPE_SDL,
virtinst.DeviceGraphics.TYPE_RDP]):
return str(gtype).upper()
return str(gtype).capitalize()
########################## ##########################
# Initialization methods # # Initialization methods #
########################## ##########################
@ -109,7 +123,7 @@ class vmmGraphicsDetails(vmmGObjectUI):
if not drm.is_drm_render(): if not drm.is_drm_render():
continue continue
rendernode = drm.get_devnode().path rendernode = drm.get_devnode().path
model.append([rendernode, i.xmlobj.pretty_name()]) model.append([rendernode, i.pretty_name()])
def _get_config_graphics_ports(self): def _get_config_graphics_ports(self):
port = uiutil.spin_get_helper(self.widget("graphics-port")) port = uiutil.spin_get_helper(self.widget("graphics-port"))
@ -193,8 +207,8 @@ class vmmGraphicsDetails(vmmGObjectUI):
is_vnc = (gtype == "vnc") is_vnc = (gtype == "vnc")
is_sdl = (gtype == "sdl") is_sdl = (gtype == "sdl")
is_spice = (gtype == "spice") is_spice = (gtype == "spice")
title = (_("%(graphicstype)s Server") % pretty_type = vmmGraphicsDetails.graphics_pretty_type_simple(gtype)
{"graphicstype": gfx.pretty_type_simple(gtype)}) title = (_("%(graphicstype)s Server") % {"graphicstype": pretty_type})
if is_vnc or is_spice: if is_vnc or is_spice:
use_passwd = gfx.passwd is not None use_passwd = gfx.passwd is not None

View File

@ -275,8 +275,15 @@ class vmmHostNets(vmmGObjectUI):
def _populate_qos_state(self, net): def _populate_qos_state(self, net):
qos = net.get_qos() qos = net.get_qos()
self.widget("net-qos-inbound-enable").set_active(qos.is_inbound()) def is_inbound():
self.widget("net-qos-outbound-enable").set_active(qos.is_outbound()) return bool(qos.inbound_average or qos.inbound_peak or
qos.inbound_burst or qos.inbound_floor)
def is_outbound():
return bool(qos.outbound_average or qos.outbound_peak or
qos.outbound_burst)
self.widget("net-qos-inbound-enable").set_active(is_inbound())
self.widget("net-qos-outbound-enable").set_active(is_outbound())
self._update_qos_widgets() self._update_qos_widgets()

View File

@ -125,8 +125,6 @@ class vmmNetwork(vmmLibvirtObject):
return self.get_xmlobj().ipv6 return self.get_xmlobj().ipv6
def get_ipv4_forward_mode(self): def get_ipv4_forward_mode(self):
return self.get_xmlobj().forward.mode return self.get_xmlobj().forward.mode
def pretty_forward_mode(self):
return self.get_xmlobj().forward.pretty_desc()
def get_qos(self): def get_qos(self):
return self.get_xmlobj().bandwidth return self.get_xmlobj().bandwidth
@ -200,3 +198,30 @@ class vmmNetwork(vmmLibvirtObject):
pf_name = xmlobj.forward.pf[0].dev pf_name = xmlobj.forward.pf[0].dev
vfs = xmlobj.forward.vfs vfs = xmlobj.forward.vfs
return (ret, pf_name, vfs) return (ret, pf_name, vfs)
def pretty_forward_mode(self):
mode = self.xmlobj.forward.mode
dev = self.xmlobj.forward.dev
if not mode:
return _("Isolated network")
if mode == "nat":
if dev:
desc = _("NAT to %s") % dev
else:
desc = _("NAT")
elif mode == "route":
if dev:
desc = _("Route to %s") % dev
else:
desc = _("Routed network")
else:
modestr = mode.capitalize()
if dev:
desc = (_("%(mode)s to %(device)s") %
{"mode": modestr, "device": dev})
else:
desc = _("%s network") % modestr
return desc

View File

@ -9,6 +9,64 @@ from virtinst import NodeDevice
from .libvirtobject import vmmLibvirtObject from .libvirtobject import vmmLibvirtObject
def _usb_pretty_name(xmlobj):
# Hypervisor may return a rather sparse structure, missing
# some ol all stringular descriptions of the device altogether.
# Do our best to help user identify the device.
# Certain devices pad their vendor with trailing spaces,
# such as "LENOVO ". It does not look well.
product = str(xmlobj.product_name).strip()
vendor = str(xmlobj.vendor_name).strip()
if product == "":
product = str(xmlobj.product_id)
if vendor == "":
# No stringular descriptions altogether
vendor = str(xmlobj.vendor_id)
devstr = "%s:%s" % (vendor, product)
else:
# Only the vendor is known
devstr = "%s %s" % (vendor, product)
else:
if vendor == "":
# Sometimes vendor is left out empty, but product is
# already descriptive enough or contains the vendor string:
# "Lenovo USB Laser Mouse"
devstr = product
else:
# We know everything. Perfect.
devstr = "%s %s" % (vendor, product)
busstr = "%.3d:%.3d" % (int(xmlobj.bus), int(xmlobj.device))
desc = "%s %s" % (busstr, devstr)
return desc
def _pretty_name(xmlobj):
if xmlobj.device_type == "net":
if xmlobj.interface:
return _("Interface %s") % xmlobj.interface
return xmlobj.name
if xmlobj.device_type == "pci":
devstr = "%.4X:%.2X:%.2X:%X" % (int(xmlobj.domain),
int(xmlobj.bus),
int(xmlobj.slot),
int(xmlobj.function))
return "%s %s %s" % (devstr,
xmlobj.vendor_name, xmlobj.product_name)
if xmlobj.device_type == "usb_device":
return _usb_pretty_name(xmlobj)
if xmlobj.device_type == "drm":
parent = NodeDevice.lookupNodedevFromString(
xmlobj.conn, xmlobj.parent)
return "%s (%s)" % (_pretty_name(parent), xmlobj.drm_type)
return xmlobj.name
class vmmNodeDevice(vmmLibvirtObject): class vmmNodeDevice(vmmLibvirtObject):
def __init__(self, conn, backend, key): def __init__(self, conn, backend, key):
vmmLibvirtObject.__init__(self, conn, backend, key, NodeDevice) vmmLibvirtObject.__init__(self, conn, backend, key, NodeDevice)
@ -34,3 +92,6 @@ class vmmNodeDevice(vmmLibvirtObject):
ignore = stats_update ignore = stats_update
def _init_libvirt_state(self): def _init_libvirt_state(self):
self.ensure_latest_xml() self.ensure_latest_xml()
def pretty_name(self):
return _pretty_name(self.xmlobj)

View File

@ -16,6 +16,7 @@ from gi.repository import Gtk
from gi.repository import Pango from gi.repository import Pango
from virtinst import DomainSnapshot from virtinst import DomainSnapshot
from virtinst import generatename
from virtinst import xmlutil from virtinst import xmlutil
from . import uiutil from . import uiutil
@ -117,8 +118,11 @@ class vmmSnapshotNew(vmmGObjectUI):
def _reset_state(self): def _reset_state(self):
collidelist = [s.get_xmlobj().name for s in self.vm.list_snapshots()] collidelist = [s.get_xmlobj().name for s in self.vm.list_snapshots()]
default_name = DomainSnapshot.find_free_name( basename = "snapshot"
self.vm.get_backend(), collidelist) cb = self.vm.get_backend().snapshotLookupByName
default_name = generatename.generate_name(
basename, cb, sep="", start_num=1, force_num=True,
collidelist=collidelist)
self.widget("snapshot-new-name").set_text(default_name) self.widget("snapshot-new-name").set_text(default_name)
self.widget("snapshot-new-name").emit("changed") self.widget("snapshot-new-name").emit("changed")
@ -210,8 +214,8 @@ class vmmSnapshotNew(vmmGObjectUI):
newsnap = DomainSnapshot(self.vm.conn.get_backend()) newsnap = DomainSnapshot(self.vm.conn.get_backend())
newsnap.name = name newsnap.name = name
newsnap.description = desc or None newsnap.description = desc or None
newsnap.validate()
newsnap.get_xml() newsnap.get_xml()
newsnap.validate_generic_name(_("Snapshot"), newsnap.name)
return newsnap return newsnap
except Exception as e: except Exception as e:
return self.err.val_err(_("Error validating snapshot: %s") % e) return self.err.val_err(_("Error validating snapshot: %s") % e)

View File

@ -90,62 +90,6 @@ class _DeviceChar(Device):
CHANNEL_NAME_LIBGUESTFS, CHANNEL_NAME_LIBGUESTFS,
CHANNEL_NAME_SPICE_WEBDAV] CHANNEL_NAME_SPICE_WEBDAV]
@classmethod
def get_recommended_types(cls, _guest):
if cls.XML_NAME == "console":
return [cls.TYPE_PTY]
ret = [cls.TYPE_PTY, cls.TYPE_FILE, cls.TYPE_UNIX]
if cls.XML_NAME == "channel":
ret = [cls.TYPE_SPICEVMC, cls.TYPE_SPICEPORT] + ret
return ret
@staticmethod
def pretty_channel_name(val):
if val == _DeviceChar.CHANNEL_NAME_SPICE:
return "spice"
if val == _DeviceChar.CHANNEL_NAME_QEMUGA:
return "qemu-ga"
if val == _DeviceChar.CHANNEL_NAME_LIBGUESTFS:
return "libguestfs"
if val == _DeviceChar.CHANNEL_NAME_SPICE_WEBDAV:
return "spice-webdav"
return None
@staticmethod
def pretty_type(ctype):
"""
Return a human readable description of the passed char type
"""
desc = ""
if ctype == _DeviceChar.TYPE_PTY:
desc = _("Pseudo TTY")
elif ctype == _DeviceChar.TYPE_DEV:
desc = _("Physical host character device")
elif ctype == _DeviceChar.TYPE_STDIO:
desc = _("Standard input/output")
elif ctype == _DeviceChar.TYPE_PIPE:
desc = _("Named pipe")
elif ctype == _DeviceChar.TYPE_FILE:
desc = _("Output to a file")
elif ctype == _DeviceChar.TYPE_VC:
desc = _("Virtual console")
elif ctype == _DeviceChar.TYPE_NULL:
desc = _("Null device")
elif ctype == _DeviceChar.TYPE_TCP:
desc = _("TCP net console")
elif ctype == _DeviceChar.TYPE_UDP:
desc = _("UDP net console")
elif ctype == _DeviceChar.TYPE_UNIX:
desc = _("Unix socket")
elif ctype == _DeviceChar.TYPE_SPICEVMC:
desc = _("Spice agent")
elif ctype == _DeviceChar.TYPE_SPICEPORT:
desc = _("Spice port")
return desc
def set_friendly_target(self, val): def set_friendly_target(self, val):
_set_host_helper(self, "target_address", "target_port", val) _set_host_helper(self, "target_address", "target_port", val)

View File

@ -21,31 +21,6 @@ class DeviceController(Device):
TYPE_CCID = "ccid" TYPE_CCID = "ccid"
TYPE_XENBUS = "xenbus" TYPE_XENBUS = "xenbus"
@staticmethod
def get_recommended_types(_guest):
return [DeviceController.TYPE_SCSI,
DeviceController.TYPE_USB,
DeviceController.TYPE_VIRTIOSERIAL,
DeviceController.TYPE_CCID]
@staticmethod
def pretty_type(ctype):
pretty_mappings = {
DeviceController.TYPE_IDE: "IDE",
DeviceController.TYPE_FDC: _("Floppy"),
DeviceController.TYPE_SCSI: "SCSI",
DeviceController.TYPE_SATA: "SATA",
DeviceController.TYPE_VIRTIOSERIAL: "VirtIO Serial",
DeviceController.TYPE_USB: "USB",
DeviceController.TYPE_PCI: "PCI",
DeviceController.TYPE_CCID: "CCID",
DeviceController.TYPE_XENBUS: "xenbus",
}
if ctype not in pretty_mappings:
return ctype
return pretty_mappings[ctype]
@staticmethod @staticmethod
def get_usb2_controllers(conn): def get_usb2_controllers(conn):
ret = [] ret = []
@ -101,17 +76,6 @@ class DeviceController(Device):
index = XMLProperty("./@index", is_int=True) index = XMLProperty("./@index", is_int=True)
def pretty_desc(self):
ret = self.pretty_type(self.type)
if self.type == "scsi":
if self.model == "virtio-scsi":
ret = "Virtio " + ret
elif self.address.type == "spapr-vio":
ret = "sPAPR " + ret
if self.type == "pci" and self.model == "pcie-root":
ret = "PCIe"
return ret
################## ##################
# Default config # # Default config #

View File

@ -77,54 +77,6 @@ class DeviceDisk(Device):
IO_MODE_THREADS = "threads" IO_MODE_THREADS = "threads"
IO_MODES = [IO_MODE_NATIVE, IO_MODE_THREADS] IO_MODES = [IO_MODE_NATIVE, IO_MODE_THREADS]
@staticmethod
def get_old_recommended_buses(guest):
ret = []
if guest.os.is_hvm() or guest.conn.is_test():
if not guest.os.is_q35():
ret.append("ide")
ret.append("sata")
ret.append("fdc")
ret.append("scsi")
ret.append("usb")
if guest.type in ["qemu", "kvm", "test"]:
ret.append("sd")
ret.append("virtio")
if "scsi" not in ret:
ret.append("scsi")
if guest.conn.is_xen() or guest.conn.is_test():
ret.append("xen")
return ret
@staticmethod
def get_recommended_buses(guest, domcaps, devtype):
# try to get supported disk bus types from domain capabilities
if "bus" in domcaps.devices.disk.enum_names():
buses = domcaps.devices.disk.get_enum("bus").get_values()
else:
buses = DeviceDisk.get_old_recommended_buses(guest)
bus_map = {
"disk": ["ide", "sata", "scsi", "sd", "usb", "virtio", "xen"],
"floppy": ["fdc"],
"cdrom": ["ide", "sata", "scsi"],
"lun": ["scsi"],
}
return [bus for bus in buses if bus in bus_map.get(devtype, [])]
@staticmethod
def pretty_disk_bus(bus):
if bus in ["ide", "sata", "scsi", "usb", "sd"]:
return bus.upper()
if bus in ["xen"]:
return bus.capitalize()
if bus == "virtio":
return "VirtIO"
return bus
@staticmethod @staticmethod
def path_definitely_exists(conn, path): def path_definitely_exists(conn, path):
""" """

View File

@ -72,15 +72,6 @@ class DeviceGraphics(Device):
return sort_list return sort_list
@staticmethod
def pretty_type_simple(gtype):
if (gtype in [DeviceGraphics.TYPE_VNC,
DeviceGraphics.TYPE_SDL,
DeviceGraphics.TYPE_RDP]):
return str(gtype).upper()
return str(gtype).capitalize()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
Device.__init__(self, *args, **kwargs) Device.__init__(self, *args, **kwargs)

View File

@ -68,34 +68,6 @@ class DeviceHostdev(Device):
else: else:
raise ValueError(_("Unknown node device type %s") % nodedev) raise ValueError(_("Unknown node device type %s") % nodedev)
def pretty_name(self):
def dehex(val):
if val.startswith("0x"):
val = val[2:]
return val
def safeint(val, fmt="%.3d"):
try:
int(val)
except Exception:
return str(val)
return fmt % int(val)
label = self.type.upper()
if self.vendor and self.product:
label += " %s:%s" % (dehex(self.vendor), dehex(self.product))
elif self.bus and self.device:
label += " %s:%s" % (safeint(self.bus), safeint(self.device))
elif self.bus and self.slot and self.function and self.domain:
label += (" %s:%s:%s.%s" %
(dehex(self.domain), dehex(self.bus),
dehex(self.slot), dehex(self.function)))
return label
_XML_PROP_ORDER = ["mode", "type", "managed", "vendor", "product", _XML_PROP_ORDER = ["mode", "type", "managed", "vendor", "product",
"domain", "bus", "slot", "function"] "domain", "bus", "slot", "function"]

View File

@ -20,16 +20,6 @@ class DeviceInput(Device):
BUS_VIRTIO = "virtio" BUS_VIRTIO = "virtio"
BUS_XEN = "xen" BUS_XEN = "xen"
@staticmethod
def pretty_name(typ, bus):
if typ == "tablet" and bus == "usb":
return _("EvTouch USB Graphics Tablet")
if bus in ["usb", "ps2"]:
return _("Generic") + (" %s %s" %
(bus.upper(), str(typ).capitalize()))
return "%s %s" % (str(bus).capitalize(), str(typ).capitalize())
type = XMLProperty("./@type") type = XMLProperty("./@type")
bus = XMLProperty("./@bus") bus = XMLProperty("./@bus")

View File

@ -117,42 +117,6 @@ class DeviceInterface(Device):
TYPE_ETHERNET = "ethernet" TYPE_ETHERNET = "ethernet"
TYPE_DIRECT = "direct" TYPE_DIRECT = "direct"
@staticmethod
def get_models(guest):
if not guest.os.is_hvm():
return []
ret = []
if guest.type in ["kvm", "qemu", "vz", "test"]:
ret.append("virtio")
if guest.os.is_x86():
if guest.os.is_q35():
ret.append("e1000e")
else:
ret.append("rtl8139")
ret.append("e1000")
if guest.type in ["xen", "test"]:
ret.append("netfront")
ret.sort()
return ret
@staticmethod
def get_network_type_desc(net_type):
"""
Return human readable description for passed network type
"""
desc = net_type.capitalize()
if net_type == DeviceInterface.TYPE_BRIDGE:
desc = _("Shared physical device")
elif net_type == DeviceInterface.TYPE_VIRTUAL:
desc = _("Virtual networking")
elif net_type == DeviceInterface.TYPE_USER:
desc = _("Usermode networking")
return desc
@staticmethod @staticmethod
def generate_mac(conn): def generate_mac(conn):
""" """

View File

@ -17,29 +17,6 @@ class DevicePanic(Device):
MODEL_HYPERV = "hyperv" MODEL_HYPERV = "hyperv"
MODEL_S390 = "s390" MODEL_S390 = "s390"
@staticmethod
def get_pretty_model(panic_model):
if panic_model == DevicePanic.MODEL_ISA:
return _("ISA")
elif panic_model == DevicePanic.MODEL_PSERIES:
return _("pSeries")
elif panic_model == DevicePanic.MODEL_HYPERV:
return _("Hyper-V")
elif panic_model == DevicePanic.MODEL_S390:
return _("s390")
return panic_model
@staticmethod
def get_models(os):
if os.is_x86():
return [DevicePanic.MODEL_ISA,
DevicePanic.MODEL_HYPERV]
elif os.is_pseries():
return [DevicePanic.MODEL_PSERIES]
elif os.is_s390x():
return [DevicePanic.MODEL_S390]
return []
model = XMLProperty("./@model") model = XMLProperty("./@model")
@ -47,9 +24,20 @@ class DevicePanic(Device):
# Default config # # Default config #
################## ##################
@staticmethod
def get_models(guest):
if guest.os.is_x86():
return [DevicePanic.MODEL_ISA,
DevicePanic.MODEL_HYPERV]
elif guest.os.is_pseries():
return [DevicePanic.MODEL_PSERIES]
elif guest.os.is_s390x():
return [DevicePanic.MODEL_S390]
return []
@staticmethod @staticmethod
def get_default_model(guest): def get_default_model(guest):
models = DevicePanic.get_models(guest.os) models = DevicePanic.get_models(guest)
if models: if models:
return models[0] return models[0]
return None return None

View File

@ -12,14 +12,6 @@ from ..xmlbuilder import XMLChildProperty, XMLProperty
class DeviceRedirdev(Device): class DeviceRedirdev(Device):
XML_NAME = "redirdev" XML_NAME = "redirdev"
@staticmethod
def pretty_type(typ):
if typ == "tcp":
return "TCP"
if typ == "spicevmc":
return "SpiceVMC"
return typ and typ.capitalize()
_XML_PROP_ORDER = ["bus", "type", "source"] _XML_PROP_ORDER = ["bus", "type", "source"]
bus = XMLProperty("./@bus") bus = XMLProperty("./@bus")

View File

@ -15,24 +15,6 @@ class DeviceRng(Device):
TYPE_RANDOM = "random" TYPE_RANDOM = "random"
TYPE_EGD = "egd" TYPE_EGD = "egd"
@staticmethod
def get_pretty_type(rng_type):
if rng_type == DeviceRng.TYPE_RANDOM:
return _("Random")
if rng_type == DeviceRng.TYPE_EGD:
return _("Entropy Gathering Daemon")
return rng_type
@staticmethod
def get_pretty_backend_type(backend_type):
return {"udp": "UDP",
"tcp": "TCP"}.get(backend_type) or backend_type
@staticmethod
def get_pretty_mode(mode):
return {"bind": _("Bind"),
"connect": _("Connect")}.get(mode) or mode
model = XMLProperty("./@model") model = XMLProperty("./@model")
backend_model = XMLProperty("./backend/@model") backend_model = XMLProperty("./backend/@model")

View File

@ -20,18 +20,6 @@ class _Codec(XMLBuilder):
class DeviceSound(Device): class DeviceSound(Device):
XML_NAME = "sound" XML_NAME = "sound"
@staticmethod
def get_recommended_models(_guest):
return ["ich6", "ich9", "ac97"]
@staticmethod
def pretty_model(model):
ret = model.upper()
if model in ["ich6", "ich9"]:
ret = "HDA (%s)" % model.upper()
return ret
model = XMLProperty("./@model") model = XMLProperty("./@model")
codecs = XMLChildProperty(_Codec) codecs = XMLChildProperty(_Codec)

View File

@ -24,22 +24,6 @@ class DeviceTpm(Device):
MODEL_CRB = "tpm-crb" MODEL_CRB = "tpm-crb"
MODELS = [MODEL_TIS, MODEL_CRB] MODELS = [MODEL_TIS, MODEL_CRB]
@staticmethod
def get_pretty_type(tpm_type):
if tpm_type == DeviceTpm.TYPE_PASSTHROUGH:
return _("Passthrough device")
if tpm_type == DeviceTpm.TYPE_EMULATOR:
return _("Emulated device")
return tpm_type
@staticmethod
def get_pretty_model(tpm_model):
if tpm_model == DeviceTpm.MODEL_TIS:
return _("TIS")
if tpm_model == DeviceTpm.MODEL_CRB:
return _("CRB")
return tpm_model
type = XMLProperty("./backend/@type") type = XMLProperty("./backend/@type")
version = XMLProperty("./backend/@version") version = XMLProperty("./backend/@version")
model = XMLProperty("./@model") model = XMLProperty("./@model")

View File

@ -11,20 +11,6 @@ from ..xmlbuilder import XMLProperty
class DeviceVideo(Device): class DeviceVideo(Device):
XML_NAME = "video" XML_NAME = "video"
@staticmethod
def get_recommended_models(guest):
if guest.conn.is_xen():
return ["xen", "vga"]
if guest.conn.is_qemu() or guest.conn.is_test():
return ["vga", "qxl", "virtio"]
return []
@staticmethod
def pretty_model(model):
if model in ["qxl", "vmvga", "vga"]:
return model.upper()
return model.capitalize()
_XML_PROP_ORDER = ["model", "vram", "heads", "vgamem"] _XML_PROP_ORDER = ["model", "vram", "heads", "vgamem"]
model = XMLProperty("./model/@type") model = XMLProperty("./model/@type")
vram = XMLProperty("./model/@vram", is_int=True) vram = XMLProperty("./model/@vram", is_int=True)

View File

@ -26,22 +26,6 @@ class DeviceWatchdog(Device):
ACTION_POWEROFF, ACTION_PAUSE, ACTION_POWEROFF, ACTION_PAUSE,
ACTION_DUMP, ACTION_NONE] ACTION_DUMP, ACTION_NONE]
@staticmethod
def get_action_desc(action):
if action == DeviceWatchdog.ACTION_RESET:
return _("Forcefully reset the guest")
if action == DeviceWatchdog.ACTION_SHUTDOWN:
return _("Gracefully shutdown the guest")
if action == DeviceWatchdog.ACTION_POWEROFF:
return _("Forcefully power off the guest")
if action == DeviceWatchdog.ACTION_PAUSE:
return _("Pause the guest")
if action == DeviceWatchdog.ACTION_NONE:
return _("No action")
if action == DeviceWatchdog.ACTION_DUMP:
return _("Dump guest memory core")
return action
_XML_PROP_ORDER = ["model", "action"] _XML_PROP_ORDER = ["model", "action"]
model = XMLProperty("./@model") model = XMLProperty("./@model")
action = XMLProperty("./@action") action = XMLProperty("./@action")

View File

@ -7,11 +7,6 @@
Classes for building and installing libvirt <network> XML Classes for building and installing libvirt <network> XML
""" """
import logging
import libvirt
from . import generatename
from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
@ -77,9 +72,6 @@ class _NetworkForward(XMLBuilder):
pf = XMLChildProperty(_NetworkForwardPf) pf = XMLChildProperty(_NetworkForwardPf)
vfs = XMLChildProperty(_NetworkForwardAddress) vfs = XMLChildProperty(_NetworkForwardAddress)
def pretty_desc(self):
return Network.pretty_forward_desc(self.mode, self.dev)
class _NetworkBandwidth(XMLBuilder): class _NetworkBandwidth(XMLBuilder):
XML_NAME = "bandwidth" XML_NAME = "bandwidth"
@ -93,45 +85,6 @@ class _NetworkBandwidth(XMLBuilder):
outbound_peak = XMLProperty("./outbound/@peak") outbound_peak = XMLProperty("./outbound/@peak")
outbound_burst = XMLProperty("./outbound/@burst") outbound_burst = XMLProperty("./outbound/@burst")
def is_inbound(self):
return bool(self.inbound_average or self.inbound_peak or
self.inbound_burst or self.inbound_floor)
def is_outbound(self):
return bool(self.outbound_average or self.outbound_peak or
self.outbound_burst)
def pretty_desc(self, inbound=True, outbound=True):
items_in = [(self.inbound_average, _("Average"), "KiB/s"),
(self.inbound_peak, _("Peak"), "KiB"),
(self.inbound_burst, _("Burst"), "KiB/s"),
(self.inbound_floor, _("Floor"), "KiB/s")]
items_out = [(self.outbound_average, _("Average"), "KiB/s"),
(self.outbound_peak, _("Peak"), "KiB"),
(self.outbound_burst, _("Burst"), "KiB/s")]
def stringify_items(items):
return ", ".join(["%s: %s %s" % (desc, val, unit)
for val, desc, unit in items if val])
ret = ""
show_name = inbound and outbound
if inbound:
if show_name:
ret += _("Inbound: ")
ret += stringify_items(items_in)
if outbound:
if ret:
ret += "\n"
if show_name:
ret += _("Outbound: ")
ret += stringify_items(items_out)
return ret
class _NetworkPortgroup(XMLBuilder): class _NetworkPortgroup(XMLBuilder):
XML_NAME = "portgroup" XML_NAME = "portgroup"
@ -144,70 +97,6 @@ class Network(XMLBuilder):
""" """
Top level class for <network> object XML Top level class for <network> object XML
""" """
@staticmethod
def find_free_name(conn, basename, **kwargs):
cb = conn.networkLookupByName
return generatename.generate_name(basename, cb, **kwargs)
@staticmethod
def pretty_forward_desc(mode, dev):
if not mode:
return _("Isolated network")
if mode == "nat":
if dev:
desc = _("NAT to %s") % dev
else:
desc = _("NAT")
elif mode == "route":
if dev:
desc = _("Route to %s") % dev
else:
desc = _("Routed network")
else:
modestr = mode.capitalize()
if dev:
desc = (_("%(mode)s to %(device)s") %
{"mode": modestr, "device": dev})
else:
desc = _("%s network") % modestr
return desc
###################
# Helper routines #
###################
def can_pxe(self):
forward = self.forward.mode
if forward and forward != "nat":
return True
for ip in self.ips:
if ip.bootp_file:
return True
return False
######################
# Validation helpers #
######################
@staticmethod
def validate_name(conn, name):
XMLBuilder.validate_generic_name(_("Network"), name)
try:
conn.networkLookupByName(name)
except libvirt.libvirtError:
return
raise ValueError(_("Name '%s' already in use by another network." %
name))
##################
# XML properties #
##################
XML_NAME = "network" XML_NAME = "network"
_XML_PROP_ORDER = ["ipv6", "name", "uuid", "forward", "virtualport_type", _XML_PROP_ORDER = ["ipv6", "name", "uuid", "forward", "virtualport_type",
"bridge", "stp", "delay", "domain_name", "bridge", "stp", "delay", "domain_name",
@ -235,23 +124,15 @@ class Network(XMLBuilder):
bandwidth = XMLChildProperty(_NetworkBandwidth, is_single=True) bandwidth = XMLChildProperty(_NetworkBandwidth, is_single=True)
################## ###################
# build routines # # Helper routines #
################## ###################
def install(self, start=True, autostart=True): def can_pxe(self):
xml = self.get_xml() forward = self.forward.mode
logging.debug("Creating virtual network '%s' with xml:\n%s", if forward and forward != "nat":
self.name, xml) return True
for ip in self.ips:
net = self.conn.networkDefineXML(xml) if ip.bootp_file:
try: return True
if start: return False
net.create()
if autostart:
net.setAutostart(autostart)
except Exception:
net.undefine()
raise
return net

View File

@ -106,68 +106,6 @@ class NodeDevice(XMLBuilder):
return False return False
def _usb_pretty_name(self):
# Hypervisor may return a rather sparse structure, missing
# some ol all stringular descriptions of the device altogether.
# Do our best to help user identify the device.
# Certain devices pad their vendor with trailing spaces,
# such as "LENOVO ". It does not look well.
product = str(self._product_name).strip()
vendor = str(self._vendor_name).strip()
if product == "":
product = str(self.product_id)
if vendor == "":
# No stringular descriptions altogether
vendor = str(self.vendor_id)
devstr = "%s:%s" % (vendor, product)
else:
# Only the vendor is known
devstr = "%s %s" % (vendor, product)
else:
if vendor == "":
# Sometimes vendor is left out empty, but product is
# already descriptive enough or contains the vendor string:
# "Lenovo USB Laser Mouse"
devstr = product
else:
# We know everything. Perfect.
devstr = "%s %s" % (vendor, product)
busstr = "%.3d:%.3d" % (int(self.bus), int(self.device))
desc = "%s %s" % (busstr, devstr)
return desc
def pretty_name(self):
"""
Use device information to attempt to print a human readable device
name.
:returns: Device description string
"""
if self.device_type == "net":
if self.interface:
return _("Interface %s") % self.interface
return self.name
if self.device_type == "pci":
devstr = "%.4X:%.2X:%.2X:%X" % (int(self.domain),
int(self.bus),
int(self.slot),
int(self.function))
return "%s %s %s" % (devstr,
self._vendor_name, self._product_name)
if self.device_type == "usb_device":
return self._usb_pretty_name()
if self.device_type == "drm":
parent = NodeDevice.lookupNodedevFromString(
self.conn, self.parent)
return "%s (%s)" % (parent.pretty_name(), self._drm_type)
return self.name
######################## ########################
# XML helper functions # # XML helper functions #
@ -183,7 +121,7 @@ class NodeDevice(XMLBuilder):
self.product_id in ["0x0001", "0x0002", "0x0003"]) self.product_id in ["0x0001", "0x0002", "0x0003"])
def is_drm_render(self): def is_drm_render(self):
return self.device_type == "drm" and self._drm_type == "render" return self.device_type == "drm" and self.drm_type == "render"
################## ##################
@ -198,8 +136,8 @@ class NodeDevice(XMLBuilder):
bus = XMLProperty("./capability/bus") bus = XMLProperty("./capability/bus")
slot = XMLProperty("./capability/slot") slot = XMLProperty("./capability/slot")
function = XMLProperty("./capability/function") function = XMLProperty("./capability/function")
_product_name = XMLProperty("./capability/product") product_name = XMLProperty("./capability/product")
_vendor_name = XMLProperty("./capability/vendor") vendor_name = XMLProperty("./capability/vendor")
_capability_type = XMLProperty("./capability/capability/@type") _capability_type = XMLProperty("./capability/capability/@type")
# type='usb' options # type='usb' options
@ -223,7 +161,7 @@ class NodeDevice(XMLBuilder):
is_int=True) is_int=True)
# type='drm' options # type='drm' options
_drm_type = XMLProperty("./capability/type") drm_type = XMLProperty("./capability/type")
devnodes = XMLChildProperty(DevNode) devnodes = XMLChildProperty(DevNode)
def get_devnode(self, parent="by-path"): def get_devnode(self, parent="by-path"):

View File

@ -4,9 +4,6 @@
# This work is licensed under the GNU GPLv2 or later. # This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
import libvirt
from . import generatename
from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
@ -17,30 +14,6 @@ class _SnapshotDisk(XMLBuilder):
class DomainSnapshot(XMLBuilder): class DomainSnapshot(XMLBuilder):
@staticmethod
def find_free_name(vm, collidelist):
return generatename.generate_name("snapshot", vm.snapshotLookupByName,
sep="", start_num=1, force_num=True,
collidelist=collidelist)
@staticmethod
def state_str_to_int(state):
statemap = {
"nostate": libvirt.VIR_DOMAIN_NOSTATE,
"running": libvirt.VIR_DOMAIN_RUNNING,
"blocked": libvirt.VIR_DOMAIN_BLOCKED,
"paused": libvirt.VIR_DOMAIN_PAUSED,
"shutdown": libvirt.VIR_DOMAIN_SHUTDOWN,
"shutoff": libvirt.VIR_DOMAIN_SHUTOFF,
"crashed": libvirt.VIR_DOMAIN_CRASHED,
"pmsuspended": getattr(libvirt, "VIR_DOMAIN_PMSUSPENDED", 7)
}
if state == "disk-snapshot" or state not in statemap:
state = "shutoff"
return statemap.get(state, libvirt.VIR_DOMAIN_NOSTATE)
XML_NAME = "domainsnapshot" XML_NAME = "domainsnapshot"
_XML_PROP_ORDER = ["name", "description", "creationTime"] _XML_PROP_ORDER = ["name", "description", "creationTime"]
@ -53,12 +26,3 @@ class DomainSnapshot(XMLBuilder):
memory_type = XMLProperty("./memory/@snapshot") memory_type = XMLProperty("./memory/@snapshot")
disks = XMLChildProperty(_SnapshotDisk, relative_xpath="./disks") disks = XMLChildProperty(_SnapshotDisk, relative_xpath="./disks")
##################
# Public helpers #
##################
def validate(self):
if not self.name:
raise RuntimeError(_("A name must be specified."))