2014-09-17 22:56:52 +04:00
#
# Support for parsing libvirt's domcapabilities XML
#
# Copyright 2014 Red Hat, Inc.
#
# 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
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
2015-04-08 16:53:30 +03:00
import logging
2015-02-18 23:16:48 +03:00
import re
2015-04-22 21:44:52 +03:00
from . xmlbuilder import XMLBuilder , XMLChildProperty , XMLProperty
2014-09-17 22:56:52 +04:00
class _Value ( XMLBuilder ) :
_XML_ROOT_NAME = " value "
value = XMLProperty ( " . " )
class _HasValues ( XMLBuilder ) :
values = XMLChildProperty ( _Value )
def get_values ( self ) :
return [ v . value for v in self . values ]
class _Enum ( _HasValues ) :
_XML_ROOT_NAME = " enum "
name = XMLProperty ( " ./@name " )
class _CapsBlock ( _HasValues ) :
supported = XMLProperty ( " ./@supported " , is_yesno = True )
enums = XMLChildProperty ( _Enum )
def enum_names ( self ) :
return [ e . name for e in self . enums ]
def get_enum ( self , name ) :
d = dict ( ( e . name , e ) for e in self . enums )
return d [ name ]
def _make_capsblock ( xml_root_name ) :
class TmpClass ( _CapsBlock ) :
pass
setattr ( TmpClass , " _XML_ROOT_NAME " , xml_root_name )
return TmpClass
class _OS ( _CapsBlock ) :
_XML_ROOT_NAME = " os "
loader = XMLChildProperty ( _make_capsblock ( " loader " ) , is_single = True )
class _Devices ( _CapsBlock ) :
_XML_ROOT_NAME = " devices "
hostdev = XMLChildProperty ( _make_capsblock ( " hostdev " ) , is_single = True )
disk = XMLChildProperty ( _make_capsblock ( " disk " ) , is_single = True )
2016-06-10 03:22:25 +03:00
class _Features ( _CapsBlock ) :
_XML_ROOT_NAME = " features "
gic = XMLChildProperty ( _make_capsblock ( " gic " ) , is_single = True )
2014-09-17 22:56:52 +04:00
class DomainCapabilities ( XMLBuilder ) :
2015-02-18 23:16:48 +03:00
@staticmethod
2015-02-22 18:01:02 +03:00
def build_from_params ( conn , emulator , arch , machine , hvtype ) :
2015-04-08 16:53:30 +03:00
xml = None
if conn . check_support (
2017-09-20 10:36:27 +03:00
conn . SUPPORT_CONN_DOMAIN_CAPABILITIES ) :
2015-04-08 16:53:30 +03:00
try :
xml = conn . getDomainCapabilities ( emulator , arch ,
machine , hvtype )
2017-07-24 11:26:48 +03:00
except Exception :
2015-04-08 16:53:30 +03:00
logging . debug ( " Error fetching domcapabilities XML " ,
exc_info = True )
if not xml :
2015-02-18 23:16:48 +03:00
# If not supported, just use a stub object
2015-02-22 18:01:02 +03:00
return DomainCapabilities ( conn )
return DomainCapabilities ( conn , parsexml = xml )
2015-02-18 23:16:48 +03:00
2015-02-22 18:01:02 +03:00
@staticmethod
def build_from_guest ( guest ) :
return DomainCapabilities . build_from_params ( guest . conn ,
2015-02-18 23:16:48 +03:00
guest . emulator , guest . os . arch , guest . os . machine , guest . type )
# Mapping of UEFI binary names to their associated architectures. We
# only use this info to do things automagically for the user, it shouldn't
# validate anything the user explicitly enters.
_uefi_arch_patterns = {
" x86_64 " : [
" .*OVMF_CODE \ .fd " , # RHEL
" .*ovmf-x64/OVMF.* \ .fd " , # gerd's firmware repo
2016-02-15 20:55:45 +03:00
" .*ovmf-x86_64-.* " , # SUSE
2016-06-07 18:03:32 +03:00
" .*ovmf.* " , " .*OVMF.* " , # generic attempt at a catchall
2015-02-18 23:16:48 +03:00
] ,
" aarch64 " : [
" .*AAVMF_CODE \ .fd " , # RHEL
" .*aarch64/QEMU_EFI.* " , # gerd's firmware repo
2016-06-07 18:03:32 +03:00
" .*aarch64.* " , # generic attempt at a catchall
2015-02-18 23:16:48 +03:00
] ,
}
2015-02-22 19:02:55 +03:00
def find_uefi_path_for_arch ( self ) :
2015-02-18 23:16:48 +03:00
"""
Search the loader paths for one that matches the passed arch
"""
2015-02-22 19:02:55 +03:00
if not self . arch_can_uefi ( ) :
2015-02-18 23:16:48 +03:00
return
2015-02-22 19:02:55 +03:00
patterns = self . _uefi_arch_patterns . get ( self . arch )
2015-02-18 23:16:48 +03:00
for pattern in patterns :
for path in [ v . value for v in self . os . loader . values ] :
if re . match ( pattern , path ) :
return path
2015-02-22 19:13:21 +03:00
def label_for_firmware_path ( self , path ) :
"""
Return a pretty label for passed path , based on if we know
about it or not
"""
if not path :
if self . arch in [ " i686 " , " x86_64 " ] :
return _ ( " BIOS " )
return _ ( " None " )
for arch , patterns in self . _uefi_arch_patterns . items ( ) :
for pattern in patterns :
if re . match ( pattern , path ) :
return ( _ ( " UEFI %(arch)s : %(path)s " ) %
{ " arch " : arch , " path " : path } )
return _ ( " Custom: %(path)s " % { " path " : path } )
2015-02-22 19:02:55 +03:00
def arch_can_uefi ( self ) :
2015-02-18 23:16:48 +03:00
"""
Return True if we know how to setup UEFI for the passed arch
"""
2017-10-11 14:35:46 +03:00
return self . arch in list ( self . _uefi_arch_patterns . keys ( ) )
2015-02-18 23:16:48 +03:00
def supports_uefi_xml ( self ) :
"""
Return True if libvirt advertises support for proper UEFI setup
"""
return ( " readonly " in self . os . loader . enum_names ( ) and
" yes " in self . os . loader . get_enum ( " readonly " ) . get_values ( ) )
2014-09-17 22:56:52 +04:00
_XML_ROOT_NAME = " domainCapabilities "
os = XMLChildProperty ( _OS , is_single = True )
devices = XMLChildProperty ( _Devices , is_single = True )
2015-02-22 19:02:55 +03:00
arch = XMLProperty ( " ./arch " )
2016-06-10 03:22:25 +03:00
features = XMLChildProperty ( _Features , is_single = True )