2006-06-28 23:50:17 +04:00
#
2015-02-24 15:21:24 +03:00
# Copyright (C) 2006, 2013, 2014, 2015 Red Hat, Inc.
2006-06-28 23:50:17 +04:00
# 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 19:12:20 +03:00
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
2006-06-28 23:50:17 +04:00
#
2006-06-14 18:59:40 +04:00
2012-05-14 17:24:56 +04:00
from gi . repository import GObject
2006-10-25 20:18:06 +04:00
import logging
2010-12-10 19:47:07 +03:00
import os
2015-04-02 02:10:16 +03:00
import threading
2011-04-29 01:11:04 +04:00
import time
2012-01-28 03:31:21 +04:00
import traceback
2010-01-06 21:09:33 +03:00
import libvirt
2008-02-22 19:48:29 +03:00
import virtinst
2013-07-07 21:53:37 +04:00
from virtinst import pollhelpers
2015-04-02 02:10:16 +03:00
from virtinst import support
2013-08-09 17:23:01 +04:00
from virtinst import util
2006-06-14 18:59:40 +04:00
2014-09-13 00:10:45 +04:00
from . import connectauth
from . baseclass import vmmGObject
from . domain import vmmDomain
from . interface import vmmInterface
from . network import vmmNetwork
from . nodedev import vmmNodeDevice
from . storagepool import vmmStoragePool
2006-06-14 18:59:40 +04:00
2012-01-28 03:31:21 +04:00
2014-06-02 20:00:07 +04:00
# debugging helper to turn off events
2015-09-17 22:18:22 +03:00
# Can be enabled with virt-manager --test-no-events
FORCE_DISABLE_EVENTS = False
2014-06-02 20:00:07 +04:00
2015-04-10 17:33:04 +03:00
class _ObjectList ( vmmGObject ) :
"""
Class that wraps our internal list of libvirt objects
"""
def __init__ ( self ) :
vmmGObject . __init__ ( self )
self . _objects = [ ]
2015-09-17 22:48:42 +03:00
self . _blacklist = [ ]
2015-04-10 17:33:04 +03:00
self . _lock = threading . Lock ( )
def _cleanup ( self ) :
try :
self . _lock . acquire ( )
for obj in self . _objects :
try :
obj . cleanup ( )
except :
logging . debug ( " Failed to cleanup %s " , exc_info = True )
self . _objects = [ ]
finally :
self . _lock . release ( )
2015-09-17 22:48:42 +03:00
def _blacklist_key ( self , obj ) :
return str ( obj . __class__ ) + obj . get_connkey ( )
def add_blacklist ( self , obj ) :
"""
Add an object to the blacklist . Basically a list of objects we
choose not to poll , because they threw an error at init time
: param obj : vmmLibvirtObject to blacklist
: returns : True if object added , False if object was already in list
"""
if self . in_blacklist ( obj ) :
return False
self . _blacklist . append ( self . _blacklist_key ( obj ) )
return True
def in_blacklist ( self , obj ) :
"""
: param obj : vmmLibvirtObject to check
: returns : True if object is in the blacklist
"""
return self . _blacklist_key ( obj ) in self . _blacklist
2015-04-10 17:33:04 +03:00
def remove ( self , obj ) :
"""
Remove an object from the list .
: param obj : vmmLibvirtObject to remove
: returns : True if object removed , False if object was not found
"""
try :
self . _lock . acquire ( )
# Identity check is sufficient here, since we should never be
# asked to remove an object that wasn't at one point in the list.
if obj not in self . _objects :
2015-09-17 22:48:42 +03:00
if self . in_blacklist ( obj ) :
self . _blacklist . remove ( self . _blacklist_key ( obj ) )
return True
2015-04-10 17:33:04 +03:00
return False
self . _objects . remove ( obj )
return True
finally :
self . _lock . release ( )
def add ( self , obj ) :
"""
Add an object to the list .
: param obj : vmmLibvirtObject to add
: returns : True if object added , False if object already in the list
"""
try :
self . _lock . acquire ( )
# We don't look up based on identity here, to prevent tick()
# races from adding the same domain twice
#
# We don't use lookup_object here since we need to hold the
# lock the whole time to prevent a 'time of check' issue
for checkobj in self . _objects :
if ( checkobj . __class__ == obj . __class__ and
checkobj . get_connkey ( ) == obj . get_connkey ( ) ) :
return False
if obj in self . _objects :
return False
self . _objects . append ( obj )
return True
finally :
self . _lock . release ( )
def get_objects_for_class ( self , classobj ) :
"""
Return all objects over the passed vmmLibvirtObject class
"""
try :
self . _lock . acquire ( )
return [ o for o in self . _objects if o . __class__ is classobj ]
finally :
self . _lock . release ( )
def lookup_object ( self , classobj , connkey ) :
"""
Lookup an object with the passed classobj + connkey
"""
# Doesn't require locking, since get_objects_for_class covers us
for obj in self . get_objects_for_class ( classobj ) :
if obj . get_connkey ( ) == connkey :
return obj
return None
2010-12-09 20:37:48 +03:00
class vmmConnection ( vmmGObject ) :
2012-05-14 17:24:56 +04:00
__gsignals__ = {
" vm-added " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" vm-removed " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
2015-11-03 23:56:39 +03:00
" vm-renamed " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
2012-05-14 17:24:56 +04:00
" net-added " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" net-removed " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" pool-added " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" pool-removed " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" interface-added " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" interface-removed " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" nodedev-added " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" nodedev-removed " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" resources-sampled " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
" state-changed " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
2013-07-07 04:03:42 +04:00
" connect-error " : ( GObject . SignalFlags . RUN_FIRST , None ,
[ str , str , bool ] ) ,
" priority-tick " : ( GObject . SignalFlags . RUN_FIRST , None , [ object ] ) ,
2012-05-14 17:24:56 +04:00
}
2006-06-14 21:52:46 +04:00
2014-09-12 02:16:21 +04:00
( _STATE_DISCONNECTED ,
_STATE_CONNECTING ,
_STATE_ACTIVE ) = range ( 1 , 4 )
2007-09-10 06:57:24 +04:00
2013-07-03 21:56:43 +04:00
def __init__ ( self , uri ) :
2010-12-09 20:37:48 +03:00
vmmGObject . __init__ ( self )
2009-07-01 22:59:13 +04:00
2011-05-03 21:11:33 +04:00
self . _uri = uri
if self . _uri is None or self . _uri . lower ( ) == " xen " :
self . _uri = " xen:/// "
2007-04-13 03:43:31 +04:00
2014-09-12 02:16:21 +04:00
self . _state = self . _STATE_DISCONNECTED
2013-07-05 16:59:58 +04:00
self . _backend = virtinst . VirtualConnection ( self . _uri )
2014-04-16 18:32:52 +04:00
self . _closing = False
2009-11-20 01:38:43 +03:00
2015-04-10 21:08:25 +03:00
self . _init_object_count = None
self . _init_object_event = None
2013-07-07 01:24:51 +04:00
self . _network_capable = None
2011-04-08 01:57:19 +04:00
self . _storage_capable = None
2013-07-07 01:24:51 +04:00
self . _interface_capable = None
2009-11-25 22:50:27 +03:00
self . _nodedev_capable = None
2014-02-11 22:19:15 +04:00
2014-02-11 21:07:13 +04:00
self . using_domain_events = False
2014-03-31 20:43:49 +04:00
self . _domain_cb_ids = [ ]
2014-02-11 22:19:15 +04:00
self . using_network_events = False
2014-03-31 20:43:49 +04:00
self . _network_cb_ids = [ ]
2010-02-26 03:35:01 +03:00
self . _xml_flags = { }
2006-06-14 18:59:40 +04:00
2015-04-10 17:33:04 +03:00
self . _objects = _ObjectList ( )
2015-05-05 01:16:09 +03:00
self . _stats = [ ]
self . _hostinfo = None
2006-06-14 18:59:40 +04:00
2015-04-11 20:39:25 +03:00
self . add_gsettings_handle (
self . _on_config_pretty_name_changed (
self . _config_pretty_name_changed_cb ) )
2013-07-08 02:54:08 +04:00
self . _init_virtconn ( )
2013-07-05 16:59:58 +04:00
2014-01-27 02:42:24 +04:00
@staticmethod
def pretty_hv ( gtype , domtype ) :
"""
Convert XML < domain type = ' foo ' > and < os > < type > bar < / type >
into a more human relevant string .
"""
gtype = gtype . lower ( )
domtype = domtype . lower ( )
label = domtype
2015-04-03 23:25:57 +03:00
if domtype == " xen " :
2014-01-27 02:42:24 +04:00
if gtype == " xen " :
label = " xen (paravirt) "
elif gtype == " hvm " :
label = " xen (fullvirt) "
elif domtype == " test " :
if gtype == " xen " :
label = " test (xen) "
elif gtype == " hvm " :
label = " test (hvm) "
2015-09-15 01:31:56 +03:00
elif domtype == " qemu " :
label = " QEMU TCG "
elif domtype == " kvm " :
label = " KVM "
2014-01-27 02:42:24 +04:00
return label
2009-11-26 01:07:12 +03:00
#################
# Init routines #
#################
2013-07-08 02:54:08 +04:00
def _init_virtconn ( self ) :
2013-07-10 03:50:49 +04:00
self . _backend . cb_fetch_all_guests = (
2013-09-29 04:05:13 +04:00
lambda : [ obj . get_xmlobj ( refresh_if_nec = False )
2015-04-10 17:33:04 +03:00
for obj in self . list_vms ( ) ] )
2013-09-29 04:05:13 +04:00
self . _backend . cb_fetch_all_pools = (
lambda : [ obj . get_xmlobj ( refresh_if_nec = False )
2015-04-10 17:33:04 +03:00
for obj in self . list_pools ( ) ] )
2014-09-20 19:30:24 +04:00
self . _backend . cb_fetch_all_nodedevs = (
lambda : [ obj . get_xmlobj ( refresh_if_nec = False )
2015-04-10 17:33:04 +03:00
for obj in self . list_nodedevs ( ) ] )
2014-02-27 22:16:21 +04:00
def fetch_all_vols ( ) :
ret = [ ]
2015-04-10 17:33:04 +03:00
for pool in self . list_pools ( ) :
2015-04-10 19:52:42 +03:00
for vol in pool . get_volumes ( ) :
2014-02-27 22:16:21 +04:00
try :
ret . append ( vol . get_xmlobj ( refresh_if_nec = False ) )
2014-03-06 21:04:08 +04:00
except Exception , e :
2014-02-27 22:16:21 +04:00
logging . debug ( " Fetching volume XML failed: %s " , e )
return ret
self . _backend . cb_fetch_all_vols = fetch_all_vols
2013-09-29 04:05:13 +04:00
2014-01-18 23:57:39 +04:00
def clear_cache ( pools = False ) :
if not pools :
return
2015-04-13 23:56:46 +03:00
# This isn't synchronous, so any virtinst callers need to
# take that into account.
self . schedule_priority_tick ( pollpool = True )
2014-01-18 23:57:39 +04:00
self . _backend . cb_clear_cache = clear_cache
2013-04-16 03:34:10 +04:00
2009-11-26 01:07:12 +03:00
########################
# General data getters #
########################
2009-11-26 00:12:03 +03:00
2009-11-26 00:13:46 +03:00
def get_uri ( self ) :
2011-05-03 21:11:33 +04:00
return self . _uri
2013-07-05 16:59:58 +04:00
def get_backend ( self ) :
return self . _backend
2009-03-09 23:16:45 +03:00
2010-12-08 20:17:14 +03:00
def invalidate_caps ( self ) :
2013-07-06 22:12:13 +04:00
return self . _backend . invalidate_caps ( )
caps = property ( lambda self : getattr ( self , " _backend " ) . caps )
2009-11-26 00:13:46 +03:00
def host_memory_size ( self ) :
2013-07-05 16:59:58 +04:00
if not self . _backend . is_open ( ) :
2009-11-26 00:13:46 +03:00
return 0
2015-05-05 01:16:09 +03:00
return self . _hostinfo [ 1 ] * 1024
2009-11-26 00:13:46 +03:00
def host_active_processor_count ( self ) :
2013-07-05 16:59:58 +04:00
if not self . _backend . is_open ( ) :
2009-11-26 00:13:46 +03:00
return 0
2015-05-05 01:16:09 +03:00
return self . _hostinfo [ 2 ]
2009-11-26 00:13:46 +03:00
2009-11-30 19:56:41 +03:00
def connect ( self , name , callback , * args ) :
2011-04-11 21:06:59 +04:00
handle_id = vmmGObject . connect ( self , name , callback , * args )
2009-11-26 00:13:46 +03:00
if name == " vm-added " :
2015-04-10 17:33:04 +03:00
for vm in self . list_vms ( ) :
self . emit ( " vm-added " , vm . get_connkey ( ) )
2009-11-26 00:13:46 +03:00
return handle_id
2015-04-07 20:56:48 +03:00
2009-11-26 00:13:46 +03:00
##########################
# URI + hostname helpers #
##########################
2009-11-15 23:17:03 +03:00
2015-04-16 18:21:34 +03:00
def libvirt_gethostname ( self ) :
return self . _backend . getHostname ( )
2006-11-06 18:34:54 +03:00
2013-07-06 04:36:28 +04:00
get_uri_hostname = property ( lambda s :
2015-04-11 19:08:57 +03:00
getattr ( s , " _backend " ) . get_uri_hostname )
2015-04-11 19:57:32 +03:00
get_uri_username = property ( lambda s :
getattr ( s , " _backend " ) . get_uri_username )
2015-04-11 19:08:57 +03:00
get_uri_transport = property ( lambda s :
getattr ( s , " _backend " ) . get_uri_transport )
get_uri_port = property ( lambda s : getattr ( s , " _backend " ) . get_uri_port )
2013-07-06 04:36:28 +04:00
get_driver = property ( lambda s : getattr ( s , " _backend " ) . get_uri_driver )
is_container = property ( lambda s : getattr ( s , " _backend " ) . is_container )
is_lxc = property ( lambda s : getattr ( s , " _backend " ) . is_lxc )
is_openvz = property ( lambda s : getattr ( s , " _backend " ) . is_openvz )
is_xen = property ( lambda s : getattr ( s , " _backend " ) . is_xen )
is_remote = property ( lambda s : getattr ( s , " _backend " ) . is_remote )
is_qemu = property ( lambda s : getattr ( s , " _backend " ) . is_qemu )
is_qemu_system = property ( lambda s : getattr ( s , " _backend " ) . is_qemu_system )
is_qemu_session = property ( lambda s :
getattr ( s , " _backend " ) . is_qemu_session )
is_test_conn = property ( lambda s : getattr ( s , " _backend " ) . is_test )
is_session_uri = property ( lambda s : getattr ( s , " _backend " ) . is_session_uri )
2009-03-09 23:16:45 +03:00
2010-12-11 02:03:51 +03:00
2010-02-11 04:26:40 +03:00
# Connection capabilities debug helpers
2015-02-24 15:21:24 +03:00
def stable_defaults ( self , * args , * * kwargs ) :
return self . _backend . stable_defaults ( * args , * * kwargs )
2011-09-27 02:53:00 +04:00
2013-10-01 05:41:10 +04:00
def get_cache_dir ( self ) :
uri = self . get_uri ( ) . replace ( " / " , " _ " )
ret = os . path . join ( util . get_cache_dir ( ) , uri )
if not os . path . exists ( ret ) :
2013-11-01 16:26:24 +04:00
os . makedirs ( ret , 0755 )
2013-10-01 05:41:10 +04:00
return ret
2013-10-02 23:17:15 +04:00
def get_default_storage_format ( self ) :
raw = self . config . get_default_storage_format ( raw = True )
if raw != " default " :
return raw
fmt = self . config . get_default_storage_format ( )
if fmt != " qcow2 " :
2014-02-11 03:47:58 +04:00
return fmt
2013-10-02 23:17:15 +04:00
2013-10-06 18:08:04 +04:00
if self . check_support ( self . _backend . SUPPORT_CONN_DEFAULT_QCOW2 ) :
2013-10-02 23:17:15 +04:00
return fmt
return None
2010-02-11 04:26:40 +03:00
2014-02-11 03:47:58 +04:00
2013-07-06 22:12:13 +04:00
####################################
# Connection pretty print routines #
####################################
2010-02-11 04:26:40 +03:00
2015-04-11 19:57:32 +03:00
def get_pretty_desc ( self ) :
2014-07-08 01:57:50 +04:00
"""
2015-04-11 19:57:32 +03:00
Return a pretty label for use in the manager view , and various
connection lists .
2014-07-08 01:57:50 +04:00
"""
2015-04-11 20:39:25 +03:00
if self . _get_config_pretty_name ( ) :
return self . _get_config_pretty_name ( )
2009-07-29 03:21:56 +04:00
2011-06-08 03:41:02 +04:00
pretty_map = {
" esx " : " ESX " ,
" gsx " : " GSX " ,
" libxl " : " libxl " ,
" lxc " : " LXC " ,
" openvz " : " OpenVZ " ,
" phyp " : " phyp " ,
2015-04-11 19:57:32 +03:00
" qemu " : " QEMU/KVM " ,
2011-06-08 03:41:02 +04:00
" test " : " test " ,
" uml " : " UML " ,
" vbox " : " VBox " ,
" vmware " : " VMWare " ,
2015-09-16 02:30:09 +03:00
" xen " : " Xen " ,
2011-06-08 03:41:02 +04:00
" xenapi " : " XenAPI " ,
}
2015-04-11 19:57:32 +03:00
hv = pretty_map . get ( self . get_driver ( ) , self . get_driver ( ) )
hostname = self . get_uri_hostname ( )
path = self . get_backend ( ) . get_uri_path ( )
is_session = self . get_backend ( ) . is_session_uri ( )
2014-07-08 01:57:50 +04:00
2015-04-11 19:57:32 +03:00
ret = hv
2010-12-12 07:51:20 +03:00
2015-04-11 19:57:32 +03:00
if is_session :
2015-05-03 02:20:18 +03:00
ret + = " User session "
2015-09-16 02:30:09 +03:00
elif ( path and path != " /system " and os . path . basename ( path ) ) :
2015-04-11 19:57:32 +03:00
# Used by test URIs to report what XML file they are using
ret + = " %s " % os . path . basename ( path )
2009-07-20 22:47:50 +04:00
2015-04-11 19:57:32 +03:00
if hostname :
2015-05-03 02:20:18 +03:00
ret + = " : %s " % hostname
2013-07-17 01:15:51 +04:00
2015-04-11 19:57:32 +03:00
return ret
2009-07-20 22:47:50 +04:00
2009-11-26 00:13:46 +03:00
#######################
# API support helpers #
#######################
2013-07-06 19:20:28 +04:00
for _supportname in [ _supportname for _supportname in
dir ( virtinst . VirtualConnection ) if
_supportname . startswith ( " SUPPORT_ " ) ] :
locals ( ) [ _supportname ] = getattr ( virtinst . VirtualConnection ,
_supportname )
2013-10-06 18:08:04 +04:00
def check_support ( self , * args ) :
return self . _backend . check_support ( * args )
2013-07-06 19:20:28 +04:00
2009-11-26 00:13:46 +03:00
def is_storage_capable ( self ) :
2012-11-08 17:15:02 +04:00
if self . _storage_capable is None :
2013-10-06 18:08:04 +04:00
self . _storage_capable = self . check_support (
2013-07-06 19:20:28 +04:00
self . _backend . SUPPORT_CONN_STORAGE )
2011-04-08 01:57:19 +04:00
if self . _storage_capable is False :
logging . debug ( " Connection doesn ' t seem to support storage "
" APIs. Skipping all storage polling. " )
else :
# Try to create the default storage pool
try :
2013-09-20 04:18:12 +04:00
virtinst . StoragePool . build_default_pool ( self . get_backend ( ) )
2011-04-08 01:57:19 +04:00
except Exception , e :
2012-01-17 07:04:40 +04:00
logging . debug ( " Building default pool failed: %s " , str ( e ) )
2011-04-08 01:57:19 +04:00
return self . _storage_capable
2009-11-26 00:13:46 +03:00
2011-04-10 05:51:50 +04:00
def is_network_capable ( self ) :
2013-07-07 01:24:51 +04:00
if self . _network_capable is None :
2013-10-06 18:08:04 +04:00
self . _network_capable = self . check_support (
2013-07-06 19:20:28 +04:00
self . _backend . SUPPORT_CONN_NETWORK )
2013-07-07 01:24:51 +04:00
if self . _network_capable is False :
2011-04-10 05:51:50 +04:00
logging . debug ( " Connection doesn ' t seem to support network "
" APIs. Skipping all network polling. " )
2013-07-07 01:24:51 +04:00
return self . _network_capable
2011-04-10 05:51:50 +04:00
def is_interface_capable ( self ) :
2013-07-07 01:24:51 +04:00
if self . _interface_capable is None :
2013-10-06 18:08:04 +04:00
self . _interface_capable = self . check_support (
2013-07-06 19:20:28 +04:00
self . _backend . SUPPORT_CONN_INTERFACE )
2013-07-07 01:24:51 +04:00
if self . _interface_capable is False :
2011-04-10 05:51:50 +04:00
logging . debug ( " Connection doesn ' t seem to support interface "
" APIs. Skipping all interface polling. " )
2013-07-07 01:24:51 +04:00
return self . _interface_capable
2011-04-10 05:51:50 +04:00
2009-11-26 00:13:46 +03:00
def is_nodedev_capable ( self ) :
2012-11-08 17:15:02 +04:00
if self . _nodedev_capable is None :
2013-10-06 18:08:04 +04:00
self . _nodedev_capable = self . check_support (
2013-07-06 19:20:28 +04:00
self . _backend . SUPPORT_CONN_NODEDEV )
2009-11-25 22:50:27 +03:00
return self . _nodedev_capable
2009-11-26 00:13:46 +03:00
2010-02-26 03:35:01 +03:00
def _get_flags_helper ( self , obj , key , check_func ) :
2010-12-09 19:22:35 +03:00
ignore = obj
2010-02-26 03:35:01 +03:00
flags_dict = self . _xml_flags . get ( key )
2009-11-26 00:13:46 +03:00
2012-11-08 17:15:02 +04:00
if flags_dict is None :
2010-02-26 03:35:01 +03:00
# Flags already set
inact , act = check_func ( )
flags_dict = { }
flags_dict [ " active " ] = act
flags_dict [ " inactive " ] = inact
self . _xml_flags [ key ] = flags_dict
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
2013-10-06 18:08:04 +04:00
if self . check_support (
self . _backend . SUPPORT_DOMAIN_XML_INACTIVE , vm ) :
2010-02-26 03:35:01 +03:00
inact = libvirt . VIR_DOMAIN_XML_INACTIVE
else :
logging . debug ( " Domain XML inactive flag not supported. " )
2013-10-06 18:08:04 +04:00
if self . check_support (
self . _backend . SUPPORT_DOMAIN_XML_SECURE , vm ) :
2010-02-26 03:35:01 +03:00
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 )
2009-11-26 00:13:46 +03:00
2010-02-26 03:35:01 +03:00
def get_interface_flags ( self , iface ) :
key = " interface "
def check_func ( ) :
act = 0
inact = 0
2013-10-06 18:08:04 +04:00
if self . check_support (
self . _backend . SUPPORT_INTERFACE_XML_INACTIVE , iface ) :
2010-02-26 03:35:01 +03:00
inact = libvirt . VIR_INTERFACE_XML_INACTIVE
else :
logging . debug ( " Interface XML inactive flag not supported. " )
2009-11-26 00:13:46 +03:00
2010-02-26 03:35:01 +03:00
return ( inact , act )
2009-11-26 00:13:46 +03:00
2010-02-26 03:35:01 +03:00
return self . _get_flags_helper ( iface , key , check_func )
2009-11-26 00:13:46 +03:00
2014-06-03 01:17:47 +04:00
def get_default_pool ( self ) :
2015-04-10 17:33:04 +03:00
for p in self . list_pools ( ) :
2014-06-03 01:17:47 +04:00
if p . get_name ( ) == " default " :
return p
return None
def get_vol_by_path ( self , path ) :
2015-04-10 17:33:04 +03:00
for pool in self . list_pools ( ) :
2015-04-10 19:52:42 +03:00
for vol in pool . get_volumes ( ) :
2014-12-05 04:38:55 +03:00
try :
if vol . get_target_path ( ) == path :
return vol
except Exception , e :
# Errors can happen if the volume disappeared, bug 1092739
logging . debug ( " Error looking up volume from path= %s : %s " ,
path , e )
2014-06-03 01:17:47 +04:00
return None
2013-07-06 19:20:28 +04:00
2009-11-26 00:13:46 +03:00
###################################
# Connection state getter/setters #
###################################
def _change_state ( self , newstate ) :
2014-09-12 02:16:21 +04:00
if self . _state != newstate :
self . _state = newstate
2014-09-12 02:48:04 +04:00
logging . debug ( " conn= %s changed to state= %s " ,
self . get_uri ( ) , self . get_state_text ( ) )
2009-11-26 00:13:46 +03:00
self . emit ( " state-changed " )
2014-09-12 02:16:21 +04:00
def is_active ( self ) :
return self . _state == self . _STATE_ACTIVE
def is_disconnected ( self ) :
return self . _state == self . _STATE_DISCONNECTED
def is_connecting ( self ) :
return self . _state == self . _STATE_CONNECTING
2009-11-26 00:13:46 +03:00
def get_state_text ( self ) :
2014-09-12 02:16:21 +04:00
if self . is_disconnected ( ) :
2009-11-26 00:13:46 +03:00
return _ ( " Disconnected " )
2014-09-12 02:16:21 +04:00
elif self . is_connecting ( ) :
2009-11-26 00:13:46 +03:00
return _ ( " Connecting " )
2014-09-12 02:16:21 +04:00
elif self . is_active ( ) :
2013-07-03 21:56:43 +04:00
return _ ( " Active " )
2009-11-26 00:13:46 +03:00
else :
return _ ( " Unknown " )
2014-06-03 01:17:47 +04:00
2009-11-26 00:13:46 +03:00
#################################
# Libvirt object lookup methods #
#################################
2006-06-14 22:36:26 +04:00
2014-06-03 01:17:47 +04:00
def get_vm ( self , connkey ) :
2015-04-10 17:33:04 +03:00
return self . _objects . lookup_object ( vmmDomain , connkey )
2014-06-03 01:17:47 +04:00
def list_vms ( self ) :
2015-04-10 17:33:04 +03:00
return self . _objects . get_objects_for_class ( vmmDomain )
2014-06-03 01:17:47 +04:00
def get_net ( self , connkey ) :
2015-04-10 17:33:04 +03:00
return self . _objects . lookup_object ( vmmNetwork , connkey )
2014-06-03 01:17:47 +04:00
def list_nets ( self ) :
2015-04-10 17:33:04 +03:00
return self . _objects . get_objects_for_class ( vmmNetwork )
2014-06-03 01:17:47 +04:00
def get_pool ( self , connkey ) :
2015-04-10 17:33:04 +03:00
return self . _objects . lookup_object ( vmmStoragePool , connkey )
2014-06-03 01:17:47 +04:00
def list_pools ( self ) :
2015-04-10 17:33:04 +03:00
return self . _objects . get_objects_for_class ( vmmStoragePool )
2014-06-03 01:17:47 +04:00
def get_interface ( self , connkey ) :
2015-04-10 17:33:04 +03:00
return self . _objects . lookup_object ( vmmInterface , connkey )
2014-06-03 01:17:47 +04:00
def list_interfaces ( self ) :
2015-04-10 17:33:04 +03:00
return self . _objects . get_objects_for_class ( vmmInterface )
2014-06-03 01:17:47 +04:00
def get_nodedev ( self , connkey ) :
2015-04-10 17:33:04 +03:00
return self . _objects . lookup_object ( vmmNodeDevice , connkey )
def list_nodedevs ( self ) :
return self . _objects . get_objects_for_class ( vmmNodeDevice )
2015-04-10 16:37:03 +03:00
############################
# nodedev helper functions #
############################
def filter_nodedevs ( self , devtype = None , devcap = None ) :
2009-03-09 23:20:23 +03:00
retdevs = [ ]
2015-04-10 17:33:04 +03:00
for dev in self . list_nodedevs ( ) :
2015-06-06 21:20:21 +03:00
try :
xmlobj = dev . get_xmlobj ( )
except libvirt . libvirtError , e :
2015-06-09 18:41:39 +03:00
# Libvirt nodedev XML fetching can be busted
# https://bugzilla.redhat.com/show_bug.cgi?id=1225771
if e . get_error_code ( ) != libvirt . VIR_ERR_NO_NODE_DEVICE :
logging . debug ( " Error fetching nodedev XML " , exc_info = True )
continue
2015-06-06 21:20:21 +03:00
2013-10-05 22:40:38 +04:00
if devtype and xmlobj . device_type != devtype :
2009-03-09 23:20:23 +03:00
continue
2009-11-25 22:50:27 +03:00
if devcap :
2013-10-05 22:40:38 +04:00
if ( not hasattr ( xmlobj , " capability_type " ) or
xmlobj . capability_type != devcap ) :
2009-11-25 22:50:27 +03:00
continue
2013-10-05 22:40:38 +04:00
if ( devtype == " usb_device " and
( ( " Linux Foundation " in str ( xmlobj . vendor_name ) or
( " Linux " in str ( xmlobj . vendor_name ) and
xmlobj . vendor_id == " 0x1d6b " ) ) and
( " root hub " in str ( xmlobj . product_name ) or
( " host controller " in str ( xmlobj . product_name ) . lower ( ) and
str ( xmlobj . product_id ) . startswith ( " 0x000 " ) ) ) ) ) :
continue
2015-04-07 21:12:00 +03:00
retdevs . append ( dev )
2009-03-09 23:20:23 +03:00
return retdevs
2015-04-10 16:37:03 +03:00
def get_nodedev_count ( self , devtype , vendor , product ) :
2013-04-30 18:53:10 +04:00
count = 0
2015-04-10 16:37:03 +03:00
devs = self . filter_nodedevs ( devtype )
2013-04-30 18:53:10 +04:00
for dev in devs :
2015-04-07 21:12:00 +03:00
if ( vendor == dev . xmlobj . vendor_id and
product == dev . xmlobj . product_id ) :
2013-04-30 18:53:10 +04:00
count + = 1
logging . debug ( " There are %d node devices with "
" vendorId: %s , productId: %s " ,
count , vendor , product )
return count
2009-11-26 00:13:46 +03:00
###################################
# Libvirt object creation methods #
###################################
2013-09-29 20:14:00 +04:00
def define_domain ( self , xml ) :
return self . _backend . defineXML ( xml )
def define_network ( self , xml ) :
return self . _backend . networkDefineXML ( xml )
def define_pool ( self , xml ) :
return self . _backend . storagePoolDefineXML ( xml , 0 )
def define_interface ( self , xml ) :
return self . _backend . interfaceDefineXML ( xml , 0 )
2009-12-11 21:45:53 +03:00
2015-11-03 23:56:39 +03:00
def rename_object ( self , obj , origxml , newxml , oldconnkey ) :
2015-04-10 16:15:44 +03:00
if obj . class_name ( ) == " domain " :
2014-09-21 00:55:11 +04:00
define_cb = self . define_domain
2015-04-10 16:15:44 +03:00
elif obj . class_name ( ) == " pool " :
2014-09-21 00:55:11 +04:00
define_cb = self . define_pool
2015-04-10 16:15:44 +03:00
elif obj . class_name ( ) == " network " :
2014-09-21 00:55:11 +04:00
define_cb = self . define_network
else :
raise RuntimeError ( " programming error: rename_object "
" helper doesn ' t support object class %s " % obj . __class__ )
2013-09-29 20:14:00 +04:00
# Undefine the original object
2013-09-30 23:23:14 +04:00
obj . delete ( force = False )
2011-03-23 23:56:12 +03:00
newobj = None
try :
2014-09-21 00:55:11 +04:00
# Redefine new domain
newobj = define_cb ( newxml )
except Exception , renameerr :
2011-03-23 23:56:12 +03:00
try :
2015-04-10 16:15:44 +03:00
logging . debug ( " Error defining new name %s XML " ,
obj . class_name ( ) , exc_info = True )
2014-09-21 00:55:11 +04:00
newobj = define_cb ( origxml )
except Exception , fixerr :
2015-04-10 16:15:44 +03:00
logging . debug ( " Failed to redefine original %s ! " ,
obj . class_name ( ) , exc_info = True )
2014-09-21 00:55:11 +04:00
raise RuntimeError (
_ ( " %s rename failed. Attempting to recover also "
" failed. \n \n "
" Original error: %s \n \n "
" Recover error: %s " %
2015-04-10 16:15:44 +03:00
( obj . class_name ( ) , str ( renameerr ) , str ( fixerr ) ) ) )
2014-09-21 00:55:11 +04:00
raise
2011-03-23 23:56:12 +03:00
finally :
if newobj :
2013-09-29 20:14:00 +04:00
# Reinsert handle into new obj
obj . change_name_backend ( newobj )
2015-11-03 23:56:39 +03:00
if newobj and obj . class_name ( ) == " domain " :
self . emit ( " vm-renamed " , oldconnkey , obj . get_connkey ( ) )
2009-11-26 00:13:46 +03:00
2014-02-11 21:07:13 +04:00
#########################
# Domain event handling #
#########################
# Our strategy here isn't the most efficient: since we need to keep the
# poll helpers around for compat with old libvirt, switching to a fully
# event driven setup is hard, so we end up doing more polling than
# necessary on most events.
2014-03-31 20:43:49 +04:00
def _domain_xml_misc_event ( self , conn , domain , * args ) :
# Just trigger a domain XML refresh for hotplug type events
ignore = conn
2015-04-14 01:02:16 +03:00
name = domain . name ( )
logging . debug ( " domain xmlmisc event: domain= %s args= %s " , name , args )
obj = self . get_vm ( name )
2014-03-31 20:43:49 +04:00
if not obj :
return
2015-04-10 01:02:42 +03:00
2015-04-12 00:18:25 +03:00
self . idle_add ( obj . refresh_from_event_loop )
2014-03-31 20:43:49 +04:00
2014-02-11 21:07:13 +04:00
def _domain_lifecycle_event ( self , conn , domain , event , reason , userdata ) :
ignore = conn
ignore = userdata
2015-04-14 01:02:16 +03:00
name = domain . name ( )
logging . debug ( " domain lifecycle event: domain= %s event= %s "
" reason= %s " , name , event , reason )
obj = self . get_vm ( name )
2014-02-11 21:07:13 +04:00
2014-02-11 22:19:15 +04:00
if obj :
2015-04-12 00:18:25 +03:00
self . idle_add ( obj . refresh_from_event_loop )
2014-02-11 21:07:13 +04:00
else :
self . schedule_priority_tick ( pollvm = True , force = True )
2014-02-11 22:19:15 +04:00
def _network_lifecycle_event ( self , conn , network , event , reason , userdata ) :
ignore = conn
ignore = userdata
2015-04-14 01:02:16 +03:00
name = network . name ( )
logging . debug ( " network lifecycle event: network= %s event= %s "
" reason= %s " , name , event , reason )
obj = self . get_net ( name )
2014-02-11 22:19:15 +04:00
if obj :
2015-04-12 00:18:25 +03:00
self . idle_add ( obj . refresh_from_event_loop )
2014-02-11 22:19:15 +04:00
else :
self . schedule_priority_tick ( pollnet = True , force = True )
2014-02-11 21:07:13 +04:00
2014-02-11 22:19:15 +04:00
def _add_conn_events ( self ) :
2015-02-25 18:25:21 +03:00
if not self . check_support ( support . SUPPORT_CONN_WORKING_XEN_EVENTS ) :
return
2014-02-11 21:07:13 +04:00
try :
2015-09-17 22:18:22 +03:00
if FORCE_DISABLE_EVENTS :
raise RuntimeError ( " FORCE_DISABLE_EVENTS = True " )
2014-06-02 20:00:07 +04:00
2014-03-31 20:43:49 +04:00
self . _domain_cb_ids . append (
self . get_backend ( ) . domainEventRegisterAny (
2014-02-11 22:27:59 +04:00
None , libvirt . VIR_DOMAIN_EVENT_ID_LIFECYCLE ,
2014-03-31 20:43:49 +04:00
self . _domain_lifecycle_event , None ) )
2014-02-11 21:07:13 +04:00
self . using_domain_events = True
2014-02-11 22:27:59 +04:00
logging . debug ( " Using domain events " )
2014-02-11 21:07:13 +04:00
except Exception , e :
self . using_domain_events = False
logging . debug ( " Error registering domain events: %s " , e )
2014-03-31 20:43:49 +04:00
def _add_domain_xml_event ( eventid , typestr ) :
if not self . using_domain_events :
return
try :
self . _domain_cb_ids . append (
self . get_backend ( ) . domainEventRegisterAny (
None , eventid , self . _domain_xml_misc_event , None ) )
except Exception , e :
logging . debug ( " Error registering domain %s event: %s " ,
typestr , e )
_add_domain_xml_event (
getattr ( libvirt , " VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE " , 13 ) ,
" balloon " )
_add_domain_xml_event (
getattr ( libvirt , " VIR_DOMAIN_EVENT_ID_TRAY_CHANGE " , 10 ) , " tray " )
_add_domain_xml_event (
getattr ( libvirt , " VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED " , 15 ) ,
" device removed " )
2015-04-29 12:00:40 +03:00
_add_domain_xml_event (
getattr ( libvirt , " VIR_DOMAIN_EVENT_ID_DEVICE_ADDED " , 19 ) ,
" device added " )
2014-03-31 20:43:49 +04:00
2014-02-11 22:19:15 +04:00
try :
2015-09-17 22:18:22 +03:00
if FORCE_DISABLE_EVENTS :
raise RuntimeError ( " FORCE_DISABLE_EVENTS = True " )
2014-06-02 20:00:07 +04:00
2014-03-22 19:21:19 +04:00
eventid = getattr ( libvirt , " VIR_NETWORK_EVENT_ID_LIFECYCLE " , 0 )
2014-03-31 20:43:49 +04:00
self . _network_cb_ids . append (
self . get_backend ( ) . networkEventRegisterAny (
None , eventid , self . _network_lifecycle_event , None ) )
2014-02-11 22:19:15 +04:00
self . using_network_events = True
2014-02-11 22:27:59 +04:00
logging . debug ( " Using network events " )
2014-02-11 22:19:15 +04:00
except Exception , e :
self . using_network_events = False
logging . debug ( " Error registering network events: %s " , e )
2013-07-07 05:31:50 +04:00
2009-11-26 00:13:46 +03:00
######################################
# Connection closing/opening methods #
######################################
2014-09-12 02:48:04 +04:00
def _schedule_close ( self ) :
self . _closing = True
self . idle_add ( self . close )
2009-11-26 00:13:46 +03:00
def close ( self ) :
2014-09-12 02:16:21 +04:00
if not self . is_disconnected ( ) :
2014-04-16 18:32:52 +04:00
logging . debug ( " conn.close() uri= %s " , self . get_uri ( ) )
self . _closing = True
2014-03-10 17:33:04 +04:00
try :
if not self . _backend . is_closed ( ) :
2014-03-31 20:43:49 +04:00
for eid in self . _domain_cb_ids :
self . _backend . domainEventDeregisterAny ( eid )
for eid in self . _network_cb_ids :
self . _backend . networkEventDeregisterAny ( eid )
2014-03-10 17:33:04 +04:00
except :
logging . debug ( " Failed to deregister events in conn cleanup " ,
exc_info = True )
2014-04-16 20:23:57 +04:00
finally :
self . _domain_cb_ids = [ ]
self . _network_cb_ids = [ ]
2014-02-11 22:27:59 +04:00
2013-07-05 16:59:58 +04:00
self . _backend . close ( )
2015-05-05 01:16:09 +03:00
self . _stats = [ ]
2011-04-11 19:00:57 +04:00
2015-04-10 21:08:25 +03:00
if self . _init_object_event :
self . _init_object_event . clear ( )
2015-04-10 17:33:04 +03:00
self . _objects . cleanup ( )
self . _objects = _ObjectList ( )
2011-03-23 17:07:23 +03:00
2014-09-12 02:16:21 +04:00
self . _change_state ( self . _STATE_DISCONNECTED )
2014-04-16 18:32:52 +04:00
self . _closing = False
2009-11-26 00:13:46 +03:00
2011-07-24 05:16:54 +04:00
def _cleanup ( self ) :
2011-04-13 17:27:02 +04:00
self . close ( )
2015-09-20 21:20:50 +03:00
self . _objects = None
self . _backend . cb_fetch_all_guests = None
self . _backend . cb_fetch_all_pools = None
self . _backend . cb_fetch_all_nodedevs = None
self . _backend . cb_fetch_all_vols = None
self . _backend . cb_clear_cache = None
2015-04-10 20:26:54 +03:00
def open ( self ) :
2014-09-12 02:16:21 +04:00
if not self . is_disconnected ( ) :
2007-09-10 06:57:24 +04:00
return
2014-09-12 02:16:21 +04:00
self . _change_state ( self . _STATE_CONNECTING )
2007-09-11 04:56:01 +04:00
2015-04-10 20:26:54 +03:00
logging . debug ( " Scheduling background open thread for " +
self . get_uri ( ) )
self . _start_thread ( self . _open_thread , " Connect %s " % self . get_uri ( ) )
2007-09-11 04:56:01 +04:00
2013-07-05 16:59:58 +04:00
def _do_creds_password ( self , creds ) :
2008-01-31 19:39:10 +03:00
try :
2015-04-11 19:08:57 +03:00
return connectauth . creds_dialog ( self , creds )
2014-07-05 01:37:22 +04:00
except :
logging . debug ( " Launching creds dialog failed " , exc_info = True )
2008-01-31 19:39:10 +03:00
return - 1
2007-09-11 04:56:01 +04:00
2014-09-12 02:48:04 +04:00
def _do_open ( self , retry_for_tgt = True ) :
warnconsole = False
libvirt_error_code = None
libvirt_error_message = None
2009-03-09 23:21:32 +03:00
2014-09-12 02:48:04 +04:00
try :
self . _backend . open ( self . _do_creds_password )
2014-09-12 19:30:09 +04:00
return True , None
2014-09-12 02:48:04 +04:00
except Exception , exc :
tb = " " . join ( traceback . format_exc ( ) )
if type ( exc ) is libvirt . libvirtError :
libvirt_error_code = exc . get_error_code ( )
libvirt_error_message = exc . get_error_message ( )
if ( libvirt_error_code ==
getattr ( libvirt , " VIR_ERR_AUTH_CANCELLED " , None ) ) :
logging . debug ( " User cancelled auth, not raising any error. " )
2014-09-12 19:30:09 +04:00
return False , None
2007-09-11 04:56:01 +04:00
2014-09-12 02:48:04 +04:00
if ( libvirt_error_code == libvirt . VIR_ERR_AUTH_FAILED and
" not authorized " in libvirt_error_message . lower ( ) ) :
logging . debug ( " Looks like we might have failed policykit "
" auth. Checking to see if we have a valid "
" console session " )
if ( not self . is_remote ( ) and
not connectauth . do_we_have_session ( ) ) :
warnconsole = True
if ( libvirt_error_code == libvirt . VIR_ERR_AUTH_FAILED and
" GSSAPI Error " in libvirt_error_message and
" No credentials cache found " in libvirt_error_message ) :
if retry_for_tgt and connectauth . acquire_tgt ( ) :
self . _do_open ( retry_for_tgt = False )
2014-09-12 19:30:09 +04:00
connectError = ( str ( exc ) , tb , warnconsole )
return False , connectError
2014-09-12 02:48:04 +04:00
def _populate_initial_state ( self ) :
logging . debug ( " libvirt version= %s " ,
self . _backend . local_libvirt_version ( ) )
logging . debug ( " daemon version= %s " ,
self . _backend . daemon_version ( ) )
logging . debug ( " conn version= %s " , self . _backend . conn_version ( ) )
logging . debug ( " %s capabilities: \n %s " ,
2015-04-03 19:40:16 +03:00
self . get_uri ( ) , self . caps . get_xml_config ( ) )
2014-09-12 02:48:04 +04:00
self . _add_conn_events ( )
2007-09-11 04:56:01 +04:00
2014-09-12 17:36:09 +04:00
# Prime CPU cache
2015-04-03 23:09:25 +03:00
self . caps . get_cpu_values ( " x86_64 " )
2014-09-12 17:36:09 +04:00
2014-09-12 02:48:04 +04:00
try :
self . _backend . setKeepAlive ( 20 , 1 )
except Exception , e :
if ( type ( e ) is not AttributeError and
not util . is_error_nosupport ( e ) ) :
raise
logging . debug ( " Connection doesn ' t support KeepAlive, "
" skipping " )
2009-07-12 05:23:16 +04:00
2015-04-10 21:08:25 +03:00
# The initial tick will set up a threading event that will only
# trigger after all the polled libvirt objects are fully initialized.
# That way we only report the connection is open when everything is
# nicely setup for the rest of the app.
self . _init_object_event = threading . Event ( )
self . _init_object_count = 0
self . schedule_priority_tick ( stats_update = True ,
pollvm = True , pollnet = True ,
pollpool = True , polliface = True ,
pollnodedev = True , force = True , initial_poll = True )
self . _init_object_event . wait ( )
self . _init_object_event = None
self . _init_object_count = None
2014-09-12 02:48:04 +04:00
def _open_thread ( self ) :
2014-07-05 01:37:42 +04:00
try :
2014-09-12 19:30:09 +04:00
is_active , connectError = self . _do_open ( )
2014-09-12 02:48:04 +04:00
if is_active :
self . _populate_initial_state ( )
2014-07-05 01:43:24 +04:00
2015-04-10 21:08:25 +03:00
self . idle_add ( self . _change_state , is_active and
self . _STATE_ACTIVE or self . _STATE_DISCONNECTED )
2014-07-05 01:37:42 +04:00
except Exception , e :
2014-09-12 02:48:04 +04:00
is_active = False
self . _schedule_close ( )
2014-09-12 19:30:09 +04:00
connectError = ( str ( e ) , " " . join ( traceback . format_exc ( ) ) , False )
2010-11-24 22:01:51 +03:00
2014-09-12 02:48:04 +04:00
if not is_active :
2014-09-12 19:30:09 +04:00
if connectError :
self . idle_emit ( " connect-error " , * connectError )
2007-09-11 04:56:01 +04:00
2006-10-11 01:24:59 +04:00
2009-11-26 00:13:46 +03:00
#######################
# Tick/Update methods #
#######################
2006-06-14 18:59:40 +04:00
2015-04-10 21:08:25 +03:00
def _gone_object_signals ( self , gone_objects ) :
2015-04-10 17:33:04 +03:00
"""
Responsible for signaling the UI for any updates . All possible UI
updates need to go here to enable threading that doesn ' t block the
app with long tick operations .
"""
if not self . _backend . is_open ( ) :
return
2015-04-10 16:15:44 +03:00
for obj in gone_objects :
2015-04-10 21:08:25 +03:00
class_name = obj . class_name ( )
2015-05-07 19:30:28 +03:00
try :
name = obj . get_name ( )
except :
name = str ( obj )
2015-04-10 21:08:25 +03:00
2015-04-10 17:33:04 +03:00
if not self . _objects . remove ( obj ) :
2015-04-10 21:08:25 +03:00
logging . debug ( " Requested removal of %s = %s , but it ' s "
2015-05-07 19:30:28 +03:00
" not in our object list. " , class_name , name )
2015-04-10 17:33:04 +03:00
continue
2015-05-07 19:30:28 +03:00
logging . debug ( " %s = %s removed " , class_name , name )
2015-04-10 16:15:44 +03:00
if class_name == " domain " :
self . emit ( " vm-removed " , obj . get_connkey ( ) )
elif class_name == " network " :
self . emit ( " net-removed " , obj . get_connkey ( ) )
elif class_name == " pool " :
self . emit ( " pool-removed " , obj . get_connkey ( ) )
elif class_name == " interface " :
self . emit ( " interface-removed " , obj . get_connkey ( ) )
elif class_name == " nodedev " :
self . emit ( " nodedev-removed " , obj . get_connkey ( ) )
obj . cleanup ( )
2015-09-17 22:48:42 +03:00
def _new_object_cb ( self , obj , initialize_failed ) :
2015-04-10 21:08:25 +03:00
if not self . _backend . is_open ( ) :
return
2015-04-10 17:33:04 +03:00
2015-04-10 21:08:25 +03:00
try :
2015-04-10 16:15:44 +03:00
class_name = obj . class_name ( )
2015-04-10 21:08:25 +03:00
2015-09-17 22:48:42 +03:00
if initialize_failed :
logging . debug ( " Blacklisting %s = %s " , class_name , obj . get_name ( ) )
if self . _objects . add_blacklist ( obj ) is False :
logging . debug ( " Object already blacklisted? " )
return
2015-04-10 21:08:25 +03:00
if not self . _objects . add ( obj ) :
logging . debug ( " New %s = %s requested, but it ' s already tracked. " ,
class_name , obj . get_name ( ) )
return
2015-04-10 16:15:44 +03:00
if class_name != " nodedev " :
# Skip nodedev logging since it's noisy and not interesting
logging . debug ( " %s = %s status= %s added " , class_name ,
obj . get_name ( ) , obj . run_status ( ) )
if class_name == " domain " :
self . emit ( " vm-added " , obj . get_connkey ( ) )
elif class_name == " network " :
self . emit ( " net-added " , obj . get_connkey ( ) )
elif class_name == " pool " :
self . emit ( " pool-added " , obj . get_connkey ( ) )
elif class_name == " interface " :
self . emit ( " interface-added " , obj . get_connkey ( ) )
elif class_name == " nodedev " :
self . emit ( " nodedev-added " , obj . get_connkey ( ) )
2015-04-10 21:08:25 +03:00
finally :
if self . _init_object_event :
self . _init_object_count - = 1
if self . _init_object_count < = 0 :
self . _init_object_event . set ( )
2014-09-12 19:55:34 +04:00
2015-04-10 19:52:42 +03:00
def _update_nets ( self , dopoll ) :
keymap = dict ( ( o . get_connkey ( ) , o ) for o in self . list_nets ( ) )
if not dopoll or not self . is_network_capable ( ) :
return [ ] , [ ] , keymap . values ( )
return pollhelpers . fetch_nets ( self . _backend , keymap ,
( lambda obj , key : vmmNetwork ( self , obj , key ) ) )
def _update_pools ( self , dopoll ) :
keymap = dict ( ( o . get_connkey ( ) , o ) for o in self . list_pools ( ) )
if not dopoll or not self . is_storage_capable ( ) :
return [ ] , [ ] , keymap . values ( )
return pollhelpers . fetch_pools ( self . _backend , keymap ,
( lambda obj , key : vmmStoragePool ( self , obj , key ) ) )
def _update_interfaces ( self , dopoll ) :
keymap = dict ( ( o . get_connkey ( ) , o ) for o in self . list_interfaces ( ) )
if not dopoll or not self . is_interface_capable ( ) :
return [ ] , [ ] , keymap . values ( )
return pollhelpers . fetch_interfaces ( self . _backend , keymap ,
( lambda obj , key : vmmInterface ( self , obj , key ) ) )
def _update_nodedevs ( self , dopoll ) :
keymap = dict ( ( o . get_connkey ( ) , o ) for o in self . list_nodedevs ( ) )
if not dopoll or not self . is_nodedev_capable ( ) :
return [ ] , [ ] , keymap . values ( )
return pollhelpers . fetch_nodedevs ( self . _backend , keymap ,
( lambda obj , key : vmmNodeDevice ( self , obj , key ) ) )
def _update_vms ( self , dopoll ) :
keymap = dict ( ( o . get_connkey ( ) , o ) for o in self . list_vms ( ) )
if not dopoll :
return [ ] , [ ] , keymap . values ( )
return pollhelpers . fetch_vms ( self . _backend , keymap ,
( lambda obj , key : vmmDomain ( self , obj , key ) ) )
2015-04-10 21:08:25 +03:00
def _poll ( self , initial_poll ,
pollvm , pollnet , pollpool , polliface , pollnodedev ) :
2015-04-10 19:52:42 +03:00
"""
Helper called from tick ( ) to do necessary polling and return
the relevant object lists
"""
gone_objects = [ ]
preexisting_objects = [ ]
def _process_objects ( polloutput ) :
gone , new , master = polloutput
2015-04-10 21:08:25 +03:00
if initial_poll :
self . _init_object_count + = len ( new )
2015-04-10 19:52:42 +03:00
gone_objects . extend ( gone )
preexisting_objects . extend ( [ o for o in master if o not in new ] )
2015-09-17 22:48:42 +03:00
new = [ n for n in new if not self . _objects . in_blacklist ( n ) ]
2015-04-10 19:52:42 +03:00
return new
2015-04-10 21:08:25 +03:00
new_vms = _process_objects ( self . _update_vms ( pollvm ) )
new_nets = _process_objects ( self . _update_nets ( pollnet ) )
new_pools = _process_objects ( self . _update_pools ( pollpool ) )
new_ifaces = _process_objects ( self . _update_interfaces ( polliface ) )
new_nodedevs = _process_objects ( self . _update_nodedevs ( pollnodedev ) )
# Kick off one thread per object type to handle the initial
# XML fetching. Going any more fine grained then this probably
# won't be that useful due to libvirt's locking structure.
#
# Would prefer to start refreshing some objects before all polling
# is complete, but we need init_object_count to be fully accurate
# before we start initializing objects
for newlist in [ new_vms , new_nets , new_pools ,
new_ifaces , new_nodedevs ] :
if not newlist :
continue
def cb ( lst ) :
for obj in lst :
obj . connect_once ( " initialized " , self . _new_object_cb )
obj . init_libvirt_state ( )
2015-04-10 19:52:42 +03:00
2015-04-10 21:08:25 +03:00
self . _start_thread ( cb ,
" refreshing xml for new %s " % newlist [ 0 ] . class_name ( ) ,
args = ( newlist , ) )
2015-04-10 19:52:42 +03:00
2015-04-10 21:08:25 +03:00
return gone_objects , preexisting_objects
2015-04-10 19:52:42 +03:00
2015-04-13 23:56:46 +03:00
def _tick ( self , stats_update = False ,
2013-07-07 19:06:15 +04:00
pollvm = False , pollnet = False ,
pollpool = False , polliface = False ,
2015-04-07 20:56:48 +03:00
pollnodedev = False ,
2015-04-10 21:08:25 +03:00
force = False , initial_poll = False ) :
2014-02-11 21:07:13 +04:00
"""
main update function : polls for new objects , updates stats , . . .
2015-04-10 19:52:42 +03:00
: param force : Perform the requested polling even if async events
2015-04-10 21:08:25 +03:00
are in use .
2014-02-11 21:07:13 +04:00
"""
2014-09-12 03:12:43 +04:00
if self . _closing :
2008-07-10 01:00:49 +04:00
return
2014-09-12 03:12:43 +04:00
if self . is_disconnected ( ) :
return
2015-04-10 21:08:25 +03:00
if self . is_connecting ( ) and not force :
return
2006-10-09 21:28:13 +04:00
2015-04-10 19:52:42 +03:00
# We need to set this before the event check, since stats polling
# is independent of events
2013-07-07 19:06:15 +04:00
if not pollvm :
stats_update = False
2014-02-11 22:19:15 +04:00
2014-02-11 21:07:13 +04:00
if self . using_domain_events and not force :
pollvm = False
2014-02-11 22:19:15 +04:00
if self . using_network_events and not force :
pollnet = False
2013-07-07 19:06:15 +04:00
2015-05-05 01:16:09 +03:00
self . _hostinfo = self . _backend . getInfo ( )
2008-10-06 21:21:06 +04:00
2015-04-10 21:08:25 +03:00
gone_objects , preexisting_objects = self . _poll (
initial_poll , pollvm , pollnet , pollpool , polliface , pollnodedev )
self . idle_add ( self . _gone_object_signals , gone_objects )
2008-08-08 01:37:16 +04:00
2015-04-10 19:52:42 +03:00
# Only tick() pre-existing objects, since new objects will be
# initialized asynchronously and tick() would be redundant
for obj in preexisting_objects :
2009-09-17 00:02:19 +04:00
try :
2015-04-10 19:52:42 +03:00
if obj . reports_stats ( ) and stats_update :
pass
elif obj . __class__ is vmmDomain and not pollvm :
continue
elif obj . __class__ is vmmNetwork and not pollnet :
continue
elif obj . __class__ is vmmStoragePool and not pollpool :
continue
elif obj . __class__ is vmmInterface and not polliface :
continue
elif obj . __class__ is vmmNodeDevice and not pollnodedev :
continue
2015-04-10 16:15:44 +03:00
obj . tick ( stats_update = stats_update )
2009-09-17 00:02:19 +04:00
except Exception , e :
2013-07-07 16:05:23 +04:00
logging . exception ( " Tick for %s failed " , obj )
2012-01-29 20:26:24 +04:00
if ( isinstance ( e , libvirt . libvirtError ) and
2012-02-01 04:07:32 +04:00
( getattr ( e , " get_error_code " ) ( ) ==
libvirt . VIR_ERR_SYSTEM_ERROR ) ) :
2012-01-29 20:26:24 +04:00
# Try a simple getInfo call to see if conn was dropped
2013-07-05 16:59:58 +04:00
self . _backend . getInfo ( )
2012-01-29 20:26:24 +04:00
logging . debug ( " vm tick raised system error but "
" connection doesn ' t seem to have dropped. "
" Ignoring. " )
2007-03-28 03:52:00 +04:00
2013-07-07 17:42:21 +04:00
if stats_update :
2015-04-10 19:52:42 +03:00
self . _recalculate_stats (
[ o for o in preexisting_objects if o . reports_stats ( ) ] )
2011-04-18 19:12:36 +04:00
self . idle_emit ( " resources-sampled " )
2009-07-12 05:23:16 +04:00
2013-07-07 16:12:15 +04:00
def _recalculate_stats ( self , vms ) :
2013-07-05 16:59:58 +04:00
if not self . _backend . is_open ( ) :
2010-02-11 23:25:41 +03:00
return
2013-07-07 16:12:15 +04:00
now = time . time ( )
2007-03-28 03:52:00 +04:00
expected = self . config . get_stats_history_length ( )
2015-05-05 01:16:09 +03:00
current = len ( self . _stats )
2007-03-28 03:52:00 +04:00
if current > expected :
2015-05-05 01:16:09 +03:00
del self . _stats [ expected : current ]
2007-03-28 03:52:00 +04:00
mem = 0
cpuTime = 0
2008-10-18 23:21:33 +04:00
rdRate = 0
wrRate = 0
rxRate = 0
txRate = 0
2011-07-25 23:09:42 +04:00
diskMaxRate = self . disk_io_max_rate ( ) or 10.0
netMaxRate = self . network_traffic_max_rate ( ) or 10.0
2007-03-28 03:52:00 +04:00
2013-07-07 05:42:41 +04:00
for vm in vms :
2011-04-10 06:40:22 +04:00
if not vm . is_active ( ) :
continue
cpuTime + = vm . cpu_time ( )
2011-04-10 08:02:39 +04:00
mem + = vm . stats_memory ( )
2011-04-10 06:40:22 +04:00
rdRate + = vm . disk_read_rate ( )
wrRate + = vm . disk_write_rate ( )
rxRate + = vm . network_rx_rate ( )
txRate + = vm . network_tx_rate ( )
2007-03-28 03:52:00 +04:00
2011-07-25 23:09:42 +04:00
netMaxRate = max ( netMaxRate , vm . network_traffic_max_rate ( ) )
diskMaxRate = max ( diskMaxRate , vm . disk_io_max_rate ( ) )
2011-07-12 05:22:50 +04:00
pcentHostCpu = 0
pcentMem = mem * 100.0 / self . host_memory_size ( )
2015-05-05 01:16:09 +03:00
if len ( self . _stats ) > 0 :
prevTimestamp = self . _stats [ 0 ] [ " timestamp " ]
2010-12-10 19:47:07 +03:00
host_cpus = self . host_active_processor_count ( )
2011-07-12 05:22:50 +04:00
pcentHostCpu = ( ( cpuTime ) * 100.0 /
2010-12-10 19:47:07 +03:00
( ( now - prevTimestamp ) *
1000.0 * 1000.0 * 1000.0 * host_cpus ) )
2007-03-28 03:52:00 +04:00
2011-07-12 05:22:50 +04:00
pcentHostCpu = max ( 0.0 , min ( 100.0 , pcentHostCpu ) )
pcentMem = max ( 0.0 , min ( 100.0 , pcentMem ) )
2007-03-28 03:52:00 +04:00
newStats = {
" timestamp " : now ,
" memory " : mem ,
" memoryPercent " : pcentMem ,
" cpuTime " : cpuTime ,
2011-07-12 05:22:50 +04:00
" cpuHostPercent " : pcentHostCpu ,
2008-10-18 23:21:33 +04:00
" diskRdRate " : rdRate ,
" diskWrRate " : wrRate ,
" netRxRate " : rxRate ,
" netTxRate " : txRate ,
2011-07-25 23:09:42 +04:00
" diskMaxRate " : diskMaxRate ,
" netMaxRate " : netMaxRate ,
2007-03-28 03:52:00 +04:00
}
2015-05-05 01:16:09 +03:00
self . _stats . insert ( 0 , newStats )
2007-03-28 03:52:00 +04:00
2009-11-26 00:13:46 +03:00
2015-04-10 19:52:42 +03:00
def schedule_priority_tick ( self , * * kwargs ) :
self . idle_emit ( " priority-tick " , kwargs )
2015-04-13 23:56:46 +03:00
def tick_from_engine ( self , * args , * * kwargs ) :
2015-04-10 19:52:42 +03:00
e = None
try :
self . _tick ( * args , * * kwargs )
except KeyboardInterrupt :
raise
except Exception , e :
pass
if e is None :
return
from_remote = getattr ( libvirt , " VIR_FROM_REMOTE " , None )
from_rpc = getattr ( libvirt , " VIR_FROM_RPC " , None )
sys_error = getattr ( libvirt , " VIR_ERR_SYSTEM_ERROR " , None )
2016-01-05 12:17:37 +03:00
internal_error = getattr ( libvirt , " VIR_ERR_INTERNAL_ERROR " , None )
2015-04-10 19:52:42 +03:00
dom = - 1
code = - 1
if isinstance ( e , libvirt . libvirtError ) :
dom = e . get_error_domain ( )
code = e . get_error_code ( )
logging . debug ( " Error polling connection %s " ,
self . get_uri ( ) , exc_info = True )
if ( dom in [ from_remote , from_rpc ] and
2016-01-05 12:17:37 +03:00
code in [ sys_error , internal_error ] ) :
2015-04-10 19:52:42 +03:00
e = None
logging . debug ( " Not showing user error since libvirtd "
" appears to have stopped. " )
self . _schedule_close ( )
if e :
raise e # pylint: disable=raising-bad-type
2009-11-26 00:13:46 +03:00
########################
# Stats getter methods #
########################
2012-05-14 17:24:56 +04:00
2015-05-04 23:33:56 +03:00
def _get_record_helper ( self , record_name ) :
2015-05-05 01:16:09 +03:00
if len ( self . _stats ) == 0 :
2015-05-04 23:33:56 +03:00
return 0
2015-05-05 01:16:09 +03:00
return self . _stats [ 0 ] [ record_name ]
2015-05-04 23:33:56 +03:00
def _vector_helper ( self , record_name , limit , ceil = 100.0 ) :
2007-03-28 03:52:00 +04:00
vector = [ ]
2015-05-04 23:33:56 +03:00
statslen = self . config . get_stats_history_length ( ) + 1
if limit is not None :
statslen = min ( statslen , limit )
for i in range ( statslen ) :
2015-05-05 01:16:09 +03:00
if i < len ( self . _stats ) :
vector . append ( self . _stats [ i ] [ record_name ] / ceil )
2007-03-28 03:52:00 +04:00
else :
vector . append ( 0 )
2013-04-12 16:26:21 +04:00
2015-05-04 23:33:56 +03:00
return vector
2011-04-14 20:20:02 +04:00
2015-05-04 23:33:56 +03:00
def stats_memory_vector ( self , limit = None ) :
return self . _vector_helper ( " memoryPercent " , limit )
def host_cpu_time_vector ( self , limit = None ) :
return self . _vector_helper ( " cpuHostPercent " , limit )
2011-04-14 20:20:02 +04:00
def stats_memory ( self ) :
return self . _get_record_helper ( " memory " )
2011-07-12 05:22:50 +04:00
def host_cpu_time_percentage ( self ) :
return self . _get_record_helper ( " cpuHostPercent " )
2015-05-04 23:33:56 +03:00
def guest_cpu_time_percentage ( self ) :
return self . host_cpu_time_percentage ( )
2008-10-18 23:21:33 +04:00
def network_traffic_rate ( self ) :
2015-05-04 23:33:56 +03:00
return ( self . _get_record_helper ( " netRxRate " ) +
self . _get_record_helper ( " netTxRate " ) )
def disk_io_rate ( self ) :
return ( self . _get_record_helper ( " diskRdRate " ) +
self . _get_record_helper ( " diskWrRate " ) )
2011-07-25 23:09:42 +04:00
def network_traffic_max_rate ( self ) :
return self . _get_record_helper ( " netMaxRate " )
def disk_io_max_rate ( self ) :
return self . _get_record_helper ( " diskMaxRate " )
2015-04-11 20:39:25 +03:00
###########################
# Per-conn config helpers #
###########################
def get_autoconnect ( self ) :
return self . config . get_conn_autoconnect ( self . get_uri ( ) )
def set_autoconnect ( self , val ) :
self . config . set_conn_autoconnect ( self . get_uri ( ) , val )
def set_config_pretty_name ( self , value ) :
2015-09-16 02:35:30 +03:00
cfgname = self . _get_config_pretty_name ( )
if value == cfgname :
return
if not cfgname and value == self . get_pretty_desc ( ) :
# Don't encode the default connection value into gconf right
# away, require the user to edit it first
return
self . config . set_perconn ( self . get_uri ( ) , " /pretty-name " , value )
2015-04-11 20:39:25 +03:00
def _get_config_pretty_name ( self ) :
return self . config . get_perconn ( self . get_uri ( ) , " /pretty-name " )
def _on_config_pretty_name_changed ( self , * args , * * kwargs ) :
return self . config . listen_perconn ( self . get_uri ( ) , " /pretty-name " ,
* args , * * kwargs )
def _config_pretty_name_changed_cb ( self ) :
self . emit ( " state-changed " )