[libvirt] [PATCH v3 04/12] parallels: handle events from parallels server

Maxim Nestratov mnestratov at parallels.com
Tue Nov 25 12:31:19 UTC 2014


18.11.2014 16:16, Dmitry Guryanov пишет:
> From: Alexander Burluka <aburluka at parallels.com>
>
> 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 at parallels.com>
> ---
>   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);
I would protect all event processing functions 
(prlsdkHandleVmStateEvent, prlsdkHandleVmConfigEvent, 
prlsdkHandleVmAddedEvent, prlsdkHandleVmRemovedEvent) with 
parallelsDriverLock/parallelsDriverUnlock calls to prevent possible 
races triggered by simultaneous operations on the same domain.
Otherwise, ack.




More information about the libvir-list mailing list