startupPolicy: Emit event on disk source dropping

If a disk source gets dropped because it is not accessible,
mgmt application might want to be informed about this. Therefore
we need to emit an event. The event presented in this patch
is however a bit superset of what written above. The reason is simple:
an intention to be easily expanded, e.g. on 'user ejected disk
in guest' events. Therefore, callback gets source string and disk alias
(which should be unique among a domain) and reason (an integer);
This commit is contained in:
Michal Privoznik 2011-10-18 16:15:42 +02:00
parent 12ba43222d
commit baf2ff7e90
14 changed files with 337 additions and 9 deletions

View File

@ -451,6 +451,56 @@ static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSE
}
static int remoteRelayDomainEventDiskChange(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason,
void *opaque)
{
virNetServerClientPtr client = opaque;
remote_domain_event_disk_change_msg data;
char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;
if (!client)
return -1;
VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d",
dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason);
/* build return data */
memset(&data, 0, sizeof data);
if (oldSrcPath &&
((VIR_ALLOC(oldSrcPath_p) < 0) ||
!(*oldSrcPath_p = strdup(oldSrcPath))))
goto mem_error;
if (newSrcPath &&
((VIR_ALLOC(newSrcPath_p) < 0) ||
!(*newSrcPath_p = strdup(newSrcPath))))
goto mem_error;
data.oldSrcPath = oldSrcPath_p;
data.newSrcPath = newSrcPath_p;
if (!(data.devAlias = strdup(devAlias)))
goto mem_error;
data.reason = reason;
make_nonnull_domain(&data.dom, dom);
remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
(xdrproc_t)xdr_remote_domain_event_disk_change_msg, &data);
return 0;
mem_error:
virReportOOMError();
return -1;
}
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@ -461,6 +511,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);

View File

