
# HG changeset patch # User Jay Gagnon <grendel@linux.vnet.ibm.com> # Date 1199982797 18000 # Node ID 6f3a50557ab0648b1fa0bde747914d6e58027eef # Parent ca8dc23eacc44970a2d79978bc9de65aaa600b92 Add Virt_ComputerSystemModifiedIndication, which watches for changes in our guests. Signed-off-by: Jay Gagnon <grendel@linux.vnet.ibm.com> diff -r ca8dc23eacc4 -r 6f3a50557ab0 src/Virt_ComputerSystemModifiedIndication.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Virt_ComputerSystemModifiedIndication.c Thu Jan 10 11:33:17 2008 -0500 @@ -0,0 +1,379 @@ +/* + * 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" +#include "Virt_ComputerSystemModifiedIndication.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 + +int free_dom_xml (struct dom_xml dom) +{ + free(dom.uuid); + free(dom.xml); + return 0; +} + +static bool _lifecycle_indication(const CMPIBroker *broker, + const CMPIContext *ctx, + CMPIInstance *mod_inst) +{ + CMPIObjectPath *ind_op; + CMPIInstance *ind; + CMPIStatus s; + + ind = get_typed_instance(broker, + "Xen", /* Temporary hack */ + "ComputerSystemModifiedIndication", + CIM_VIRT_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; + char *start; + char *end; + char *name; + + /* Has to be a better way. */ + tmp = strdup(xml); + start = strstr(tmp, "<name>"); + start += 6; + end = strstr(start, "</name>"); + end[0] = '\0'; + + name = strdup(start); + free(tmp); + + return name; +} + +static bool async_ind(CMPIContext *context, + virConnectPtr conn, + struct dom_xml prev_dom) +{ + bool rc; + char *name = NULL; + CMPIInstance *mod_inst; + const char *ns = CIM_VIRT_NS; + + /* Where should we be getting the namespace and classname? */ + mod_inst = get_typed_instance(_BROKER, + "Xen", + "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); + + 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; + char *xml = NULL; + char uuid[VIR_UUID_STRING_BUFLEN]; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + *dom_xml_list = malloc(dom_ptr_count * sizeof(struct dom_xml)); + for (i = 0; i < dom_ptr_count; i++) { + rc = virDomainGetUUIDString(dom_ptr_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; + } + + xml = virDomainGetXMLDesc(dom_ptr_list[i], 0); + if (xml == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get xml desc"); + break; + } + + (*dom_xml_list)[i].xml = strdup(xml); + (*dom_xml_list)[i].uuid = strdup(uuid); + + free(xml); + } + + 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; + virConnectPtr conn; + virDomainPtr *tmp_list; + struct dom_xml *cur_xml = NULL; + struct dom_xml *prev_xml = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIContext *context = (CMPIContext *)params; + + /* We can't use this anymore, can we? */ + conn = lv_connect(_BROKER, &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 */ + for (i = 0; i < prev_count; i++) { + virDomainFree(tmp_list[i]); + } + + 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 */ + for (i = 0; i < cur_count; i++) { + virDomainFree(tmp_list[i]); + } + + 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]); + } + + 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); + + return NULL; +} + +static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, + const CMPIContext* ctx, + const CMPISelectExp* se, + const char *ns, + const CMPIObjectPath* op, + CMPIBoolean first) +{ + CU_DEBUG("ActivateFilter"); + if (lifecycle_thread_id == 0) { + CMPIContext *thread_context; + + thread_context = CBPrepareAttachThread(_BROKER, ctx); + + lifecycle_thread_id = _BROKER->xft->newThread(lifecycle_thread, + thread_context, + 0); + } + + return (CMPIStatus){CMPI_RC_OK, NULL}; +} + +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: + */ diff -r ca8dc23eacc4 -r 6f3a50557ab0 src/Virt_ComputerSystemModifiedIndication.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Virt_ComputerSystemModifiedIndication.h Thu Jan 10 11:33:17 2008 -0500 @@ -0,0 +1,37 @@ +/* + * 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 + */ + +struct dom_xml { + char *uuid; + char *xml; +}; + +int free_dom_xml(struct dom_xml dom); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */