2006-06-28 15:50:17 -04:00
|
|
|
#
|
|
|
|
|
# Copyright (C) 2006 Red Hat, Inc.
|
|
|
|
|
# Copyright (C) 2006 Daniel P. Berrange <berrange@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
|
2007-11-20 11:12:20 -05:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
|
# MA 02110-1301 USA.
|
2006-06-28 15:50:17 -04:00
|
|
|
#
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2006-06-14 13:52:46 -04:00
|
|
|
import gobject
|
2006-06-14 10:59:40 -04:00
|
|
|
import libvirt
|
2006-10-25 12:18:06 -04:00
|
|
|
import logging
|
2007-04-10 18:27:37 -04:00
|
|
|
import os, sys
|
2008-02-18 10:01:21 -05:00
|
|
|
import glob
|
2007-04-10 18:27:37 -04:00
|
|
|
import traceback
|
2006-06-14 17:52:49 -04:00
|
|
|
from time import time
|
2006-11-06 10:34:54 -05:00
|
|
|
from socket import gethostbyaddr, gethostname
|
2007-03-30 15:01:41 -04:00
|
|
|
import dbus
|
2007-09-10 20:56:01 -04:00
|
|
|
import threading
|
|
|
|
|
import gtk
|
2008-02-22 11:48:29 -05:00
|
|
|
import virtinst
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2006-06-14 17:52:49 -04:00
|
|
|
from virtManager.domain import vmmDomain
|
2007-03-21 12:28:36 -04:00
|
|
|
from virtManager.network import vmmNetwork
|
2007-03-30 15:01:41 -04:00
|
|
|
from virtManager.netdev import vmmNetDevice
|
2008-08-07 17:37:16 -04:00
|
|
|
from virtManager.storagepool import vmmStoragePool
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2007-08-28 17:57:25 -04:00
|
|
|
def get_local_hostname():
|
|
|
|
|
try:
|
2008-11-18 14:48:10 -05:00
|
|
|
return gethostbyaddr(gethostname())[0]
|
2007-08-28 17:57:25 -04:00
|
|
|
except:
|
|
|
|
|
logging.warning("Unable to resolve local hostname for machine")
|
|
|
|
|
return "localhost"
|
2007-09-06 20:11:47 -04:00
|
|
|
|
2006-06-14 13:52:46 -04:00
|
|
|
class vmmConnection(gobject.GObject):
|
|
|
|
|
__gsignals__ = {
|
|
|
|
|
"vm-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
2006-06-14 17:52:49 -04:00
|
|
|
[str, str]),
|
2007-03-14 15:51:26 -04:00
|
|
|
"vm-started": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
2006-06-14 13:52:46 -04:00
|
|
|
"vm-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
2006-06-14 17:52:49 -04:00
|
|
|
[str, str]),
|
2007-03-29 21:22:31 -04:00
|
|
|
"net-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
|
|
|
|
"net-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
2007-04-03 14:01:45 -04:00
|
|
|
"net-started": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
|
|
|
|
"net-stopped": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
2008-08-07 17:37:16 -04:00
|
|
|
"pool-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
|
|
|
|
"pool-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
|
|
|
|
"pool-started": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
|
|
|
|
"pool-stopped": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str, str]),
|
2007-04-04 10:56:10 -04:00
|
|
|
"netdev-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str]),
|
|
|
|
|
"netdev-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str]),
|
2007-03-27 19:52:00 -04:00
|
|
|
"resources-sampled": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[]),
|
2007-09-09 22:57:24 -04:00
|
|
|
"state-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[]),
|
2007-09-10 20:56:01 -04:00
|
|
|
"connect-error": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
[str]),
|
2006-06-14 13:52:46 -04:00
|
|
|
}
|
|
|
|
|
|
2007-09-09 22:57:24 -04:00
|
|
|
STATE_DISCONNECTED = 0
|
|
|
|
|
STATE_CONNECTING = 1
|
|
|
|
|
STATE_ACTIVE = 2
|
|
|
|
|
STATE_INACTIVE = 3
|
|
|
|
|
|
|
|
|
|
def __init__(self, config, uri, readOnly = None):
|
2006-06-14 13:52:46 -04:00
|
|
|
self.__gobject_init__()
|
2006-06-14 10:59:40 -04:00
|
|
|
self.config = config
|
|
|
|
|
|
2007-09-10 20:56:01 -04:00
|
|
|
self.connectThread = None
|
2008-06-04 14:30:18 -04:00
|
|
|
self.connectThreadEvent = threading.Event()
|
|
|
|
|
self.connectThreadEvent.set()
|
2007-09-10 20:56:01 -04:00
|
|
|
self.connectError = None
|
2007-09-09 22:57:24 -04:00
|
|
|
self.uri = uri
|
|
|
|
|
if self.uri is None or self.uri.lower() == "xen":
|
|
|
|
|
self.uri = "xen:///"
|
2007-04-12 19:43:31 -04:00
|
|
|
|
2008-02-23 15:38:32 -05:00
|
|
|
self.readOnly = readOnly
|
2007-09-09 22:57:24 -04:00
|
|
|
self.state = self.STATE_DISCONNECTED
|
|
|
|
|
self.vmm = None
|
2008-09-10 15:02:49 -04:00
|
|
|
self.storage_capable = None
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
# Connection Storage pools: UUID -> vmmStoragePool
|
|
|
|
|
self.pools = {}
|
2007-09-09 22:57:24 -04:00
|
|
|
# Host network devices. name -> vmmNetDevice object
|
2007-03-30 15:01:41 -04:00
|
|
|
self.netdevs = {}
|
2007-09-09 22:57:24 -04:00
|
|
|
# Virtual networks UUUID -> vmmNetwork object
|
2007-03-21 12:28:36 -04:00
|
|
|
self.nets = {}
|
2007-09-09 22:57:24 -04:00
|
|
|
# Virtual machines. UUID -> vmmDomain object
|
2006-06-14 10:59:40 -04:00
|
|
|
self.vms = {}
|
2007-09-09 22:57:24 -04:00
|
|
|
# Running virtual machines. UUID -> vmmDomain object
|
2007-03-14 15:51:26 -04:00
|
|
|
self.activeUUIDs = []
|
2007-09-09 22:57:24 -04:00
|
|
|
# Resource utilization statistics
|
2007-03-27 19:52:00 -04:00
|
|
|
self.record = []
|
2007-09-09 22:57:24 -04:00
|
|
|
self.hostinfo = None
|
2008-03-24 11:39:19 -04:00
|
|
|
self.autoconnect = self.config.get_conn_autoconnect(self.get_uri())
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2008-02-18 10:01:21 -05:00
|
|
|
# Probe for network devices
|
2007-03-30 15:01:41 -04:00
|
|
|
try:
|
|
|
|
|
# Get a connection to the SYSTEM bus
|
|
|
|
|
self.bus = dbus.SystemBus()
|
|
|
|
|
# Get a handle to the HAL service
|
|
|
|
|
hal_object = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
|
|
|
|
|
self.hal_iface = dbus.Interface(hal_object, 'org.freedesktop.Hal.Manager')
|
|
|
|
|
|
|
|
|
|
# Track device add/removes so we can detect newly inserted CD media
|
2008-02-18 10:01:21 -05:00
|
|
|
self.hal_iface.connect_to_signal("DeviceAdded", self._net_phys_device_added)
|
|
|
|
|
self.hal_iface.connect_to_signal("DeviceRemoved", self._net_phys_device_removed)
|
|
|
|
|
|
|
|
|
|
# find all bonding master devices and register them
|
|
|
|
|
# XXX bonding stuff is linux specific
|
|
|
|
|
bondMasters = self._net_get_bonding_masters()
|
2008-06-25 11:56:36 -04:00
|
|
|
logging.debug("Bonding masters are: %s" % bondMasters)
|
2008-05-21 13:34:02 -04:00
|
|
|
for bond in bondMasters:
|
|
|
|
|
sysfspath = "/sys/class/net/" + bond
|
|
|
|
|
mac = self._net_get_mac_address(bond, sysfspath)
|
2008-06-25 11:56:36 -04:00
|
|
|
if mac:
|
|
|
|
|
self._net_device_added(bond, mac, sysfspath)
|
|
|
|
|
# Add any associated VLANs
|
|
|
|
|
self._net_tag_device_added(bond, sysfspath)
|
2008-02-18 10:01:21 -05:00
|
|
|
|
|
|
|
|
# Find info about all current present physical net devices
|
|
|
|
|
# This is OS portable...
|
2007-03-30 15:01:41 -04:00
|
|
|
for path in self.hal_iface.FindDeviceByCapability("net"):
|
2008-02-18 10:01:21 -05:00
|
|
|
self._net_phys_device_added(path)
|
2007-04-10 18:27:37 -04:00
|
|
|
except:
|
2008-11-18 15:42:51 -05:00
|
|
|
(_type, value, stacktrace) = sys.exc_info ()
|
2007-04-10 18:27:37 -04:00
|
|
|
logging.error("Unable to connect to HAL to list network devices: '%s'" + \
|
2008-11-18 15:42:51 -05:00
|
|
|
str(_type) + " " + str(value) + "\n" + \
|
2007-04-10 18:27:37 -04:00
|
|
|
traceback.format_exc (stacktrace))
|
2007-03-30 15:01:41 -04:00
|
|
|
self.bus = None
|
|
|
|
|
self.hal_iface = None
|
|
|
|
|
|
2008-02-18 10:01:21 -05:00
|
|
|
def _net_phys_device_added(self, path):
|
|
|
|
|
logging.debug("Got physical device %s" % path)
|
2007-03-30 15:01:41 -04:00
|
|
|
obj = self.bus.get_object("org.freedesktop.Hal", path)
|
2008-03-05 12:47:52 -05:00
|
|
|
objif = dbus.Interface(obj, "org.freedesktop.Hal.Device")
|
|
|
|
|
if objif.QueryCapability("net"):
|
|
|
|
|
name = objif.GetPropertyString("net.interface")
|
2008-02-18 10:01:21 -05:00
|
|
|
# XXX ...but this is Linux specific again - patches welcomed
|
2008-03-05 12:47:52 -05:00
|
|
|
#sysfspath = objif.GetPropertyString("linux.sysfs_path")
|
2008-02-18 10:01:21 -05:00
|
|
|
# XXX hal gives back paths to /sys/devices/pci0000:00/0000:00:1e.0/0000:01:00.0/net/eth0
|
|
|
|
|
# which doesnt' work so well - we want this:
|
|
|
|
|
sysfspath = "/sys/class/net/" + name
|
|
|
|
|
|
|
|
|
|
# If running a device in bridged mode, there's a reasonable
|
|
|
|
|
# chance that the actual ethernet device has been renamed to
|
|
|
|
|
# something else. ethN -> pethN
|
|
|
|
|
psysfspath = sysfspath[0:len(sysfspath)-len(name)] + "p" + name
|
|
|
|
|
if os.path.exists(psysfspath):
|
|
|
|
|
logging.debug("Device %s named to p%s" % (name, name))
|
|
|
|
|
name = "p" + name
|
|
|
|
|
sysfspath = psysfspath
|
|
|
|
|
|
|
|
|
|
# Ignore devices that are slaves of a bond
|
|
|
|
|
if self._net_is_bonding_slave(name, sysfspath):
|
|
|
|
|
logging.debug("Skipping device %s in bonding slave" % name)
|
|
|
|
|
return
|
|
|
|
|
|
2008-03-05 12:47:52 -05:00
|
|
|
mac = objif.GetPropertyString("net.address")
|
2007-07-30 09:56:44 -04:00
|
|
|
|
2008-02-18 10:01:21 -05:00
|
|
|
# Add the main NIC
|
|
|
|
|
self._net_device_added(name, mac, sysfspath)
|
|
|
|
|
|
|
|
|
|
# Add any associated VLANs
|
|
|
|
|
self._net_tag_device_added(name, sysfspath)
|
|
|
|
|
|
|
|
|
|
def _net_tag_device_added(self, name, sysfspath):
|
|
|
|
|
logging.debug("Checking for VLANs on %s" % sysfspath)
|
|
|
|
|
for vlanpath in glob.glob(sysfspath + ".*"):
|
|
|
|
|
if os.path.exists(vlanpath):
|
|
|
|
|
logging.debug("Process VLAN %s" % vlanpath)
|
|
|
|
|
vlanmac = self._net_get_mac_address(name, vlanpath)
|
2008-06-25 11:56:36 -04:00
|
|
|
if vlanmac:
|
|
|
|
|
(ignore,vlanname) = os.path.split(vlanpath)
|
2008-07-25 13:35:01 -04:00
|
|
|
|
|
|
|
|
# If running a device in bridged mode, there's areasonable
|
|
|
|
|
# chance that the actual ethernet device has beenrenamed to
|
|
|
|
|
# something else. ethN -> pethN
|
|
|
|
|
pvlanpath = vlanpath[0:len(vlanpath)-len(vlanname)] + "p" + vlanname
|
|
|
|
|
if os.path.exists(pvlanpath):
|
|
|
|
|
logging.debug("Device %s named to p%s" % (vlanname, vlanname))
|
|
|
|
|
vlanname = "p" + vlanname
|
|
|
|
|
vlanpath = pvlanpath
|
2008-06-25 11:56:36 -04:00
|
|
|
self._net_device_added(vlanname, vlanmac, vlanpath)
|
2008-02-18 10:01:21 -05:00
|
|
|
|
|
|
|
|
def _net_device_added(self, name, mac, sysfspath):
|
|
|
|
|
# Race conditions mean we can occassionally see device twice
|
|
|
|
|
if self.netdevs.has_key(name):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
bridge = self._net_get_bridge_owner(name, sysfspath)
|
|
|
|
|
shared = False
|
|
|
|
|
if bridge is not None:
|
|
|
|
|
shared = True
|
|
|
|
|
|
2008-05-07 14:18:49 -04:00
|
|
|
logging.debug("Adding net device %s %s %s (bridge: %s)" % (name, mac, sysfspath, str(bridge)))
|
2008-02-18 10:01:21 -05:00
|
|
|
|
|
|
|
|
dev = vmmNetDevice(self.config, self, name, mac, shared, bridge)
|
|
|
|
|
self.netdevs[name] = dev
|
|
|
|
|
self.emit("netdev-added", dev.get_name())
|
|
|
|
|
|
|
|
|
|
def _net_phys_device_removed(self, path):
|
|
|
|
|
obj = self.bus.get_object("org.freedesktop.Hal", path)
|
2008-03-05 12:47:52 -05:00
|
|
|
objif = dbus.Interface(obj, "org.freedesktop.Hal.Device")
|
|
|
|
|
if objif.QueryCapability("net"):
|
|
|
|
|
name = objif.GetPropertyString("net.interface")
|
2008-02-18 10:01:21 -05:00
|
|
|
|
2008-05-09 19:33:36 -04:00
|
|
|
if self.netdevs.has_key(name):
|
|
|
|
|
logging.debug("Removing physical net device %s from list." % name)
|
|
|
|
|
dev = self.netdevs[name]
|
|
|
|
|
self.emit("netdev-removed", dev.get_name())
|
|
|
|
|
del self.netdevs[name]
|
2007-03-30 15:01:41 -04:00
|
|
|
|
2006-06-28 10:40:35 -04:00
|
|
|
def is_read_only(self):
|
|
|
|
|
return self.readOnly
|
|
|
|
|
|
2007-02-19 22:23:15 -05:00
|
|
|
def get_type(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
if self.vmm is None:
|
|
|
|
|
return None
|
2007-02-19 22:23:15 -05:00
|
|
|
return self.vmm.getType()
|
|
|
|
|
|
2007-09-09 22:57:24 -04:00
|
|
|
def get_short_hostname(self):
|
|
|
|
|
hostname = self.get_hostname()
|
|
|
|
|
offset = hostname.find(".")
|
|
|
|
|
if offset > 0 and not hostname[0].isdigit():
|
|
|
|
|
return hostname[0:offset]
|
|
|
|
|
return hostname
|
|
|
|
|
|
|
|
|
|
def get_hostname(self, resolveLocal=False):
|
2008-10-30 15:35:16 -04:00
|
|
|
return virtinst.util.get_uri_hostname(self.uri)
|
2006-11-06 10:34:54 -05:00
|
|
|
|
2007-08-27 21:35:22 -04:00
|
|
|
def get_transport(self):
|
2008-10-30 15:35:16 -04:00
|
|
|
return virtinst.util.get_uri_transport(self.uri)
|
2007-09-09 22:57:24 -04:00
|
|
|
|
|
|
|
|
def get_driver(self):
|
2008-10-30 15:35:16 -04:00
|
|
|
return virtinst.util.get_uri_driver(self.uri)
|
2007-08-28 17:57:25 -04:00
|
|
|
|
2008-03-09 18:18:33 -04:00
|
|
|
def get_capabilities(self):
|
|
|
|
|
return virtinst.CapabilitiesParser.parse(self.vmm.getCapabilities())
|
|
|
|
|
|
2007-08-28 17:57:25 -04:00
|
|
|
def is_remote(self):
|
2008-10-30 15:35:16 -04:00
|
|
|
return virtinst.util.is_uri_remote(self.uri)
|
2007-08-27 21:35:22 -04:00
|
|
|
|
2008-09-22 17:50:49 +02:00
|
|
|
def is_qemu_session(self):
|
2008-11-18 14:48:10 -05:00
|
|
|
(scheme, ignore, ignore, \
|
|
|
|
|
path, ignore, ignore) = virtinst.util.uri_split(self.uri)
|
2008-09-22 17:50:49 +02:00
|
|
|
if path == "/session" and scheme.startswith("qemu"):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
2006-06-14 14:36:26 -04:00
|
|
|
def get_uri(self):
|
|
|
|
|
return self.uri
|
|
|
|
|
|
2006-06-14 16:20:06 -04:00
|
|
|
def get_vm(self, uuid):
|
|
|
|
|
return self.vms[uuid]
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2007-03-21 12:28:36 -04:00
|
|
|
def get_net(self, uuid):
|
|
|
|
|
return self.nets[uuid]
|
|
|
|
|
|
2007-04-10 18:27:37 -04:00
|
|
|
def get_net_device(self, path):
|
|
|
|
|
return self.netdevs[path]
|
2007-03-30 15:01:41 -04:00
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
def get_pool(self, uuid):
|
|
|
|
|
return self.pools[uuid]
|
|
|
|
|
|
2007-09-09 22:57:24 -04:00
|
|
|
def open(self):
|
|
|
|
|
if self.state != self.STATE_DISCONNECTED:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.state = self.STATE_CONNECTING
|
|
|
|
|
self.emit("state-changed")
|
2007-09-10 20:56:01 -04:00
|
|
|
|
|
|
|
|
logging.debug("Scheduling background open thread for " + self.uri)
|
2008-06-04 14:30:18 -04:00
|
|
|
self.connectThreadEvent.clear()
|
2007-09-10 20:56:01 -04:00
|
|
|
self.connectThread = threading.Thread(target = self._open_thread, name="Connect " + self.uri)
|
|
|
|
|
self.connectThread.setDaemon(True)
|
|
|
|
|
self.connectThread.start()
|
|
|
|
|
|
2008-01-31 11:39:10 -05:00
|
|
|
def _do_creds_polkit(self, action):
|
2008-09-24 14:55:03 -04:00
|
|
|
if os.getuid() == 0:
|
|
|
|
|
logging.debug("Skipping policykit check as root")
|
|
|
|
|
return 0
|
2008-01-31 11:39:10 -05:00
|
|
|
logging.debug("Doing policykit for %s" % action)
|
|
|
|
|
bus = dbus.SessionBus()
|
2008-05-05 19:38:10 -04:00
|
|
|
|
|
|
|
|
try:
|
2008-05-07 15:00:41 -04:00
|
|
|
# First try to use org.freedesktop.PolicyKit.AuthenticationAgent
|
|
|
|
|
# which is introduced with PolicyKit-0.7
|
2008-05-05 19:38:10 -04:00
|
|
|
obj = bus.get_object("org.freedesktop.PolicyKit.AuthenticationAgent", "/")
|
|
|
|
|
pkit = dbus.Interface(obj, "org.freedesktop.PolicyKit.AuthenticationAgent")
|
|
|
|
|
pkit.ObtainAuthorization(action, 0, os.getpid())
|
2008-05-07 15:00:41 -04:00
|
|
|
except dbus.exceptions.DBusException, e:
|
|
|
|
|
if e.get_dbus_name() != "org.freedesktop.DBus.Error.ServiceUnknown":
|
|
|
|
|
raise e
|
|
|
|
|
logging.debug("Falling back to org.gnome.PolicyKit")
|
2008-05-05 19:38:10 -04:00
|
|
|
# If PolicyKit < 0.7, fallback to org.gnome.PolicyKit
|
|
|
|
|
obj = bus.get_object("org.gnome.PolicyKit", "/org/gnome/PolicyKit/Manager")
|
|
|
|
|
pkit = dbus.Interface(obj, "org.gnome.PolicyKit.Manager")
|
|
|
|
|
pkit.ShowDialog(action, 0)
|
2008-01-31 11:39:10 -05:00
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
def _do_creds_dialog(self, creds):
|
|
|
|
|
try:
|
|
|
|
|
gtk.gdk.threads_enter()
|
|
|
|
|
return self._do_creds_dialog_main(creds)
|
|
|
|
|
finally:
|
|
|
|
|
gtk.gdk.threads_leave()
|
|
|
|
|
|
|
|
|
|
def _do_creds_dialog_main(self, creds):
|
|
|
|
|
dialog = gtk.Dialog("Authentication required", None, 0, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
|
|
|
|
|
label = []
|
|
|
|
|
entry = []
|
|
|
|
|
|
|
|
|
|
box = gtk.Table(2, len(creds))
|
|
|
|
|
|
|
|
|
|
row = 0
|
|
|
|
|
for cred in creds:
|
|
|
|
|
if cred[0] == libvirt.VIR_CRED_AUTHNAME or cred[0] == libvirt.VIR_CRED_PASSPHRASE:
|
|
|
|
|
label.append(gtk.Label(cred[1]))
|
|
|
|
|
else:
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
ent = gtk.Entry()
|
|
|
|
|
if cred[0] == libvirt.VIR_CRED_PASSPHRASE:
|
|
|
|
|
ent.set_visibility(False)
|
|
|
|
|
entry.append(ent)
|
|
|
|
|
|
|
|
|
|
box.attach(label[row], 0, 1, row, row+1, 0, 0, 3, 3)
|
|
|
|
|
box.attach(entry[row], 1, 2, row, row+1, 0, 0, 3, 3)
|
|
|
|
|
row = row + 1
|
|
|
|
|
|
|
|
|
|
vbox = dialog.get_child()
|
|
|
|
|
vbox.add(box)
|
|
|
|
|
|
|
|
|
|
dialog.show_all()
|
|
|
|
|
res = dialog.run()
|
|
|
|
|
dialog.hide()
|
|
|
|
|
|
|
|
|
|
if res == gtk.RESPONSE_OK:
|
|
|
|
|
row = 0
|
|
|
|
|
for cred in creds:
|
|
|
|
|
cred[4] = entry[row].get_text()
|
|
|
|
|
row = row + 1
|
|
|
|
|
dialog.destroy()
|
|
|
|
|
return 0
|
|
|
|
|
else:
|
|
|
|
|
dialog.destroy()
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
def _do_creds(self, creds, cbdata):
|
|
|
|
|
try:
|
|
|
|
|
if len(creds) == 1 and creds[0][0] == libvirt.VIR_CRED_EXTERNAL and creds[0][2] == "PolicyKit":
|
|
|
|
|
return self._do_creds_polkit(creds[0][1])
|
|
|
|
|
|
|
|
|
|
for cred in creds:
|
2008-03-03 16:11:29 -05:00
|
|
|
if cred[0] == libvirt.VIR_CRED_EXTERNAL:
|
2008-01-31 11:39:10 -05:00
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
return self._do_creds_dialog(creds)
|
|
|
|
|
except:
|
2008-11-18 15:42:51 -05:00
|
|
|
(_type, value, stacktrace) = sys.exc_info ()
|
2008-01-31 11:39:10 -05:00
|
|
|
# Detailed error message, in English so it can be Googled.
|
|
|
|
|
self.connectError = \
|
|
|
|
|
("Failed to get credentials '%s':\n" %
|
|
|
|
|
str(self.uri)) + \
|
2008-11-18 15:42:51 -05:00
|
|
|
str(_type) + " " + str(value) + "\n" + \
|
2008-01-31 11:39:10 -05:00
|
|
|
traceback.format_exc (stacktrace)
|
|
|
|
|
logging.error(self.connectError)
|
|
|
|
|
return -1
|
2007-09-10 20:56:01 -04:00
|
|
|
|
2009-01-26 11:10:39 -05:00
|
|
|
def _try_open(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
try:
|
2008-01-31 11:39:10 -05:00
|
|
|
flags = 0
|
|
|
|
|
if self.readOnly:
|
2008-08-21 12:29:33 +01:00
|
|
|
logging.info("Caller requested read only connection")
|
2008-01-31 11:39:10 -05:00
|
|
|
flags = libvirt.VIR_CONNECT_RO
|
|
|
|
|
|
|
|
|
|
self.vmm = libvirt.openAuth(self.uri,
|
|
|
|
|
[[libvirt.VIR_CRED_AUTHNAME,
|
|
|
|
|
libvirt.VIR_CRED_PASSPHRASE,
|
|
|
|
|
libvirt.VIR_CRED_EXTERNAL],
|
|
|
|
|
self._do_creds,
|
|
|
|
|
None], flags)
|
2009-01-26 11:10:39 -05:00
|
|
|
except:
|
|
|
|
|
exc_info = sys.exc_info()
|
|
|
|
|
|
|
|
|
|
# If the previous attempt was read/write try to fall back
|
|
|
|
|
# on read-only connection, otherwise report the error.
|
|
|
|
|
if not self.readOnly:
|
|
|
|
|
try:
|
|
|
|
|
self.vmm = libvirt.openReadOnly(self.uri)
|
|
|
|
|
self.readOnly = True
|
|
|
|
|
logging.info("Read/write connection failed to %s,"
|
|
|
|
|
"falling back on read-only." % self.uri)
|
|
|
|
|
return
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
return exc_info
|
2008-01-31 11:39:10 -05:00
|
|
|
|
2009-01-26 11:10:39 -05:00
|
|
|
|
|
|
|
|
def _open_thread(self):
|
|
|
|
|
logging.debug("Background thread is running")
|
|
|
|
|
|
|
|
|
|
open_error = self._try_open()
|
|
|
|
|
|
|
|
|
|
if not open_error:
|
2007-09-09 22:57:24 -04:00
|
|
|
self.state = self.STATE_ACTIVE
|
2009-01-26 11:10:39 -05:00
|
|
|
else:
|
2007-09-09 22:57:24 -04:00
|
|
|
self.state = self.STATE_DISCONNECTED
|
2007-09-10 20:56:01 -04:00
|
|
|
|
2009-01-26 11:10:39 -05:00
|
|
|
(_type, value, stacktrace) = open_error
|
2007-09-10 20:56:01 -04:00
|
|
|
# Detailed error message, in English so it can be Googled.
|
|
|
|
|
self.connectError = \
|
|
|
|
|
("Unable to open connection to hypervisor URI '%s':\n" %
|
|
|
|
|
str(self.uri)) + \
|
2008-11-18 15:42:51 -05:00
|
|
|
str(_type) + " " + str(value) + "\n" + \
|
2007-09-10 20:56:01 -04:00
|
|
|
traceback.format_exc (stacktrace)
|
|
|
|
|
logging.error(self.connectError)
|
|
|
|
|
|
|
|
|
|
# We want to kill off this thread asap, so schedule a gobject
|
|
|
|
|
# idle even to inform the UI of result
|
|
|
|
|
logging.debug("Background open thread complete, scheduling notify")
|
|
|
|
|
gtk.gdk.threads_enter()
|
|
|
|
|
try:
|
|
|
|
|
gobject.idle_add(self._open_notify)
|
|
|
|
|
finally:
|
|
|
|
|
gtk.gdk.threads_leave()
|
|
|
|
|
self.connectThread = None
|
|
|
|
|
|
|
|
|
|
def _open_notify(self):
|
|
|
|
|
logging.debug("Notifying open result")
|
|
|
|
|
gtk.gdk.threads_enter()
|
|
|
|
|
try:
|
|
|
|
|
if self.state == self.STATE_ACTIVE:
|
|
|
|
|
self.tick()
|
2007-09-09 22:57:24 -04:00
|
|
|
self.emit("state-changed")
|
2007-09-10 20:56:01 -04:00
|
|
|
|
|
|
|
|
if self.state == self.STATE_DISCONNECTED:
|
|
|
|
|
self.emit("connect-error", self.connectError)
|
|
|
|
|
self.connectError = None
|
|
|
|
|
finally:
|
2008-06-04 14:30:18 -04:00
|
|
|
self.connectThreadEvent.set()
|
2007-09-10 20:56:01 -04:00
|
|
|
gtk.gdk.threads_leave()
|
|
|
|
|
|
2007-09-09 22:57:24 -04:00
|
|
|
|
|
|
|
|
def pause(self):
|
|
|
|
|
if self.state != self.STATE_ACTIVE:
|
|
|
|
|
return
|
|
|
|
|
self.state = self.STATE_INACTIVE
|
|
|
|
|
self.emit("state-changed")
|
|
|
|
|
|
|
|
|
|
def resume(self):
|
|
|
|
|
if self.state != self.STATE_INACTIVE:
|
|
|
|
|
return
|
|
|
|
|
self.state = self.STATE_ACTIVE
|
|
|
|
|
self.emit("state-changed")
|
|
|
|
|
|
2006-08-21 14:00:32 -04:00
|
|
|
def close(self):
|
2006-06-14 14:36:26 -04:00
|
|
|
if self.vmm == None:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
#self.vmm.close()
|
2006-06-14 13:52:46 -04:00
|
|
|
self.vmm = None
|
2007-09-09 22:57:24 -04:00
|
|
|
self.nets = {}
|
2008-08-07 17:37:16 -04:00
|
|
|
self.pools = {}
|
2007-09-09 22:57:24 -04:00
|
|
|
self.vms = {}
|
|
|
|
|
self.activeUUIDs = []
|
|
|
|
|
self.record = []
|
|
|
|
|
self.state = self.STATE_DISCONNECTED
|
|
|
|
|
self.emit("state-changed")
|
2006-06-14 13:52:46 -04:00
|
|
|
|
2006-10-10 17:24:59 -04:00
|
|
|
def list_vm_uuids(self):
|
|
|
|
|
return self.vms.keys()
|
|
|
|
|
|
2007-03-21 12:28:36 -04:00
|
|
|
def list_net_uuids(self):
|
|
|
|
|
return self.nets.keys()
|
|
|
|
|
|
2007-04-10 18:27:37 -04:00
|
|
|
def list_net_device_paths(self):
|
|
|
|
|
return self.netdevs.keys()
|
2007-03-30 15:01:41 -04:00
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
def list_pool_uuids(self):
|
|
|
|
|
return self.pools.keys()
|
|
|
|
|
|
2006-06-14 10:59:40 -04:00
|
|
|
def get_host_info(self):
|
2006-06-14 17:52:49 -04:00
|
|
|
return self.hostinfo
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2008-11-18 15:42:51 -05:00
|
|
|
def get_max_vcpus(self, _type=None):
|
|
|
|
|
return virtinst.util.get_max_vcpus(self.vmm, _type)
|
2007-06-18 15:16:20 -04:00
|
|
|
|
2008-03-24 11:39:19 -04:00
|
|
|
def get_autoconnect(self):
|
|
|
|
|
# Use a local variable to cache autoconnect so we don't repeatedly
|
|
|
|
|
# have to poll gconf
|
|
|
|
|
return self.autoconnect
|
|
|
|
|
|
|
|
|
|
def toggle_autoconnect(self):
|
|
|
|
|
self.config.toggle_conn_autoconnect(self.get_uri())
|
|
|
|
|
self.autoconnect = (not self.autoconnect)
|
|
|
|
|
|
2006-06-14 13:52:46 -04:00
|
|
|
def connect(self, name, callback):
|
2006-08-21 14:00:32 -04:00
|
|
|
handle_id = gobject.GObject.connect(self, name, callback)
|
2006-06-14 18:51:58 -04:00
|
|
|
|
2006-06-14 13:52:46 -04:00
|
|
|
if name == "vm-added":
|
2006-06-14 10:59:40 -04:00
|
|
|
for uuid in self.vms.keys():
|
2006-06-14 17:52:49 -04:00
|
|
|
self.emit("vm-added", self.uri, uuid)
|
|
|
|
|
|
2006-08-21 14:00:32 -04:00
|
|
|
return handle_id
|
|
|
|
|
|
2007-03-27 19:52:00 -04:00
|
|
|
def pretty_host_memory_size(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
if self.vmm is None:
|
|
|
|
|
return ""
|
2007-03-27 19:52:00 -04:00
|
|
|
mem = self.host_memory_size()
|
|
|
|
|
if mem > (1024*1024):
|
|
|
|
|
return "%2.2f GB" % (mem/(1024.0*1024.0))
|
|
|
|
|
else:
|
|
|
|
|
return "%2.2f MB" % (mem/1024.0)
|
|
|
|
|
|
|
|
|
|
|
2006-06-14 17:52:49 -04:00
|
|
|
def host_memory_size(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
if self.vmm is None:
|
|
|
|
|
return 0
|
2006-06-14 17:52:49 -04:00
|
|
|
return self.hostinfo[1]*1024
|
|
|
|
|
|
2007-03-27 19:52:00 -04:00
|
|
|
def host_architecture(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
if self.vmm is None:
|
|
|
|
|
return ""
|
2007-03-27 19:52:00 -04:00
|
|
|
return self.hostinfo[0]
|
|
|
|
|
|
2006-06-14 17:52:49 -04:00
|
|
|
def host_active_processor_count(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
if self.vmm is None:
|
|
|
|
|
return 0
|
2006-06-14 17:52:49 -04:00
|
|
|
return self.hostinfo[2]
|
|
|
|
|
|
|
|
|
|
def host_maximum_processor_count(self):
|
2007-09-09 22:57:24 -04:00
|
|
|
if self.vmm is None:
|
|
|
|
|
return 0
|
2006-06-14 17:52:49 -04:00
|
|
|
return self.hostinfo[4] * self.hostinfo[5] * self.hostinfo[6] * self.hostinfo[7]
|
|
|
|
|
|
2007-03-29 21:22:31 -04:00
|
|
|
def create_network(self, xml, start=True, autostart=True):
|
|
|
|
|
net = self.vmm.networkDefineXML(xml)
|
|
|
|
|
uuid = self.uuidstr(net.UUID())
|
2007-04-04 10:56:10 -04:00
|
|
|
self.nets[uuid] = vmmNetwork(self.config, self, net, uuid, False)
|
2007-03-29 21:22:31 -04:00
|
|
|
self.nets[uuid].start()
|
2007-04-04 10:56:10 -04:00
|
|
|
self.nets[uuid].set_active(True)
|
2007-03-29 21:22:31 -04:00
|
|
|
self.nets[uuid].set_autostart(True)
|
|
|
|
|
self.emit("net-added", self.uri, uuid)
|
2007-04-03 14:01:45 -04:00
|
|
|
self.emit("net-started", self.uri, uuid)
|
2007-03-29 21:22:31 -04:00
|
|
|
return self.nets[uuid]
|
|
|
|
|
|
2007-04-12 17:50:22 -04:00
|
|
|
def define_domain(self, xml):
|
|
|
|
|
self.vmm.defineXML(xml)
|
|
|
|
|
|
2006-07-20 11:16:07 -04:00
|
|
|
def restore(self, frm):
|
2006-07-24 13:50:11 -04:00
|
|
|
status = self.vmm.restore(frm)
|
|
|
|
|
if(status == 0):
|
|
|
|
|
os.remove(frm)
|
|
|
|
|
return status
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
def _update_nets(self):
|
|
|
|
|
"""Return lists of start/stopped/new networks"""
|
|
|
|
|
|
|
|
|
|
origNets = self.nets
|
|
|
|
|
currentNets = {}
|
|
|
|
|
startNets = []
|
|
|
|
|
stopNets = []
|
|
|
|
|
newNets = []
|
2007-04-03 14:01:45 -04:00
|
|
|
newActiveNetNames = []
|
|
|
|
|
newInactiveNetNames = []
|
|
|
|
|
try:
|
|
|
|
|
newActiveNetNames = self.vmm.listNetworks()
|
|
|
|
|
except:
|
|
|
|
|
logging.warn("Unable to list active networks")
|
|
|
|
|
try:
|
|
|
|
|
newInactiveNetNames = self.vmm.listDefinedNetworks()
|
|
|
|
|
except:
|
|
|
|
|
logging.warn("Unable to list inactive networks")
|
|
|
|
|
|
|
|
|
|
for name in newActiveNetNames:
|
2008-03-14 10:15:27 -04:00
|
|
|
try:
|
|
|
|
|
net = self.vmm.networkLookupByName(name)
|
|
|
|
|
uuid = self.uuidstr(net.UUID())
|
2008-07-09 17:00:49 -04:00
|
|
|
if not origNets.has_key(uuid):
|
|
|
|
|
# Brand new network
|
|
|
|
|
currentNets[uuid] = vmmNetwork(self.config, self, net,
|
|
|
|
|
uuid, True)
|
|
|
|
|
newNets.append(uuid)
|
|
|
|
|
startNets.append(uuid)
|
2008-03-14 10:15:27 -04:00
|
|
|
else:
|
2008-07-09 17:00:49 -04:00
|
|
|
# Already present network, see if it changed state
|
|
|
|
|
currentNets[uuid] = origNets[uuid]
|
|
|
|
|
if not currentNets[uuid].is_active():
|
|
|
|
|
currentNets[uuid].set_active(True)
|
|
|
|
|
startNets.append(uuid)
|
|
|
|
|
del origNets[uuid]
|
2008-03-14 10:15:27 -04:00
|
|
|
except libvirt.libvirtError:
|
2008-07-09 17:00:49 -04:00
|
|
|
logging.warn("Couldn't fetch active network name '%s'" % name)
|
2008-03-14 10:15:27 -04:00
|
|
|
|
2007-04-03 14:01:45 -04:00
|
|
|
for name in newInactiveNetNames:
|
2008-03-14 10:15:27 -04:00
|
|
|
try:
|
|
|
|
|
net = self.vmm.networkLookupByName(name)
|
|
|
|
|
uuid = self.uuidstr(net.UUID())
|
2008-07-09 17:00:49 -04:00
|
|
|
if not origNets.has_key(uuid):
|
|
|
|
|
currentNets[uuid] = vmmNetwork(self.config, self, net,
|
|
|
|
|
uuid, False)
|
2008-07-31 16:02:39 -04:00
|
|
|
newNets.append(uuid)
|
2008-03-14 10:15:27 -04:00
|
|
|
else:
|
2008-07-09 17:00:49 -04:00
|
|
|
currentNets[uuid] = origNets[uuid]
|
|
|
|
|
if currentNets[uuid].is_active():
|
|
|
|
|
currentNets[uuid].set_active(False)
|
|
|
|
|
stopNets.append(uuid)
|
|
|
|
|
del origNets[uuid]
|
2008-03-14 10:15:27 -04:00
|
|
|
except libvirt.libvirtError:
|
2008-07-09 17:00:49 -04:00
|
|
|
logging.warn("Couldn't fetch inactive network name '%s'" % name)
|
|
|
|
|
|
|
|
|
|
return (startNets, stopNets, newNets, origNets, currentNets)
|
|
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
def _update_pools(self):
|
|
|
|
|
origPools = self.pools
|
|
|
|
|
currentPools = {}
|
|
|
|
|
startPools = []
|
|
|
|
|
stopPools = []
|
|
|
|
|
newPools = []
|
|
|
|
|
newActivePoolNames = []
|
|
|
|
|
newInactivePoolNames = []
|
|
|
|
|
|
2008-09-10 15:02:49 -04:00
|
|
|
if self.storage_capable == None:
|
|
|
|
|
self.storage_capable = virtinst.util.is_storage_capable(self.vmm)
|
|
|
|
|
|
|
|
|
|
if not self.storage_capable:
|
|
|
|
|
return (stopPools, startPools, origPools, newPools, currentPools)
|
|
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
try:
|
|
|
|
|
newActivePoolNames = self.vmm.listStoragePools()
|
|
|
|
|
except:
|
|
|
|
|
logging.warn("Unable to list active pools")
|
|
|
|
|
try:
|
|
|
|
|
newInactivePoolNames = self.vmm.listDefinedStoragePools()
|
|
|
|
|
except:
|
|
|
|
|
logging.warn("Unable to list inactive pools")
|
|
|
|
|
|
|
|
|
|
for name in newActivePoolNames:
|
|
|
|
|
try:
|
|
|
|
|
pool = self.vmm.storagePoolLookupByName(name)
|
|
|
|
|
uuid = self.uuidstr(pool.UUID())
|
|
|
|
|
if not origPools.has_key(uuid):
|
|
|
|
|
currentPools[uuid] = vmmStoragePool(self.config, self,
|
|
|
|
|
pool, uuid, True)
|
|
|
|
|
newPools.append(uuid)
|
|
|
|
|
startPools.append(uuid)
|
|
|
|
|
else:
|
|
|
|
|
currentPools[uuid] = origPools[uuid]
|
|
|
|
|
if not currentPools[uuid].is_active():
|
|
|
|
|
currentPools[uuid].set_active(True)
|
|
|
|
|
startPools.append(uuid)
|
|
|
|
|
del origPools[uuid]
|
|
|
|
|
except libvirt.libvirtError:
|
|
|
|
|
logging.warn("Couldn't fetch active pool '%s'" % name)
|
|
|
|
|
|
|
|
|
|
for name in newInactivePoolNames:
|
|
|
|
|
try:
|
|
|
|
|
pool = self.vmm.storagePoolLookupByName(name)
|
|
|
|
|
uuid = self.uuidstr(pool.UUID())
|
|
|
|
|
if not origPools.has_key(uuid):
|
|
|
|
|
currentPools[uuid] = vmmStoragePool(self.config, self,
|
|
|
|
|
pool, uuid, False)
|
|
|
|
|
newPools.append(uuid)
|
|
|
|
|
else:
|
|
|
|
|
currentPools[uuid] = origPools[uuid]
|
|
|
|
|
if currentPools[uuid].is_active():
|
|
|
|
|
currentPools[uuid].set_active(False)
|
|
|
|
|
stopPools.append(uuid)
|
|
|
|
|
del origPools[uuid]
|
|
|
|
|
except libvirt.libvirtError:
|
|
|
|
|
logging.warn("Couldn't fetch inactive pool '%s'" % name)
|
|
|
|
|
return (stopPools, startPools, origPools, newPools, currentPools)
|
|
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
def _update_vms(self):
|
|
|
|
|
"""returns lists of changed VM states"""
|
2007-03-21 12:28:36 -04:00
|
|
|
|
2006-10-09 13:28:13 -04:00
|
|
|
oldActiveIDs = {}
|
|
|
|
|
oldInactiveNames = {}
|
2006-07-13 13:35:24 -04:00
|
|
|
for uuid in self.vms.keys():
|
2007-03-14 15:51:26 -04:00
|
|
|
# first pull out all the current inactive VMs we know about
|
2006-07-13 13:35:24 -04:00
|
|
|
vm = self.vms[uuid]
|
2006-10-09 13:28:13 -04:00
|
|
|
if vm.get_id() == -1:
|
|
|
|
|
oldInactiveNames[vm.get_name()] = vm
|
2007-03-14 15:51:26 -04:00
|
|
|
for uuid in self.activeUUIDs:
|
2008-07-09 17:00:49 -04:00
|
|
|
# Now get all the vms that were active the last time around
|
|
|
|
|
# and are still active
|
2007-03-14 15:51:26 -04:00
|
|
|
vm = self.vms[uuid]
|
|
|
|
|
if vm.get_id() != -1:
|
2006-10-09 13:28:13 -04:00
|
|
|
oldActiveIDs[vm.get_id()] = vm
|
|
|
|
|
|
2008-03-14 10:15:27 -04:00
|
|
|
newActiveIDs = []
|
|
|
|
|
try:
|
|
|
|
|
newActiveIDs = self.vmm.listDomainsID()
|
|
|
|
|
except:
|
|
|
|
|
logging.warn("Unable to list active domains")
|
|
|
|
|
|
2006-10-11 12:05:50 -04:00
|
|
|
newInactiveNames = []
|
|
|
|
|
try:
|
|
|
|
|
newInactiveNames = self.vmm.listDefinedDomains()
|
|
|
|
|
except:
|
|
|
|
|
logging.warn("Unable to list inactive domains")
|
2006-10-09 13:28:13 -04:00
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
curUUIDs = {} # new master list of vms
|
|
|
|
|
maybeNewUUIDs = {} # list of vms that changed state or are brand new
|
|
|
|
|
oldUUIDs = {} # no longer present vms
|
|
|
|
|
newUUIDs = [] # brand new vms
|
|
|
|
|
startedUUIDs = [] # previously present vms that are now running
|
|
|
|
|
activeUUIDs = [] # all running vms
|
2006-10-09 13:28:13 -04:00
|
|
|
|
|
|
|
|
# NB in these first 2 loops, we go to great pains to
|
|
|
|
|
# avoid actually instantiating a new VM object so that
|
|
|
|
|
# the common case of 'no new/old VMs' avoids hitting
|
|
|
|
|
# XenD too much & thus slowing stuff down.
|
|
|
|
|
|
|
|
|
|
# Filter out active domains which haven't changed
|
|
|
|
|
if newActiveIDs != None:
|
2008-11-18 15:42:51 -05:00
|
|
|
for _id in newActiveIDs:
|
|
|
|
|
if oldActiveIDs.has_key(_id):
|
2006-10-09 13:28:13 -04:00
|
|
|
# No change, copy across existing VM object
|
2008-11-18 15:42:51 -05:00
|
|
|
vm = oldActiveIDs[_id]
|
2006-10-09 13:28:13 -04:00
|
|
|
curUUIDs[vm.get_uuid()] = vm
|
2008-07-09 17:00:49 -04:00
|
|
|
activeUUIDs.append(vm.get_uuid())
|
2006-07-13 13:35:24 -04:00
|
|
|
else:
|
2006-10-09 13:28:13 -04:00
|
|
|
# May be a new VM, we have no choice but
|
|
|
|
|
# to create the wrapper so we can see
|
|
|
|
|
# if its a previously inactive domain.
|
2008-03-14 10:15:27 -04:00
|
|
|
try:
|
2008-11-18 15:42:51 -05:00
|
|
|
vm = self.vmm.lookupByID(_id)
|
2008-03-14 10:15:27 -04:00
|
|
|
uuid = self.uuidstr(vm.UUID())
|
|
|
|
|
maybeNewUUIDs[uuid] = vm
|
|
|
|
|
startedUUIDs.append(uuid)
|
2008-07-09 17:00:49 -04:00
|
|
|
activeUUIDs.append(uuid)
|
2008-03-14 10:15:27 -04:00
|
|
|
except libvirt.libvirtError:
|
2008-11-18 15:42:51 -05:00
|
|
|
logging.debug("Couldn't fetch domain id '%s'" % str(_id)
|
2008-07-09 17:00:49 -04:00
|
|
|
+ ": it probably went away")
|
2006-10-09 13:28:13 -04:00
|
|
|
|
|
|
|
|
# Filter out inactive domains which haven't changed
|
|
|
|
|
if newInactiveNames != None:
|
|
|
|
|
for name in newInactiveNames:
|
|
|
|
|
if oldInactiveNames.has_key(name):
|
|
|
|
|
# No change, copy across existing VM object
|
|
|
|
|
vm = oldInactiveNames[name]
|
|
|
|
|
curUUIDs[vm.get_uuid()] = vm
|
|
|
|
|
else:
|
|
|
|
|
# May be a new VM, we have no choice but
|
|
|
|
|
# to create the wrapper so we can see
|
|
|
|
|
# if its a previously inactive domain.
|
2006-10-25 12:18:06 -04:00
|
|
|
try:
|
2006-11-13 10:31:29 -05:00
|
|
|
vm = self.vmm.lookupByName(name)
|
2006-10-25 12:18:06 -04:00
|
|
|
uuid = self.uuidstr(vm.UUID())
|
2006-11-13 10:31:29 -05:00
|
|
|
maybeNewUUIDs[uuid] = vm
|
2006-10-25 12:18:06 -04:00
|
|
|
except libvirt.libvirtError:
|
2008-07-09 17:00:49 -04:00
|
|
|
logging.debug("Couldn't fetch domain id '%s'" % str(id)
|
|
|
|
|
+ ": it probably went away")
|
2006-10-09 13:28:13 -04:00
|
|
|
|
|
|
|
|
# At this point, maybeNewUUIDs has domains which are
|
|
|
|
|
# either completely new, or changed state.
|
|
|
|
|
|
|
|
|
|
# Filter out VMs which merely changed state, leaving
|
|
|
|
|
# only new domains
|
|
|
|
|
for uuid in maybeNewUUIDs.keys():
|
2006-10-10 17:24:59 -04:00
|
|
|
rawvm = maybeNewUUIDs[uuid]
|
|
|
|
|
if not(self.vms.has_key(uuid)):
|
|
|
|
|
vm = vmmDomain(self.config, self, rawvm, uuid)
|
2008-07-09 17:00:49 -04:00
|
|
|
newUUIDs.append(uuid)
|
2006-10-10 17:24:59 -04:00
|
|
|
curUUIDs[uuid] = vm
|
2006-10-09 13:28:13 -04:00
|
|
|
else:
|
2006-10-10 17:24:59 -04:00
|
|
|
vm = self.vms[uuid]
|
2007-07-24 15:13:03 -04:00
|
|
|
vm.release_handle()
|
2006-10-10 17:24:59 -04:00
|
|
|
vm.set_handle(rawvm)
|
|
|
|
|
curUUIDs[uuid] = vm
|
2006-10-09 13:28:13 -04:00
|
|
|
|
|
|
|
|
# Finalize list of domains which went away altogether
|
|
|
|
|
for uuid in self.vms.keys():
|
|
|
|
|
vm = self.vms[uuid]
|
|
|
|
|
if not(curUUIDs.has_key(uuid)):
|
|
|
|
|
oldUUIDs[uuid] = vm
|
|
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
return (startedUUIDs, newUUIDs, oldUUIDs, curUUIDs, activeUUIDs)
|
2006-10-09 13:28:13 -04:00
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
def tick(self, noStatsUpdate=False):
|
|
|
|
|
""" main update function: polls for new objects, updates stats, ..."""
|
|
|
|
|
if self.state != self.STATE_ACTIVE:
|
|
|
|
|
return
|
2006-10-09 13:28:13 -04:00
|
|
|
|
2008-10-06 13:21:06 -04:00
|
|
|
self.hostinfo = self.vmm.getInfo()
|
|
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
# Poll for new virtual network objects
|
|
|
|
|
(startNets, stopNets, newNets,
|
|
|
|
|
oldNets, self.nets) = self._update_nets()
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
# Update pools
|
|
|
|
|
(stopPools, startPools, oldPools,
|
|
|
|
|
newPools, self.pools) = self._update_pools()
|
|
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
# Poll for changed/new/removed VMs
|
|
|
|
|
(startVMs, newVMs, oldVMs,
|
|
|
|
|
self.vms, self.activeUUIDs) = self._update_vms()
|
|
|
|
|
|
|
|
|
|
# Update VM states
|
|
|
|
|
for uuid in oldVMs:
|
|
|
|
|
self.emit("vm-removed", self.uri, uuid)
|
|
|
|
|
oldVMs[uuid].release_handle()
|
|
|
|
|
for uuid in newVMs:
|
|
|
|
|
self.emit("vm-added", self.uri, uuid)
|
|
|
|
|
for uuid in startVMs:
|
2007-03-14 15:51:26 -04:00
|
|
|
self.emit("vm-started", self.uri, uuid)
|
|
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
# Update virtual network states
|
2007-03-29 21:22:31 -04:00
|
|
|
for uuid in oldNets:
|
|
|
|
|
self.emit("net-removed", self.uri, uuid)
|
|
|
|
|
for uuid in newNets:
|
|
|
|
|
self.emit("net-added", self.uri, uuid)
|
2007-04-03 14:01:45 -04:00
|
|
|
for uuid in startNets:
|
|
|
|
|
self.emit("net-started", self.uri, uuid)
|
|
|
|
|
for uuid in stopNets:
|
|
|
|
|
self.emit("net-stopped", self.uri, uuid)
|
|
|
|
|
|
2008-08-07 17:37:16 -04:00
|
|
|
for uuid in oldPools:
|
|
|
|
|
self.emit("pool-removed", self.uri, uuid)
|
|
|
|
|
for uuid in newPools:
|
|
|
|
|
self.emit("pool-added", self.uri, uuid)
|
|
|
|
|
for uuid in startPools:
|
|
|
|
|
self.emit("pool-started", self.uri, uuid)
|
|
|
|
|
for uuid in stopPools:
|
|
|
|
|
self.emit("pool-stopped", self.uri, uuid)
|
|
|
|
|
|
2006-10-09 13:28:13 -04:00
|
|
|
# Finally, we sample each domain
|
2006-06-14 17:52:49 -04:00
|
|
|
now = time()
|
2006-06-14 10:59:40 -04:00
|
|
|
|
2006-10-03 11:53:07 -04:00
|
|
|
updateVMs = self.vms
|
|
|
|
|
if noStatsUpdate:
|
2008-07-09 17:00:49 -04:00
|
|
|
updateVMs = newVMs
|
2006-10-03 11:53:07 -04:00
|
|
|
|
2008-07-09 17:00:49 -04:00
|
|
|
for uuid in updateVMs:
|
2006-10-03 11:53:07 -04:00
|
|
|
self.vms[uuid].tick(now)
|
2007-03-27 19:52:00 -04:00
|
|
|
|
|
|
|
|
if not noStatsUpdate:
|
2007-09-09 22:57:24 -04:00
|
|
|
self._recalculate_stats(now)
|
2007-03-27 19:52:00 -04:00
|
|
|
|
2006-06-14 10:59:40 -04:00
|
|
|
return 1
|
|
|
|
|
|
2007-09-09 22:57:24 -04:00
|
|
|
def _recalculate_stats(self, now):
|
2007-03-27 19:52:00 -04:00
|
|
|
expected = self.config.get_stats_history_length()
|
|
|
|
|
current = len(self.record)
|
|
|
|
|
if current > expected:
|
|
|
|
|
del self.record[expected:current]
|
|
|
|
|
|
|
|
|
|
mem = 0
|
|
|
|
|
cpuTime = 0
|
2008-10-18 21:21:33 +02:00
|
|
|
rdRate = 0
|
|
|
|
|
wrRate = 0
|
|
|
|
|
rxRate = 0
|
|
|
|
|
txRate = 0
|
2007-03-27 19:52:00 -04:00
|
|
|
|
|
|
|
|
for uuid in self.vms:
|
|
|
|
|
vm = self.vms[uuid]
|
|
|
|
|
if vm.get_id() != -1:
|
|
|
|
|
cpuTime = cpuTime + vm.get_cputime()
|
|
|
|
|
mem = mem + vm.get_memory()
|
2008-10-18 21:21:33 +02:00
|
|
|
rdRate += vm.disk_read_rate()
|
|
|
|
|
wrRate += vm.disk_write_rate()
|
|
|
|
|
rxRate += vm.network_rx_rate()
|
|
|
|
|
txRate += vm.network_tx_rate()
|
2007-03-27 19:52:00 -04:00
|
|
|
|
|
|
|
|
pcentCpuTime = 0
|
|
|
|
|
if len(self.record) > 0:
|
|
|
|
|
prevTimestamp = self.record[0]["timestamp"]
|
|
|
|
|
|
|
|
|
|
pcentCpuTime = (cpuTime) * 100.0 / ((now - prevTimestamp)*1000.0*1000.0*1000.0*self.host_active_processor_count())
|
|
|
|
|
# Due to timing diffs between getting wall time & getting
|
|
|
|
|
# the domain's time, its possible to go a tiny bit over
|
|
|
|
|
# 100% utilization. This freaks out users of the data, so
|
|
|
|
|
# we hard limit it.
|
|
|
|
|
if pcentCpuTime > 100.0:
|
|
|
|
|
pcentCpuTime = 100.0
|
|
|
|
|
# Enforce >= 0 just in case
|
|
|
|
|
if pcentCpuTime < 0.0:
|
|
|
|
|
pcentCpuTime = 0.0
|
|
|
|
|
|
|
|
|
|
pcentMem = mem * 100.0 / self.host_memory_size()
|
|
|
|
|
|
|
|
|
|
newStats = {
|
|
|
|
|
"timestamp": now,
|
|
|
|
|
"memory": mem,
|
|
|
|
|
"memoryPercent": pcentMem,
|
|
|
|
|
"cpuTime": cpuTime,
|
2008-10-18 21:21:33 +02:00
|
|
|
"cpuTimePercent": pcentCpuTime,
|
|
|
|
|
"diskRdRate" : rdRate,
|
|
|
|
|
"diskWrRate" : wrRate,
|
|
|
|
|
"netRxRate" : rxRate,
|
|
|
|
|
"netTxRate" : txRate,
|
2007-03-27 19:52:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.record.insert(0, newStats)
|
|
|
|
|
self.emit("resources-sampled")
|
|
|
|
|
|
|
|
|
|
def cpu_time_vector(self):
|
|
|
|
|
vector = []
|
|
|
|
|
stats = self.record
|
|
|
|
|
for i in range(self.config.get_stats_history_length()+1):
|
|
|
|
|
if i < len(stats):
|
|
|
|
|
vector.append(stats[i]["cpuTimePercent"]/100.0)
|
|
|
|
|
else:
|
|
|
|
|
vector.append(0)
|
|
|
|
|
return vector
|
|
|
|
|
|
|
|
|
|
def cpu_time_vector_limit(self, limit):
|
|
|
|
|
cpudata = self.cpu_time_vector()
|
|
|
|
|
if len(cpudata) > limit:
|
|
|
|
|
cpudata = cpudata[0:limit]
|
|
|
|
|
return cpudata
|
|
|
|
|
|
|
|
|
|
def cpu_time_percentage(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["cpuTimePercent"]
|
|
|
|
|
|
|
|
|
|
def current_memory(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["memory"]
|
|
|
|
|
|
|
|
|
|
def pretty_current_memory(self):
|
|
|
|
|
mem = self.current_memory()
|
|
|
|
|
if mem > (1024*1024):
|
|
|
|
|
return "%2.2f GB" % (mem/(1024.0*1024.0))
|
|
|
|
|
else:
|
|
|
|
|
return "%2.2f MB" % (mem/1024.0)
|
|
|
|
|
|
|
|
|
|
def current_memory_percentage(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["memoryPercent"]
|
|
|
|
|
|
|
|
|
|
def current_memory_vector(self):
|
|
|
|
|
vector = []
|
|
|
|
|
stats = self.record
|
|
|
|
|
for i in range(self.config.get_stats_history_length()+1):
|
|
|
|
|
if i < len(stats):
|
|
|
|
|
vector.append(stats[i]["memoryPercent"]/100.0)
|
|
|
|
|
else:
|
|
|
|
|
vector.append(0)
|
|
|
|
|
return vector
|
|
|
|
|
|
2008-10-18 21:21:33 +02:00
|
|
|
def network_rx_rate(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["netRxRate"]
|
|
|
|
|
|
|
|
|
|
def network_tx_rate(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["netTxRate"]
|
|
|
|
|
|
|
|
|
|
def network_traffic_rate(self):
|
|
|
|
|
return self.network_tx_rate() + self.network_rx_rate()
|
|
|
|
|
|
|
|
|
|
def disk_read_rate(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["diskRdRate"]
|
|
|
|
|
|
|
|
|
|
def disk_write_rate(self):
|
|
|
|
|
if len(self.record) == 0:
|
|
|
|
|
return 0
|
|
|
|
|
return self.record[0]["diskWrRate"]
|
|
|
|
|
|
|
|
|
|
def disk_io_rate(self):
|
|
|
|
|
return self.disk_read_rate() + self.disk_write_rate()
|
2008-10-18 21:28:57 +02:00
|
|
|
|
|
|
|
|
def disk_io_vector_limit(self, dummy):
|
|
|
|
|
"""No point to accumulate unnormalized I/O for a conenction"""
|
|
|
|
|
return [ 0.0 ]
|
|
|
|
|
|
|
|
|
|
def network_traffic_vector_limit(self, dummy):
|
|
|
|
|
"""No point to accumulate unnormalized Rx/Tx for a conenction"""
|
|
|
|
|
return [ 0.0 ]
|
2008-10-18 21:21:33 +02:00
|
|
|
|
2006-06-14 10:59:40 -04:00
|
|
|
def uuidstr(self, rawuuid):
|
2008-11-18 15:42:51 -05:00
|
|
|
hx = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
|
2006-06-14 10:59:40 -04:00
|
|
|
uuid = []
|
|
|
|
|
for i in range(16):
|
2008-11-18 15:42:51 -05:00
|
|
|
uuid.append(hx[((ord(rawuuid[i]) >> 4) & 0xf)])
|
|
|
|
|
uuid.append(hx[(ord(rawuuid[i]) & 0xf)])
|
2006-06-14 10:59:40 -04:00
|
|
|
if i == 3 or i == 5 or i == 7 or i == 9:
|
|
|
|
|
uuid.append('-')
|
|
|
|
|
return "".join(uuid)
|
|
|
|
|
|
2007-09-09 22:57:24 -04:00
|
|
|
def get_state(self):
|
|
|
|
|
return self.state
|
|
|
|
|
|
|
|
|
|
def get_state_text(self):
|
|
|
|
|
if self.state == self.STATE_DISCONNECTED:
|
|
|
|
|
return _("Disconnected")
|
|
|
|
|
elif self.state == self.STATE_CONNECTING:
|
|
|
|
|
return _("Connecting")
|
|
|
|
|
elif self.state == self.STATE_ACTIVE:
|
2008-08-21 12:03:31 +01:00
|
|
|
if self.is_read_only():
|
|
|
|
|
return _("Active (RO)")
|
|
|
|
|
else:
|
|
|
|
|
return _("Active")
|
2007-09-09 22:57:24 -04:00
|
|
|
elif self.state == self.STATE_INACTIVE:
|
|
|
|
|
return _("Inactive")
|
2007-07-11 19:52:53 -04:00
|
|
|
else:
|
2007-09-09 22:57:24 -04:00
|
|
|
return _("Unknown")
|
2007-08-09 16:19:41 -04:00
|
|
|
|
2008-02-18 10:01:21 -05:00
|
|
|
def _net_get_bridge_owner(self, name, sysfspath):
|
|
|
|
|
# Now magic to determine if the device is part of a bridge
|
|
|
|
|
brportpath = os.path.join(sysfspath, "brport")
|
|
|
|
|
try:
|
|
|
|
|
if os.path.exists(brportpath):
|
|
|
|
|
brlinkpath = os.path.join(brportpath, "bridge")
|
|
|
|
|
dest = os.readlink(brlinkpath)
|
|
|
|
|
(ignore,bridge) = os.path.split(dest)
|
|
|
|
|
return bridge
|
|
|
|
|
except:
|
2008-11-18 15:42:51 -05:00
|
|
|
(_type, value, stacktrace) = sys.exc_info ()
|
2008-02-18 10:01:21 -05:00
|
|
|
logging.error("Unable to determine if device is shared:" +
|
2008-11-18 15:42:51 -05:00
|
|
|
str(_type) + " " + str(value) + "\n" + \
|
2008-02-18 10:01:21 -05:00
|
|
|
traceback.format_exc (stacktrace))
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def _net_get_mac_address(self, name, sysfspath):
|
|
|
|
|
mac = None
|
|
|
|
|
addrpath = sysfspath + "/address"
|
|
|
|
|
if os.path.exists(addrpath):
|
|
|
|
|
df = open(addrpath, 'r')
|
2008-06-25 11:56:36 -04:00
|
|
|
mac = df.readline().strip(" \n\t")
|
2008-02-18 10:01:21 -05:00
|
|
|
df.close()
|
2008-06-25 11:56:36 -04:00
|
|
|
return mac
|
2008-02-18 10:01:21 -05:00
|
|
|
|
|
|
|
|
def _net_get_bonding_masters(self):
|
|
|
|
|
masters = []
|
2008-02-21 07:37:22 -05:00
|
|
|
if os.path.exists("/sys/class/net/bonding_masters"):
|
|
|
|
|
f = open("/sys/class/net/bonding_masters")
|
|
|
|
|
while True:
|
|
|
|
|
rline = f.readline()
|
2008-11-18 17:01:22 -05:00
|
|
|
if not rline:
|
|
|
|
|
break
|
|
|
|
|
if rline == "\x00":
|
|
|
|
|
continue
|
2008-02-21 07:37:22 -05:00
|
|
|
rline = rline.strip("\n\t")
|
2008-07-15 13:34:39 -04:00
|
|
|
masters = rline[:].split(' ')
|
2008-05-21 13:34:02 -04:00
|
|
|
return masters
|
2008-02-18 10:01:21 -05:00
|
|
|
|
2008-04-08 13:30:47 -05:00
|
|
|
def _net_is_bonding_slave(self, name, sysfspath):
|
|
|
|
|
masterpath = sysfspath + "/master"
|
|
|
|
|
if os.path.exists(masterpath):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
2006-06-14 13:52:46 -04:00
|
|
|
gobject.type_register(vmmConnection)
|
2006-06-14 10:59:40 -04:00
|
|
|
|