@ -285,6 +285,25 @@ static int myDomainEventControlErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED
}
const char *diskChangeReasonStrings[] = {
"startupPolicy", /* 0 */
/* add new reason here */
};
static int myDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
oldSrcPath, newSrcPath, devAlias, diskChangeReasonStrings[reason]);
return 0;
}
static void myFreeFunc(void *opaque)
{
char *str = opaque;
@ -319,6 +338,7 @@ int main(int argc, char **argv)
int callback6ret = -1;
int callback7ret = -1;
int callback8ret = -1;
int callback9ret = -1;
struct sigaction action_stop;
memset(&action_stop, 0, sizeof action_stop);
@ -382,6 +402,11 @@ int main(int argc, char **argv)
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventControlErrorCallback),
strdup("callback control error"), myFreeFunc);
callback9ret = virConnectDomainEventRegisterAny(dconn,
NULL,
VIR_DOMAIN_EVENT_ID_DISK_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDiskChangeCallback),
strdup("disk change"), myFreeFunc);
if ((callback1ret != -1) &&
(callback2ret != -1) &&
@ -389,7 +414,8 @@ int main(int argc, char **argv)
(callback4ret != -1) &&
(callback5ret != -1) &&
(callback6ret != -1) &&
(callback7ret != -1)) {
(callback7ret != -1) &&
(callback9ret != -1)) {
while (run) {
if (virEventRunDefaultImpl() < 0) {
virErrorPtr err = virGetLastError();
@ -406,6 +432,7 @@ int main(int argc, char **argv)
virConnectDomainEventDeregisterAny(dconn, callback5ret);
virConnectDomainEventDeregisterAny(dconn, callback6ret);
virConnectDomainEventDeregisterAny(dconn, callback7ret);
virConnectDomainEventDeregisterAny(dconn, callback9ret);
if (callback8ret != -1)
virConnectDomainEventDeregisterAny(dconn, callback8ret);
}

View File

@ -469,6 +469,9 @@ def myDomainEventIOErrorCallback(conn, dom, srcpath, devalias, action, opaque):
def myDomainEventGraphicsCallback(conn, dom, phase, localAddr, remoteAddr, authScheme, subject, opaque):
print "myDomainEventGraphicsCallback: Domain %s(%s) %d %s" % (dom.name(), dom.ID(), phase, authScheme)
def myDomainEventDiskChangeCallback(conn, dom, oldSrcPath, newSrcPath, devAlias, reason, opaque):
print "myDomainEventDiskChangeCallback: Domain %s(%s) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s" % (
dom.name(), dom.ID(), oldSrcPath, newSrcPath, devAlias, reason)
def usage(out=sys.stderr):
print >>out, "usage: "+os.path.basename(sys.argv[0])+" [-hdl] [uri]"
print >>out, " uri will default to qemu:///system"
@ -526,6 +529,7 @@ def main():
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR, myDomainEventIOErrorCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG, myDomainEventWatchdogCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, myDomainEventGraphicsCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DISK_CHANGE, myDomainEventDiskChangeCallback, None)
# The rest of your app would go here normally, but for sake
# of demo we'll just go to sleep. The other option is to

View File

@ -2995,6 +2995,41 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
int status,
void *opaque);
/**
* virConnectDomainEventDisChangeReason:
*
* The reason describing why this callback is called
*/
typedef enum {
VIR_DOMAIN_DISK_CHANGE_MISSING_ON_START = 0, /* oldSrcPath is set */
} virConnectDomainEventDiskChangeReason;
/**
* virConnectDomainEventDiskChangeCallback:
* @conn: connection object
* @dom: domain on which the event occurred
* @oldSrcPath: old source path
* @newSrcPath: new source path
* @reason: reason why this callback was called; any of
* virConnectDomainEventDiskChangeReason
* @opaque: application specified data
*
* This callback occurs when disk gets changed. However,
* not all @reason will cause both @oldSrcPath and @newSrcPath
* to be non-NULL. Please see virConnectDomainEventDiskChangeReason
* for more details.
*
* The callback signature to use when registering for an event of type
* VIR_DOMAIN_EVENT_ID_IO_ERROR with virConnectDomainEventRegisterAny()
*/
typedef void (*virConnectDomainEventDiskChangeCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason,
void *opaque);
/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
@ -3014,6 +3049,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON = 6, /* virConnectDomainEventIOErrorReasonCallback */
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7, /* virConnectDomainEventGenericCallback */
VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8, /* virConnectDomainEventBlockJobCallback */
VIR_DOMAIN_EVENT_ID_DISK_CHANGE = 9, /* virConnectDomainEventDiskChangeCallback */
/*
* NB: this enum value will increase over time as new events are

View File

@ -125,6 +125,15 @@
except AttributeError:
pass
def _dispatchDomainEventDiskChangeCallback(self, dom, oldSrcPath, newSrcPath, devAlias, reason, cbData):
"""Dispatches event to python user domain diskChange event callbacks
"""
cb = cbData["cb"]
opaque = cbData["opaque"]
cb(self, virDomain(self, _obj=dom), oldSrcPath, newSrcPath, devAlias, reason, opaque)
return 0;
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """

View File

@ -4374,6 +4374,56 @@ libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSE
return ret;
}
static int
libvirt_virConnectDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason,
void *opaque)
{
PyObject *pyobj_cbData = (PyObject*)opaque;
PyObject *pyobj_dom;
PyObject *pyobj_ret;
PyObject *pyobj_conn;
PyObject *dictKey;
int ret = -1;
LIBVIRT_ENSURE_THREAD_STATE;
/* Create a python instance of this virDomainPtr */
virDomainRef(dom);
pyobj_dom = libvirt_virDomainPtrWrap(dom);
Py_INCREF(pyobj_cbData);
dictKey = libvirt_constcharPtrWrap("conn");
pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
Py_DECREF(dictKey);
/* Call the Callback Dispatcher */
pyobj_ret = PyObject_CallMethod(pyobj_conn,
(char*)"_dispatchDomainEventDiskChangeCallback",
(char*)"OsssiO",
pyobj_dom,
oldSrcPath, newSrcPath,
devAlias, reason, pyobj_cbData);
Py_DECREF(pyobj_cbData);
Py_DECREF(pyobj_dom);
if(!pyobj_ret) {
DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
PyErr_Print();
} else {
Py_DECREF(pyobj_ret);
ret = 0;
}
LIBVIRT_RELEASE_THREAD_STATE;
return ret;
}
static PyObject *
libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
PyObject * args)
@ -4431,6 +4481,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBlockJobCallback);
break;
case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventDiskChangeCallback);
break;
}
if (!cb) {

View File

@ -88,6 +88,12 @@ struct _virDomainEvent {
int type;
int status;
} blockJob;
struct {
char *oldSrcPath;
char *newSrcPath;
char *devAlias;
int reason;
} diskChange;
} data;
};
@ -509,6 +515,12 @@ void virDomainEventFree(virDomainEventPtr event)
case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
VIR_FREE(event->data.blockJob.path);
break;
case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
VIR_FREE(event->data.diskChange.oldSrcPath);
VIR_FREE(event->data.diskChange.newSrcPath);
VIR_FREE(event->data.diskChange.devAlias);
break;
}
VIR_FREE(event->dom.name);
@ -961,6 +973,61 @@ virDomainEventPtr virDomainEventControlErrorNewFromObj(virDomainObjPtr obj)
return ev;
}
static virDomainEventPtr
virDomainEventDiskChangeNew(int id, const char *name,
unsigned char *uuid,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias, int reason)
{
virDomainEventPtr ev =
virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_DISK_CHANGE,
id, name, uuid);
if (ev) {
if (!(ev->data.diskChange.devAlias = strdup(devAlias)))
goto error;
if (oldSrcPath &&
!(ev->data.diskChange.oldSrcPath = strdup(oldSrcPath)))
goto error;
if (newSrcPath &&
!(ev->data.diskChange.newSrcPath = strdup(newSrcPath)))
goto error;
ev->data.diskChange.reason = reason;
}
return ev;
error:
virReportOOMError();
virDomainEventFree(ev);
return NULL;
}
virDomainEventPtr virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason)
{
return virDomainEventDiskChangeNew(obj->def->id, obj->def->name,
obj->def->uuid, oldSrcPath,
newSrcPath, devAlias, reason);
}
virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason)
{
return virDomainEventDiskChangeNew(dom->id, dom->name, dom->uuid,
oldSrcPath, newSrcPath,
devAlias, reason);
}
/**
* virDomainEventQueuePop:
@ -1104,6 +1171,15 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
((virConnectDomainEventDiskChangeCallback)cb)(conn, dom,
event->data.diskChange.oldSrcPath,
event->data.diskChange.newSrcPath,
event->data.diskChange.devAlias,
event->data.diskChange.reason,
cbopaque);
break;
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;

View File

@ -179,6 +179,17 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
int type,
int status);
virDomainEventPtr virDomainEventDiskChangeNewFromObj(virDomainObjPtr obj,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason);
virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason);
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);

View File

@ -481,6 +481,8 @@ virDomainEventCallbackListRemoveConn;
virDomainEventCallbackListRemoveID;
virDomainEventControlErrorNewFromDom;
virDomainEventControlErrorNewFromObj;
virDomainEventDiskChangeNewFromDom;
virDomainEventDiskChangeNewFromObj;
virDomainEventDispatch;
virDomainEventDispatchDefaultFunc;
virDomainEventFree;

View File

@ -35,6 +35,7 @@
#include "ignore-value.h"
#include "uuid.h"
#include "virfile.h"
#include "domain_event.h"
#include <sys/time.h>
#include <fcntl.h>
@ -1619,6 +1620,7 @@ qemuDomainCheckDiskPresence(struct qemud_driver *driver,
int accessRet;
virDomainDiskDefPtr disk;
char uuid[VIR_UUID_STRING_BUFLEN] ATTRIBUTE_UNUSED;
virDomainEventPtr event = NULL;
virUUIDFormat(vm->def->uuid, uuid);
@ -1666,6 +1668,11 @@ qemuDomainCheckDiskPresence(struct qemud_driver *driver,
"due to not accessible source '%s'",
disk->dst, vm->def->name, uuid, disk->src);
event = virDomainEventDiskChangeNewFromObj(vm, disk->src, NULL, disk->info.alias,
VIR_DOMAIN_DISK_CHANGE_MISSING_ON_START);
if (event)
qemuDomainEventQueue(driver, event);
VIR_FREE(disk->src);
}

View File

@ -2880,13 +2880,6 @@ int qemuProcessStart(virConnectPtr conn,
NULL) < 0)
goto cleanup;
if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0)
goto cleanup;
VIR_DEBUG("Checking for CDROM and floppy presence");
if (qemuDomainCheckDiskPresence(driver, vm, migrateFrom != NULL) < 0)
goto cleanup;
/* If you are using a SecurityDriver with dynamic labelling,
then generate a security label for isolation */
VIR_DEBUG("Generating domain security label (if required)");
@ -2956,6 +2949,13 @@ int qemuProcessStart(virConnectPtr conn,
&priv->qemuCaps) < 0)
goto cleanup;
if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0)
goto cleanup;
VIR_DEBUG("Checking for CDROM and floppy presence");
if (qemuDomainCheckDiskPresence(driver, vm, migrateFrom != NULL) < 0)
goto cleanup;
VIR_DEBUG("Setting up domain cgroup (if required)");
if (qemuSetupCgroup(driver, vm) < 0)
goto cleanup;

