Factor out a common 'libvirt object' class.

Use simply now for some common XML routines.
This commit is contained in:
Cole Robinson 2010-02-25 19:35:01 -05:00
parent 7f1d543f76
commit b377a740ca
4 changed files with 247 additions and 163 deletions

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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)