2013-03-17 17:06:52 -04:00
#
2013-10-27 21:59:46 +01:00
# Copyright 2009, 2013 Red Hat, Inc.
2013-03-17 17: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-27 21:59:47 +01:00
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2013-03-17 17: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 logging
2013-08-08 20:47:17 -04:00
import libvirt
2013-03-17 17:06:52 -04:00
2013-09-22 18:13:24 -04:00
from virtinst . xmlbuilder import XMLBuilder
from virtinst . xmlbuilder import XMLProperty as OrigXMLProperty
2013-08-08 20:47:17 -04:00
2013-09-22 18:13:24 -04:00
# We had a pre-existing set of parse tests when this was converted to
# XMLBuilder. We do this to appease the check in xmlparse.py without
# moving all the nodedev.py tests to one file. Should find a way to
# drop it.
class XMLProperty ( OrigXMLProperty ) :
def __init__ ( self , * args , * * kwargs ) :
kwargs [ " track " ] = False
OrigXMLProperty . __init__ ( self , * args , * * kwargs )
2013-03-17 17:06:52 -04:00
2013-04-13 14:34:52 -04:00
2013-09-22 18:13:24 -04:00
def _lookupNodeName ( conn , name ) :
2013-09-27 18:06:39 -04:00
try :
nodedev = conn . nodeDeviceLookupByName ( name )
except libvirt . libvirtError , e :
raise libvirt . libvirtError (
_ ( " Did not find node device ' %s ' : %s " %
( name , str ( e ) ) ) )
2013-09-22 18:13:24 -04:00
xml = nodedev . XMLDesc ( 0 )
return NodeDevice . parse ( conn , xml )
class NodeDevice ( XMLBuilder ) :
CAPABILITY_TYPE_SYSTEM = " system "
CAPABILITY_TYPE_NET = " net "
CAPABILITY_TYPE_PCI = " pci "
CAPABILITY_TYPE_USBDEV = " usb_device "
CAPABILITY_TYPE_USBBUS = " usb "
CAPABILITY_TYPE_STORAGE = " storage "
CAPABILITY_TYPE_SCSIBUS = " scsi_host "
CAPABILITY_TYPE_SCSIDEV = " scsi "
( HOSTDEV_ADDR_TYPE_LIBVIRT ,
HOSTDEV_ADDR_TYPE_PCI ,
HOSTDEV_ADDR_TYPE_USB_BUSADDR ,
HOSTDEV_ADDR_TYPE_USB_VENPRO ) = range ( 1 , 5 )
@staticmethod
def lookupNodeName ( conn , name ) :
"""
Convert the passed libvirt node device name to a NodeDevice
instance , with proper error reporting . If the name is name is not
found , we will attempt to parse the name as would be passed to
devAddressToNodeDev
2013-05-13 16:45:51 -04:00
2013-09-22 18:13:24 -04:00
@param conn : libvirt . virConnect instance to perform the lookup on
@param name : libvirt node device name to lookup , or address for
2013-09-27 18:06:39 -04:00
_devAddressToNodedev
2013-03-17 17:06:52 -04:00
2013-09-22 18:13:24 -04:00
@rtype : L { NodeDevice } instance
"""
2013-10-06 10:08:04 -04:00
if not conn . check_support ( conn . SUPPORT_CONN_NODEDEV ) :
2013-09-22 18:13:24 -04:00
raise ValueError ( _ ( " Connection does not support host device "
" enumeration. " ) )
try :
2013-09-27 18:06:39 -04:00
return _lookupNodeName ( conn , name )
2013-09-22 18:13:24 -04:00
except libvirt . libvirtError , e :
2014-03-22 11:21:19 -04:00
try :
_isAddressStr ( name )
except :
2013-09-22 18:13:24 -04:00
raise e
2013-09-27 18:06:39 -04:00
return _devAddressToNodedev ( conn , name )
2013-09-22 18:13:24 -04:00
@staticmethod
def parse ( conn , xml ) :
tmpdev = NodeDevice ( conn , parsexml = xml , allow_node_instantiate = True )
cls = _typeToDeviceClass ( tmpdev . device_type )
return cls ( conn , parsexml = xml , allow_node_instantiate = True )
def __init__ ( self , * args , * * kwargs ) :
instantiate = kwargs . pop ( " allow_node_instantiate " , False )
if self . __class__ is NodeDevice and not instantiate :
raise RuntimeError ( " Can not instantiate NodeDevice directly " )
2013-09-27 18:06:39 -04:00
self . addr_type = None
2013-09-22 18:13:24 -04:00
XMLBuilder . __init__ ( self , * args , * * kwargs )
_XML_ROOT_NAME = " device "
name = XMLProperty ( " ./name " )
parent = XMLProperty ( " ./parent " )
device_type = XMLProperty ( " ./capability/@type " )
2013-03-17 17:06:52 -04:00
2014-01-12 14:52:15 -05:00
def pretty_name ( self ) :
2013-03-17 17:06:52 -04:00
"""
Use device information to attempt to print a human readable device
name .
@returns : Device description string
@rtype C { str }
"""
return self . name
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class SystemDevice ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
hw_vendor = XMLProperty ( " ./capability/hardware/vendor " )
hw_version = XMLProperty ( " ./capability/hardware/version " )
hw_serial = XMLProperty ( " ./capability/hardware/serial " )
hw_uuid = XMLProperty ( " ./capability/hardware/uuid " )
fw_vendor = XMLProperty ( " ./capability/firmware/vendor " )
fw_version = XMLProperty ( " ./capability/firmware/version " )
fw_date = XMLProperty ( " ./capability/firmware/release_date " )
2013-03-17 17:06:52 -04:00
2014-01-12 14:52:15 -05:00
def pretty_name ( self ) :
2013-03-17 17:06:52 -04:00
desc = _ ( " System " )
if self . hw_vendor :
desc + = " : %s " % self . hw_vendor
if self . hw_version :
desc + = " %s " % self . hw_version
return desc
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class NetDevice ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
interface = XMLProperty ( " ./capability/interface " )
address = XMLProperty ( " ./capability/address " )
capability_type = XMLProperty ( " ./capability/capability/@type " )
2013-03-17 17:06:52 -04:00
2014-01-12 14:52:15 -05:00
def pretty_name ( self ) :
2013-03-17 17:06:52 -04:00
desc = self . name
if self . interface :
desc = _ ( " Interface %s " ) % self . interface
return desc
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class PCIDevice ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
domain = XMLProperty ( " ./capability/domain " )
bus = XMLProperty ( " ./capability/bus " )
slot = XMLProperty ( " ./capability/slot " )
function = XMLProperty ( " ./capability/function " )
2013-03-17 17:06:52 -04:00
2013-09-22 18:13:24 -04:00
product_name = XMLProperty ( " ./capability/product " )
product_id = XMLProperty ( " ./capability/product/@id " )
vendor_name = XMLProperty ( " ./capability/vendor " )
vendor_id = XMLProperty ( " ./capability/vendor/@id " )
2013-03-17 17:06:52 -04:00
2013-10-10 09:41:49 -04:00
iommu_group = XMLProperty ( " ./capability/iommuGroup/@number " , is_int = True )
2014-01-12 14:52:15 -05:00
def pretty_name ( self ) :
2014-04-15 16:22:33 +02:00
devstr = " %.4X : %.2X : %.2X : %X " % ( int ( self . domain ) ,
int ( self . bus ) ,
int ( self . slot ) ,
int ( self . function ) )
2014-01-12 14:52:15 -05:00
2014-01-12 14:52:33 -05:00
return " %s %s %s " % ( devstr , self . vendor_name , self . product_name )
2013-03-17 17:06:52 -04:00
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class USBDevice ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
bus = XMLProperty ( " ./capability/bus " )
device = XMLProperty ( " ./capability/device " )
2013-03-17 17:06:52 -04:00
2013-09-22 18:13:24 -04:00
product_name = XMLProperty ( " ./capability/product " )
product_id = XMLProperty ( " ./capability/product/@id " )
vendor_name = XMLProperty ( " ./capability/vendor " )
vendor_id = XMLProperty ( " ./capability/vendor/@id " )
2013-03-17 17:06:52 -04:00
2014-01-12 14:52:15 -05:00
def pretty_name ( self ) :
2013-03-17 17:06:52 -04:00
devstr = " %.3d : %.3d " % ( int ( self . bus ) , int ( self . device ) )
desc = " %s %s %s " % ( devstr , str ( self . vendor_name ) ,
str ( self . product_name ) )
return desc
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class StorageDevice ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
block = XMLProperty ( " ./capability/block " )
bus = XMLProperty ( " ./capability/bus " )
drive_type = XMLProperty ( " ./capability/drive_type " )
size = XMLProperty ( " ./capability/size " , is_int = True )
model = XMLProperty ( " ./capability/model " )
vendor = XMLProperty ( " ./capability/vendor " )
hotpluggable = XMLProperty (
" ./capability/capability[@type= ' hotpluggable ' ] " , is_bool = True )
removable = XMLProperty (
" ./capability/capability[@type= ' removable ' ] " , is_bool = True )
media_size = XMLProperty (
" ./capability/capability[@type= ' removable ' ]/media_size " , is_int = True )
media_label = XMLProperty (
" ./capability/capability[@type= ' removable ' ]/media_label " )
_media_available = XMLProperty (
" ./capability/capability[@type= ' removable ' ]/media_available " ,
is_int = True )
def _get_media_available ( self ) :
m = self . _media_available
if m is None :
return None
return bool ( m )
def _set_media_available ( self , val ) :
self . _media_available = val
media_available = property ( _get_media_available , _set_media_available )
2013-03-17 17:06:52 -04:00
2014-01-12 14:52:15 -05:00
def pretty_name ( self ) :
2013-03-17 17:06:52 -04:00
desc = " "
if self . drive_type :
desc = self . drive_type
if self . block :
desc = " : " . join ( ( desc , self . block ) )
elif self . model :
desc = " : " . join ( ( desc , self . model ) )
else :
desc = " : " . join ( ( desc , self . name ) )
return desc
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class USBBus ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
number = XMLProperty ( " ./capability/number " )
classval = XMLProperty ( " ./capability/class " )
subclass = XMLProperty ( " ./capability/subclass " )
protocol = XMLProperty ( " ./capability/protocol " )
2013-03-17 17:06:52 -04:00
class SCSIDevice ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
host = XMLProperty ( " ./capability/host " )
bus = XMLProperty ( " ./capability/bus " )
target = XMLProperty ( " ./capability/target " )
lun = XMLProperty ( " ./capability/lun " )
type = XMLProperty ( " ./capability/type " )
2013-03-17 17:06:52 -04:00
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
class SCSIBus ( NodeDevice ) :
2013-09-22 18:13:24 -04:00
host = XMLProperty ( " ./capability/host " )
2013-03-17 17:06:52 -04:00
2013-09-22 18:13:24 -04:00
vport_ops = XMLProperty (
" ./capability/capability[@type= ' vport_ops ' ] " , is_bool = True )
2013-04-13 14:34:52 -04:00
2013-09-22 18:13:24 -04:00
fc_host = XMLProperty (
" ./capability/capability[@type= ' fc_host ' ] " , is_bool = True )
wwnn = XMLProperty ( " ./capability/capability[@type= ' fc_host ' ]/wwnn " )
wwpn = XMLProperty ( " ./capability/capability[@type= ' fc_host ' ]/wwpn " )
2013-03-17 17:06:52 -04:00
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
def _isAddressStr ( addrstr ) :
cmp_func = None
2013-04-30 22:53:11 +08:00
addr_type = None
2013-03-17 17:06:52 -04:00
try :
# Determine addrstr type
if addrstr . count ( " : " ) in [ 1 , 2 ] and addrstr . count ( " . " ) :
2013-09-22 18:13:24 -04:00
devtype = NodeDevice . CAPABILITY_TYPE_PCI
2013-03-17 17:06:52 -04:00
addrstr , func = addrstr . split ( " . " , 1 )
addrstr , slot = addrstr . rsplit ( " : " , 1 )
domain = " 0 "
if addrstr . count ( " : " ) :
domain , bus = addrstr . split ( " : " , 1 )
else :
bus = addrstr
func = int ( func , 16 )
slot = int ( slot , 16 )
domain = int ( domain , 16 )
bus = int ( bus , 16 )
def pci_cmp ( nodedev ) :
return ( ( int ( nodedev . domain ) == domain ) and
( int ( nodedev . function ) == func ) and
( int ( nodedev . bus ) == bus ) and
( int ( nodedev . slot ) == slot ) )
cmp_func = pci_cmp
2013-09-22 18:13:24 -04:00
addr_type = NodeDevice . HOSTDEV_ADDR_TYPE_PCI
2013-03-17 17:06:52 -04:00
elif addrstr . count ( " : " ) :
2013-09-22 18:13:24 -04:00
devtype = NodeDevice . CAPABILITY_TYPE_USBDEV
2013-03-17 17:06:52 -04:00
vendor , product = addrstr . split ( " : " )
vendor = int ( vendor , 16 )
product = int ( product , 16 )
def usbprod_cmp ( nodedev ) :
return ( ( int ( nodedev . vendor_id , 16 ) == vendor ) and
( int ( nodedev . product_id , 16 ) == product ) )
cmp_func = usbprod_cmp
2013-09-22 18:13:24 -04:00
addr_type = NodeDevice . HOSTDEV_ADDR_TYPE_USB_VENPRO
2013-03-17 17:06:52 -04:00
elif addrstr . count ( " . " ) :
2013-09-22 18:13:24 -04:00
devtype = NodeDevice . CAPABILITY_TYPE_USBDEV
2013-03-17 17:06:52 -04:00
bus , addr = addrstr . split ( " . " , 1 )
bus = int ( bus )
addr = int ( addr )
def usbaddr_cmp ( nodedev ) :
return ( ( int ( nodedev . bus ) == bus ) and
( int ( nodedev . device ) == addr ) )
cmp_func = usbaddr_cmp
2013-09-22 18:13:24 -04:00
addr_type = NodeDevice . HOSTDEV_ADDR_TYPE_USB_BUSADDR
2013-09-27 18:06:39 -04:00
else :
2014-03-22 11:21:19 -04:00
raise RuntimeError ( " Unknown address type " )
2013-03-17 17:06:52 -04:00
except :
logging . exception ( " Error parsing node device string. " )
2014-03-22 11:21:19 -04:00
raise
2013-03-17 17:06:52 -04:00
2013-04-30 22:53:11 +08:00
return cmp_func , devtype , addr_type
2013-03-17 17:06:52 -04:00
2013-04-13 14:34:52 -04:00
2013-09-27 18:06:39 -04:00
def _devAddressToNodedev ( conn , addrstr ) :
2013-03-17 17:06:52 -04:00
"""
Look up the passed host device address string as a libvirt node device ,
parse its xml , and return a NodeDevice instance .
@param conn : libvirt . virConnect instance to perform the lookup on
@param addrstr : host device string to parse and lookup
- bus . addr ( ex . 001.003 for a usb device )
- vendor : product ( ex . 0x1234 : 0x5678 for a usb device
- ( domain : ) bus : slot . func ( ex . 00 : 10.0 for a pci device )
@param addrstr : C { str }
"""
2014-03-22 11:21:19 -04:00
try :
ret = _isAddressStr ( addrstr )
except :
2013-03-17 17:06:52 -04:00
raise ValueError ( _ ( " Could not determine format of ' %s ' " ) % addrstr )
2013-04-30 22:53:11 +08:00
cmp_func , devtype , addr_type = ret
2013-03-17 17:06:52 -04:00
# Iterate over node devices and compare
2013-04-24 18:05:08 +08:00
count = 0
nodedev = None
2013-03-17 17:06:52 -04:00
nodenames = conn . listDevices ( devtype , 0 )
for name in nodenames :
2013-04-24 18:05:08 +08:00
tmpnode = _lookupNodeName ( conn , name )
if cmp_func ( tmpnode ) :
nodedev = tmpnode
count + = 1
if count == 1 :
2013-09-27 18:06:39 -04:00
nodedev . addr_type = addr_type
return nodedev
2013-04-24 18:05:08 +08:00
elif count > 1 :
raise ValueError ( _ ( " %s corresponds to multiple node devices " ) %
addrstr )
elif count < 1 :
raise ValueError ( _ ( " Did not find a matching node device for ' %s ' " ) %
addrstr )
2013-03-17 17:06:52 -04:00
2013-04-13 14:34:52 -04:00
2013-03-17 17:06:52 -04:00
def _typeToDeviceClass ( t ) :
2013-09-22 18:13:24 -04:00
if t == NodeDevice . CAPABILITY_TYPE_SYSTEM :
2013-03-17 17:06:52 -04:00
return SystemDevice
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_NET :
2013-03-17 17:06:52 -04:00
return NetDevice
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_PCI :
2013-03-17 17:06:52 -04:00
return PCIDevice
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_USBDEV :
2013-03-17 17:06:52 -04:00
return USBDevice
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_USBBUS :
2013-03-17 17:06:52 -04:00
return USBBus
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_STORAGE :
2013-03-17 17:06:52 -04:00
return StorageDevice
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_SCSIBUS :
2013-03-17 17:06:52 -04:00
return SCSIBus
2013-09-22 18:13:24 -04:00
elif t == NodeDevice . CAPABILITY_TYPE_SCSIDEV :
2013-03-17 17:06:52 -04:00
return SCSIDevice
else :
return NodeDevice