View File

@ -228,6 +228,11 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
static void
remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
remoteDomainBuildEventRTCChange,
@ -265,6 +270,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventBlockJob,
sizeof(remote_domain_event_block_job_msg),
(xdrproc_t)xdr_remote_domain_event_block_job_msg },
{ REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
remoteDomainBuildEventDiskChange,
sizeof(remote_domain_event_disk_change_msg),
(xdrproc_t)xdr_remote_domain_event_disk_change_msg },
};
enum virDrvOpenRemoteFlags {
@ -3327,6 +3336,33 @@ remoteDomainBuildEventControlError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
}
static void
remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
{
virConnectPtr conn = opaque;
struct private_data *priv = conn->privateData;
remote_domain_event_disk_change_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
return;
event = virDomainEventDiskChangeNewFromDom(dom,
msg->oldSrcPath ? *msg->oldSrcPath : NULL,
msg->newSrcPath ? *msg->newSrcPath : NULL,
msg->devAlias,
msg->reason);
virDomainFree(dom);
remoteDomainEventQueue(priv, event);
}
static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth,
unsigned int flags)

View File

@ -2010,6 +2010,14 @@ struct remote_domain_event_block_job_msg {
int status;
};
struct remote_domain_event_disk_change_msg {
remote_nonnull_domain dom;
remote_string oldSrcPath;
remote_string newSrcPath;
remote_nonnull_string devAlias;
int reason;
};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@ -2546,7 +2554,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SNAPSHOT_GET_PARENT = 244, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_RESET = 245, /* autogen autogen */
REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN = 246, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247 /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?

View File

@ -1509,6 +1509,13 @@ struct remote_domain_event_block_job_msg {
int type;
int status;
};
struct remote_domain_event_disk_change_msg {
remote_nonnull_domain dom;
remote_string oldSrcPath;
remote_string newSrcPath;
remote_nonnull_string devAlias;
int reason;
};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;