From: Alexander Burluka <aburluka@xxxxxxxxxxxxx> Subscribe to events from parallels server. It's needed for 2 things: to update cached domains list and to send corresponding libvirt events. Parallels server sends a lot of different events, in this patch we handle only some of them. In the future we can handle for example, changes in a host network configuration or devices states. Signed-off-by: Dmitry Guryanov <dguryanov@xxxxxxxxxxxxx> --- src/parallels/parallels_driver.c | 46 ++++++ src/parallels/parallels_sdk.c | 295 ++++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 2 + 3 files changed, 341 insertions(+), 2 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 83995d5..e145766 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -223,6 +223,12 @@ parallelsOpenDefault(virConnectPtr conn) if (!(privconn->domains = virDomainObjListNew())) goto error; + if (!(privconn->domainEventState = virObjectEventStateNew())) + goto error; + + if (prlsdkSubscribeToPCSEvents(privconn)) + goto error; + conn->privateData = privconn; if (prlsdkLoadDomains(privconn)) @@ -234,6 +240,7 @@ parallelsOpenDefault(virConnectPtr conn) virObjectUnref(privconn->domains); virObjectUnref(privconn->caps); virStoragePoolObjListFree(&privconn->pools); + virObjectEventStateFree(privconn->domainEventState); prlsdkDisconnect(privconn); prlsdkDeinit(); err_free: @@ -280,9 +287,11 @@ parallelsConnectClose(virConnectPtr conn) parallelsConnPtr privconn = conn->privateData; parallelsDriverLock(privconn); + prlsdkUnsubscribeFromPCSEvents(privconn); virObjectUnref(privconn->caps); virObjectUnref(privconn->xmlopt); virObjectUnref(privconn->domains); + virObjectEventStateFree(privconn->domainEventState); prlsdkDisconnect(privconn); conn->privateData = NULL; prlsdkDeinit(); @@ -1717,6 +1726,41 @@ parallelsNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED, return nodeGetCPUMap(cpumap, online, flags); } +static int +parallelsConnectDomainEventRegisterAny(virConnectPtr conn, + virDomainPtr domain, + int eventID, + virConnectDomainEventGenericCallback callback, + void *opaque, + virFreeCallback freecb) +{ + int ret = -1; + parallelsConnPtr privconn = conn->privateData; + if (virDomainEventStateRegisterID(conn, + privconn->domainEventState, + domain, eventID, + callback, opaque, freecb, &ret) < 0) + ret = -1; + return ret; +} + +static int +parallelsConnectDomainEventDeregisterAny(virConnectPtr conn, + int callbackID) +{ + parallelsConnPtr privconn = conn->privateData; + int ret = -1; + + if (virObjectEventStateDeregisterID(conn, + privconn->domainEventState, + callbackID) < 0) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} static virHypervisorDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, @@ -1749,6 +1793,8 @@ static virHypervisorDriver parallelsDriver = { .domainShutdown = parallelsDomainShutdown, /* 0.10.0 */ .domainCreate = parallelsDomainCreate, /* 0.10.0 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ + .connectDomainEventRegisterAny = parallelsConnectDomainEventRegisterAny, /* 1.2.10 */ + .connectDomainEventDeregisterAny = parallelsConnectDomainEventDeregisterAny, /* 1.2.10 */ .nodeGetCPUMap = parallelsNodeGetCPUMap, /* 1.2.8 */ .connectIsEncrypted = parallelsConnectIsEncrypted, /* 1.2.5 */ .connectIsSecure = parallelsConnectIsSecure, /* 1.2.5 */ diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index c6cf78a..01efc22 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -27,6 +27,7 @@ #include "virstring.h" #include "nodeinfo.h" #include "virlog.h" +#include "datatypes.h" #include "parallels_sdk.h" @@ -1130,9 +1131,7 @@ prlsdkLoadDomain(parallelsConnPtr privconn, * for state and domain name */ dom = olddom; virDomainDefFree(dom->def); - virDomainDefFree(dom->newDef); dom->def = def; - dom->newDef = def; } else { if (!(dom = virDomainObjListAdd(privconn->domains, def, privconn->xmlopt, @@ -1247,3 +1246,295 @@ prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid) PrlHandle_Free(sdkdom); return dom; } + +static int +prlsdkUpdateDomain(parallelsConnPtr privconn, virDomainObjPtr dom) +{ + PRL_HANDLE job; + virDomainObjPtr retdom = NULL; + parallelsDomObjPtr pdom = dom->privateData; + + job = PrlVm_RefreshConfig(pdom->sdkdom); + if (waitJob(job, privconn->jobTimeout)) + return -1; + + retdom = prlsdkLoadDomain(privconn, pdom->sdkdom, dom); + return retdom ? 0 : -1; +} + +static int prlsdkSendEvent(parallelsConnPtr privconn, + virDomainObjPtr dom, + virDomainEventType lvEventType, + int lvEventTypeDetails) +{ + virObjectEventPtr event = NULL; + + event = virDomainEventLifecycleNewFromObj(dom, + lvEventType, + lvEventTypeDetails); + if (!event) + return -1; + + virObjectEventStateQueue(privconn->domainEventState, event); + return 0; +} + +static void +prlsdkNewStateToEvent(VIRTUAL_MACHINE_STATE domainState, + virDomainEventType *lvEventType, + int *lvEventTypeDetails) +{ + /* We skip all intermediate states here, because + * libvirt doesn't have correspoding event types for + * them */ + switch (domainState) { + case VMS_STOPPED: + case VMS_MOUNTED: + *lvEventType = VIR_DOMAIN_EVENT_STOPPED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN; + break; + case VMS_RUNNING: + *lvEventType = VIR_DOMAIN_EVENT_STARTED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_STARTED_BOOTED; + break; + case VMS_PAUSED: + *lvEventType = VIR_DOMAIN_EVENT_SUSPENDED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED; + break; + case VMS_SUSPENDED: + *lvEventType = VIR_DOMAIN_EVENT_STOPPED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SAVED; + break; + default: + VIR_DEBUG("Skip sending event about changing state to %X", + domainState); + break; + } +} + +static PRL_RESULT +prlsdkHandleVmStateEvent(parallelsConnPtr privconn, + PRL_HANDLE prlEvent, + unsigned char *uuid) +{ + PRL_RESULT pret = PRL_ERR_FAILURE; + PRL_HANDLE eventParam = PRL_INVALID_HANDLE; + PRL_INT32 domainState; + virDomainObjPtr dom = NULL; + parallelsDomObjPtr pdom; + virDomainEventType lvEventType; + int lvEventTypeDetails; + + pret = PrlEvent_GetParamByName(prlEvent, "vminfo_vm_state", &eventParam); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlEvtPrm_ToInt32(eventParam, &domainState); + prlsdkCheckRetGoto(pret, cleanup); + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) { + pret = PRL_ERR_VM_UUID_NOT_FOUND; + goto cleanup; + } + + pdom = dom->privateData; + if (prlsdkConvertDomainState(domainState, pdom->id, dom) < 0) + goto cleanup; + + prlsdkNewStateToEvent(domainState, + &lvEventType, + &lvEventTypeDetails); + + if (prlsdkSendEvent(privconn, dom, lvEventType, lvEventTypeDetails) < 0) { + pret = PRL_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + cleanup: + if (dom) + virObjectUnlock(dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmConfigEvent(parallelsConnPtr privconn, + unsigned char *uuid) +{ + PRL_RESULT pret = PRL_ERR_FAILURE; + virDomainObjPtr dom = NULL; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) { + pret = PRL_ERR_VM_UUID_NOT_FOUND; + goto cleanup; + } + + if (prlsdkUpdateDomain(privconn, dom) < 0) + goto cleanup; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_UPDATED) < 0) { + pret = PRL_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + pret = PRL_ERR_SUCCESS; + cleanup: + if (dom) + virObjectUnlock(dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmAddedEvent(parallelsConnPtr privconn, + unsigned char *uuid) +{ + PRL_RESULT pret; + virDomainObjPtr dom = NULL; + + dom = prlsdkAddDomain(privconn, uuid); + if (!dom) + return PRL_ERR_FAILURE; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_ADDED) < 0) { + pret = PRL_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + pret = PRL_ERR_SUCCESS; + cleanup: + if (dom) + virObjectUnlock(dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmRemovedEvent(parallelsConnPtr privconn, + unsigned char *uuid) +{ + virDomainObjPtr dom = NULL; + PRL_RESULT pret = PRL_ERR_SUCCESS; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) { + /* domain was removed from the list from the libvirt + * API function in current connection */ + return PRL_ERR_SUCCESS; + } + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) < 0) + pret = PRL_ERR_OUT_OF_MEMORY; + + virDomainObjListRemove(privconn->domains, dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmEvent(parallelsConnPtr privconn, PRL_HANDLE prlEvent) +{ + PRL_RESULT pret; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + unsigned char uuid[VIR_UUID_BUFLEN]; + PRL_UINT32 bufsize = ARRAY_CARDINALITY(uuidstr); + PRL_EVENT_TYPE prlEventType; + + pret = PrlEvent_GetType(prlEvent, &prlEventType); + prlsdkCheckRetGoto(pret, error); + + pret = PrlEvent_GetIssuerId(prlEvent, uuidstr, &bufsize); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkUUIDParse(uuidstr, uuid) < 0) + return PRL_ERR_FAILURE; + + switch (prlEventType) { + case PET_DSP_EVT_VM_STATE_CHANGED: + return prlsdkHandleVmStateEvent(privconn, prlEvent, uuid); + case PET_DSP_EVT_VM_CONFIG_CHANGED: + return prlsdkHandleVmConfigEvent(privconn, uuid); + case PET_DSP_EVT_VM_CREATED: + case PET_DSP_EVT_VM_ADDED: + return prlsdkHandleVmAddedEvent(privconn, uuid); + case PET_DSP_EVT_VM_DELETED: + case PET_DSP_EVT_VM_UNREGISTERED: + return prlsdkHandleVmRemovedEvent(privconn, uuid); + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't handle event of type %d"), prlEventType); + return PRL_ERR_FAILURE; + } + + error: + return PRL_ERR_FAILURE; +} + +static PRL_RESULT +prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) +{ + parallelsConnPtr privconn = opaque; + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + PRL_HANDLE_TYPE handleType; + PRL_EVENT_TYPE prlEventType; + + pret = PrlHandle_GetType(prlEvent, &handleType); + prlsdkCheckRetGoto(pret, cleanup); + + if (handleType != PHT_EVENT) { + /* Currently, there is no need to handle anything but events */ + pret = PRL_ERR_SUCCESS; + goto cleanup; + } + + if (privconn == NULL) { + pret = PRL_ERR_INVALID_ARG; + goto cleanup; + } + + PrlEvent_GetType(prlEvent, &prlEventType); + prlsdkCheckRetGoto(pret, cleanup); + + switch (prlEventType) { + case PET_DSP_EVT_VM_STATE_CHANGED: + case PET_DSP_EVT_VM_CONFIG_CHANGED: + case PET_DSP_EVT_VM_CREATED: + case PET_DSP_EVT_VM_ADDED: + case PET_DSP_EVT_VM_DELETED: + case PET_DSP_EVT_VM_UNREGISTERED: + pret = prlsdkHandleVmEvent(privconn, prlEvent); + break; + default: + VIR_DEBUG("Skipping event of type %d", prlEventType); + } + + pret = PRL_ERR_SUCCESS; + cleanup: + PrlHandle_Free(prlEvent); + return pret; +} + +int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn) +{ + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + + pret = PrlSrv_RegEventHandler(privconn->server, + prlsdkEventsHandler, + privconn); + prlsdkCheckRetGoto(pret, error); + return 0; + + error: + return -1; +} + +void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn) +{ + PRL_RESULT ret = PRL_ERR_UNINITIALIZED; + ret = PrlSrv_UnregEventHandler(privconn->server, + prlsdkEventsHandler, + privconn); + if (PRL_FAILED(ret)) + logPrlError(ret); +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index d9461ca..5ffbf53 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -32,3 +32,5 @@ int prlsdkLoadDomains(parallelsConnPtr privconn); virDomainObjPtr prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); +int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn); +void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn); -- 1.9.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list