virt-manager/virtManager/interface.py
Cole Robinson 5e9e444dec connection: Do non-VM polling on demand
The goal here is to reduce the amount of tick() polling that we do by default.
For things like pools, networks, and interfaces, the constant polling is
not very helpful and causes CPU churn and slowness for remote connections.

Switch to a more on demand style. Pages that want new information for
these objects now request a priority tick that only refreshes the info
we want.

This isn't perfect, but neither was the previous solution in the face of
things like XML updates behind our back. The real solution here is libvirt
event support across the board.
2013-07-07 12:17:54 -04:00

250 lines
7.1 KiB
Python

#
# Copyright (C) 2009 Red Hat, Inc.
# Copyright (C) 2009 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 import Interface
from virtManager import util
from virtManager.libvirtobject import vmmLibvirtObject
class vmmInterface(vmmLibvirtObject):
def __init__(self, conn, backend, key):
vmmLibvirtObject.__init__(self, conn, backend, key)
self._name = key
self._active = True
self._xml = None
self._xml_flags = None
(self._inactive_xml_flags,
self._active_xml_flags) = self.conn.get_interface_flags(
self._backend)
self._support_isactive = None
self.tick()
self.refresh_xml()
# Routines from vmmLibvirtObject
def _XMLDesc(self, flags):
return self._backend.XMLDesc(flags)
def _define(self, xml):
return self.conn.define_interface(xml)
def xpath(self, *args, **kwargs):
# Must use this function for ALL XML parsing
ret = util.xpath(self.get_xml(), *args, **kwargs)
if ret:
return ret
if not self.is_active():
return ret
# The running config did not have the info requested
return util.xpath(self.get_xml(inactive=True), *args, **kwargs)
def set_active(self, state):
if state == self._active:
return
self.idle_emit(state and "started" or "stopped")
self._active = state
self.refresh_xml()
def _backend_get_active(self):
ret = True
if self._support_isactive is None:
self._support_isactive = self.conn.check_interface_support(
self._backend,
self.conn.SUPPORT_INTERFACE_ISACTIVE)
if not self._support_isactive:
return True
return bool(self._backend.isActive())
def tick(self):
self.set_active(self._backend_get_active())
def is_active(self):
return self._active
def get_name(self):
return self._name
def get_mac(self):
return self.xpath("/interface/mac/@address")
def _kick_conn(self):
self.conn.schedule_priority_tick(polliface=True)
def start(self):
self._backend.create(0)
self.idle_add(self.refresh_xml)
self._kick_conn()
def stop(self):
self._backend.destroy(0)
self.idle_add(self.refresh_xml)
self._kick_conn()
def delete(self):
self._backend.undefine()
self._kick_conn()
def is_bridge(self):
typ = self.get_type()
return typ == "bridge"
def get_type(self):
return self.xpath("/interface/@type")
def get_pretty_type(self):
itype = self.get_type()
if itype == Interface.Interface.INTERFACE_TYPE_VLAN:
return "VLAN"
elif itype:
return str(itype).capitalize()
else:
return "Interface"
def get_startmode(self):
return self.xpath("/interface/start/@mode") or "none"
def set_startmode(self, newmode):
def set_start_xml(doc, ctx):
node = ctx.xpathEval("/interface/start[1]")
node = (node and node[0] or None)
iface_node = ctx.xpathEval("/interface")[0]
if not node:
node = iface_node.newChild(None, "start", None)
node.setProp("mode", newmode)
return doc.serialize()
self._redefine(util.xml_parse_wrapper, set_start_xml)
def get_slaves(self):
typ = self.get_type()
xpath = "/interface/%s/interface/@name" % typ
def node_func(ctx):
nodes = ctx.xpathEval(xpath)
names = [x.content for x in nodes]
ret = []
for name in names:
type_path = ("/interface/%s/interface[@name='%s']/@type" %
(typ, name))
nodes = ctx.xpathEval(type_path)
ret.append((name, nodes and nodes[0].content or "Unknown"))
return ret
ret = self.xpath(func=node_func)
if not ret:
return []
return ret
def get_slave_names(self):
# Returns a list of names of all enslaved interfaces
return [x[0] for x in self.get_slaves()]
def get_ipv4(self):
base_xpath = "/interface/protocol[@family='ipv4']"
if not self.xpath(base_xpath):
return []
dhcp = bool(self.xpath("count(%s/dhcp)" % base_xpath))
addr = self.xpath(base_xpath + "/ip/@address")
if addr:
prefix = self.xpath(base_xpath + "/ip[@address='%s']/@prefix" %
addr)
if prefix:
addr += "/%s" % prefix
return [dhcp, addr]
def get_ipv6(self):
base_xpath = "/interface/protocol[@family='ipv6']"
if not self.xpath(base_xpath):
return []
dhcp = bool(self.xpath("count(%s/dhcp)" % base_xpath))
autoconf = bool(self.xpath("count(%s/autoconf)" % base_xpath))
def addr_func(ctx):
nodes = ctx.xpathEval(base_xpath + "/ip")
nodes = nodes or []
ret = []
for node in nodes:
addr = node.prop("address")
pref = node.prop("prefix")
if not addr:
continue
if pref:
addr += "/%s" % pref
ret.append(addr)
return ret
ret = self.xpath(func=addr_func)
return [dhcp, autoconf, ret]
def get_protocol_xml(self):
def protocol(ctx):
node = ctx.xpathEval("/interface/protocol")
node = node and node[0] or None
ret = None
if node:
ret = node.serialize()
return ret
ret = self.xpath(func=protocol)
if ret:
ret = " %s\n" % ret
return ret
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._xml_to_redefine()
# 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)
self._redefine_xml(newxml)