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
#
# 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
2013-10-28 00:59:47 +04:00
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2013-07-05 16:59:58 +04:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
import logging
2013-07-10 03:50:49 +04:00
import weakref
2013-07-05 16:59:58 +04:00
import libvirt
2016-12-13 20:36:49 +03:00
from virtcli import CLIConfig
2014-09-12 23:59:22 +04:00
from . import pollhelpers
from . import support
from . import util
2015-04-03 19:40:16 +03:00
from . import Capabilities
2014-09-12 23:59:22 +04:00
from . guest import Guest
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
2013-07-05 16:59:58 +04:00
class VirtualConnection ( object ) :
"""
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
"""
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
self . _uri = self . _magic_uri . make_fake_uri ( )
self . _fake_conn_predictable = self . _magic_uri . predictable
self . _fake_conn_remote = self . _magic_uri . remote
self . _fake_conn_session = self . _magic_uri . session
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_conn_remote = False
self . _fake_conn_session = 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-06 23:53:35 +04:00
self . _support_cache = { }
2013-07-08 00:38:11 +04:00
self . _fetch_cache = { }
# Setting this means we only do fetch_all* once and just carry
# the result. For the virt-* CLI tools this ensures any revalidation
# isn't hammering the connection over and over
self . cache_object_fetch = False
2013-07-06 23:53:35 +04:00
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
self . cb_fetch_all_guests = None
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
2014-01-18 23:57:39 +04:00
self . cb_clear_cache = None
2013-07-08 02:54:08 +04: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 ) :
if attr in self . __dict__ :
return self . __dict__ [ 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 :
2015-04-03 19:40:16 +03:00
self . _caps = Capabilities ( self ,
self . _libvirtconn . getCapabilities ( ) )
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
##############
# Public API #
##############
2014-02-12 01:26:15 +04:00
def is_closed ( self ) :
return not bool ( self . _libvirtconn )
2013-07-05 16:59:58 +04:00
def close ( self ) :
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 = { }
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 )
def open ( self , passwordcb ) :
open_flags = 0
valid_auth_options = [ libvirt . VIR_CRED_AUTHNAME ,
libvirt . VIR_CRED_PASSPHRASE ]
authcb = self . _auth_cb
authcb_data = passwordcb
2013-07-06 04:36:28 +04:00
conn = libvirt . openAuth ( self . _open_uri ,
2013-07-05 16:59:58 +04:00
[ valid_auth_options , authcb ,
( authcb_data , valid_auth_options ) ] ,
open_flags )
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
2014-09-20 19:30:24 +04:00
def set_keep_alive ( self , interval , count ) :
if hasattr ( self . _libvirtconn , " setKeepAlive " ) :
self . _libvirtconn . setKeepAlive ( interval , count )
####################
# Polling routines #
####################
2014-01-18 23:57:39 +04:00
_FETCH_KEY_GUESTS = " vms "
_FETCH_KEY_POOLS = " pools "
_FETCH_KEY_VOLS = " vols "
2014-09-20 19:30:24 +04:00
_FETCH_KEY_NODEDEVS = " nodedevs "
def clear_cache ( self , pools = False ) :
if self . cb_clear_cache :
self . cb_clear_cache ( pools = pools ) # pylint: disable=not-callable
return
if pools :
self . _fetch_cache . pop ( self . _FETCH_KEY_POOLS , None )
2014-01-18 23:57:39 +04:00
2013-09-29 04:05:13 +04:00
def _fetch_all_guests_cached ( self ) :
2014-01-18 23:57:39 +04:00
key = self . _FETCH_KEY_GUESTS
2013-07-08 00:38:11 +04:00
if key in self . _fetch_cache :
return self . _fetch_cache [ key ]
2015-04-10 19:52:42 +03:00
ignore , ignore , ret = pollhelpers . fetch_vms (
self , { } , lambda obj , ignore : obj )
2013-07-10 03:50:49 +04:00
ret = [ Guest ( weakref . ref ( self ) , parsexml = obj . XMLDesc ( 0 ) )
2015-04-10 19:52:42 +03:00
for obj in ret ]
2013-07-08 00:38:11 +04:00
if self . cache_object_fetch :
self . _fetch_cache [ key ] = ret
return ret
2013-07-07 22:54:48 +04:00
2013-09-29 04:05:13 +04:00
def fetch_all_guests ( self ) :
"""
Returns a list of Guest ( ) objects
"""
if self . cb_fetch_all_guests :
2014-04-03 02:39:43 +04:00
return self . cb_fetch_all_guests ( ) # pylint: disable=not-callable
2013-09-29 04:05:13 +04:00
return self . _fetch_all_guests_cached ( )
2013-07-08 02:54:08 +04:00
2013-09-29 04:05:13 +04:00
def _fetch_all_pools_cached ( self ) :
2014-01-18 23:57:39 +04:00
key = self . _FETCH_KEY_POOLS
2013-07-08 00:38:11 +04:00
if key in self . _fetch_cache :
return self . _fetch_cache [ key ]
2015-04-10 19:52:42 +03:00
ignore , ignore , ret = pollhelpers . fetch_pools (
self , { } , lambda obj , ignore : obj )
2013-09-29 04:05:13 +04:00
ret = [ StoragePool ( weakref . ref ( self ) , parsexml = obj . XMLDesc ( 0 ) )
2015-04-10 19:52:42 +03:00
for obj in ret ]
2013-09-29 04:05:13 +04:00
if self . cache_object_fetch :
self . _fetch_cache [ key ] = ret
return ret
def fetch_all_pools ( self ) :
"""
Returns a list of StoragePool objects
"""
if self . cb_fetch_all_pools :
2014-04-03 02:39:43 +04:00
return self . cb_fetch_all_pools ( ) # pylint: disable=not-callable
2013-09-29 04:05:13 +04:00
return self . _fetch_all_pools_cached ( )
def _fetch_all_vols_cached ( self ) :
2014-01-18 23:57:39 +04:00
key = self . _FETCH_KEY_VOLS
2013-09-29 04:05:13 +04:00
if key in self . _fetch_cache :
return self . _fetch_cache [ key ]
ret = [ ]
for xmlobj in self . fetch_all_pools ( ) :
pool = self . _libvirtconn . storagePoolLookupByName ( xmlobj . name )
2014-12-05 03:25:15 +03:00
if pool . info ( ) [ 0 ] != libvirt . VIR_STORAGE_POOL_RUNNING :
continue
2013-09-29 17:31:39 +04:00
ignore , ignore , vols = pollhelpers . fetch_volumes (
self , pool , { } , lambda obj , ignore : obj )
2014-02-12 22:57:44 +04:00
2015-04-10 19:52:42 +03:00
for vol in vols :
2014-02-12 22:57:44 +04:00
try :
xml = vol . XMLDesc ( 0 )
ret . append ( StorageVolume ( weakref . ref ( self ) , parsexml = xml ) )
2017-05-05 19:47:21 +03:00
except Exception as e :
2014-02-12 22:57:44 +04:00
logging . debug ( " Fetching volume XML failed: %s " , e )
2013-09-29 04:05:13 +04:00
2013-07-08 00:38:11 +04:00
if self . cache_object_fetch :
self . _fetch_cache [ key ] = ret
return ret
2013-07-07 22:54:48 +04:00
2013-09-29 04:05:13 +04:00
def fetch_all_vols ( self ) :
"""
Returns a list of StorageVolume objects
"""
if self . cb_fetch_all_vols :
2014-04-03 02:39:43 +04:00
return self . cb_fetch_all_vols ( ) # pylint: disable=not-callable
2013-09-29 04:05:13 +04:00
return self . _fetch_all_vols_cached ( )
2014-09-20 19:30:24 +04:00
def _fetch_all_nodedevs_cached ( self ) :
key = self . _FETCH_KEY_NODEDEVS
if key in self . _fetch_cache :
return self . _fetch_cache [ key ]
2014-01-18 23:57:39 +04:00
2014-09-20 19:30:24 +04:00
ignore , ignore , ret = pollhelpers . fetch_nodedevs (
self , { } , lambda obj , ignore : obj )
ret = [ NodeDevice . parse ( weakref . ref ( self ) , obj . XMLDesc ( 0 ) )
2015-04-10 19:52:42 +03:00
for obj in ret ]
2014-09-20 19:30:24 +04:00
if self . cache_object_fetch :
self . _fetch_cache [ key ] = ret
return ret
def fetch_all_nodedevs ( self ) :
"""
Returns a list of NodeDevice ( ) objects
"""
if self . cb_fetch_all_nodedevs :
return self . cb_fetch_all_nodedevs ( ) # pylint: disable=not-callable
return self . _fetch_all_nodedevs_cached ( )
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
return util . local_libvirt_version ( )
def daemon_version ( self ) :
if self . _fake_libvirt_version is not None :
return self . _fake_libvirt_version
if not self . is_remote ( ) :
return self . local_libvirt_version ( )
if not self . _daemon_version :
2013-10-06 18:08:04 +04:00
if not self . check_support ( support . SUPPORT_CONN_LIBVERSION ) :
2013-07-06 23:39:00 +04:00
self . _daemon_version = 0
else :
2014-03-20 21:34:34 +04:00
self . _daemon_version = self . _libvirtconn . getLibVersion ( )
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
if not self . _conn_version :
2013-10-06 18:08:04 +04:00
if not self . check_support ( support . SUPPORT_CONN_GETVERSION ) :
2013-07-06 23:39:00 +04:00
self . _conn_version = 0
else :
2014-03-20 21:34:34 +04:00
self . _conn_version = self . _libvirtconn . getVersion ( )
2013-07-06 23:39:00 +04:00
return self . _conn_version
2015-03-25 16:04:51 +03:00
def stable_defaults ( self , emulator = None , force = False ) :
"""
: param force : Just check if we are running on RHEL , regardless of
whether stable defaults are requested by the build . This is needed
to ensure we don ' t enable VM devices that are compiled out on
RHEL , like vmvga
"""
2015-04-06 22:42:40 +03:00
if not CLIConfig . stable_defaults and not force :
2015-03-23 23:48:43 +03:00
return False
2015-11-05 15:31:43 +03:00
if not self . is_qemu ( ) :
2015-02-24 15:21:24 +03:00
return False
2015-03-23 23:48:43 +03:00
2015-02-24 15:21:24 +03:00
if emulator :
2015-03-23 23:48:43 +03:00
return str ( emulator ) . startswith ( " /usr/libexec " )
for guest in self . caps . guests :
for dom in guest . domains :
if dom . emulator . startswith ( " /usr/libexec " ) :
return True
return False
2013-07-06 23:39:00 +04:00
2013-07-06 04:36:28 +04:00
###################
# Public URI bits #
###################
def is_remote ( self ) :
2015-09-06 17:36:17 +03:00
return ( self . _fake_conn_remote or self . _uriobj . hostname )
2015-08-10 19:46:47 +03:00
def is_session_uri ( self ) :
2015-09-06 17:36:17 +03:00
return ( self . _fake_conn_session or self . get_uri_path ( ) == " /session " )
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 " )
2013-07-06 04:36:28 +04:00
def is_qemu_system ( self ) :
2015-09-06 17:36:17 +03:00
return ( self . is_qemu ( ) and self . _uriobj . path == " /system " )
2013-07-06 04:36:28 +04:00
def is_qemu_session ( self ) :
return ( self . is_qemu ( ) and self . is_session_uri ( ) )
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 " )
2013-07-06 04:36:28 +04:00
def is_container ( self ) :
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 " ) )
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 #
#########################
for _supportname in [ _supportname for _supportname in dir ( support ) if
_supportname . startswith ( " SUPPORT_ " ) ] :
locals ( ) [ _supportname ] = getattr ( support , _supportname )
2013-10-06 18:08:04 +04:00
def check_support ( self , feature , data = None ) :
2013-07-06 23:53:35 +04:00
key = feature
2013-10-06 18:08:04 +04:00
data = data or self
2013-07-06 23:53:35 +04:00
if key not in self . _support_cache :
2013-09-29 17:26:03 +04:00
self . _support_cache [ key ] = support . check_support (
self , feature , data )
2013-07-06 23:53:35 +04:00
return self . _support_cache [ key ]
2013-09-29 17:26:03 +04:00
2013-10-06 18:08:04 +04:00
def support_remote_url_install ( self ) :
2015-09-06 17:36:17 +03:00
if self . _magic_uri :
2013-10-06 18:08:04 +04:00
return False
return ( self . check_support ( self . SUPPORT_CONN_STREAM ) and
self . check_support ( self . SUPPORT_STREAM_UPLOAD ) )
2013-07-06 19:20:28 +04:00
2013-07-05 16:59:58 +04:00
###################
# Private helpers #
###################
def _auth_cb ( self , creds , ( passwordcb , passwordcreds ) ) :
for cred in creds :
if cred [ 0 ] not in passwordcreds :
raise RuntimeError ( " Unknown cred type ' %s ' , expected only "
" %s " % ( cred [ 0 ] , passwordcreds ) )
return passwordcb ( creds )