[Libvirt-cim] [PATCH] (#2) [RFC] Add Virt_ComputerSystemModifiedIndication, which watches for changes in our guests

Jay Gagnon grendel at linux.vnet.ibm.com
Mon Jan 14 19:38:19 UTC 2008


# HG changeset patch
# User Jay Gagnon <grendel at 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 at 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 at 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:
+ */




More information about the Libvirt-cim mailing list