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

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

Jay Gagnon wrote:
# HG changeset patch # User Jay Gagnon <grendel@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@linux.vnet.ibm.com>
If everyone is okay with things I will be integrating this into the existing CS indication provider (although codewise it might really be more like the other way around). If there is anything major here then I can do one more round of RFC before I integrate, but any minor things will be handled along with the integration. Oh, and just as a matter of taste, I prefer (#2) over .#2 as a method of comment protection in the commit message. Opinions? -- -Jay

Jay Gagnon wrote:
+ + printf("Delivering Indication: %s\n", + CMGetCharPtr(CMObjectPathToString(ind_op, NULL)));
Don't forget to change this to a CU_DEBUG().
+ + conn = connect_by_classname(_BROKER, CLASSNAME(args->ref), &s);
Don't forget to free the connection. -- Kaitlin Rupert IBM Linux Technology Center karupert@us.ibm.com

Kaitlin Rupert wrote:
Jay Gagnon wrote:
+ + printf("Delivering Indication: %s\n", + CMGetCharPtr(CMObjectPathToString(ind_op, NULL)));
Don't forget to change this to a CU_DEBUG().
+ + conn = connect_by_classname(_BROKER, CLASSNAME(args->ref), &s);
Don't forget to free the connection.
Eagle eyes, this one. :) -- -Jay
participants (2)
-
Jay Gagnon
-
Kaitlin Rupert