2013-07-05 16:59:58 +04:00
#
2015-02-24 15:21:24 +03:00
# Copyright 2013, 2014, 2015 Red Hat, Inc.
2013-07-05 16:59:58 +04:00
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2013-07-05 16:59:58 +04:00
2019-06-08 00:50:58 +03:00
import os
2013-07-10 03:50:49 +04:00
import weakref
2013-07-05 16:59:58 +04:00
import libvirt
2020-07-18 01:46:54 +03:00
from . import Capabilities
2014-09-12 23:59:22 +04:00
from . import pollhelpers
from . import support
2020-07-18 01:46:54 +03:00
from . import xmlutil
2014-09-12 23:59:22 +04:00
from . guest import Guest
2019-06-17 04:12:39 +03:00
from . logger import log
2014-09-20 19:30:24 +04:00
from . nodedev import NodeDevice
2014-09-12 23:59:22 +04:00
from . storage import StoragePool , StorageVolume
2015-09-06 17:36:17 +03:00
from . uri import URI , MagicURI
2013-07-05 16:59:58 +04:00
2013-07-11 03:42:28 +04:00
2019-06-08 00:15:10 +03:00
def _real_local_libvirt_version ( ) :
"""
Lookup the local libvirt library version , but cache the value since
it never changes .
"""
key = " __virtinst_cached_getVersion "
if not hasattr ( libvirt , key ) :
setattr ( libvirt , key , libvirt . getVersion ( ) )
return getattr ( libvirt , key )
2018-03-20 19:18:35 +03:00
class VirtinstConnection ( object ) :
2013-07-05 16:59:58 +04:00
"""
Wrapper for libvirt connection that provides various bits like
- caching static data
- lookup for API feature support
- simplified API wrappers that handle new and old ways of doing things
"""
2019-06-08 00:50:58 +03:00
@staticmethod
def get_app_cache_dir ( ) :
2020-01-27 12:49:54 +03:00
ret = os . environ . get ( " XDG_CACHE_HOME " )
2019-06-08 00:50:58 +03:00
if not ret :
ret = os . path . expanduser ( " ~/.cache " )
return os . path . join ( ret , " virt-manager " )
2019-06-08 04:40:47 +03:00
@staticmethod
def in_testsuite ( ) :
2020-07-18 01:46:54 +03:00
return xmlutil . in_testsuite ( )
2019-06-08 04:40:47 +03:00
2013-07-05 16:59:58 +04:00
def __init__ ( self , uri ) :
2015-09-06 17:36:17 +03:00
_initial_uri = uri or " "
if MagicURI . uri_is_magic ( _initial_uri ) :
self . _magic_uri = MagicURI ( _initial_uri )
self . _open_uri = self . _magic_uri . open_uri
2020-02-03 02:16:48 +03:00
self . _uri = self . _magic_uri . fakeuri or self . _open_uri
2015-09-06 17:36:17 +03:00
self . _fake_conn_predictable = self . _magic_uri . predictable
self . _fake_conn_version = self . _magic_uri . conn_version
self . _fake_libvirt_version = self . _magic_uri . libvirt_version
else :
self . _magic_uri = None
self . _open_uri = _initial_uri
self . _uri = _initial_uri
self . _fake_conn_predictable = False
self . _fake_libvirt_version = None
self . _fake_conn_version = None
2013-07-06 04:36:28 +04:00
2013-07-17 01:15:51 +04:00
self . _daemon_version = None
self . _conn_version = None
2013-07-06 04:36:28 +04:00
self . _libvirtconn = None
2015-09-06 17:36:17 +03:00
self . _uriobj = URI ( self . _uri )
2013-07-06 23:53:35 +04:00
self . _caps = None
2013-07-06 23:39:00 +04:00
2013-07-08 00:38:11 +04:00
self . _fetch_cache = { }
2013-07-08 02:54:08 +04:00
# These let virt-manager register a callback which provides its
# own cached object lists, rather than doing fresh calls
2018-08-31 22:20:50 +03:00
self . cb_fetch_all_domains = None
2013-07-08 02:54:08 +04:00
self . cb_fetch_all_pools = None
2013-09-29 04:05:13 +04:00
self . cb_fetch_all_vols = None
2014-09-20 19:30:24 +04:00
self . cb_fetch_all_nodedevs = None
2017-07-19 22:56:43 +03:00
self . cb_cache_new_pool = None
2013-07-08 02:54:08 +04:00
2019-06-07 21:48:59 +03:00
self . support = support . SupportCache ( weakref . proxy ( self ) )
2019-06-07 21:45:25 +03:00
2013-07-06 22:12:13 +04:00
2013-07-06 23:53:35 +04:00
##############
# Properties #
##############
2013-07-05 16:59:58 +04:00
def __getattr__ ( self , attr ) :
2014-03-20 21:34:34 +04:00
# Proxy virConnect API calls
2013-07-05 16:59:58 +04:00
libvirtconn = self . __dict__ . get ( " _libvirtconn " )
return getattr ( libvirtconn , attr )
2013-07-06 04:36:28 +04:00
def _get_uri ( self ) :
return self . _uri or self . _open_uri
uri = property ( _get_uri )
2013-07-06 22:12:13 +04:00
def _get_caps ( self ) :
if not self . _caps :
2022-06-28 23:56:09 +03:00
capsxml = self . _libvirtconn . getCapabilities ( )
self . _caps = Capabilities ( self , capsxml )
log . debug ( " Fetched capabilities for %s : %s " , self . _uri , capsxml )
2013-07-06 22:12:13 +04:00
return self . _caps
caps = property ( _get_caps )
2014-03-20 21:34:34 +04:00
def get_conn_for_api_arg ( self ) :
return self . _libvirtconn
2013-07-05 16:59:58 +04:00
2022-08-01 12:56:25 +03:00
###################
# Private helpers #
###################
def _log_versions ( self ) :
def format_version ( num ) :
major = int ( num / 1000000 )
minor = int ( num / 1000 ) % 1000
micro = num % 1000
return " %s . %s . %s " % ( major , minor , micro )
log . debug ( " libvirt URI versions library= %s driver= %s hypervisor= %s " ,
format_version ( self . local_libvirt_version ( ) ) ,
format_version ( self . daemon_version ( ) ) ,
format_version ( self . conn_version ( ) ) )
2013-07-05 16:59:58 +04:00
##############
# Public API #
##############
def close ( self ) :
2018-03-12 23:31:13 +03:00
ret = 0
if self . _libvirtconn :
ret = self . _libvirtconn . close ( )
2013-07-05 16:59:58 +04:00
self . _libvirtconn = None
2013-07-06 04:36:28 +04:00
self . _uri = None
2013-07-08 00:38:11 +04:00
self . _fetch_cache = { }
2018-03-12 23:31:13 +03:00
return ret
2013-07-05 16:59:58 +04:00
2015-09-06 17:36:17 +03:00
def fake_conn_predictable ( self ) :
return self . _fake_conn_predictable
2013-07-06 22:12:13 +04:00
def invalidate_caps ( self ) :
self . _caps = None
2013-07-05 16:59:58 +04:00
def is_open ( self ) :
return bool ( self . _libvirtconn )
2018-05-03 02:55:07 +03:00
def open ( self , authcb , cbdata ) :
2020-02-03 02:16:48 +03:00
if self . _magic_uri :
self . _magic_uri . validate ( )
2018-05-03 02:55:07 +03:00
# Mirror the set of libvirt.c virConnectCredTypeDefault
valid_auth_options = [
libvirt . VIR_CRED_AUTHNAME ,
libvirt . VIR_CRED_ECHOPROMPT ,
libvirt . VIR_CRED_REALM ,
libvirt . VIR_CRED_PASSPHRASE ,
libvirt . VIR_CRED_NOECHOPROMPT ,
libvirt . VIR_CRED_EXTERNAL ,
]
2013-07-05 16:59:58 +04:00
open_flags = 0
2013-07-06 04:36:28 +04:00
conn = libvirt . openAuth ( self . _open_uri ,
2018-05-03 02:55:07 +03:00
[ valid_auth_options , authcb , cbdata ] ,
open_flags )
2013-07-05 16:59:58 +04:00
2015-09-06 17:36:17 +03:00
if self . _magic_uri :
self . _magic_uri . overwrite_conn_functions ( conn )
2013-07-05 16:59:58 +04:00
self . _libvirtconn = conn
2013-07-14 00:31:05 +04:00
if not self . _open_uri :
self . _uri = self . _libvirtconn . getURI ( )
2015-09-06 17:36:17 +03:00
self . _uriobj = URI ( self . _uri )
2013-07-05 16:59:58 +04:00
2022-08-01 12:56:25 +03:00
self . _log_versions ( )
self . _get_caps ( ) # cache and log capabilities
2022-06-19 00:15:27 +03:00
def get_libvirt_data_root_dir ( self ) :
if self . is_privileged ( ) :
return " /var/lib/libvirt "
return os . environ . get ( " XDG_DATA_HOME " ,
os . path . expanduser ( " ~/.local/share/libvirt " ) )
2014-09-20 19:30:24 +04:00
####################
# Polling routines #
####################
2018-08-31 22:20:50 +03:00
_FETCH_KEY_DOMAINS = " vms "
2014-01-18 23:57:39 +04:00
_FETCH_KEY_POOLS = " pools "
_FETCH_KEY_VOLS = " vols "
2014-09-20 19:30:24 +04:00
_FETCH_KEY_NODEDEVS = " nodedevs "
2020-01-27 13:13:53 +03:00
def _fetch_helper ( self , key , raw_cb , override_cb ) :
if override_cb :
2020-01-27 12:49:46 +03:00
return override_cb ( ) # pragma: no cover
2020-01-27 13:13:53 +03:00
if key not in self . _fetch_cache :
self . _fetch_cache [ key ] = raw_cb ( )
return self . _fetch_cache [ key ] [ : ]
2018-08-31 22:20:50 +03:00
def _fetch_all_domains_raw ( self ) :
2020-03-30 23:04:12 +03:00
dummy1 , dummy2 , ret = pollhelpers . fetch_vms (
2015-04-10 19:52:42 +03:00
self , { } , lambda obj , ignore : obj )
2020-11-24 16:24:06 +03:00
domains = [ ]
for obj in ret :
# TOCTOU race: a domain may go away in between enumeration and inspection
try :
xml = obj . XMLDesc ( 0 )
except libvirt . libvirtError as e : # pragma: no cover
log . debug ( " Fetching domain XML failed: %s " , e )
continue
domains . append ( Guest ( weakref . proxy ( self ) , parsexml = xml ) )
return domains
2013-07-07 22:54:48 +04:00
2017-07-19 23:11:17 +03:00
def _build_pool_raw ( self , poolobj ) :
2019-06-07 22:53:36 +03:00
return StoragePool ( weakref . proxy ( self ) ,
2017-07-19 23:11:17 +03:00
parsexml = poolobj . XMLDesc ( 0 ) )
2017-07-19 22:28:07 +03:00
def _fetch_all_pools_raw ( self ) :
2020-03-30 23:04:12 +03:00
dummy1 , dummy2 , ret = pollhelpers . fetch_pools (
2015-04-10 19:52:42 +03:00
self , { } , lambda obj , ignore : obj )
2020-11-05 15:38:15 +03:00
pools = [ ]
for poolobj in ret :
# TOCTOU race: a pool may go away in between enumeration and inspection
try :
pool = self . _build_pool_raw ( poolobj )
except libvirt . libvirtError as e : # pragma: no cover
log . debug ( " Fetching pool XML failed: %s " , e )
continue
pools . append ( pool )
return pools
2013-09-29 04:05:13 +04:00
2020-01-27 13:13:53 +03:00
def _fetch_all_nodedevs_raw ( self ) :
2020-03-30 23:04:12 +03:00
dummy1 , dummy2 , ret = pollhelpers . fetch_nodedevs (
2020-01-27 13:13:53 +03:00
self , { } , lambda obj , ignore : obj )
return [ NodeDevice ( weakref . proxy ( self ) , obj . XMLDesc ( 0 ) )
for obj in ret ]
2013-09-29 04:05:13 +04:00
2017-07-19 23:11:17 +03:00
def _fetch_vols_raw ( self , poolxmlobj ) :
2013-09-29 04:05:13 +04:00
ret = [ ]
2020-11-05 15:38:15 +03:00
# TOCTOU race: a volume may go away in between enumeration and inspection
try :
pool = self . _libvirtconn . storagePoolLookupByName ( poolxmlobj . name )
2021-10-04 22:38:24 +03:00
except libvirt . libvirtError : # pragma: no cover
2020-11-05 15:38:15 +03:00
return ret
2017-07-19 23:11:17 +03:00
if pool . info ( ) [ 0 ] != libvirt . VIR_STORAGE_POOL_RUNNING :
return ret
2020-03-30 23:04:12 +03:00
dummy1 , dummy2 , vols = pollhelpers . fetch_volumes (
2017-07-19 23:11:17 +03:00
self , pool , { } , lambda obj , ignore : obj )
for vol in vols :
try :
xml = vol . XMLDesc ( 0 )
2019-06-07 22:53:36 +03:00
ret . append ( StorageVolume ( weakref . proxy ( self ) , parsexml = xml ) )
2020-11-05 15:38:15 +03:00
except libvirt . libvirtError as e : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . debug ( " Fetching volume XML failed: %s " , e )
2017-07-19 23:11:17 +03:00
return ret
2013-09-29 04:05:13 +04:00
2017-07-19 23:11:17 +03:00
def _fetch_all_vols_raw ( self ) :
ret = [ ]
for poolxmlobj in self . fetch_all_pools ( ) :
ret . extend ( self . _fetch_vols_raw ( poolxmlobj ) )
2013-07-08 00:38:11 +04:00
return ret
2013-07-07 22:54:48 +04:00
2017-07-18 22:42:11 +03:00
def _cache_new_pool_raw ( self , poolobj ) :
2017-07-19 23:11:17 +03:00
# Make sure cache is primed
if self . _FETCH_KEY_POOLS not in self . _fetch_cache :
# Nothing cached yet, so next poll will pull in latest bits,
# so there's nothing to do
return
poollist = self . _fetch_cache [ self . _FETCH_KEY_POOLS ]
poolxmlobj = self . _build_pool_raw ( poolobj )
poollist . append ( poolxmlobj )
2017-08-30 17:34:17 +03:00
if self . _FETCH_KEY_VOLS not in self . _fetch_cache :
return
2017-07-19 23:11:17 +03:00
vollist = self . _fetch_cache [ self . _FETCH_KEY_VOLS ]
vollist . extend ( self . _fetch_vols_raw ( poolxmlobj ) )
2017-07-18 22:42:11 +03:00
def cache_new_pool ( self , poolobj ) :
"""
Insert the passed poolobj into our cache
"""
if self . cb_cache_new_pool :
# pylint: disable=not-callable
return self . cb_cache_new_pool ( poolobj )
return self . _cache_new_pool_raw ( poolobj )
2020-01-27 13:13:53 +03:00
def fetch_all_domains ( self ) :
"""
Returns a list of Guest ( ) objects
"""
return self . _fetch_helper (
self . _FETCH_KEY_DOMAINS ,
self . _fetch_all_domains_raw ,
self . cb_fetch_all_domains )
def fetch_all_pools ( self ) :
"""
Returns a list of StoragePool objects
"""
return self . _fetch_helper (
self . _FETCH_KEY_POOLS ,
self . _fetch_all_pools_raw ,
self . cb_fetch_all_pools )
def fetch_all_vols ( self ) :
"""
Returns a list of StorageVolume objects
"""
return self . _fetch_helper (
self . _FETCH_KEY_VOLS ,
self . _fetch_all_vols_raw ,
self . cb_fetch_all_vols )
2014-09-20 19:30:24 +04:00
def fetch_all_nodedevs ( self ) :
"""
Returns a list of NodeDevice ( ) objects
"""
2020-01-27 13:13:53 +03:00
return self . _fetch_helper (
self . _FETCH_KEY_NODEDEVS ,
self . _fetch_all_nodedevs_raw ,
self . cb_fetch_all_nodedevs )
2013-07-26 00:21:30 +04:00
2013-07-05 16:59:58 +04:00
2013-07-11 03:42:28 +04:00
#########################
# Libvirt API overrides #
#########################
def getURI ( self ) :
return self . _uri
2013-07-06 23:39:00 +04:00
#########################
# Public version checks #
#########################
def local_libvirt_version ( self ) :
if self . _fake_libvirt_version is not None :
return self . _fake_libvirt_version
# This handles caching for us
2019-06-08 00:15:10 +03:00
return _real_local_libvirt_version ( )
2013-07-06 23:39:00 +04:00
def daemon_version ( self ) :
if self . _fake_libvirt_version is not None :
return self . _fake_libvirt_version
if not self . is_remote ( ) :
2019-06-08 00:15:10 +03:00
return _real_local_libvirt_version ( )
2013-07-06 23:39:00 +04:00
2018-09-01 00:43:58 +03:00
if self . _daemon_version is None :
self . _daemon_version = 0
try :
2014-03-20 21:34:34 +04:00
self . _daemon_version = self . _libvirtconn . getLibVersion ( )
2020-01-27 12:49:46 +03:00
except Exception : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . debug ( " Error calling getLibVersion " , exc_info = True )
2013-07-06 23:39:00 +04:00
return self . _daemon_version
def conn_version ( self ) :
if self . _fake_conn_version is not None :
return self . _fake_conn_version
2018-09-01 00:43:58 +03:00
if self . _conn_version is None :
self . _conn_version = 0
try :
2014-03-20 21:34:34 +04:00
self . _conn_version = self . _libvirtconn . getVersion ( )
2020-01-27 12:49:46 +03:00
except Exception : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . debug ( " Error calling getVersion " , exc_info = True )
2013-07-06 23:39:00 +04:00
return self . _conn_version
2013-07-06 04:36:28 +04:00
###################
# Public URI bits #
###################
def is_remote ( self ) :
2020-02-03 03:43:06 +03:00
return bool ( self . _uriobj . hostname )
def is_privileged ( self ) :
if self . get_uri_path ( ) == " /session " :
return False
if self . get_uri_path ( ) == " /embed " :
return os . getuid ( ) == 0
return True
def is_unprivileged ( self ) :
return not self . is_privileged ( )
2013-07-06 04:36:28 +04:00
def get_uri_hostname ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . hostname
2015-04-11 19:08:57 +03:00
def get_uri_port ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . port
2015-04-11 19:08:57 +03:00
def get_uri_username ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . username
2013-07-06 04:36:28 +04:00
def get_uri_transport ( self ) :
2016-06-21 18:31:26 +03:00
if self . get_uri_hostname ( ) and not self . _uriobj . transport :
# Libvirt defaults to transport=tls if hostname specified but
# no transport is specified
return " tls "
2015-09-06 17:36:17 +03:00
return self . _uriobj . transport
2015-04-11 19:57:32 +03:00
def get_uri_path ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . path
2013-07-06 04:36:28 +04:00
def get_uri_driver ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . scheme
2013-07-06 04:36:28 +04:00
def is_qemu ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . scheme . startswith ( " qemu " )
2020-02-03 03:43:06 +03:00
def is_qemu_privileged ( self ) :
return ( self . is_qemu ( ) and self . is_privileged ( ) )
def is_qemu_unprivileged ( self ) :
return ( self . is_qemu ( ) and self . is_unprivileged ( ) )
2013-07-06 04:36:28 +04:00
2014-12-09 20:36:09 +03:00
def is_really_test ( self ) :
2015-09-06 17:36:17 +03:00
return URI ( self . _open_uri ) . scheme . startswith ( " test " )
2013-07-06 04:36:28 +04:00
def is_test ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . scheme . startswith ( " test " )
2013-07-06 04:36:28 +04:00
def is_xen ( self ) :
2015-09-06 17:36:17 +03:00
return ( self . _uriobj . scheme . startswith ( " xen " ) or
self . _uriobj . scheme . startswith ( " libxl " ) )
2013-07-06 04:36:28 +04:00
def is_lxc ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . scheme . startswith ( " lxc " )
2013-07-06 04:36:28 +04:00
def is_openvz ( self ) :
2015-09-06 17:36:17 +03:00
return self . _uriobj . scheme . startswith ( " openvz " )
2020-08-22 20:22:51 +03:00
def is_container_only ( self ) :
2013-07-06 04:36:28 +04:00
return self . is_lxc ( ) or self . is_openvz ( )
2017-03-13 15:01:53 +03:00
def is_vz ( self ) :
return ( self . _uriobj . scheme . startswith ( " vz " ) or
self . _uriobj . scheme . startswith ( " parallels " ) )
2021-02-11 18:41:11 +03:00
def is_bhyve ( self ) :
return self . _uriobj . scheme . startswith ( " bhyve " )
2013-07-06 04:36:28 +04:00
2013-07-05 16:59:58 +04:00
2013-07-06 19:20:28 +04:00
#########################
# Support check helpers #
#########################
2013-10-06 18:08:04 +04:00
def support_remote_url_install ( self ) :
2020-01-27 12:49:46 +03:00
ret = self . support . conn_stream ( )
if self . _magic_uri or self . is_test ( ) :
ret = False
return self . in_testsuite ( ) or ret