2018-02-27 19:57:29 +03:00
# Copyright (C) 2018 Red Hat, Inc.
#
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.
2018-02-27 19:57:29 +03:00
import logging
import re
import libvirt
2018-02-27 20:29:52 +03:00
if not hasattr ( libvirt , " VIR_DOMAIN_PMSUSPENDED " ) :
setattr ( libvirt , " VIR_DOMAIN_PMSUSPENDED " , 7 )
2018-02-27 19:57:29 +03:00
class _LibvirtEnumMap ( object ) :
"""
Helper for mapping libvirt event int values to their API names
"""
# Some values we define to distinguish between API objects
( DOMAIN_EVENT ,
2018-07-04 11:10:36 +03:00
DOMAIN_AGENT_EVENT ,
2018-02-27 19:57:29 +03:00
NETWORK_EVENT ,
STORAGE_EVENT ,
2018-07-04 11:10:36 +03:00
NODEDEV_EVENT ) = range ( 1 , 6 )
2018-02-27 19:57:29 +03:00
# Regex map for naming all event types depending on the API object
_EVENT_PREFIX = {
DOMAIN_EVENT : " VIR_DOMAIN_EVENT_ID_ " ,
2018-07-04 11:10:36 +03:00
DOMAIN_AGENT_EVENT : " VIR_DOMAIN_EVENT_ID_AGENT_ " ,
2018-02-27 19:57:29 +03:00
NETWORK_EVENT : " VIR_NETWORK_EVENT_ID_ " ,
STORAGE_EVENT : " VIR_STORAGE_POOL_EVENT_ID_ " ,
NODEDEV_EVENT : " VIR_NODE_DEVICE_EVENT_ID_ " ,
}
# Regex map for 'state' values returned from lifecycle and other events
_DETAIL1_PREFIX = {
" VIR_DOMAIN_EVENT_ID_LIFECYCLE " : " VIR_DOMAIN_EVENT_[^_]+$ " ,
2018-07-04 11:10:36 +03:00
" VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE " : _ ( " VIR_CONNECT_DOMAIN_EVENT_AGENT "
" _LIFECYCLE_STATE_[^_]+$ " ) ,
2018-02-27 19:57:29 +03:00
" VIR_NETWORK_EVENT_ID_LIFECYCLE " : " VIR_NETWORK_EVENT_[^_]+$ " ,
" VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE " : " VIR_STORAGE_POOL_EVENT_[^_]+$ " ,
" VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE " : " VIR_NODE_DEVICE_EVENT_[^_]+$ " ,
}
# Regex map for 'reason' values returned from lifecycle and other events
_DETAIL2_PREFIX = {
" VIR_DOMAIN_EVENT_DEFINED " : " VIR_DOMAIN_EVENT_DEFINED_ " ,
" VIR_DOMAIN_EVENT_UNDEFINED " : " VIR_DOMAIN_EVENT_UNDEFINED_ " ,
" VIR_DOMAIN_EVENT_STARTED " : " VIR_DOMAIN_EVENT_STARTED_ " ,
" VIR_DOMAIN_EVENT_SUSPENDED " : " VIR_DOMAIN_EVENT_SUSPENDED_ " ,
" VIR_DOMAIN_EVENT_RESUMED " : " VIR_DOMAIN_EVENT_RESUMED_ " ,
" VIR_DOMAIN_EVENT_STOPPED " : " VIR_DOMAIN_EVENT_STOPPED_ " ,
" VIR_DOMAIN_EVENT_SHUTDOWN " : " VIR_DOMAIN_EVENT_SHUTDOWN_ " ,
" VIR_DOMAIN_EVENT_PMSUSPENDED " : " VIR_DOMAIN_EVENT_PMSUSPENDED_ " ,
" VIR_DOMAIN_EVENT_CRASHED " : " VIR_DOMAIN_EVENT_CRASHED_ " ,
}
2018-02-27 20:29:52 +03:00
VM_STATUS_ICONS = {
libvirt . VIR_DOMAIN_BLOCKED : " state_running " ,
libvirt . VIR_DOMAIN_CRASHED : " state_shutoff " ,
libvirt . VIR_DOMAIN_PAUSED : " state_paused " ,
libvirt . VIR_DOMAIN_RUNNING : " state_running " ,
libvirt . VIR_DOMAIN_SHUTDOWN : " state_shutoff " ,
libvirt . VIR_DOMAIN_SHUTOFF : " state_shutoff " ,
libvirt . VIR_DOMAIN_NOSTATE : " state_running " ,
libvirt . VIR_DOMAIN_PMSUSPENDED : " state_paused " ,
}
@staticmethod
def pretty_run_status ( status , has_managed_save ) :
if status == libvirt . VIR_DOMAIN_RUNNING :
return _ ( " Running " )
elif status == libvirt . VIR_DOMAIN_PAUSED :
return _ ( " Paused " )
elif status == libvirt . VIR_DOMAIN_SHUTDOWN :
return _ ( " Shutting Down " )
elif status == libvirt . VIR_DOMAIN_SHUTOFF :
if has_managed_save :
return _ ( " Saved " )
else :
return _ ( " Shutoff " )
elif status == libvirt . VIR_DOMAIN_CRASHED :
return _ ( " Crashed " )
elif status == libvirt . VIR_DOMAIN_PMSUSPENDED :
return _ ( " Suspended " )
logging . debug ( " Unknown status %s , returning ' Unknown ' " , status )
return _ ( " Unknown " )
@staticmethod
def pretty_status_reason ( status , reason ) :
def key ( x , y ) :
return getattr ( libvirt , " VIR_DOMAIN_ " + x , y )
reasons = {
libvirt . VIR_DOMAIN_RUNNING : {
key ( " RUNNING_BOOTED " , 1 ) : _ ( " Booted " ) ,
key ( " RUNNING_MIGRATED " , 2 ) : _ ( " Migrated " ) ,
key ( " RUNNING_RESTORED " , 3 ) : _ ( " Restored " ) ,
key ( " RUNNING_FROM_SNAPSHOT " , 4 ) : _ ( " From snapshot " ) ,
key ( " RUNNING_UNPAUSED " , 5 ) : _ ( " Unpaused " ) ,
key ( " RUNNING_MIGRATION_CANCELED " , 6 ) : _ ( " Migration canceled " ) ,
key ( " RUNNING_SAVE_CANCELED " , 7 ) : _ ( " Save canceled " ) ,
key ( " RUNNING_WAKEUP " , 8 ) : _ ( " Event wakeup " ) ,
key ( " RUNNING_CRASHED " , 9 ) : _ ( " Crashed " ) ,
} ,
libvirt . VIR_DOMAIN_PAUSED : {
key ( " PAUSED_USER " , 1 ) : _ ( " User " ) ,
key ( " PAUSED_MIGRATION " , 2 ) : _ ( " Migrating " ) ,
key ( " PAUSED_SAVE " , 3 ) : _ ( " Saving " ) ,
key ( " PAUSED_DUMP " , 4 ) : _ ( " Dumping " ) ,
key ( " PAUSED_IOERROR " , 5 ) : _ ( " I/O error " ) ,
key ( " PAUSED_WATCHDOG " , 6 ) : _ ( " Watchdog " ) ,
key ( " PAUSED_FROM_SNAPSHOT " , 7 ) : _ ( " From snapshot " ) ,
key ( " PAUSED_SHUTTING_DOWN " , 8 ) : _ ( " Shutting down " ) ,
key ( " PAUSED_SNAPSHOT " , 9 ) : _ ( " Creating snapshot " ) ,
key ( " PAUSED_CRASHED " , 10 ) : _ ( " Crashed " ) ,
} ,
libvirt . VIR_DOMAIN_SHUTDOWN : {
key ( " SHUTDOWN_USER " , 1 ) : _ ( " User " ) ,
} ,
libvirt . VIR_DOMAIN_SHUTOFF : {
key ( " SHUTOFF_SHUTDOWN " , 1 ) : _ ( " Shut Down " ) ,
key ( " SHUTOFF_DESTROYED " , 2 ) : _ ( " Destroyed " ) ,
key ( " SHUTOFF_CRASHED " , 3 ) : _ ( " Crashed " ) ,
key ( " SHUTOFF_MIGRATED " , 4 ) : _ ( " Migrated " ) ,
key ( " SHUTOFF_SAVED " , 5 ) : _ ( " Saved " ) ,
key ( " SHUTOFF_FAILED " , 6 ) : _ ( " Failed " ) ,
key ( " SHUTOFF_FROM_SNAPSHOT " , 7 ) : _ ( " From snapshot " ) ,
} ,
libvirt . VIR_DOMAIN_CRASHED : {
key ( " CRASHED_PANICKED " , 1 ) : _ ( " Panicked " ) ,
}
}
return reasons . get ( status ) and reasons [ status ] . get ( reason )
2018-02-27 19:57:29 +03:00
def __init__ ( self ) :
self . _mapping = { }
def _make_map ( self , regex ) :
# Run the passed regex over dir(libvirt) output
ret = { }
for key in [ a for a in dir ( libvirt ) if re . match ( regex , a ) ] :
val = getattr ( libvirt , key )
if type ( val ) is not int :
logging . debug ( " libvirt regex= %s key= %s val= %s "
" isn ' t an integer " , regex , key , val )
continue
if val in ret :
logging . debug ( " libvirt regex= %s key= %s val= %s is already "
" in dict as key= %s " , regex , key , val , regex [ val ] )
continue
ret [ val ] = key
return ret
def _get_map ( self , key , regex ) :
if regex is None :
return { }
if key not in self . _mapping :
self . _mapping [ key ] = self . _make_map ( regex )
return self . _mapping [ key ]
def _make_strs ( self , api , event , detail1 , detail2 ) :
eventstr = str ( event )
detail1str = str ( detail1 )
detail2str = str ( detail2 )
eventmap = self . _get_map ( api , self . _EVENT_PREFIX [ api ] )
2018-07-04 11:10:36 +03:00
if eventmap :
if event not in eventmap :
event = next ( iter ( eventmap ) )
2018-02-27 19:57:29 +03:00
eventstr = eventmap [ event ]
detail1map = self . _get_map ( eventstr ,
self . _DETAIL1_PREFIX . get ( eventstr ) )
if detail1 in detail1map :
detail1str = detail1map [ detail1 ]
detail2map = self . _get_map ( detail1str ,
self . _DETAIL2_PREFIX . get ( detail1str ) )
if detail2 in detail2map :
detail2str = detail2map [ detail2 ]
return eventstr , detail1str , detail2str
def _state_str ( self , api , detail1 , detail2 ) :
ignore , d1str , d2str = self . _make_strs ( api , 0 ,
detail1 , detail2 )
return " state= %s reason= %s " % ( d1str , d2str )
def domain_lifecycle_str ( self , detail1 , detail2 ) :
return self . _state_str ( self . DOMAIN_EVENT , detail1 , detail2 )
def network_lifecycle_str ( self , detail1 , detail2 ) :
return self . _state_str ( self . NETWORK_EVENT , detail1 , detail2 )
def storage_lifecycle_str ( self , detail1 , detail2 ) :
return self . _state_str ( self . STORAGE_EVENT , detail1 , detail2 )
def nodedev_lifecycle_str ( self , detail1 , detail2 ) :
return self . _state_str ( self . NODEDEV_EVENT , detail1 , detail2 )
2018-07-04 11:10:36 +03:00
def domain_agent_lifecycle_str ( self , detail1 , detail2 ) :
return self . _state_str ( self . DOMAIN_AGENT_EVENT , detail1 , detail2 )
2018-02-27 19:57:29 +03:00
LibvirtEnumMap = _LibvirtEnumMap ( )