|
|
|
@ -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-33ac-84c5-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-33ac-84c5-d16727083a77/
|
|
|
|
|
LogicalPartition/794654F5-B6E9-4A51-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)
|
|
|
|
|