@ -26,6 +26,7 @@ from nova.objects import flavor as flavor_obj
from nova import utils as n_utils
from nova . virt import configdrive
from nova . virt import driver
from nova . virt import event
import re
from oslo_log import log as logging
@ -41,6 +42,7 @@ from pypowervm.helpers import vios_busy as vio_hlp
from pypowervm . tasks import memory as pvm_mem
from pypowervm . tasks import power as pvm_pwr
from pypowervm . tasks import vterm as pvm_vterm
from pypowervm import util as pvm_util
from pypowervm . wrappers import base_partition as pvm_bp
from pypowervm . wrappers import managed_system as pvm_ms
from pypowervm . wrappers import virtual_io_server as pvm_vios
@ -118,11 +120,26 @@ class PowerVMDriver(driver.ComputeDriver):
LOG . info ( _LI ( " The compute driver has been initialized. " ) )
def cleanup_host ( self , host ) :
""" Clean up anything that is necessary for the driver gracefully stop,
including ending remote sessions . This is optional .
"""
# Stop listening for events
try :
self . session . get_event_listener ( ) . shutdown ( )
except Exception :
pass
LOG . info ( _LI ( " The compute driver has been shutdown. " ) )
def _get_adapter ( self ) :
self . session = pvm_apt . Session ( )
self . adapter = pvm_apt . Adapter (
self . session , helpers = [ log_hlp . log_helper ,
vio_hlp . vios_busy_retry_helper ] )
# Register the event handler
eh = NovaEventHandler ( self )
self . session . get_event_listener ( ) . subscribe ( eh )
def _get_disk_adapter ( self ) :
conn_info = { ' adapter ' : self . adapter , ' host_uuid ' : self . host_uuid ,
@ -1687,3 +1704,124 @@ class PowerVMDriver(driver.ComputeDriver):
return boot_conn_type
else :
return boot_conn_type
class NovaEventHandler ( pvm_apt . RawEventHandler ) :
""" Used to receive and handle events from PowerVM. """
inst_actions_handled = { ' PartitionState ' }
def __init__ ( self , driver ) :
self . _driver = driver
def _handle_event ( self , uri , etype , details , eid ) :
""" Handle an individual event.
: param uri : PowerVM event uri
: param etype : PowerVM event type
: param details : PowerVM event details
: param eid : PowerVM event id
"""
# See if this uri ends with a PowerVM UUID.
if not pvm_util . is_instance_path ( uri ) :
return
pvm_uuid = pvm_util . get_req_path_uuid (
uri , preserve_case = True )
# If a vm event and one we handle, call the inst handler.
if ( uri . endswith ( ' LogicalPartition/ ' + pvm_uuid ) and
( self . inst_actions_handled & set ( details ) ) ) :
inst = vm . get_instance ( ctx . get_admin_context ( ) ,
pvm_uuid )
if inst :
LOG . debug ( ' Handle action " %(action)s " event for instance: '
' %(inst)s ' %
dict ( action = details , inst = inst . name ) )
self . _handle_inst_event (
inst , pvm_uuid , uri , etype , details , eid )
def _handle_inst_event ( self , inst , pvm_uuid , uri , etype , details , eid ) :
""" Handle an instance event.
This method will check if an instance event signals a change in the
state of the instance as known to OpenStack and if so , trigger an
event upward .
: param inst : the instance object .
: param pvm_uuid : the PowerVM uuid of the vm
: param uri : PowerVM event uri
: param etype : PowerVM event type
: param details : PowerVM event details
: param eid : PowerVM event id
"""
# If the state of the vm changed see if it should be handled
if ' PartitionState ' in details :
# Get the current state
pvm_state = vm . get_vm_qp ( self . _driver . adapter , pvm_uuid ,
' PartitionState ' )
# See if it's really a change of state from what OpenStack knows
transition = vm . translate_event ( pvm_state , inst . power_state )
if transition is not None :
LOG . debug ( ' New state for instance: %s ' , pvm_state ,
instance = inst )
# Now create an event and sent it.
lce = event . LifecycleEvent ( inst . uuid , transition )
LOG . info ( _LI ( ' Sending life cycle event for instance state '
' change to: %s ' ) , pvm_state , instance = inst )
self . _driver . emit_event ( lce )
def process ( self , events ) :
""" Process the event that comes back from PowerVM.
Example of event data :
< EventType kb = " ROR " kxe = " false " > NEW_CLIENT < / EventType >
< EventID kxe = " false " kb = " ROR " > 1452692619554 < / EventID >
< EventData kxe = " false " kb = " ROR " / >
< EventDetail kb = " ROR " kxe = " false " / >
< EventType kb = " ROR " kxe = " false " > MODIFY_URI < / EventType >
< EventID kxe = " false " kb = " ROR " > 1452692619557 < / EventID >
< EventData kxe = " false " kb = " ROR " > http : / / localhost : 12080 / rest / api /
uom / ManagedSystem / c889bf0d - 9996 - 33 ac - 84 c5 - d16727083a77
< / EventData >
< EventDetail kb = " ROR " kxe = " false " > Other < / EventDetail >
< EventType kb = " ROR " kxe = " false " > MODIFY_URI < / EventType >
< EventID kxe = " false " kb = " ROR " > 1452692619566 < / EventID >
< EventData kxe = " false " kb = " ROR " > http : / / localhost : 12080 / rest / api /
uom / ManagedSystem / c889bf0d - 9996 - 33 ac - 84 c5 - d16727083a77 /
LogicalPartition / 794654 F5 - B6E9 - 4 A51 - BEC2 - A73E41EAA938
< / EventData >
< EventDetail kb = " ROR " kxe = " false " > RMCState , PartitionState , Other
< / EventDetail >
: param events : A sequence of event dicts that has come back from the
system .
Format :
[
{
' EventType ' : < type > ,
' EventID ' : < id > ,
' EventData ' : < data > ,
' EventDetail ' : < detail >
} ,
]
"""
for pvm_event in events :
try :
# Pull all the pieces of the event.
uri = pvm_event [ ' EventData ' ]
etype = pvm_event [ ' EventType ' ]
details = pvm_event [ ' EventDetail ' ]
details = details . split ( ' , ' ) if details else [ ]
eid = pvm_event [ ' EventID ' ]
if etype not in [ ' NEW_CLIENT ' ] :
LOG . debug ( ' PowerVM Event-Action: %s URI: %s Details %s ' %
( etype , uri , details ) )
self . _handle_event ( uri , etype , details , eid )
except Exception as e :
LOG . exception ( e )
LOG . warning ( _LW ( ' Unable to parse event URI: %s from PowerVM. ' ) ,
uri )