On Mon, Nov 17, 2008 at 01:05:30PM +0000, Daniel P. Berrange wrote: > On Mon, Nov 17, 2008 at 01:03:29PM +0100, Daniel Veillard wrote: > > On Fri, Nov 14, 2008 at 05:44:29PM +0000, Daniel P. Berrange wrote: > > > As per our earlier discussion today, this patch expands the callback for > > > domain events so that it also gets a event type specific 'detail' field. > > > This is also kept as an int, and we define enumerations for the possible > > > values associated with each type. > > [...] > > > > Okay, that made the overall callbacks set clearer, ACK > > > > > If a event type has no detail, 0 is passed. > > > > Actually I would define a detail enum for all event type just to > > make clear what the value will be and expose how it's intended to be > > extended if needed. This new patch does that now. > > > > > A word about migration... > > > > > > - The destination host first gets a STARTED event, with detail MIGRATED > > > when it starts running > > > - The source host then gets a STOPPED event with detail MIGRATED when > > > it completes > > > > What about 'live' migration, i.e. events sent when the migration flows > > begin but the domain is stil running. I don't know if KVM has this but > > on Xen I would expect to be able to notice this. On the target host that > > could be indicated by SUSPENDED + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED > > because it will consume the memory resource like a suspended domain but > > no actual CPU cycle (well except for migration itself). On the source > > host this is a bit harder to indicate, maybe this isn't needed as the > > resource usage doesn't really change at that point. > > The problem with live migration is that, by definition, there is no change > in the domain on the source host until migration is complete. It remains > in the 'running' state the entire time and does not undergo any lifecycle > transitions, so there's no event we could generate for the start of a > migrate event on the source. Only the destination host gets an explicit > lifecycle change at the start & end of migration operation. > > For non-live migration of course, you would get a transition from the > running state, to the paused state on the source host when migration > starts, and that actually does mean we need to define another enum for > 'detail' on the 'suspended' and 'resumed' events too. Turns out the QEMU migration implementation was incorrectly ignoring the 'flags' argument and doing all migration operations as 'live'. So this patch fixes that, to pause the VM before migration if non-live was requested. It'll emit VIR_DOMAIN_EVENT_SUSPENDED, with detail field value of VIR_DOMAIN_EVENT_SUSPENED_MIGRATED when starting a non-live migration. I also fixed the patch to use VIR_DOMAIN_EVENT_RESUMED_MIGRATED when the migration operation completes on the destination. Daniel diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c --- a/examples/domain-events/events-c/event-test.c +++ b/examples/domain-events/events-c/event-test.c @@ -35,9 +35,9 @@ void *t_opaque = NULL; /* Prototypes */ const char *eventToString(int event); int myDomainEventCallback1 (virConnectPtr conn, virDomainPtr dom, - int event, void *opaque); + int event, int detail, void *opaque); int myDomainEventCallback2 (virConnectPtr conn, virDomainPtr dom, - int event, void *opaque); + int event, int detail, void *opaque); int myEventAddHandleFunc (int fd, int event, virEventHandleCallback cb, void *opaque); void myEventUpdateHandleFunc(int fd, int event); @@ -58,11 +58,11 @@ const char *eventToString(int event) { const char *eventToString(int event) { const char *ret = NULL; switch(event) { - case VIR_DOMAIN_EVENT_ADDED: - ret ="Added"; + case VIR_DOMAIN_EVENT_DEFINED: + ret ="Defined"; break; - case VIR_DOMAIN_EVENT_REMOVED: - ret ="Removed"; + case VIR_DOMAIN_EVENT_UNDEFINED: + ret ="Undefined"; break; case VIR_DOMAIN_EVENT_STARTED: ret ="Started"; @@ -76,14 +76,56 @@ const char *eventToString(int event) { case VIR_DOMAIN_EVENT_STOPPED: ret ="Stopped"; break; - case VIR_DOMAIN_EVENT_SAVED: - ret ="Saved"; - break; - case VIR_DOMAIN_EVENT_RESTORED: - ret ="Restored"; - break; default: ret ="Unknown Event"; + } + return ret; +} + +static const char *eventDetailToString(int event, int detail) { + const char *ret = ""; + switch(event) { + case VIR_DOMAIN_EVENT_DEFINED: + if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) + ret = "Added"; + else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) + ret = "Updated"; + break; + case VIR_DOMAIN_EVENT_STARTED: + switch (detail) { + case VIR_DOMAIN_EVENT_STARTED_BOOTED: + ret = "Booted"; + break; + case VIR_DOMAIN_EVENT_STARTED_MIGRATED: + ret = "Migrated"; + break; + case VIR_DOMAIN_EVENT_STARTED_RESTORED: + ret = "Restored"; + break; + } + break; + case VIR_DOMAIN_EVENT_STOPPED: + switch (detail) { + case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN: + ret = "Shutdown"; + break; + case VIR_DOMAIN_EVENT_STOPPED_DESTROYED: + ret = "Destroyed"; + break; + case VIR_DOMAIN_EVENT_STOPPED_CRASHED: + ret = "Crashed"; + break; + case VIR_DOMAIN_EVENT_STOPPED_MIGRATED: + ret = "Migrated"; + break; + case VIR_DOMAIN_EVENT_STOPPED_SAVED: + ret = "Failed"; + break; + case VIR_DOMAIN_EVENT_STOPPED_FAILED: + ret = "Failed"; + break; + } + break; } return ret; } @@ -91,20 +133,24 @@ int myDomainEventCallback1 (virConnectPt int myDomainEventCallback1 (virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, int event, + int detail, void *opaque ATTRIBUTE_UNUSED) { - printf("%s EVENT: Domain %s(%d) %s\n", __FUNCTION__, virDomainGetName(dom), - virDomainGetID(dom), eventToString(event)); + printf("%s EVENT: Domain %s(%d) %s %s\n", __FUNCTION__, virDomainGetName(dom), + virDomainGetID(dom), eventToString(event), + eventDetailToString(event, detail)); return 0; } int myDomainEventCallback2 (virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, int event, + int detail, void *opaque ATTRIBUTE_UNUSED) { - printf("%s EVENT: Domain %s(%d) %s\n", __FUNCTION__, virDomainGetName(dom), - virDomainGetID(dom), eventToString(event)); + printf("%s EVENT: Domain %s(%d) %s %s\n", __FUNCTION__, virDomainGetName(dom), + virDomainGetID(dom), eventToString(event), + eventDetailToString(event, detail)); return 0; } diff --git a/examples/domain-events/events-python/event-test.py b/examples/domain-events/events-python/event-test.py --- a/examples/domain-events/events-python/event-test.py +++ b/examples/domain-events/events-python/event-test.py @@ -32,11 +32,11 @@ def eventToString(event): "Restored" ); return eventStrings[event]; -def myDomainEventCallback1 (conn, dom, event, opaque): - print "myDomainEventCallback1 EVENT: Domain %s(%s) %s" % (dom.name(), dom.ID(), eventToString(event)) +def myDomainEventCallback1 (conn, dom, event, detail, opaque): + print "myDomainEventCallback1 EVENT: Domain %s(%s) %s %d" % (dom.name(), dom.ID(), eventToString(event), detail) -def myDomainEventCallback2 (conn, dom, event, opaque): - print "myDomainEventCallback2 EVENT: Domain %s(%s) %s" % (dom.name(), dom.ID(), eventToString(event)) +def myDomainEventCallback2 (conn, dom, event, detail, opaque): + print "myDomainEventCallback2 EVENT: Domain %s(%s) %s %d" % (dom.name(), dom.ID(), eventToString(event), detail) ##################################################### # EventImpl Functions diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -1004,21 +1004,85 @@ virDomainPtr virDomainCreateL * a virDomainEventType is emitted during domain lifecycle events */ typedef enum { - VIR_DOMAIN_EVENT_ADDED = 0, - VIR_DOMAIN_EVENT_REMOVED = 1, + VIR_DOMAIN_EVENT_DEFINED = 0, + VIR_DOMAIN_EVENT_UNDEFINED = 1, VIR_DOMAIN_EVENT_STARTED = 2, VIR_DOMAIN_EVENT_SUSPENDED = 3, VIR_DOMAIN_EVENT_RESUMED = 4, VIR_DOMAIN_EVENT_STOPPED = 5, - VIR_DOMAIN_EVENT_SAVED = 6, - VIR_DOMAIN_EVENT_RESTORED = 7, } virDomainEventType; + +/** + * virDomainEventDefinedDetailType: + * + * Details on the caused of the 'defined' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_DEFINED_ADDED = 0, /* Newly created config file */ + VIR_DOMAIN_EVENT_DEFINED_UPDATED = 1, /* Changed config file */ +} virDomainEventDefinedDetailType; + +/** + * virDomainEventUndefinedDetailType: + * + * Details on the caused of the 'undefined' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED = 0, /* Deleted the config file */ +} virDomainEventUndefinedDetailType; + +/** + * virDomainEventStartedDetailType: + * + * Details on the caused of the 'started' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_STARTED_BOOTED = 0, /* Normal startup from boot */ + VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host */ + VIR_DOMAIN_EVENT_STARTED_RESTORED = 2, /* Restored from a state file */ +} virDomainEventStartedDetailType; + +/** + * virDomainEventSuspendedDetailType: + * + * Details on the caused of the 'suspended' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED = 0, /* Normal suspend due to admin pause */ + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration */ +} virDomainEventSuspendedDetailType; + +/** + * virDomainEventResumedDetailType: + * + * Details on the caused of the 'resumed' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_RESUMED_UNPAUSED = 0, /* Normal resume due to admin unpause */ + VIR_DOMAIN_EVENT_RESUMED_MIGRATED = 1, /* Resumed for completion of migration */ +} virDomainEventResumedDetailType; + +/** + * virDomainEventStoppedDetailType: + * + * Details on the caused of the 'stopped' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN = 0, /* Normal shutdown */ + VIR_DOMAIN_EVENT_STOPPED_DESTROYED = 1, /* Forced poweroff from host */ + VIR_DOMAIN_EVENT_STOPPED_CRASHED = 2, /* Guest crashed */ + VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3, /* Migrated off to another host */ + VIR_DOMAIN_EVENT_STOPPED_SAVED = 4, /* Saved to a state file */ + VIR_DOMAIN_EVENT_STOPPED_FAILED = 5, /* Host emulator/mgmt failed */ +} virDomainEventStoppedDetailType; + /** * virConnectDomainEventCallback: * @conn: virConnect connection * @dom: The domain on which the event occured * @event: The specfic virDomainEventType which occured + * @detail: event specific detail information * @opaque: opaque user data * * A callback function to be registered, and called when a domain event occurs @@ -1026,6 +1090,7 @@ typedef int (*virConnectDomainEventCallb typedef int (*virConnectDomainEventCallback)(virConnectPtr conn, virDomainPtr dom, int event, + int detail, void *opaque); int virConnectDomainEventRegister(virConnectPtr conn, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1004,21 +1004,85 @@ virDomainPtr virDomainCreateL * a virDomainEventType is emitted during domain lifecycle events */ typedef enum { - VIR_DOMAIN_EVENT_ADDED = 0, - VIR_DOMAIN_EVENT_REMOVED = 1, + VIR_DOMAIN_EVENT_DEFINED = 0, + VIR_DOMAIN_EVENT_UNDEFINED = 1, VIR_DOMAIN_EVENT_STARTED = 2, VIR_DOMAIN_EVENT_SUSPENDED = 3, VIR_DOMAIN_EVENT_RESUMED = 4, VIR_DOMAIN_EVENT_STOPPED = 5, - VIR_DOMAIN_EVENT_SAVED = 6, - VIR_DOMAIN_EVENT_RESTORED = 7, } virDomainEventType; + +/** + * virDomainEventDefinedDetailType: + * + * Details on the caused of the 'defined' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_DEFINED_ADDED = 0, /* Newly created config file */ + VIR_DOMAIN_EVENT_DEFINED_UPDATED = 1, /* Changed config file */ +} virDomainEventDefinedDetailType; + +/** + * virDomainEventUndefinedDetailType: + * + * Details on the caused of the 'undefined' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED = 0, /* Deleted the config file */ +} virDomainEventUndefinedDetailType; + +/** + * virDomainEventStartedDetailType: + * + * Details on the caused of the 'started' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_STARTED_BOOTED = 0, /* Normal startup from boot */ + VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host */ + VIR_DOMAIN_EVENT_STARTED_RESTORED = 2, /* Restored from a state file */ +} virDomainEventStartedDetailType; + +/** + * virDomainEventSuspendedDetailType: + * + * Details on the caused of the 'suspended' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED = 0, /* Normal suspend due to admin pause */ + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration */ +} virDomainEventSuspendedDetailType; + +/** + * virDomainEventResumedDetailType: + * + * Details on the caused of the 'resumed' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_RESUMED_UNPAUSED = 0, /* Normal resume due to admin unpause */ + VIR_DOMAIN_EVENT_RESUMED_MIGRATED = 1, /* Resumed for completion of migration */ +} virDomainEventResumedDetailType; + +/** + * virDomainEventStoppedDetailType: + * + * Details on the caused of the 'stopped' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN = 0, /* Normal shutdown */ + VIR_DOMAIN_EVENT_STOPPED_DESTROYED = 1, /* Forced poweroff from host */ + VIR_DOMAIN_EVENT_STOPPED_CRASHED = 2, /* Guest crashed */ + VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3, /* Migrated off to another host */ + VIR_DOMAIN_EVENT_STOPPED_SAVED = 4, /* Saved to a state file */ + VIR_DOMAIN_EVENT_STOPPED_FAILED = 5, /* Host emulator/mgmt failed */ +} virDomainEventStoppedDetailType; + /** * virConnectDomainEventCallback: * @conn: virConnect connection * @dom: The domain on which the event occured * @event: The specfic virDomainEventType which occured + * @detail: event specific detail information * @opaque: opaque user data * * A callback function to be registered, and called when a domain event occurs @@ -1026,6 +1090,7 @@ typedef int (*virConnectDomainEventCallb typedef int (*virConnectDomainEventCallback)(virConnectPtr conn, virDomainPtr dom, int event, + int detail, void *opaque); int virConnectDomainEventRegister(virConnectPtr conn, diff --git a/python/libvir.c b/python/libvir.c --- a/python/libvir.c +++ b/python/libvir.c @@ -1538,6 +1538,7 @@ libvirt_virConnectDomainEventCallback(vi libvirt_virConnectDomainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, int event, + int detail, void *opaque) { PyObject *pyobj_ret; @@ -1595,9 +1596,10 @@ libvirt_virConnectDomainEventCallback(vi /* Call the Callback Dispatcher */ pyobj_ret = PyObject_CallMethod(pyobj_conn_inst, (char*)"dispatchDomainEventCallbacks", - (char*)"Oi", + (char*)"Oii", pyobj_dom_inst, - event); + event, + detail); Py_DECREF(pyobj_dom_inst); diff --git a/qemud/qemud.h b/qemud/qemud.h --- a/qemud/qemud.h +++ b/qemud/qemud.h @@ -190,6 +190,7 @@ int remoteRelayDomainEvent (virConnectPt int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, int event, + int detail, void *opaque); #endif diff --git a/qemud/remote.c b/qemud/remote.c --- a/qemud/remote.c +++ b/qemud/remote.c @@ -80,7 +80,8 @@ static void static void remoteDispatchDomainEventSend (struct qemud_client *client, virDomainPtr dom, - virDomainEventType event); + int event, + int detail); /* This function gets called from qemud when it detects an incoming * remote protocol message. At this point, client->buffer contains @@ -413,15 +414,16 @@ remoteDispatchError (struct qemud_client } int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int event, - void *opaque) + virDomainPtr dom, + int event, + int detail, + void *opaque) { struct qemud_client *client = opaque; - REMOTE_DEBUG("Relaying domain event %d", event); + REMOTE_DEBUG("Relaying domain event %d %d", event, detail); if(client) { - remoteDispatchDomainEventSend (client, dom, event); + remoteDispatchDomainEventSend (client, dom, event, detail); qemudDispatchClientWrite(client->server,client); } return 0; @@ -3779,8 +3781,9 @@ remoteDispatchDomainEventsDeregister (st static void remoteDispatchDomainEventSend (struct qemud_client *client, - virDomainPtr dom, - virDomainEventType event) + virDomainPtr dom, + int event, + int detail) { remote_message_header rep; XDR xdr; @@ -3816,7 +3819,8 @@ remoteDispatchDomainEventSend (struct qe /* build return data */ make_nonnull_domain (&data.dom, dom); - data.event = (int) event; + data.event = event; + data.detail = detail; if (!xdr_remote_domain_event_ret(&xdr, &data)) { remoteDispatchError (client, NULL, "%s", _("serialise return struct")); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -2033,6 +2033,8 @@ xdr_remote_domain_event_ret (XDR *xdrs, return FALSE; if (!xdr_int (xdrs, &objp->event)) return FALSE; + if (!xdr_int (xdrs, &objp->detail)) + return FALSE; return TRUE; } diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -1135,6 +1135,7 @@ struct remote_domain_event_ret { struct remote_domain_event_ret { remote_nonnull_domain dom; int event; + int detail; }; typedef struct remote_domain_event_ret remote_domain_event_ret; #define REMOTE_PROGRAM 0x20008086 diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -1011,6 +1011,7 @@ struct remote_domain_event_ret { struct remote_domain_event_ret { remote_nonnull_domain dom; int event; + int detail; }; /*----- Protocol. -----*/ diff --git a/src/domain_event.c b/src/domain_event.c --- a/src/domain_event.c +++ b/src/domain_event.c @@ -198,7 +198,8 @@ int int virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue, virDomainPtr dom, - virDomainEventType event) + int event, + int detail) { virDomainEventPtr domEvent; @@ -214,6 +215,7 @@ virDomainEventCallbackQueuePush(virDomai } domEvent->dom = dom; domEvent->event = event; + domEvent->detail = detail; /* Make space on queue */ if (VIR_REALLOC_N(evtQueue->events, diff --git a/src/domain_event.h b/src/domain_event.h --- a/src/domain_event.h +++ b/src/domain_event.h @@ -58,7 +58,8 @@ int virDomainEventCallbackListRemove(vir */ struct _virDomainEvent { virDomainPtr dom; - virDomainEventType event; + int event; + int detail; }; typedef struct _virDomainEvent virDomainEvent; typedef virDomainEvent *virDomainEventPtr; @@ -72,7 +73,8 @@ typedef virDomainEventQueue *virDomainEv int virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue, virDomainPtr dom, - virDomainEventType event); + int event, + int detail); virDomainEventPtr virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue); diff --git a/src/qemu_driver.c b/src/qemu_driver.c --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -107,7 +107,8 @@ static int qemudSetNonBlock(int fd) { static void qemudDomainEventDispatch (struct qemud_driver *driver, virDomainObjPtr vm, - virDomainEventType evt); + int event, + int detail); static void qemudDispatchVMEvent(int fd, int events, @@ -137,13 +138,19 @@ qemudAutostartConfigs(struct qemud_drive unsigned int i; for (i = 0 ; i < driver->domains.count ; i++) { - if (driver->domains.objs[i]->autostart && - !virDomainIsActive(driver->domains.objs[i]) && - qemudStartVMDaemon(NULL, driver, driver->domains.objs[i], NULL) < 0) { - virErrorPtr err = virGetLastError(); - qemudLog(QEMUD_ERR, _("Failed to autostart VM '%s': %s\n"), - driver->domains.objs[i]->def->name, - err ? err->message : NULL); + virDomainObjPtr vm = driver->domains.objs[i]; + if (vm->autostart && + !virDomainIsActive(vm)) { + int ret = qemudStartVMDaemon(NULL, driver, vm, NULL); + if (ret < 0) { + virErrorPtr err = virGetLastError(); + qemudLog(QEMUD_ERR, _("Failed to autostart VM '%s': %s\n"), + vm->def->name, + err ? err->message : NULL); + } else { + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); + } } } } @@ -945,7 +952,6 @@ static int qemudStartVMDaemon(virConnect qemudShutdownVMDaemon(conn, driver, vm); return -1; } - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED); } return ret; @@ -1030,6 +1036,9 @@ static int qemudDispatchVMLog(struct qem static int qemudDispatchVMLog(struct qemud_driver *driver, virDomainObjPtr vm, int fd) { if (qemudVMData(driver, vm, fd) < 0) { qemudShutdownVMDaemon(NULL, driver, vm); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_FAILED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); @@ -1040,7 +1049,9 @@ static int qemudDispatchVMFailure(struct static int qemudDispatchVMFailure(struct qemud_driver *driver, virDomainObjPtr vm, int fd ATTRIBUTE_UNUSED) { qemudShutdownVMDaemon(NULL, driver, vm); - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); @@ -1518,6 +1529,9 @@ static virDomainPtr qemudDomainCreate(vi vm); return NULL; } + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); dom = virGetDomain(conn, vm->def->name, vm->def->uuid); if (dom) dom->id = vm->def->id; @@ -1548,7 +1562,9 @@ static int qemudDomainSuspend(virDomainP } vm->state = VIR_DOMAIN_PAUSED; qemudDebug("Reply %s", info); - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SUSPENDED); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); VIR_FREE(info); return 0; } @@ -1577,7 +1593,9 @@ static int qemudDomainResume(virDomainPt } vm->state = VIR_DOMAIN_RUNNING; qemudDebug("Reply %s", info); - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESUMED); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_RESUMED_UNPAUSED); VIR_FREE(info); return 0; } @@ -1616,7 +1634,9 @@ static int qemudDomainDestroy(virDomainP } qemudShutdownVMDaemon(dom->conn, driver, vm); - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_DESTROYED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); @@ -1947,10 +1967,12 @@ static int qemudDomainSave(virDomainPtr /* Shut it down */ qemudShutdownVMDaemon(dom->conn, driver, vm); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SAVED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SAVED); return 0; } @@ -2245,6 +2267,10 @@ static int qemudDomainRestore(virConnect return -1; } + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_RESTORED); + /* If it was running before, resume it now. */ if (header.was_running) { char *info; @@ -2257,7 +2283,6 @@ static int qemudDomainRestore(virConnect vm->state = VIR_DOMAIN_RUNNING; } - qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESTORED); return 0; } @@ -2317,6 +2342,7 @@ static int qemudDomainStart(virDomainPtr static int qemudDomainStart(virDomainPtr dom) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid); + int ret; if (!vm) { qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, @@ -2324,7 +2350,13 @@ static int qemudDomainStart(virDomainPtr return -1; } - return qemudStartVMDaemon(dom->conn, driver, vm, NULL); + ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL); + if (ret < 0) + return ret; + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); + return 0; } @@ -3345,7 +3377,8 @@ qemudDomainEventDeregister (virConnectPt static void qemudDomainEventDispatch (struct qemud_driver *driver, virDomainObjPtr vm, - virDomainEventType evt) + int event, + int detail) { int i; virDomainEventCallbackListPtr cbList; @@ -3359,11 +3392,11 @@ static void qemudDomainEventDispatch (st vm->def->uuid); if (dom) { dom->id = virDomainIsActive(vm) ? vm->def->id : -1; - DEBUG("Dispatching callback %p %p event %d", - cbList->callbacks[i], - cbList->callbacks[i]->cb, evt); + DEBUG("Dispatching callback %p %p event %d detail %d", + cbList->callbacks[i], + cbList->callbacks[i]->cb, event, detail); cbList->callbacks[i]->cb(cbList->callbacks[i]->conn, - dom, evt, + dom, event, detail, cbList->callbacks[i]->opaque); virDomainFree(dom); } @@ -3512,6 +3545,9 @@ qemudDomainMigratePrepare2 (virConnectPt return -1; } + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_MIGRATED); return 0; } @@ -3542,6 +3578,18 @@ qemudDomainMigratePerform (virDomainPtr qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("domain is not running")); return -1; + } + + if (!(flags & VIR_MIGRATE_LIVE)) { + /* Pause domain for non-live migration */ + snprintf(cmd, sizeof cmd, "%s", "stop"); + qemudMonitorCommand (driver, vm, cmd, &info); + DEBUG ("stop reply: %s", info); + VIR_FREE(info); + + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); } if (resource > 0) { @@ -3583,6 +3631,9 @@ qemudDomainMigratePerform (virDomainPtr /* Clean up the source domain. */ qemudShutdownVMDaemon (dom->conn, driver, vm); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_MIGRATED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); @@ -3617,9 +3668,15 @@ qemudDomainMigrateFinish2 (virConnectPtr dom = virGetDomain (dconn, vm->def->name, vm->def->uuid); VIR_FREE(info); vm->state = VIR_DOMAIN_RUNNING; + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_RESUMED_MIGRATED); return dom; } else { qemudShutdownVMDaemon (dconn, driver, vm); + qemudDomainEventDispatch(driver, vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_FAILED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); return NULL; diff --git a/src/remote_internal.c b/src/remote_internal.c --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -5206,7 +5206,7 @@ remoteRegister (void) */ static int remoteDomainReadEvent(virConnectPtr conn, XDR *xdr, - virDomainPtr *dom, int *event) + virDomainPtr *dom, int *event, int *detail) { remote_domain_event_ret ret; memset (&ret, 0, sizeof ret); @@ -5220,6 +5220,7 @@ remoteDomainReadEvent(virConnectPtr conn *dom = get_nonnull_domain(conn,ret.dom); *event = ret.event; + *detail = ret.detail; return 0; } @@ -5228,15 +5229,16 @@ remoteDomainProcessEvent(virConnectPtr c remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr) { virDomainPtr dom; - int event,i; - struct private_data *priv = conn->privateData; - - if(!remoteDomainReadEvent(conn, xdr, &dom, &event)) { + int event, detail, i; + struct private_data *priv = conn->privateData; + + if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail)) { DEBUG0("Calling domain event callbacks (no queue)"); for(i=0 ; i < priv->callbackList->count ; i++) { - if( priv->callbackList->callbacks[i] ) - priv->callbackList->callbacks[i]->cb(conn, dom, event, - priv->callbackList->callbacks[i]->opaque); + if (priv->callbackList->callbacks[i] ) + priv->callbackList->callbacks[i]->cb( + conn, dom, event, detail, + priv->callbackList->callbacks[i]->opaque); } } } @@ -5245,13 +5247,13 @@ remoteDomainQueueEvent(virConnectPtr con remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr) { virDomainPtr dom; - int event; - struct private_data *priv = conn->privateData; - - if(!remoteDomainReadEvent(conn, xdr, &dom, &event)) + int event, detail; + struct private_data *priv = conn->privateData; + + if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail)) { if( virDomainEventCallbackQueuePush(priv->domainEvents, - dom, event) < 0 ) { + dom, event, detail) < 0 ) { DEBUG("%s", "Error adding event to queue"); } } @@ -5344,6 +5346,7 @@ remoteDomainEventQueueFlush(int timer AT priv->callbackList->callbacks[i]->cb(domEvent->dom->conn, domEvent->dom, domEvent->event, + domEvent->detail, user_data); } } -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list