From: "Eduardo Lima (Etrunko)" <eblima(a)br.ibm.com>
As it happens for Shutdown, the RequestStateChange method returns immediately
with return code 0 (successful) even though the state change is still not
completed.
Change the current job implementation to support reboot as well. For this we
need the libvirt domain events APIs and event loop implementation, which are
only available in libvirt version 0.9.0 or newer.
Signed-off-by: Eduardo Lima (Etrunko) <eblima(a)br.ibm.com>
---
src/Virt_ComputerSystem.c | 90 ++++++++++++++++++++++++++++++++++++++-------
1 files changed, 76 insertions(+), 14 deletions(-)
diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c
index 778809d..04584f3 100644
--- a/src/Virt_ComputerSystem.c
+++ b/src/Virt_ComputerSystem.c
@@ -32,6 +32,7 @@
#include <uuid.h>
#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
#include <libcmpiutil/libcmpiutil.h>
#include <libcmpiutil/std_invokemethod.h>
@@ -61,6 +62,8 @@ struct _state_change_job {
uint16_t status; /* job status */
};
+static bool events_registered = false;
+
/* Set the "Name" property of an instance from a domain */
static int set_name_from_dom(virDomainPtr dom, CMPIInstance *instance)
{
@@ -1203,14 +1206,12 @@ static CMPIStatus __state_change(const char *name,
s = state_change_enable(dom, &info);
else if (state == CIM_STATE_DISABLED)
s = state_change_disable(dom, &info);
- else if (state == CIM_STATE_SHUTDOWN)
- s.rc = CIM_SVPC_RETURN_JOB_STARTED;
else if (state == CIM_STATE_PAUSED)
s = state_change_pause(dom, &info);
- else if (state == CIM_STATE_REBOOT)
- s = state_change_reboot(dom, &info);
else if (state == CIM_STATE_RESET)
s = state_change_reset(dom, &info);
+ else if (state == CIM_STATE_SHUTDOWN || state == CIM_STATE_REBOOT)
+ s.rc = CIM_SVPC_RETURN_JOB_STARTED;
else
cu_statusf(_BROKER, &s,
CMPI_RC_ERR_NOT_SUPPORTED,
@@ -1333,6 +1334,25 @@ static CMPIStatus create_state_change_job(const CMPIObjectPath
*ref,
return s;
}
+static void state_change_reboot_cb(virConnectPtr conn,
+ virDomainPtr dom,
+ void *data)
+{
+ state_change_job_t *job = (state_change_job_t *) data;
+ job->status = CIM_JOB_STATE_COMPLETED;
+}
+
+static void state_change_shutdown_cb(virConnectPtr conn,
+ virDomainPtr dom,
+ int event,
+ int detail,
+ void *data)
+{
+ state_change_job_t *job = (state_change_job_t *) data;
+ if (event == VIR_DOMAIN_EVENT_SHUTDOWN)
+ job->status = CIM_JOB_STATE_COMPLETED;
+}
+
static CMPI_THREAD_RETURN state_change_thread(void *data)
{
CMPIStatus s;
@@ -1341,8 +1361,10 @@ static CMPI_THREAD_RETURN state_change_thread(void *data)
virConnectPtr conn = NULL;
virDomainPtr dom = NULL;
virDomainInfo info;
+ int job_cb = -1;
- if (job->dom_state != CIM_STATE_SHUTDOWN) {
+ if (job->dom_state != CIM_STATE_SHUTDOWN &&
+ job->dom_state != CIM_STATE_REBOOT) {
CU_DEBUG("Unrecognized state '%d'",
job->dom_state);
goto end;
}
@@ -1382,17 +1404,56 @@ static CMPI_THREAD_RETURN state_change_thread(void *data)
goto out;
}
- s = state_change_shutdown(dom, &info);
- if (s.rc != CMPI_RC_OK) {
- CU_DEBUG("Unable to trigger domain shutdown: '%s'",
- CMGetCharPtr(s.msg));
- goto out;
+ if (events_registered == false) {
+ events_registered = true;
+ virEventRegisterDefaultImpl();
+ }
+
+ if (job->dom_state == CIM_STATE_REBOOT) {
+ job_cb = virConnectDomainEventRegisterAny(conn, NULL,
+ VIR_DOMAIN_EVENT_ID_REBOOT,
+ VIR_DOMAIN_EVENT_CALLBACK(state_change_reboot_cb),
+ job, NULL);
+
+ if (job_cb == -1) {
+ CU_DEBUG("Unable to connect domain reboot callback");
+ goto out;
+ }
+
+ s = state_change_reboot(dom, &info);
+
+ if (s.rc != CMPI_RC_OK) {
+ CU_DEBUG("Unable to trigger domain reboot:
'%s'",
+ CMGetCharPtr(s.msg));
+ goto out;
+ }
+ } else if (job->dom_state == CIM_STATE_SHUTDOWN) {
+ job_cb = virConnectDomainEventRegisterAny(conn, NULL,
+ VIR_DOMAIN_EVENT_ID_LIFECYCLE,
+ VIR_DOMAIN_EVENT_CALLBACK(state_change_shutdown_cb),
+ job, NULL);
+
+ if (job_cb == -1) {
+ CU_DEBUG("Unable to connect domain shutdown
callback");
+ goto out;
+ }
+
+ s = state_change_shutdown(dom, &info);
+
+ if (s.rc != CMPI_RC_OK) {
+ CU_DEBUG("Unable to trigger domain shutdown:
'%s'",
+ CMGetCharPtr(s.msg));
+ goto out;
+ }
}
/* Wait for operation (shutdown/reboot) to complete */
- while (info.state != VIR_DOMAIN_SHUTOFF) {
- usleep(100 * 1000);
- virDomainGetInfo(dom, &info);
+ while (job->status == CIM_JOB_STATE_RUNNING) {
+ if (virEventRunDefaultImpl() < 0) {
+ virErrorPtr err = virGetLastError();
+ CU_DEBUG("Failed to run event loop: %s\n",
+ err && err->message ? err->message : "Unknown
error");
+ }
}
CU_DEBUG("Job completed");
@@ -1405,6 +1466,8 @@ static CMPI_THREAD_RETURN state_change_thread(void *data)
(CMPIValue *) "Completed", CMPI_chars);
}
+ virConnectDomainEventDeregisterAny(conn, job_cb);
+
out:
virDomainFree(dom);
virConnectClose(conn);
@@ -1412,7 +1475,6 @@ static CMPI_THREAD_RETURN state_change_thread(void *data)
CBDetachThread(_BROKER, job->context);
free(job->dom_name);
free(job);
-
end:
return NULL;
}
--
1.7.7.6