return 0;
}
+static int remoteRelayDomainEventBlockJob(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_block_job_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i",
+ dom->name, dom->id, path, type, status);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ make_nonnull_domain(&data.dom, dom);
+ data.path = (char*)path;
+ data.type = type;
+ data.status = status;
+
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
+ (xdrproc_t)xdr_remote_domain_event_block_job_msg, &data);
+
+ return 0;
+}
+
static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
+/**
+ * virConnectDomainEventBlockJobStatus:
+ *
+ * The final status of a virDomainBlockPullAll() operation
+ */
+typedef enum {
+ VIR_DOMAIN_BLOCK_JOB_COMPLETED = 0,
+ VIR_DOMAIN_BLOCK_JOB_FAILED = 1,
+} virConnectDomainEventBlockJobStatus;
+
+/**
+ * virConnectDomainEventBlockJobCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @path: fully-qualified filename of the affected disk
+ * @type: type of block job (virDomainBlockJobType)
+ * @status: final status of the operation (virConnectDomainEventBlockJobStatus)
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_BLOCK_JOB with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ void *opaque);
+
/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
VIR_DOMAIN_EVENT_ID_GRAPHICS = 5, /* virConnectDomainEventGraphicsCallback */
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 */
/*
* NB: this enum value will increase over time as new events are
authScheme, subject, opaque)
return 0
+ def dispatchDomainEventBlockPullCallback(self, dom, path, type, status, cbData):
+ """Dispatches events to python user domain blockJob event callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), path, type, status, opaque)
+ return 0
+ except AttributeError:
+ pass
+
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
return ret;
}
+static int
+libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ 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*)"dispatchDomainEventBlockPullCallback",
+ (char*)"OsiiO",
+ pyobj_dom, path, type, status, pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ 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)
case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventGenericCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBlockJobCallback);
+ break;
}
if (!cb) {
char *authScheme;
virDomainEventGraphicsSubjectPtr subject;
} graphics;
+ struct {
+ char *path;
+ int type;
+ int status;
+ } blockJob;
} data;
};
}
VIR_FREE(event->data.graphics.subject);
}
+ break;
+
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ VIR_FREE(event->data.blockJob.path);
+ break;
}
VIR_FREE(event->dom.name);
return ev;
}
+static virDomainEventPtr
+virDomainEventBlockJobNew(int id, const char *name, unsigned char *uuid,
+ const char *path, int type, int status)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
+ id, name, uuid);
+
+ if (ev) {
+ if (!(ev->data.blockJob.path = strdup(path))) {
+ virReportOOMError();
+ virDomainEventFree(ev);
+ return NULL;
+ }
+ ev->data.blockJob.type = type;
+ ev->data.blockJob.status = status;
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventBlockJobNewFromObj(virDomainObjPtr obj,
+ const char *path,
+ int type,
+ int status)
+{
+ return virDomainEventBlockJobNew(obj->def->id, obj->def->name,
+ obj->def->uuid, path, type, status);
+}
+
+virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
+ const char *path,
+ int type,
+ int status)
+{
+ return virDomainEventBlockJobNew(dom->id, dom->name, dom->uuid,
+ path, type, status);
+}
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
cbopaque);
break;
+ case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
+ ((virConnectDomainEventBlockJobCallback)cb)(conn, dom,
+ event->data.blockJob.path,
+ event->data.blockJob.type,
+ event->data.blockJob.status,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom);
virDomainEventPtr virDomainEventControlErrorNewFromObj(virDomainObjPtr obj);
-
+virDomainEventPtr virDomainEventBlockJobNewFromObj(virDomainObjPtr obj,
+ const char *path,
+ int type,
+ int status);
+virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
+ const char *path,
+ int type,
+ int status);
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
# domain_event.h
+virDomainEventBlockJobNewFromObj;
+virDomainEventBlockJobNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
virDomainEventCallbackListCount;
return ret;
}
+int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
+ const char *diskAlias,
+ int type,
+ int status)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainBlockJob, mon->vm,
+ diskAlias, type, status);
+ return ret;
+}
+
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
const char *authScheme,
const char *x509dname,
const char *saslUsername);
+ int (*domainBlockJob)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *diskAlias,
+ int type,
+ int status);
};
const char *authScheme,
const char *x509dname,
const char *saslUsername);
+int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
+ const char *diskAlias,
+ int type,
+ int status);
+
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data);
struct {
const char *type;
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
+ { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJob, },
};
qemuMonitorJSONHandleVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
}
+static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data)
+{
+ const char *device;
+ const char *type_str;
+ int type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+ unsigned long long offset, len;
+ int status = VIR_DOMAIN_BLOCK_JOB_FAILED;
+
+ if ((device = virJSONValueObjectGetString(data, "device")) == NULL) {
+ VIR_WARN("missing device in block job event");
+ goto out;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "offset", &offset) < 0) {
+ VIR_WARN("missing offset in block job event");
+ goto out;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(data, "len", &len) < 0) {
+ VIR_WARN("missing len in block job event");
+ goto out;
+ }
+
+ if ((type_str = virJSONValueObjectGetString(data, "type")) == NULL) {
+ VIR_WARN("missing type in block job event");
+ goto out;
+ }
+
+ if (STREQ(type_str, "stream"))
+ type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
+
+ if (offset != 0 && offset == len)
+ status = VIR_DOMAIN_BLOCK_JOB_COMPLETED;
+
+out:
+ qemuMonitorEmitBlockJob(mon, device, type, status);
+}
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
return 0;
}
+static int
+qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *diskAlias,
+ int type,
+ int status)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+ const char *path;
+ virDomainDiskDefPtr disk;
+
+ virDomainObjLock(vm);
+ disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias);
+
+ if (disk) {
+ path = disk->src;
+ event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
+ }
+
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
static int
qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
.domainWatchdog = qemuProcessHandleWatchdog,
.domainIOError = qemuProcessHandleIOError,
.domainGraphics = qemuProcessHandleGraphics,
+ .domainBlockJob = qemuProcessHandleBlockJob,
};
static int
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
remoteDomainBuildEventRTCChange,
remoteDomainBuildEventControlError,
sizeof(remote_domain_event_control_error_msg),
(xdrproc_t)xdr_remote_domain_event_control_error_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
+ remoteDomainBuildEventBlockJob,
+ sizeof(remote_domain_event_block_job_msg),
+ (xdrproc_t)xdr_remote_domain_event_block_job_msg },
};
enum virDrvOpenRemoteFlags {
remoteDomainEventQueue(priv, event);
}
+static void
+remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_block_job_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventBlockJobNewFromDom(dom, msg->path, msg->type,
+ msg->status);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
static void
remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
+struct remote_domain_event_block_job_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string path;
+ int type;
+ int status;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
REMOTE_PROC_DOMAIN_BLOCK_JOB_ABORT = 237, /* autogen autogen */
REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO = 238, /* skipgen skipgen */
REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 239, /* autogen autogen */
- REMOTE_PROC_DOMAIN_BLOCK_PULL = 240 /* autogen autogen */
+ REMOTE_PROC_DOMAIN_BLOCK_PULL = 240, /* autogen autogen */
+
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
remote_domain_event_graphics_identity * subject_val;
} subject;
};
+struct remote_domain_event_block_job_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string path;
+ int type;
+ int status;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO = 238,
REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 239,
REMOTE_PROC_DOMAIN_BLOCK_PULL = 240,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241,
};