# HG changeset patch
# User Jay Gagnon <grendel(a)linux.vnet.ibm.com>
# Date 1200339496 18000
# Node ID 83dd6d18f98c2f43b59cbed5e025969f94a43f84
# Parent 51c57a6dabe9068f8638a6b923779085ff98b67e
(#2) [RFC] Add Virt_ComputerSystemModifiedIndication, which watches for changes in our
guests.
Changes since last time:
change free_dom_xml from int to void return type
use *far* better sys_name_from_xml logic
use calloc instead of malloc for allocating array
get UUID for domain directly into dom_xml structure
changed struct dom_xml's uuid member to suit
get xml for domain directly into dom_xml structure
add cleanup_domain_list function
use ObjectPath from CIMOM for prefix, classname, etc instead of literals
Signed-off-by: Jay Gagnon <grendel(a)linux.vnet.ibm.com>
diff -r 51c57a6dabe9 -r 83dd6d18f98c src/Virt_ComputerSystemModifiedIndication.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Virt_ComputerSystemModifiedIndication.c Mon Jan 14 14:38:16 2008 -0500
@@ -0,0 +1,410 @@
+/*
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Jay Gagnon <grendel(a)linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libvirt/libvirt.h>
+
+#include <libcmpiutil.h>
+#include <misc_util.h>
+#include <std_indication.h>
+#include <cs_util.h>
+
+#include "config.h"
+
+#include "Virt_ComputerSystem.h"
+
+static const CMPIBroker *_BROKER;
+
+static CMPI_THREAD_TYPE lifecycle_thread_id = 0;
+
+enum CS_EVENTS {
+ CS_MODIFIED,
+};
+
+static pthread_cond_t lifecycle_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool lifecycle_enabled = 0;
+
+#ifdef CMPI_EI_VOID
+# define _EI_RTYPE void
+# define _EI_RET() return
+#else
+# define _EI_RTYPE CMPIStatus
+# define _EI_RET() return (CMPIStatus){CMPI_RC_OK, NULL}
+#endif
+
+struct dom_xml {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ char *xml;
+};
+
+struct ind_args {
+ CMPIContext *context;
+ const CMPIObjectPath *ref;
+};
+
+static void free_dom_xml (struct dom_xml dom)
+{
+ free(dom.xml);
+}
+
+static void free_ind_args (struct ind_args args)
+{
+ /* Nothing to do right now, but if this ends up with
+ something that does need to be freed I want everything in place. */
+}
+
+static void cleanup_domain_list(virDomainPtr *list, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ virDomainFree(list[i]);
+ }
+}
+
+static bool _lifecycle_indication(const CMPIBroker *broker,
+ const CMPIContext *ctx,
+ CMPIInstance *mod_inst,
+ char *prefix,
+ char *ns)
+{
+ CMPIObjectPath *ind_op;
+ CMPIInstance *ind;
+ CMPIStatus s;
+
+ ind = get_typed_instance(broker,
+ prefix,
+ "ComputerSystemModifiedIndication",
+ ns);
+ if (ind == NULL) {
+ CU_DEBUG("Failed to create ind");
+ return false;
+ }
+
+ ind_op = CMGetObjectPath(ind, &s);
+ if (s.rc != CMPI_RC_OK) {
+ CU_DEBUG("Failed to get ind_op");
+ return false;
+ }
+
+ CMSetProperty(ind, "PreviousInstance",
+ (CMPIValue *)&mod_inst, CMPI_instance);
+
+ printf("Delivering Indication: %s\n",
+ CMGetCharPtr(CMObjectPathToString(ind_op, NULL)));
+
+ CBDeliverIndication(_BROKER,
+ ctx,
+ CIM_VIRT_NS,
+ ind);
+
+ return true;
+}
+
+static bool wait_for_event(void)
+{
+ struct timespec timeout;
+ int ret;
+
+
+ clock_gettime(CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 3;
+
+ ret = pthread_cond_timedwait(&lifecycle_cond,
+ &lifecycle_mutex,
+ &timeout);
+
+ return true;
+}
+
+static char *sys_name_from_xml(char *xml)
+{
+ char *tmp = NULL;
+ char *name = NULL;
+ int rc;
+
+ tmp = strstr(xml, "<name>");
+ if (tmp == NULL)
+ goto out;
+
+ rc = sscanf(tmp, "<name>%a[^<]s</name>", &name);
+ if (rc != 1)
+ name = NULL;
+
+ out:
+ return name;
+}
+
+static bool async_ind(CMPIContext *context,
+ virConnectPtr conn,
+ struct dom_xml prev_dom,
+ char *prefix,
+ char *ns)
+{
+ bool rc;
+ char *name = NULL;
+ CMPIInstance *mod_inst;
+
+ /* Where should we be getting the namespace and classname? */
+ mod_inst = get_typed_instance(_BROKER,
+ prefix,
+ "ComputerSystem",
+ ns);
+
+ name = sys_name_from_xml(prev_dom.xml);
+ CU_DEBUG("Name for system: '%s'", name);
+ if (name == NULL) {
+ rc = false;
+ goto out;
+ }
+
+ CMSetProperty(mod_inst, "Name",
+ (CMPIValue *)name, CMPI_chars);
+ CMSetProperty(mod_inst, "UUID",
+ (CMPIValue *)prev_dom.uuid, CMPI_chars);
+
+ rc = _lifecycle_indication(_BROKER, context, mod_inst, prefix, ns);
+
+ out:
+ free(name);
+ return rc;
+}
+
+static CMPIStatus doms_to_xml(struct dom_xml **dom_xml_list,
+ virDomainPtr *dom_ptr_list,
+ int dom_ptr_count)
+{
+ int i;
+ int rc;
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+
+ *dom_xml_list = calloc(dom_ptr_count, sizeof(struct dom_xml));
+ for (i = 0; i < dom_ptr_count; i++) {
+ rc = virDomainGetUUIDString(dom_ptr_list[i],
+ (*dom_xml_list)[i].uuid);
+ if (rc == -1) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "Failed to get UUID");
+ /* If any domain fails, we fail. */
+ break;
+ }
+
+ (*dom_xml_list)[i].xml = virDomainGetXMLDesc(dom_ptr_list[i],
+ 0);
+ if ((*dom_xml_list)[i].xml == NULL) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "Failed to get xml desc");
+ break;
+ }
+ }
+
+ return s;
+}
+
+static bool dom_changed(struct dom_xml prev_dom,
+ struct dom_xml *cur_xml,
+ int cur_count)
+{
+ int i;
+ bool ret = false;
+
+ for (i = 0; i < cur_count; i++) {
+ if (strcmp(cur_xml[i].uuid, prev_dom.uuid) != 0)
+ continue;
+
+ if (strcmp(cur_xml[i].xml, prev_dom.xml) != 0)
+ ret = true;
+
+ break;
+ }
+
+ return ret;
+}
+
+static CMPI_THREAD_RETURN lifecycle_thread(void *params)
+{
+ int i;
+ int cur_count;
+ int prev_count;
+ char *ns = NULL;
+ virConnectPtr conn;
+ char *prefix = NULL;
+ virDomainPtr *tmp_list;
+ CMPIContext *context = NULL;
+ struct dom_xml *cur_xml = NULL;
+ struct dom_xml *prev_xml = NULL;
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ struct ind_args *args = (struct ind_args *)params;
+
+ context = args->context;
+ prefix = class_prefix_name(CLASSNAME(args->ref));
+ ns = NAMESPACE(args->ref);
+
+ conn = connect_by_classname(_BROKER, CLASSNAME(args->ref), &s);
+
+ pthread_mutex_lock(&lifecycle_mutex);
+
+ CBAttachThread(_BROKER, context);
+
+ prev_count = get_domain_list(conn, &tmp_list);
+ s = doms_to_xml(&prev_xml, tmp_list, prev_count);
+ /* TODO: status check */
+ cleanup_domain_list(tmp_list, prev_count);
+
+ CU_DEBUG("entering event loop");
+ while (lifecycle_enabled) {
+ bool modified;
+
+ cur_count = get_domain_list(conn, &tmp_list);
+ s = doms_to_xml(&cur_xml, tmp_list, cur_count);
+ /* TODO: status check */
+ cleanup_domain_list(tmp_list, cur_count);
+
+ for (i = 0; i < prev_count; i++) {
+ modified = dom_changed(prev_xml[i], cur_xml, cur_count);
+ if (modified) {
+ CU_DEBUG("Domain '%s' modified.",
prev_xml[i].uuid);
+ async_ind(context, conn, prev_xml[i], prefix, ns);
+ }
+ free_dom_xml(prev_xml[i]);
+ }
+
+ free(prev_xml);
+ prev_xml = cur_xml;
+ wait_for_event();
+ }
+ CU_DEBUG("exiting event loop");
+
+ pthread_mutex_unlock(&lifecycle_mutex);
+ free_ind_args(*args);
+ free(prefix);
+ /* Should I free args as well here, since it's malloced in activate? */
+
+ return NULL;
+}
+
+static CMPIStatus ActivateFilter(CMPIIndicationMI* mi,
+ const CMPIContext* ctx,
+ const CMPISelectExp* se,
+ const char *ns,
+ const CMPIObjectPath* op,
+ CMPIBoolean first)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ struct ind_args *args = malloc(sizeof(struct ind_args));
+
+ CU_DEBUG("ActivateFilter");
+
+ if (CMIsNullObject(op)) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "No ObjectPath given");
+ goto out;
+ }
+ args->ref = op;
+
+ if (lifecycle_thread_id == 0) {
+ args->context = CBPrepareAttachThread(_BROKER, ctx);
+
+ lifecycle_thread_id = _BROKER->xft->newThread(lifecycle_thread,
+ args,
+ 0);
+ }
+
+ out:
+ return s;
+}
+
+static CMPIStatus DeActivateFilter(CMPIIndicationMI* mi,
+ const CMPIContext* ctx,
+ const CMPISelectExp* se,
+ const char *ns,
+ const CMPIObjectPath* op,
+ CMPIBoolean last)
+{
+ return (CMPIStatus){CMPI_RC_OK, NULL};
+}
+
+static _EI_RTYPE EnableIndications(CMPIIndicationMI* mi,
+ const CMPIContext *ctx)
+{
+ pthread_mutex_lock(&lifecycle_mutex);
+ lifecycle_enabled = true;
+ pthread_mutex_unlock(&lifecycle_mutex);
+
+ CU_DEBUG("ComputerSystemModifiedIndication enabled");
+
+ _EI_RET();
+}
+
+static _EI_RTYPE DisableIndications(CMPIIndicationMI* mi,
+ const CMPIContext *ctx)
+{
+ pthread_mutex_lock(&lifecycle_mutex);
+ lifecycle_enabled = false;
+ pthread_mutex_unlock(&lifecycle_mutex);
+
+ CU_DEBUG("ComputerSystemModifiedIndication disabled");
+
+ _EI_RET();
+}
+
+static CMPIStatus trigger_indication(const CMPIContext *context)
+{
+ pthread_cond_signal(&lifecycle_cond);
+ CU_DEBUG("CSMI triggered");
+ return(CMPIStatus){CMPI_RC_OK, NULL};
+}
+
+static struct std_indication_handler csmi = {
+ .raise_fn = NULL,
+ .trigger_fn = trigger_indication,
+};
+
+DEFAULT_IND_CLEANUP();
+DEFAULT_AF();
+DEFAULT_MP();
+
+STDI_IndicationMIStub(, Virt_ComputerSystemModifiedIndicationProvider,
+ _BROKER, libvirt_cim_init(), &csmi);
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */