mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-25 18:55:27 -06:00
This base connection object will be used to simplify the API in various places, reduce libvirt API calls, and better share code between virtinst and virt-manager. For now it just centralizes connection opening. This also exposed various places where our handling for older libvirt was busted, so raise our minimum host version to 0.6.0, the first version that supports threaded client requests.
285 lines
9.9 KiB
Python
285 lines
9.9 KiB
Python
#
|
|
# Base class for all VM devices
|
|
#
|
|
# Copyright 2008, 2013 Red Hat, Inc.
|
|
# Cole Robinson <crobinso@redhat.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
# MA 02110-1301 USA.
|
|
|
|
from virtinst.XMLBuilderDomain import XMLBuilderDomain, _xml_property
|
|
import logging
|
|
|
|
|
|
class VirtualDevice(XMLBuilderDomain):
|
|
"""
|
|
Base class for all domain xml device objects.
|
|
"""
|
|
|
|
VIRTUAL_DEV_DISK = "disk"
|
|
VIRTUAL_DEV_NET = "interface"
|
|
VIRTUAL_DEV_INPUT = "input"
|
|
VIRTUAL_DEV_GRAPHICS = "graphics"
|
|
VIRTUAL_DEV_AUDIO = "sound"
|
|
VIRTUAL_DEV_HOSTDEV = "hostdev"
|
|
VIRTUAL_DEV_SERIAL = "serial"
|
|
VIRTUAL_DEV_PARALLEL = "parallel"
|
|
VIRTUAL_DEV_CHANNEL = "channel"
|
|
VIRTUAL_DEV_CONSOLE = "console"
|
|
VIRTUAL_DEV_VIDEO = "video"
|
|
VIRTUAL_DEV_CONTROLLER = "controller"
|
|
VIRTUAL_DEV_WATCHDOG = "watchdog"
|
|
VIRTUAL_DEV_FILESYSTEM = "filesystem"
|
|
VIRTUAL_DEV_SMARTCARD = "smartcard"
|
|
VIRTUAL_DEV_REDIRDEV = "redirdev"
|
|
VIRTUAL_DEV_MEMBALLOON = "memballoon"
|
|
VIRTUAL_DEV_TPM = "tpm"
|
|
|
|
# Ordering in this list is important: it will be the order the
|
|
# Guest class outputs XML. So changing this may upset the test suite
|
|
virtual_device_types = [VIRTUAL_DEV_DISK,
|
|
VIRTUAL_DEV_CONTROLLER,
|
|
VIRTUAL_DEV_FILESYSTEM,
|
|
VIRTUAL_DEV_NET,
|
|
VIRTUAL_DEV_INPUT,
|
|
VIRTUAL_DEV_GRAPHICS,
|
|
VIRTUAL_DEV_SERIAL,
|
|
VIRTUAL_DEV_PARALLEL,
|
|
VIRTUAL_DEV_CONSOLE,
|
|
VIRTUAL_DEV_CHANNEL,
|
|
VIRTUAL_DEV_AUDIO,
|
|
VIRTUAL_DEV_VIDEO,
|
|
VIRTUAL_DEV_HOSTDEV,
|
|
VIRTUAL_DEV_WATCHDOG,
|
|
VIRTUAL_DEV_SMARTCARD,
|
|
VIRTUAL_DEV_REDIRDEV,
|
|
VIRTUAL_DEV_MEMBALLOON,
|
|
VIRTUAL_DEV_TPM]
|
|
|
|
# General device type (disk, interface, etc.)
|
|
_virtual_device_type = None
|
|
|
|
def __init__(self, conn=None, parsexml=None, parsexmlnode=None, caps=None):
|
|
"""
|
|
Initialize device state
|
|
|
|
@param conn: libvirt connection to validate device against
|
|
"""
|
|
XMLBuilderDomain.__init__(self, conn, parsexml, parsexmlnode,
|
|
caps=caps)
|
|
|
|
self.alias = VirtualDeviceAlias(conn,
|
|
parsexml=parsexml,
|
|
parsexmlnode=parsexmlnode,
|
|
caps=caps)
|
|
self.address = VirtualDeviceAddress(conn,
|
|
parsexml=parsexml,
|
|
parsexmlnode=parsexmlnode,
|
|
caps=caps)
|
|
|
|
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:
|
|
raise ValueError(_("Unknown virtual device type '%s'.") %
|
|
self._virtual_device_type)
|
|
|
|
|
|
def get_virtual_device_type(self):
|
|
return self._virtual_device_type
|
|
virtual_device_type = property(get_virtual_device_type)
|
|
|
|
def _get_xml_config(self):
|
|
# See XMLBuilderDomain for docs
|
|
raise NotImplementedError()
|
|
|
|
def setup_dev(self, conn=None, meter=None):
|
|
"""
|
|
Perform potentially hazardous device initialization, like
|
|
storage creation or host device reset
|
|
|
|
@param conn: Optional connection to use if necessary. If not
|
|
specified, device's 'conn' will be used
|
|
@param meter: Optional progress meter to use
|
|
"""
|
|
# Will be overwritten by subclasses if necessary.
|
|
ignore = conn
|
|
ignore = meter
|
|
return
|
|
|
|
def set_address(self, addrstr):
|
|
self.address = VirtualDeviceAddress(self.conn, addrstr=addrstr)
|
|
|
|
|
|
class VirtualDeviceAlias(XMLBuilderDomain):
|
|
def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
|
|
XMLBuilderDomain.__init__(self, conn, parsexml, parsexmlnode,
|
|
caps=caps)
|
|
|
|
self._name = None
|
|
|
|
|
|
def _get_name(self):
|
|
return self._name
|
|
def _set_name(self, val):
|
|
self._name = val
|
|
name = _xml_property(_get_name, _set_name, xpath="./alias/@name")
|
|
|
|
def _get_xml_config(self):
|
|
return ""
|
|
|
|
|
|
class VirtualDeviceAddress(XMLBuilderDomain):
|
|
|
|
ADDRESS_TYPE_PCI = "pci"
|
|
ADDRESS_TYPE_DRIVE = "drive"
|
|
ADDRESS_TYPE_VIRTIO_SERIAL = "virtio-serial"
|
|
ADDRESS_TYPE_CCID = "ccid"
|
|
ADDRESS_TYPE_SPAPR_VIO = "spapr-vio"
|
|
|
|
TYPES = [ADDRESS_TYPE_PCI, ADDRESS_TYPE_DRIVE,
|
|
ADDRESS_TYPE_VIRTIO_SERIAL, ADDRESS_TYPE_CCID,
|
|
ADDRESS_TYPE_SPAPR_VIO]
|
|
|
|
def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None,
|
|
addrstr=None):
|
|
XMLBuilderDomain.__init__(self, conn, parsexml, parsexmlnode,
|
|
caps=caps)
|
|
|
|
self._type = None
|
|
|
|
# PCI address:
|
|
# <address type='pci' domain='0x0000' bus='0x00' slot='0x04' \
|
|
# function='0x0'/>
|
|
self._bus = None
|
|
self._domain = None
|
|
self._slot = None
|
|
self._function = None
|
|
|
|
# Drive address:
|
|
# <address type='drive' controller='0' bus='0' unit='0'/>
|
|
self._controller = None
|
|
self._unit = None
|
|
|
|
# VirtioSerial address:
|
|
# <address type='virtio-serial' controller='1' bus='0' port='4'/>
|
|
self._port = None
|
|
|
|
# CCID address:
|
|
# <address type='ccid' controller='0' slot='0'/>
|
|
|
|
if addrstr:
|
|
self.parse_friendly_address(addrstr)
|
|
|
|
def parse_friendly_address(self, addrstr):
|
|
try:
|
|
if addrstr.count(":") in [1, 2] and addrstr.count("."):
|
|
self.type = self.ADDRESS_TYPE_PCI
|
|
addrstr, self.function = addrstr.split(".", 1)
|
|
addrstr, self.slot = addrstr.rsplit(":", 1)
|
|
self.domain = "0"
|
|
if addrstr.count(":"):
|
|
self.domain, self.bus = addrstr.split(":", 1)
|
|
elif addrstr == "spapr-vio":
|
|
self.type = self.ADDRESS_TYPE_SPAPR_VIO
|
|
else:
|
|
raise ValueError(_("Could not determine or unsupported format of '%s'") % addrstr)
|
|
except:
|
|
logging.exception("Error parsing address.")
|
|
return None
|
|
|
|
|
|
def clear(self):
|
|
self._type = None
|
|
self._bus = None
|
|
self._domain = None
|
|
self._slot = None
|
|
self._function = None
|
|
self._controller = None
|
|
self._unit = None
|
|
self._port = None
|
|
|
|
if self._is_parse():
|
|
self._remove_child_xpath("./address")
|
|
|
|
def _get_type(self):
|
|
return self._type
|
|
def _set_type(self, val):
|
|
self._type = val
|
|
type = _xml_property(_get_type, _set_type, xpath="./address/@type")
|
|
|
|
def _get_domain(self):
|
|
return self._domain
|
|
def _set_domain(self, val):
|
|
self._domain = val
|
|
domain = _xml_property(_get_domain, _set_domain, xpath="./address/@domain")
|
|
|
|
def _get_bus(self):
|
|
return self._bus
|
|
def _set_bus(self, val):
|
|
self._bus = val
|
|
bus = _xml_property(_get_bus, _set_bus, xpath="./address/@bus")
|
|
|
|
def _get_slot(self):
|
|
return self._slot
|
|
def _set_slot(self, val):
|
|
self._slot = val
|
|
slot = _xml_property(_get_slot, _set_slot, xpath="./address/@slot")
|
|
|
|
def _get_function(self):
|
|
return self._function
|
|
def _set_function(self, val):
|
|
self._function = val
|
|
function = _xml_property(_get_function, _set_function,
|
|
xpath="./address/@function")
|
|
|
|
def _get_controller(self):
|
|
return self._controller
|
|
def _set_controller(self, val):
|
|
self._controller = val
|
|
controller = _xml_property(_get_controller, _set_controller,
|
|
xpath="./address/@controller")
|
|
|
|
def _get_unit(self):
|
|
return self._unit
|
|
def _set_unit(self, val):
|
|
self._unit = val
|
|
unit = _xml_property(_get_unit, _set_unit, xpath="./address/@unit")
|
|
|
|
def _get_port(self):
|
|
return self._port
|
|
def _set_port(self, val):
|
|
self._port = val
|
|
port = _xml_property(_get_port, _set_port, xpath="./address/@port")
|
|
|
|
def _get_xml_config(self):
|
|
if not self.type:
|
|
return
|
|
|
|
def format_props(*args):
|
|
return "".join([" %s='%s'" % (k, getattr(self, k)) for k in args if getattr(self, k, None) is not None])
|
|
|
|
xml = "<address type='%s'" % self.type
|
|
if self.type == self.ADDRESS_TYPE_PCI:
|
|
xml += format_props("domain", "bus", "slot", "function")
|
|
elif self.type == self.ADDRESS_TYPE_DRIVE:
|
|
xml += format_props("controller", "bus", "unit")
|
|
elif self.type == self.ADDRESS_TYPE_VIRTIO_SERIAL:
|
|
xml += format_props("controller", "bus", "port")
|
|
elif self.type == self.ADDRESS_TYPE_CCID:
|
|
xml += format_props("controller", "slot")
|
|
xml += "/>"
|
|
return xml
|