Factor out a common 'libvirt object' class.
Use simply now for some common XML routines.
This commit is contained in:
parent
7f1d543f76
commit
b377a740ca
|
@ -125,7 +125,8 @@ class vmmConnection(gobject.GObject):
|
|||
self.storage_capable = None
|
||||
self.interface_capable = None
|
||||
self._nodedev_capable = None
|
||||
self.dom_xml_flags = None
|
||||
|
||||
self._xml_flags = {}
|
||||
|
||||
# Physical network interfaces: name -> virtinst.NodeDevice
|
||||
self.nodedevs = {}
|
||||
|
@ -488,29 +489,67 @@ class vmmConnection(gobject.GObject):
|
|||
self._nodedev_capable = virtinst.NodeDeviceParser.is_nodedev_capable(self.vmm)
|
||||
return self._nodedev_capable
|
||||
|
||||
def set_dom_flags(self, vm):
|
||||
if self.dom_xml_flags != None:
|
||||
# Already set
|
||||
return
|
||||
def _get_flags_helper(self, obj, key, check_func):
|
||||
flags_dict = self._xml_flags.get(key)
|
||||
|
||||
self.dom_xml_flags = []
|
||||
for flags in [libvirt.VIR_DOMAIN_XML_SECURE,
|
||||
libvirt.VIR_DOMAIN_XML_INACTIVE,
|
||||
(libvirt.VIR_DOMAIN_XML_SECURE |
|
||||
libvirt.VIR_DOMAIN_XML_INACTIVE )]:
|
||||
try:
|
||||
vm.XMLDesc(flags)
|
||||
self.dom_xml_flags.append(flags)
|
||||
except libvirt.libvirtError, e:
|
||||
logging.debug("%s does not support flags=%d : %s" %
|
||||
(self.get_uri(), flags, str(e)))
|
||||
if flags_dict == None:
|
||||
# Flags already set
|
||||
inact, act = check_func()
|
||||
flags_dict = {}
|
||||
flags_dict["active"] = act
|
||||
flags_dict["inactive"] = inact
|
||||
|
||||
def has_dom_flags(self, flags):
|
||||
if self.dom_xml_flags == None:
|
||||
return False
|
||||
self._xml_flags[key] = flags_dict
|
||||
|
||||
return bool(self.dom_xml_flags.count(flags))
|
||||
active_flags = flags_dict["active"]
|
||||
inactive_flags = flags_dict["inactive"]
|
||||
|
||||
return (inactive_flags, active_flags)
|
||||
|
||||
def get_dom_flags(self, vm):
|
||||
key = "domain"
|
||||
|
||||
def check_func():
|
||||
act = 0
|
||||
inact = 0
|
||||
|
||||
if virtinst.support.check_domain_support(vm,
|
||||
virtinst.support.SUPPORT_DOMAIN_XML_INACTIVE):
|
||||
inact = libvirt.VIR_DOMAIN_XML_INACTIVE
|
||||
else:
|
||||
logging.debug("Domain XML inactive flag not supported.")
|
||||
|
||||
if virtinst.support.check_domain_support(vm,
|
||||
virtinst.support.SUPPORT_DOMAIN_XML_SECURE):
|
||||
inact |= libvirt.VIR_DOMAIN_XML_SECURE
|
||||
act = libvirt.VIR_DOMAIN_XML_SECURE
|
||||
else:
|
||||
logging.debug("Domain XML secure flag not supported.")
|
||||
|
||||
return inact, act
|
||||
|
||||
return self._get_flags_helper(vm, key, check_func)
|
||||
|
||||
def get_interface_flags(self, iface):
|
||||
key = "interface"
|
||||
|
||||
def check_func():
|
||||
act = 0
|
||||
inact = 0
|
||||
|
||||
if virtinst.support.check_interface_support(iface,
|
||||
virtinst.support.SUPPORT_INTERFACE_XML_INACTIVE):
|
||||
inact = libvirt.VIR_INTERFACE_XML_INACTIVE
|
||||
|
||||
# XXX: We intentionally use 'inactive' XML even for active
|
||||
# interfaces, since active XML doesn't show much info
|
||||
act = inact
|
||||
else:
|
||||
logging.debug("Interface XML inactive flag not supported.")
|
||||
|
||||
return (inact, act)
|
||||
|
||||
return self._get_flags_helper(iface, key, check_func)
|
||||
|
||||
###################################
|
||||
# Connection state getter/setters #
|
||||
|
@ -698,6 +737,8 @@ class vmmConnection(gobject.GObject):
|
|||
|
||||
def define_domain(self, xml):
|
||||
self.vmm.defineXML(xml)
|
||||
def define_interface(self, xml):
|
||||
self.vmm.interfaceDefineXML(xml, 0)
|
||||
|
||||
def restore(self, frm):
|
||||
self.vmm.restore(frm)
|
||||
|
|
|
@ -30,6 +30,8 @@ import virtinst.util as vutil
|
|||
import virtinst.support as support
|
||||
from virtinst import VirtualDevice
|
||||
|
||||
from virtManager.libvirtobject import vmmLibvirtObject
|
||||
|
||||
def safeint(val, fmt="%.3d"):
|
||||
try:
|
||||
int(val)
|
||||
|
@ -54,7 +56,7 @@ def disk_type_to_target_prop(disk_type):
|
|||
return "dir"
|
||||
return "file"
|
||||
|
||||
class vmmDomainBase(gobject.GObject):
|
||||
class vmmDomainBase(vmmLibvirtObject):
|
||||
"""
|
||||
Base class for vmmDomain objects. Provides common set up and methods
|
||||
for domain backends (libvirt virDomain, virtinst Guest)
|
||||
|
@ -66,15 +68,11 @@ class vmmDomainBase(gobject.GObject):
|
|||
"resources-sampled": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE,
|
||||
[]),
|
||||
"config-changed": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE,
|
||||
[]),
|
||||
}
|
||||
|
||||
def __init__(self, config, connection, backend, uuid):
|
||||
self.__gobject_init__()
|
||||
self.config = config
|
||||
self.connection = connection
|
||||
vmmLibvirtObject.__init__(self, config, connection)
|
||||
|
||||
self._backend = backend
|
||||
self.uuid = uuid
|
||||
|
||||
|
@ -97,13 +95,6 @@ class vmmDomainBase(gobject.GObject):
|
|||
def status(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_xml(self):
|
||||
raise NotImplementedError()
|
||||
def refresh_xml(self):
|
||||
raise NotImplementedError()
|
||||
def _get_inactive_xml(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_memory(self):
|
||||
raise NotImplementedError()
|
||||
def get_memory_percentage(self):
|
||||
|
@ -196,9 +187,6 @@ class vmmDomainBase(gobject.GObject):
|
|||
def get_handle(self):
|
||||
return self._backend
|
||||
|
||||
def get_connection(self):
|
||||
return self.connection
|
||||
|
||||
def is_read_only(self):
|
||||
if self.connection.is_read_only():
|
||||
return True
|
||||
|
@ -1170,9 +1158,6 @@ class vmmDomain(vmmDomainBase):
|
|||
"netRxRate" : 10.0,
|
||||
}
|
||||
|
||||
self._xml = None
|
||||
self._is_xml_valid = False
|
||||
|
||||
self._update_status()
|
||||
|
||||
self.config.on_stats_enable_net_poll_changed(self.toggle_sample_network_traffic)
|
||||
|
@ -1186,15 +1171,14 @@ class vmmDomain(vmmDomainBase):
|
|||
|
||||
# Determine available XML flags (older libvirt versions will error
|
||||
# out if passed SECURE_XML, INACTIVE_XML, etc)
|
||||
self._set_dom_flags()
|
||||
(self._inactive_xml_flags,
|
||||
self._active_xml_flags) = self.connection.get_dom_flags(
|
||||
self._backend)
|
||||
|
||||
##########################
|
||||
# Internal virDomain API #
|
||||
##########################
|
||||
|
||||
def _set_dom_flags(self):
|
||||
self.connection.set_dom_flags(self._backend)
|
||||
|
||||
def _define(self, newxml):
|
||||
self.get_connection().define_domain(newxml)
|
||||
|
||||
|
@ -1359,96 +1343,6 @@ class vmmDomain(vmmDomainBase):
|
|||
# XML fetching routines #
|
||||
#########################
|
||||
|
||||
def get_xml(self):
|
||||
"""
|
||||
Get domain xml. If cached xml is invalid, update.
|
||||
"""
|
||||
return self._xml_fetch_helper(refresh_if_necc=True)
|
||||
|
||||
def refresh_xml(self):
|
||||
# Force an xml update. Signal 'config-changed' if domain xml has
|
||||
# changed since last refresh
|
||||
|
||||
flags = libvirt.VIR_DOMAIN_XML_SECURE
|
||||
if not self.connection.has_dom_flags(flags):
|
||||
flags = 0
|
||||
|
||||
origxml = self._xml
|
||||
self._xml = self._XMLDesc(flags)
|
||||
self._is_xml_valid = True
|
||||
|
||||
if origxml != self._xml:
|
||||
# 'tick' to make sure we have the latest time
|
||||
self.tick(time.time())
|
||||
util.safe_idle_add(util.idle_emit, self, "config-changed")
|
||||
|
||||
def _redefine(self, xml_func, *args):
|
||||
"""
|
||||
Helper function for altering a redefining VM xml
|
||||
|
||||
@param xml_func: Function to alter the running XML. Takes the
|
||||
original XML as its first argument.
|
||||
@param args: Extra arguments to pass to xml_func
|
||||
"""
|
||||
origxml = self._get_xml_to_define()
|
||||
# Sanitize origxml to be similar to what we will get back
|
||||
origxml = util.xml_parse_wrapper(origxml, lambda d, c: d.serialize())
|
||||
|
||||
newxml = xml_func(origxml, *args)
|
||||
|
||||
if origxml == newxml:
|
||||
logging.debug("Redefinition request XML was no different,"
|
||||
" redefining anyways")
|
||||
else:
|
||||
diff = "".join(difflib.unified_diff(origxml.splitlines(1),
|
||||
newxml.splitlines(1),
|
||||
fromfile="Original XML",
|
||||
tofile="New XML"))
|
||||
logging.debug("Redefining '%s' with XML diff:\n%s",
|
||||
self.get_name(), diff)
|
||||
|
||||
self._define(newxml)
|
||||
|
||||
# Invalidate cached XML
|
||||
self._invalidate_xml()
|
||||
|
||||
def _get_xml_no_refresh(self):
|
||||
"""
|
||||
Fetch XML, but don't force a refresh. Useful to prevent updating
|
||||
xml in the tick loop when it's not that important (disk/net stats)
|
||||
"""
|
||||
return self._xml_fetch_helper(refresh_if_necc=False)
|
||||
|
||||
def _get_xml_to_define(self):
|
||||
if self.is_active():
|
||||
return self._get_inactive_xml()
|
||||
else:
|
||||
self._invalidate_xml()
|
||||
return self.get_xml()
|
||||
|
||||
def _xml_fetch_helper(self, refresh_if_necc):
|
||||
# Helper to fetch xml with various options
|
||||
if self._xml is None:
|
||||
self.refresh_xml()
|
||||
elif refresh_if_necc and not self._is_xml_valid:
|
||||
self.refresh_xml()
|
||||
|
||||
return self._xml
|
||||
|
||||
def _invalidate_xml(self):
|
||||
# Mark cached xml as invalid
|
||||
self._is_xml_valid = False
|
||||
|
||||
def _get_inactive_xml(self):
|
||||
flags = (libvirt.VIR_DOMAIN_XML_INACTIVE |
|
||||
libvirt.VIR_DOMAIN_XML_SECURE)
|
||||
if not self.connection.has_dom_flags(flags):
|
||||
flags = libvirt.VIR_DOMAIN_XML_INACTIVE
|
||||
|
||||
if not self.connection.has_dom_flags(flags):
|
||||
flags = 0
|
||||
|
||||
return self._XMLDesc(flags)
|
||||
|
||||
|
||||
#############################
|
||||
|
@ -1972,11 +1866,12 @@ class vmmDomainVirtinst(vmmDomainBase):
|
|||
|
||||
def get_xml(self):
|
||||
return self._backend.get_config_xml()
|
||||
def _get_inactive_xml(self):
|
||||
return self.get_xml()
|
||||
|
||||
def refresh_xml(self):
|
||||
# No caching, so no refresh needed
|
||||
return
|
||||
def _get_inactive_xml(self):
|
||||
return self.get_xml()
|
||||
|
||||
def get_autostart(self):
|
||||
return self._backend.autostart
|
||||
|
|
|
@ -21,16 +21,16 @@
|
|||
import gobject
|
||||
|
||||
import virtinst
|
||||
import libvirt
|
||||
from virtinst import Interface
|
||||
|
||||
class vmmInterface(gobject.GObject):
|
||||
from virtManager.libvirtobject import vmmLibvirtObject
|
||||
|
||||
class vmmInterface(vmmLibvirtObject):
|
||||
__gsignals__ = { }
|
||||
|
||||
def __init__(self, config, connection, interface, name, active):
|
||||
self.__gobject_init__()
|
||||
self.config = config
|
||||
self.connection = connection
|
||||
vmmLibvirtObject.__init__(self, config, connection)
|
||||
|
||||
self.interface = interface # Libvirt virInterface object
|
||||
self.name = name # String name
|
||||
self.active = active # bool indicating if it is running
|
||||
|
@ -38,27 +38,26 @@ class vmmInterface(gobject.GObject):
|
|||
self._xml = None # xml cache
|
||||
self._xml_flags = None
|
||||
|
||||
self._check_xml_flags()
|
||||
(self._inactive_xml_flags,
|
||||
self._active_xml_flags) = self.connection.get_interface_flags(
|
||||
self.interface)
|
||||
|
||||
self._update_xml()
|
||||
self.refresh_xml()
|
||||
|
||||
def _check_xml_flags(self):
|
||||
self._xml_flags = 0
|
||||
if virtinst.support.check_interface_support(
|
||||
self.interface,
|
||||
virtinst.support.SUPPORT_INTERFACE_XML_INACTIVE):
|
||||
self._xml_flags = libvirt.VIR_INTERFACE_XML_INACTIVE
|
||||
# Routines from vmmLibvirtObject
|
||||
def _XMLDesc(self, flags):
|
||||
return self.interface.XMLDesc(flags)
|
||||
|
||||
def _define(self, xml):
|
||||
return self.get_connection().interface_define(xml)
|
||||
|
||||
def set_active(self, state):
|
||||
self.active = state
|
||||
self._update_xml()
|
||||
self.refresh_xml()
|
||||
|
||||
def is_active(self):
|
||||
return self.active
|
||||
|
||||
def get_connection(self):
|
||||
return self.connection
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
|
@ -68,23 +67,15 @@ class vmmInterface(gobject.GObject):
|
|||
|
||||
def start(self):
|
||||
self.interface.create(0)
|
||||
self._update_xml()
|
||||
self.refresh_xml()
|
||||
|
||||
def stop(self):
|
||||
self.interface.destroy(0)
|
||||
self._update_xml()
|
||||
self.refresh_xml()
|
||||
|
||||
def delete(self):
|
||||
self.interface.undefine()
|
||||
|
||||
def _update_xml(self):
|
||||
self._xml = self.interface.XMLDesc(self._xml_flags)
|
||||
|
||||
def get_xml(self):
|
||||
if self._xml is None:
|
||||
self._update_xml()
|
||||
return self._xml
|
||||
|
||||
def is_bridge(self):
|
||||
typ = self.get_type()
|
||||
return typ == "bridge"
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
#
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
# Copyright (C) 2010 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.
|
||||
#
|
||||
|
||||
import gobject
|
||||
|
||||
import time
|
||||
import difflib
|
||||
import logging
|
||||
|
||||
from virtManager import util
|
||||
|
||||
class vmmLibvirtObject(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
"config-changed": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE,
|
||||
[]),
|
||||
}
|
||||
|
||||
def __init__(self, config, connection):
|
||||
self.__gobject_init__()
|
||||
self.config = config
|
||||
self.connection = connection
|
||||
|
||||
self._xml = None
|
||||
self._is_xml_valid = False
|
||||
|
||||
# These should be set by the child classes if necessary
|
||||
self._inactive_xml_flags = 0
|
||||
self._active_xml_flags = 0
|
||||
|
||||
def get_connection(self):
|
||||
return self.connection
|
||||
|
||||
#############################################################
|
||||
# Functions that should probably be overridden in sub class #
|
||||
#############################################################
|
||||
|
||||
def _XMLDesc(self, flags):
|
||||
ignore = flags
|
||||
return
|
||||
|
||||
def _define(self, xml):
|
||||
ignore = xml
|
||||
return
|
||||
|
||||
def tick(self, now):
|
||||
ignore = now
|
||||
|
||||
##################
|
||||
# Public XML API #
|
||||
##################
|
||||
|
||||
def get_xml(self):
|
||||
"""
|
||||
Get domain xml. If cached xml is invalid, update.
|
||||
"""
|
||||
return self._xml_fetch_helper(refresh_if_necc=True)
|
||||
|
||||
def refresh_xml(self):
|
||||
# Force an xml update. Signal 'config-changed' if domain xml has
|
||||
# changed since last refresh
|
||||
|
||||
origxml = self._xml
|
||||
self._xml = self._XMLDesc(self._active_xml_flags)
|
||||
self._is_xml_valid = True
|
||||
|
||||
if origxml != self._xml:
|
||||
# 'tick' to make sure we have the latest time
|
||||
self.tick(time.time())
|
||||
util.safe_idle_add(util.idle_emit, self, "config-changed")
|
||||
|
||||
######################################
|
||||
# Internal XML cache/update routines #
|
||||
######################################
|
||||
|
||||
def _get_xml_no_refresh(self):
|
||||
"""
|
||||
Fetch XML, but don't force a refresh. Useful to prevent updating
|
||||
xml in the tick loop when it's not that important (disk/net stats)
|
||||
"""
|
||||
return self._xml_fetch_helper(refresh_if_necc=False)
|
||||
|
||||
def _get_xml_to_define(self):
|
||||
if self.is_active():
|
||||
return self._get_inactive_xml()
|
||||
else:
|
||||
self._invalidate_xml()
|
||||
return self.get_xml()
|
||||
|
||||
def _invalidate_xml(self):
|
||||
# Mark cached xml as invalid
|
||||
self._is_xml_valid = False
|
||||
|
||||
def _xml_fetch_helper(self, refresh_if_necc):
|
||||
# Helper to fetch xml with various options
|
||||
if self._xml is None:
|
||||
self.refresh_xml()
|
||||
elif refresh_if_necc and not self._is_xml_valid:
|
||||
self.refresh_xml()
|
||||
|
||||
return self._xml
|
||||
|
||||
def _get_inactive_xml(self):
|
||||
return self._XMLDesc(self._inactive_xml_flags)
|
||||
|
||||
##########################
|
||||
# Internal API functions #
|
||||
##########################
|
||||
|
||||
def _redefine(self, xml_func, *args):
|
||||
"""
|
||||
Helper function for altering a redefining VM xml
|
||||
|
||||
@param xml_func: Function to alter the running XML. Takes the
|
||||
original XML as its first argument.
|
||||
@param args: Extra arguments to pass to xml_func
|
||||
"""
|
||||
origxml = self._get_xml_to_define()
|
||||
# Sanitize origxml to be similar to what we will get back
|
||||
origxml = util.xml_parse_wrapper(origxml, lambda d, c: d.serialize())
|
||||
|
||||
newxml = xml_func(origxml, *args)
|
||||
|
||||
if origxml == newxml:
|
||||
logging.debug("Redefinition request XML was no different,"
|
||||
" redefining anyways")
|
||||
else:
|
||||
diff = "".join(difflib.unified_diff(origxml.splitlines(1),
|
||||
newxml.splitlines(1),
|
||||
fromfile="Original XML",
|
||||
tofile="New XML"))
|
||||
logging.debug("Redefining '%s' with XML diff:\n%s",
|
||||
self.get_name(), diff)
|
||||
|
||||
self._define(newxml)
|
||||
|
||||
# Invalidate cached XML
|
||||
self._invalidate_xml()
|
||||
|
||||
gobject.type_register(vmmLibvirtObject)
|
Loading…
Reference in New Issue