2013-03-18 01:06:52 +04:00
#
# Helper functions for determining if libvirt supports certain features
#
2014-03-13 15:52:51 +04:00
# Copyright 2009, 2013, 2014 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
# Cole Robinson <crobinso@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
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-03-18 01:06:52 +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 libvirt
2014-09-12 23:59:22 +04:00
from . import util
2013-03-18 01:06:52 +04:00
# Check that command is present in the python bindings, and return the
# the requested function
def _get_command ( funcname , objname = None , obj = None ) :
if not obj :
obj = libvirt
if objname :
if not hasattr ( libvirt , objname ) :
return None
obj = getattr ( libvirt , objname )
if not hasattr ( obj , funcname ) :
return None
return getattr ( obj , funcname )
2013-04-13 22:34:52 +04:00
2013-07-06 04:36:28 +04:00
# Make sure libvirt object 'objname' has function 'funcname'
2013-03-18 01:06:52 +04:00
def _has_command ( funcname , objname = None , obj = None ) :
return bool ( _get_command ( funcname , objname , obj ) )
2013-04-13 22:34:52 +04:00
2013-07-06 04:36:28 +04:00
# Make sure libvirt object has flag 'flag_name'
2013-03-18 01:06:52 +04:00
def _get_flag ( flag_name ) :
return _get_command ( flag_name )
2013-07-06 04:36:28 +04:00
2013-03-18 01:06:52 +04:00
# Try to call the passed function, and look for signs that libvirt or driver
# doesn't support it
def _try_command ( func , args , check_all_error = False ) :
try :
func ( * args )
except libvirt . libvirtError , e :
2013-07-06 19:20:28 +04:00
if util . is_error_nosupport ( e ) :
2013-03-18 01:06:52 +04:00
return False
if check_all_error :
return False
except Exception :
# Other python exceptions likely mean the bindings are horked
return False
return True
2013-04-13 22:34:52 +04:00
2013-07-06 19:20:28 +04:00
# Return the hypervisor version
2013-03-18 01:06:52 +04:00
def _split_function_name ( function ) :
if not function :
return ( None , None )
output = function . split ( " . " )
if len ( output ) == 1 :
return ( None , output [ 0 ] )
else :
return ( output [ 0 ] , output [ 1 ] )
2013-04-13 22:34:52 +04:00
2014-02-11 02:12:24 +04:00
def _check_function ( function , flag , args , data ) :
2014-02-11 02:02:22 +04:00
object_name , function_name = _split_function_name ( function )
if not function_name :
return None
# Make sure function is present in either libvirt module or
# object_name class
flag_tuple = ( )
if not _has_command ( function_name , objname = object_name ) :
return False
if flag :
found_flag = _get_flag ( flag )
if not bool ( found_flag ) :
return False
flag_tuple = ( found_flag , )
if args is None :
return None
# If function requires an object, make sure the passed obj
# is of the correct type
if object_name :
classobj = _get_command ( object_name )
if not isinstance ( data , classobj ) :
raise ValueError (
" Passed obj %s with args must be of type %s , was %s " %
( data , str ( classobj ) , type ( data ) ) )
cmd = _get_command ( function_name , obj = data )
# Function with args specified is all the proof we need
return _try_command ( cmd , args + flag_tuple ,
check_all_error = bool ( flag_tuple ) )
2014-02-11 01:53:47 +04:00
def _version_str_to_int ( verstr ) :
if verstr is None :
return None
if verstr == 0 :
return 0
if verstr . count ( " . " ) != 2 :
raise RuntimeError ( " programming error: version string ' %s ' needs "
" two ' . ' in it. " )
return ( ( int ( verstr . split ( " . " ) [ 0 ] ) * 1000000 ) +
( int ( verstr . split ( " . " ) [ 1 ] ) * 1000 ) + ( int ( verstr . split ( " . " ) [ 2 ] ) ) )
2013-08-09 23:56:18 +04:00
class _SupportCheck ( object ) :
"""
@version : Minimum libvirt version required for this feature . Not used
2014-02-11 02:12:24 +04:00
if ' args ' provided .
2013-08-09 23:56:18 +04:00
@function : Function name to check exists . If object not specified ,
2014-02-11 02:12:24 +04:00
function is checked against libvirt module . If run_args is specified ,
this function will actually be called , so beware .
@run_args : Argument tuple to actually test ' function ' with , and check
for an ' unsupported ' error from libvirt .
2013-08-09 23:56:18 +04:00
@flag : A flag to check exists . This will be appended to the argument
2014-02-11 02:12:24 +04:00
list if run_args are provided , otherwise we will only check against
that the flag is present in the python bindings .
@hv_version : A dictionary with hypervisor names for keys , and
hypervisor versions as values . This is for saying ' this feature
is only supported with qemu version 1.5 .0 ' or similar. If the
version is 0 , then perform no version check .
@hv_libvirt_version : Similar to hv_version , but this will check
the version of libvirt for a specific hv key . Use this to say
' this feature is supported with qemu and libvirt version 1.0.0,
and xen with libvirt version 1.1 .0 '
2013-08-09 23:56:18 +04:00
"""
def __init__ ( self ,
2014-02-11 02:12:24 +04:00
function = None , run_args = None , flag = None ,
version = None , hv_version = None , hv_libvirt_version = None ) :
2013-08-09 23:56:18 +04:00
self . function = function
2014-02-11 02:12:24 +04:00
self . run_args = run_args
2013-08-09 23:56:18 +04:00
self . flag = flag
2014-02-11 01:53:47 +04:00
self . version = version
2014-02-11 02:12:24 +04:00
self . hv_version = hv_version or { }
self . hv_libvirt_version = hv_libvirt_version or { }
2013-08-09 23:56:18 +04:00
2014-02-11 02:12:24 +04:00
versions = ( [ self . version ] + self . hv_libvirt_version . values ( ) )
2014-02-11 01:53:47 +04:00
for vstr in versions :
v = _version_str_to_int ( vstr )
if vstr is not None and v != 0 and v < 7009 :
2014-02-11 01:37:17 +04:00
raise RuntimeError ( " programming error: Cannot enforce "
" support checks for libvirt versions less than 0.7.9, "
2014-02-11 01:53:47 +04:00
" since required APIs were not available. ver= %s " % vstr )
2014-02-11 01:37:17 +04:00
2013-08-09 23:56:18 +04:00
def check_support ( self , conn , data ) :
2014-02-11 02:12:24 +04:00
ret = _check_function ( self . function , self . flag , self . run_args , data )
2014-02-11 02:02:22 +04:00
if ret is not None :
return ret
2013-08-09 23:56:18 +04:00
# Do this after the function check, since there's an ordering issue
# with VirtualConnection
2014-02-11 02:12:24 +04:00
hv_type = conn . get_uri_driver ( )
actual_libvirt_version = conn . daemon_version ( )
actual_hv_version = conn . conn_version ( )
2013-08-09 23:56:18 +04:00
# Check that local libvirt version is sufficient
2014-02-11 02:12:24 +04:00
if _version_str_to_int ( self . version ) > actual_libvirt_version :
2013-08-09 23:56:18 +04:00
return False
2014-02-11 02:12:24 +04:00
if self . hv_version :
if hv_type not in self . hv_version :
if " all " not in self . hv_version :
2014-02-11 01:14:39 +04:00
return False
2014-02-11 02:12:24 +04:00
elif ( actual_hv_version <
_version_str_to_int ( self . hv_version [ hv_type ] ) ) :
2013-08-09 23:56:18 +04:00
return False
2014-02-11 02:12:24 +04:00
if self . hv_libvirt_version :
if hv_type not in self . hv_libvirt_version :
if " all " not in self . hv_version :
2014-02-11 01:14:39 +04:00
return False
2014-02-11 02:12:24 +04:00
elif ( actual_libvirt_version <
_version_str_to_int ( self . hv_libvirt_version [ hv_type ] ) ) :
2013-08-09 23:56:18 +04:00
return False
return True
_support_id = 0
_support_objs = [ ]
def _make ( * args , * * kwargs ) :
global _support_id
_support_id + = 1
obj = _SupportCheck ( * args , * * kwargs )
_support_objs . append ( obj )
return _support_id
2014-02-11 02:12:24 +04:00
SUPPORT_CONN_STORAGE = _make (
function = " virConnect.listStoragePools " , run_args = ( ) )
SUPPORT_CONN_NODEDEV = _make (
function = " virConnect.listDevices " , run_args = ( None , 0 ) )
2013-08-09 23:56:18 +04:00
SUPPORT_CONN_FINDPOOLSOURCES = _make (
2014-02-11 02:12:24 +04:00
function = " virConnect.findStoragePoolSources " )
SUPPORT_CONN_KEYMAP_AUTODETECT = _make ( hv_version = { " qemu " : " 0.11.0 " } )
SUPPORT_CONN_GETHOSTNAME = _make (
function = " virConnect.getHostname " , run_args = ( ) )
SUPPORT_CONN_NETWORK = _make ( function = " virConnect.listNetworks " , run_args = ( ) )
SUPPORT_CONN_INTERFACE = _make (
function = " virConnect.listInterfaces " , run_args = ( ) )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_MAXVCPUS_XML = _make ( version = " 0.8.5 " )
2013-08-09 23:56:18 +04:00
# Earliest version with working bindings
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_STREAM = _make (
2014-02-11 02:12:24 +04:00
version = " 0.9.3 " , function = " virConnect.newStream " , run_args = ( 0 , ) )
SUPPORT_CONN_GETVERSION = _make ( function = " virConnect.getVersion " , run_args = ( ) )
SUPPORT_CONN_LIBVERSION = _make (
function = " virConnect.getLibVersion " , run_args = ( ) )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_LISTALLDOMAINS = _make (
2014-02-11 02:12:24 +04:00
function = " virConnect.listAllDomains " , run_args = ( ) )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_LISTALLNETWORKS = _make (
2014-02-11 02:12:24 +04:00
function = " virConnect.listAllNetworks " , run_args = ( ) )
2013-08-09 23:56:18 +04:00
SUPPORT_CONN_LISTALLSTORAGEPOOLS = _make (
2014-02-11 02:12:24 +04:00
function = " virConnect.listAllStoragePools " , run_args = ( ) )
SUPPORT_CONN_LISTALLINTERFACES = _make (
function = " virConnect.listAllInterfaces " , run_args = ( ) )
SUPPORT_CONN_LISTALLDEVICES = _make (
function = " virConnect.listAllDevices " , run_args = ( ) )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_VIRTIO_MMIO = _make (
2014-02-11 02:12:24 +04:00
version = " 1.1.2 " , hv_version = { " qemu " : " 1.6.0 " } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_DISK_SD = _make ( version = " 1.1.2 " )
2013-10-02 23:17:15 +04:00
# This is an arbitrary check to say whether it's a good idea to
# default to qcow2. It might be fine for xen or qemu older than the versions
# here, but until someone tests things I'm going to be a bit conservative.
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_DEFAULT_QCOW2 = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.0 " , hv_version = { " qemu " : " 1.2.0 " , " test " : 0 } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_DEFAULT_USB2 = _make (
2014-02-11 02:12:24 +04:00
version = " 0.9.7 " , hv_version = { " qemu " : " 1.0.0 " , " test " : 0 } )
SUPPORT_CONN_CAN_ACPI = _make ( hv_version = { " xen " : " 3.1.0 " , " all " : 0 } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_SOUND_AC97 = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.0 " , hv_version = { " qemu " : " 0.11.0 " } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_SOUND_ICH6 = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.8 " , hv_version = { " qemu " : " 0.14.0 " } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_GRAPHICS_SPICE = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.6 " , hv_version = { " qemu " : " 0.14.0 " } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_CHAR_SPICEVMC = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.8 " , hv_version = { " qemu " : " 0.14.0 " } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_DIRECT_INTERFACE = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.7 " , hv_version = { " qemu " : 0 , " test " : 0 } )
2013-10-03 00:41:23 +04:00
SUPPORT_CONN_FILESYSTEM = _make (
2014-02-11 02:12:24 +04:00
hv_version = { " qemu " : " 0.13.0 " , " lxc " : 0 , " openvz " : 0 , " test " : 0 } ,
hv_libvirt_version = { " qemu " : " 0.8.5 " , " lxc " : 0 , " openvz " : 0 , " test " : 0 } )
SUPPORT_CONN_AUTOSOCKET = _make ( hv_libvirt_version = { " qemu " : " 1.0.6 " } )
SUPPORT_CONN_ADVANCED_CLOCK = _make ( hv_libvirt_version = { " qemu " : " 0.8.0 " } )
SUPPORT_CONN_VIRTIO_CONSOLE = _make ( hv_libvirt_version = { " qemu " : " 0.8.3 " } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_PANIC_DEVICE = _make (
2014-02-11 02:12:24 +04:00
version = " 1.2.1 " , hv_version = { " qemu " : " 1.5.0 " , " test " : 0 } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_PM_DISABLE = _make (
2014-02-11 02:12:24 +04:00
version = " 0.10.2 " , hv_version = { " qemu " : " 1.2.0 " , " test " : 0 } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_QCOW2_LAZY_REFCOUNTS = _make (
2014-02-11 02:12:24 +04:00
version = " 1.1.0 " , hv_version = { " qemu " : " 1.2.0 " , " test " : 0 } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_USBREDIR = _make (
2014-02-11 02:12:24 +04:00
version = " 0.9.5 " , hv_version = { " qemu " : " 1.3.0 " , " test " : 0 } )
2014-02-11 01:53:47 +04:00
SUPPORT_CONN_DEVICE_BOOTORDER = _make (
2014-02-11 02:12:24 +04:00
version = " 0.8.8 " , hv_version = { " qemu " : 0 , " test " : 0 } )
2014-02-26 00:05:58 +04:00
SUPPORT_CONN_INPUT_KEYBOARD = _make (
version = " 1.2.2 " , hv_version = { " qemu " : 0 , " test " : 0 } )
2014-03-06 20:29:23 +04:00
SUPPORT_CONN_POOL_GLUSTERFS = _make ( version = " 1.2.0 " )
2014-03-13 15:52:51 +04:00
SUPPORT_CONN_CPU_MODEL_NAMES = _make ( function = " virConnect.getCPUModelNames " ,
run_args = ( " x86_64 " , 0 ) )
2014-07-07 02:46:16 +04:00
SUPPORT_CONN_HYPERV_VAPIC = _make (
version = " 1.1.0 " , hv_version = { " qemu " : " 1.1.0 " , " test " : 0 } )
SUPPORT_CONN_HYPERV_CLOCK = _make (
version = " 1.2.2 " , hv_version = { " qemu " : " 2.0.0 " , " test " : 0 } )
2014-09-16 06:02:57 +04:00
SUPPORT_CONN_LOADER_ROM = _make ( version = " 1.2.9 " )
2013-10-05 21:54:28 +04:00
2013-08-09 23:56:18 +04:00
# Domain checks
2014-02-11 02:12:24 +04:00
SUPPORT_DOMAIN_GETVCPUS = _make ( function = " virDomain.vcpus " , run_args = ( ) )
SUPPORT_DOMAIN_XML_INACTIVE = _make ( function = " virDomain.XMLDesc " , run_args = ( ) ,
2014-02-11 01:37:17 +04:00
flag = " VIR_DOMAIN_XML_INACTIVE " )
2014-02-11 02:12:24 +04:00
SUPPORT_DOMAIN_XML_SECURE = _make ( function = " virDomain.XMLDesc " , run_args = ( ) ,
2014-02-11 01:37:17 +04:00
flag = " VIR_DOMAIN_XML_SECURE " )
SUPPORT_DOMAIN_MANAGED_SAVE = _make (
function = " virDomain.hasManagedSaveImage " ,
2014-02-11 02:12:24 +04:00
run_args = ( 0 , ) )
2013-08-09 23:56:18 +04:00
SUPPORT_DOMAIN_MIGRATE_DOWNTIME = _make (
2014-02-11 01:37:17 +04:00
function = " virDomain.migrateSetMaxDowntime " ,
# Use a bogus flags value, so that we don't overwrite existing
# downtime value
2014-02-11 02:12:24 +04:00
run_args = ( 30 , 12345678 ) )
SUPPORT_DOMAIN_JOB_INFO = _make ( function = " virDomain.jobInfo " , run_args = ( ) )
2014-02-11 01:53:47 +04:00
SUPPORT_DOMAIN_CONSOLE_STREAM = _make ( version = " 0.8.6 " )
SUPPORT_DOMAIN_SET_METADATA = _make ( version = " 0.9.10 " )
SUPPORT_DOMAIN_CPU_HOST_MODEL = _make ( version = " 0.9.10 " )
2014-02-11 01:37:17 +04:00
SUPPORT_DOMAIN_LIST_SNAPSHOTS = _make (
2014-02-11 02:12:24 +04:00
function = " virDomain.listAllSnapshots " , run_args = ( ) )
2013-09-24 14:52:59 +04:00
SUPPORT_DOMAIN_GET_METADATA = _make ( function = " virDomain.metadata " ,
2014-02-11 02:12:24 +04:00
run_args = ( getattr ( libvirt , " VIR_DOMAIN_METADATA_TITLE " , 1 ) , None , 0 ) )
SUPPORT_DOMAIN_MEMORY_STATS = _make (
function = " virDomain.memoryStats " , run_args = ( ) )
2014-03-18 18:04:59 +04:00
SUPPORT_DOMAIN_STATE = _make ( function = " virDomain.state " , run_args = ( ) )
2013-08-06 01:20:35 +04:00
2013-08-09 23:56:18 +04:00
# Pool checks
2014-02-11 01:53:47 +04:00
SUPPORT_POOL_CREATEVOLFROM = _make (
function = " virStoragePool.createXMLFrom " , version = " 0.8.0 " )
2014-02-11 02:12:24 +04:00
SUPPORT_POOL_ISACTIVE = _make ( function = " virStoragePool.isActive " , run_args = ( ) )
2014-02-11 01:37:17 +04:00
SUPPORT_POOL_LISTALLVOLUMES = _make (
2014-02-11 02:12:24 +04:00
function = " virStoragePool.listAllVolumes " , run_args = ( ) )
2013-10-01 22:29:58 +04:00
SUPPORT_POOL_METADATA_PREALLOC = _make (
flag = " VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA " ,
2014-02-11 01:53:47 +04:00
version = " 1.0.1 " )
2013-08-09 23:56:18 +04:00
# Interface checks
SUPPORT_INTERFACE_XML_INACTIVE = _make ( function = " virInterface.XMLDesc " ,
2014-02-11 01:37:17 +04:00
flag = " VIR_INTERFACE_XML_INACTIVE " ,
2014-02-11 02:12:24 +04:00
run_args = ( ) )
SUPPORT_INTERFACE_ISACTIVE = _make (
function = " virInterface.isActive " , run_args = ( ) )
2013-08-09 23:56:18 +04:00
# Stream checks
# Latest I tested with, and since we will use it by default
# for URL installs, want to be sure it works
2014-02-11 01:53:47 +04:00
SUPPORT_STREAM_UPLOAD = _make ( version = " 0.9.4 " )
2013-08-09 23:56:18 +04:00
# Network checks
2014-02-11 02:12:24 +04:00
SUPPORT_NET_ISACTIVE = _make ( function = " virNetwork.isActive " , run_args = ( ) )
2013-08-09 23:56:18 +04:00
2013-07-06 23:39:00 +04:00
def check_support ( virtconn , feature , data = None ) :
2013-03-18 01:06:52 +04:00
"""
Attempt to determine if a specific libvirt feature is support given
the passed connection .
@param conn : Libvirt connection to check feature on
@param feature : Feature type to check support for
@type feature : One of the SUPPORT_ * flags
@param data : Option libvirt object to use in feature checking
@type data : Could be virDomain , virNetwork , virStoragePool ,
hv name , etc
@returns : True if feature is supported , False otherwise
"""
2013-07-05 16:59:58 +04:00
if " VirtualConnection " in repr ( data ) :
2014-03-20 21:34:34 +04:00
data = data . get_conn_for_api_arg ( )
2013-07-05 16:59:58 +04:00
2013-08-09 23:56:18 +04:00
sobj = _support_objs [ feature - 1 ]
return sobj . check_support ( virtconn , data )