[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

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



18.11.2014 16:16, Dmitry Guryanov пишет:
From: Alexander Burluka <aburluka 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 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.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]