parallels: handle events from parallels server

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>
This commit is contained in:
Alexander Burluka 2014-12-01 18:38:50 +03:00 committed by Peter Krempa
parent 8dec6bbbfe
commit 0a7aba408e
3 changed files with 341 additions and 2 deletions

View File

@ -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 */

View File

@ -27,6 +27,7 @@
#include "virstring.h"
#include "nodeinfo.h"
#include "virlog.h"
#include "datatypes.h"
#include "parallels_sdk.h"
@ -1140,9 +1141,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,
@ -1257,3 +1256,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 = 0;
int lvEventTypeDetails = 0;
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);
}

View File

@ -32,3 +32,5 @@ int
prlsdkLoadDomains(parallelsConnPtr privconn);
virDomainObjPtr
prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid);
int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn);
void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn);