def test_events(self): got_events = [] def handler(event): got_events.append(event) self.connection.register_event_listener(handler) event1 = virtevent.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", virtevent.EVENT_LIFECYCLE_STARTED) event2 = virtevent.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", virtevent.EVENT_LIFECYCLE_PAUSED) self.connection.emit_event(event1) self.connection.emit_event(event2) want_events = [event1, event2] self.assertEqual(want_events, got_events) event3 = virtevent.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", virtevent.EVENT_LIFECYCLE_RESUMED) event4 = virtevent.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", virtevent.EVENT_LIFECYCLE_STOPPED) self.connection.emit_event(event3) self.connection.emit_event(event4) want_events = [event1, event2, event3, event4] self.assertEqual(want_events, got_events)
def test_event_dispatch(self): # Validate that the libvirt self-pipe for forwarding # events between threads is working sanely def handler(event): got_events.append(event) hostimpl = host.Host("qemu:///system", lifecycle_event_handler=handler) got_events = [] hostimpl._init_events_pipe() event1 = event.LifecycleEvent("cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_STARTED) event2 = event.LifecycleEvent("cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_PAUSED) hostimpl._queue_event(event1) hostimpl._queue_event(event2) hostimpl._dispatch_events() want_events = [event1, event2] self.assertEqual(want_events, got_events) event3 = event.LifecycleEvent("cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_RESUMED) event4 = event.LifecycleEvent("cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_STOPPED) hostimpl._queue_event(event3) hostimpl._queue_event(event4) hostimpl._dispatch_events() want_events = [event1, event2, event3, event4] self.assertEqual(want_events, got_events)
def _event_lifecycle_callback(conn, dom, event, detail, opaque): """Receives lifecycle events from libvirt. NB: this method is executing in a native thread, not an eventlet coroutine. It can only invoke other libvirt APIs, or use self._queue_event(). Any use of logging APIs in particular is forbidden. """ self = opaque uuid = dom.UUIDString() transition = None if event == libvirt.VIR_DOMAIN_EVENT_STOPPED: # WRS: transition to crashed if stop failed if detail == libvirt.VIR_DOMAIN_EVENT_STOPPED_FAILED: transition = virtevent.EVENT_LIFECYCLE_CRASHED else: transition = virtevent.EVENT_LIFECYCLE_STOPPED elif event == libvirt.VIR_DOMAIN_EVENT_STARTED: transition = virtevent.EVENT_LIFECYCLE_STARTED elif event == libvirt.VIR_DOMAIN_EVENT_SUSPENDED: transition = virtevent.EVENT_LIFECYCLE_PAUSED elif event == libvirt.VIR_DOMAIN_EVENT_RESUMED: transition = virtevent.EVENT_LIFECYCLE_RESUMED if transition is not None: self._queue_event(virtevent.LifecycleEvent(uuid, transition))
def _event_lifecycle_callback(conn, dom, event, detail, opaque): """Receives lifecycle events from libvirt. NB: this method is executing in a native thread, not an eventlet coroutine. It can only invoke other libvirt APIs, or use self._queue_event(). Any use of logging APIs in particular is forbidden. """ self = opaque uuid = dom.UUIDString() transition = None if event == libvirt.VIR_DOMAIN_EVENT_STOPPED: transition = virtevent.EVENT_LIFECYCLE_STOPPED elif event == libvirt.VIR_DOMAIN_EVENT_STARTED: transition = virtevent.EVENT_LIFECYCLE_STARTED elif event == libvirt.VIR_DOMAIN_EVENT_SUSPENDED: if detail == libvirt.VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: transition = virtevent.EVENT_LIFECYCLE_POSTCOPY_STARTED # FIXME(mriedem): VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED is also sent # when live migration of the guest fails, so we cannot simply rely # on the event itself but need to check if the job itself was # successful. # elif detail == libvirt.VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: # transition = virtevent.EVENT_LIFECYCLE_MIGRATION_COMPLETED else: transition = virtevent.EVENT_LIFECYCLE_PAUSED elif event == libvirt.VIR_DOMAIN_EVENT_RESUMED: transition = virtevent.EVENT_LIFECYCLE_RESUMED if transition is not None: self._queue_event(virtevent.LifecycleEvent(uuid, transition))
def _emit_event(self, pvm_state, inst, is_immed): if is_immed: # Cancel out any delayed events cancel_thread = self._delayed_event_threads.get(inst.uuid) if cancel_thread: cancel_thread.cancel() del self._delayed_event_threads[inst.uuid] else: # Make sure you're still in the thread. If not (thread was started # but the is_immed _emit_event had run the del), then just bail inst_queue = self._delayed_event_threads.get(inst.uuid) if not inst_queue: return # 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 None: return # Log as if normal event 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) if not is_immed: # Delete out the queue del self._delayed_event_threads[inst.uuid]
def test_event_emit_delayed_call_delayed(self, spawn_after_mock): hostimpl = host.Host("xen:///", lifecycle_event_handler=lambda e: None) ev = event.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_STOPPED) hostimpl._event_emit_delayed(ev) spawn_after_mock.assert_called_once_with(15, hostimpl._event_emit, ev)
def test_event_emit_delayed_call_delayed_pending(self, spawn_after_mock): hostimpl = host.Host("xen:///", lifecycle_event_handler=lambda e: None) uuid = "cef19ce0-0ca2-11df-855d-b19fbce37686" hostimpl._events_delayed[uuid] = None ev = event.LifecycleEvent(uuid, event.EVENT_LIFECYCLE_STOPPED) hostimpl._event_emit_delayed(ev) self.assertFalse(spawn_after_mock.called)
def test_event_delayed_cleanup(self): hostimpl = host.Host("xen:///", lifecycle_event_handler=lambda e: None) uuid = "cef19ce0-0ca2-11df-855d-b19fbce37686" ev = event.LifecycleEvent(uuid, event.EVENT_LIFECYCLE_STARTED) gt_mock = mock.Mock() hostimpl._events_delayed[uuid] = gt_mock hostimpl._event_emit_delayed(ev) gt_mock.cancel.assert_called_once_with() self.assertNotIn(uuid, hostimpl._events_delayed.keys())
def test_event_emit_delayed_call_delayed(self): ev = event.LifecycleEvent("cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_STOPPED) for uri in ("qemu:///system", "xen:///"): spawn_after_mock = mock.Mock() greenthread.spawn_after = spawn_after_mock hostimpl = host.Host(uri, lifecycle_event_handler=lambda e: None) hostimpl._event_emit_delayed(ev) spawn_after_mock.assert_called_once_with(15, hostimpl._event_emit, ev)
def test_emit_unicode_event(self): """Tests that we do not fail on translated unicode events.""" started_event = virtevent.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", virtevent.EVENT_LIFECYCLE_STARTED) callback = mock.Mock() self.connection.register_event_listener(callback) with mock.patch.object(started_event, 'get_name', return_value=u'\xF0\x9F\x92\xA9'): self.connection.emit_event(started_event) callback.assert_called_once_with(started_event)
def test_event_emit_delayed_call_now(self): got_events = [] def handler(event): got_events.append(event) hostimpl = host.Host("qemu:///system", lifecycle_event_handler=handler) ev = event.LifecycleEvent("cef19ce0-0ca2-11df-855d-b19fbce37686", event.EVENT_LIFECYCLE_STOPPED) hostimpl._event_emit_delayed(ev) self.assertEqual(1, len(got_events)) self.assertEqual(ev, got_events[0])
def test_event_repr(self): t = time.time() uuid = '1234' lifecycle = event.EVENT_LIFECYCLE_RESUMED e = event.Event(t) self.assertEqual(str(e), "<Event: %s>" % t) e = event.InstanceEvent(uuid, timestamp=t) self.assertEqual(str(e), "<InstanceEvent: %s, %s>" % (t, uuid)) e = event.LifecycleEvent(uuid, lifecycle, timestamp=t) self.assertEqual(str(e), "<LifecycleEvent: %s, %s => Resumed>" % (t, uuid))
def _event_lifecycle_callback(conn, dom, event, detail, opaque): """Receives lifecycle events from libvirt. NB: this method is executing in a native thread, not an eventlet coroutine. It can only invoke other libvirt APIs, or use self._queue_event(). Any use of logging APIs in particular is forbidden. """ self = opaque uuid = dom.UUIDString() transition = None if event == libvirt.VIR_DOMAIN_EVENT_STOPPED: transition = virtevent.EVENT_LIFECYCLE_STOPPED elif event == libvirt.VIR_DOMAIN_EVENT_STARTED: transition = virtevent.EVENT_LIFECYCLE_STARTED elif event == libvirt.VIR_DOMAIN_EVENT_SUSPENDED: if detail == libvirt.VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: transition = virtevent.EVENT_LIFECYCLE_POSTCOPY_STARTED elif detail == libvirt.VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: # VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED is also sent when live # migration of the guest fails, so we cannot simply rely # on the event itself but need to check if the job itself was # successful. # NOTE(mriedem): The job check logic here is copied from # LibvirtDriver._live_migration_monitor. guest = libvirt_guest.Guest(dom) info = guest.get_job_info() if info.type == libvirt.VIR_DOMAIN_JOB_NONE: # Either still running, or failed or completed, # lets untangle the mess. info.type = libvirt_migrate.find_job_type(guest, instance=None, logging_ok=False) if info.type == libvirt.VIR_DOMAIN_JOB_COMPLETED: transition = virtevent.EVENT_LIFECYCLE_MIGRATION_COMPLETED else: # Failed or some other status we don't know about, so just # opt to report the guest is paused. transition = virtevent.EVENT_LIFECYCLE_PAUSED else: transition = virtevent.EVENT_LIFECYCLE_PAUSED elif event == libvirt.VIR_DOMAIN_EVENT_RESUMED: transition = virtevent.EVENT_LIFECYCLE_RESUMED if transition is not None: self._queue_event(virtevent.LifecycleEvent(uuid, transition))
def _emit_event(self, pvm_uuid, inst): # Get the current state try: pvm_state = vm.get_vm_qp(self._driver.adapter, pvm_uuid, 'PartitionState') except exception.InstanceNotFound: LOG.debug("LPAR %s was deleted while event was delayed.", pvm_uuid, instance=inst) return LOG.debug('New state %s for partition %s', pvm_state, pvm_uuid, instance=inst) inst = _get_instance(inst, pvm_uuid) if inst is None: LOG.debug("Not emitting LifecycleEvent: no instance for LPAR %s", pvm_uuid) return # If we're in the middle of a nova-driven operation, no event necessary if inst.task_state in _NO_EVENT_TASK_STATES: LOG.debug("Not emitting LifecycleEvent: instance task_state is %s", inst.task_state, instance=inst) return # 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 None: LOG.debug( "No LifecycleEvent necessary for pvm_state(%s) and " "power_state(%s).", pvm_state, power_state.STATE_MAP[inst.power_state], instance=inst) return # Log as if normal event lce = event.LifecycleEvent(inst.uuid, transition) LOG.info('Sending LifecycleEvent for instance state change to: %s', pvm_state, instance=inst) self._driver.emit_event(lce) # Delete out the queue del self._delayed_event_threads[pvm_uuid]
def test_event_bad_callback(self): # Check that if a callback raises an exception, # it does not propagate back out of the # 'emit_event' call def handler(event): raise Exception("Hit Me!") self.connection.register_event_listener(handler) event1 = virtevent.LifecycleEvent( "cef19ce0-0ca2-11df-855d-b19fbce37686", virtevent.EVENT_LIFECYCLE_STARTED) self.connection.emit_event(event1)
def _event_lifecycle_callback(conn, dom, event, detail, opaque): """Receives lifecycle events from libvirt. NB: this method is executing in a native thread, not an eventlet coroutine. It can only invoke other libvirt APIs, or use self._queue_event(). Any use of logging APIs in particular is forbidden. """ self = opaque uuid = dom.UUIDString() transition = None if event == libvirt.VIR_DOMAIN_EVENT_STOPPED: transition = virtevent.EVENT_LIFECYCLE_STOPPED elif event == libvirt.VIR_DOMAIN_EVENT_STARTED: transition = virtevent.EVENT_LIFECYCLE_STARTED elif event == libvirt.VIR_DOMAIN_EVENT_SUSPENDED: # NOTE(siva_krishnan): We have to check if # VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY and # VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED exist since the current # minimum version of libvirt (1.3.1) don't have those attributes. # This check can be removed once MIN_LIBVIRT_VERSION is bumped to # at least 1.3.3. if (hasattr(libvirt, 'VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY') and detail == libvirt.VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY): transition = virtevent.EVENT_LIFECYCLE_POSTCOPY_STARTED # FIXME(mriedem): VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED is also sent # when live migration of the guest fails, so we cannot simply rely # on the event itself but need to check if the job itself was # successful. # elif (hasattr(libvirt, 'VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED') and # detail == libvirt.VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED): # transition = virtevent.EVENT_LIFECYCLE_MIGRATION_COMPLETED else: transition = virtevent.EVENT_LIFECYCLE_PAUSED elif event == libvirt.VIR_DOMAIN_EVENT_RESUMED: transition = virtevent.EVENT_LIFECYCLE_RESUMED if transition is not None: self._queue_event(virtevent.LifecycleEvent(uuid, transition))
def _get_virt_event(self, instance_uuid, instance_state): transition = self._TRANSITION_MAP[instance_state] return virtevent.LifecycleEvent(uuid=instance_uuid, transition=transition)