# HG changeset patch
# User Richard Maciel <rmaciel(a)linux.vnet.ibm.com>
# Date 1248549583 10800
# Node ID c91e92f9a0075e82710c429da17f095a7295ef66
# Parent cd707d323dcfcf2b7557fc4be9e0aac4fda65502
Raises GuestCrashAlertIndication when QEMU crashes
Signed-off-by: Richard Maciel <rmaciel(a)linux.vnet.ibm.com>
diff -r cd707d323dcf -r c91e92f9a007 src/Makefile.am
--- a/src/Makefile.am Sat Jul 25 16:19:43 2009 -0300
+++ b/src/Makefile.am Sat Jul 25 16:19:43 2009 -0300
@@ -75,7 +75,8 @@
libVirt_ServiceAffectsElement.la \
libVirt_HostedAccessPoint.la \
libVirt_ServiceAccessBySAP.la \
- libVirt_SAPAvailableForElement.la
+ libVirt_SAPAvailableForElement.la \
+ libVirt_GuestCrashAlertIndication.la
libVirt_ComputerSystem_la_SOURCES = Virt_ComputerSystem.c
libVirt_ComputerSystem_la_DEPENDENCIES = libVirt_VirtualSystemSnapshotService.la
@@ -233,3 +234,7 @@
libVirt_SAPAvailableForElement_la_SOURCES = Virt_SAPAvailableForElement.c
libVirt_SAPAvailableForElement_la_LIBADD = -lVirt_ComputerSystem
-lVirt_KVMRedirectionSAP
+libVirt_GuestCrashAlertIndication_la_DEPENDENCIES = libVirt_ComputerSystem.la
+libVirt_GuestCrashAlertIndication_la_SOURCES = Virt_GuestCrashAlertIndication.c
+libVirt_GuestCrashAlertIndication_la_LIBADD = -lVirt_ComputerSystem
+
diff -r cd707d323dcf -r c91e92f9a007 src/Virt_GuestCrashAlertIndication.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Virt_GuestCrashAlertIndication.c Sat Jul 25 16:19:43 2009 -0300
@@ -0,0 +1,545 @@
+/*
+ * Copyright IBM Corp. 2009
+ *
+ * Authors:
+ * Richard Maciel <rmaciel(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 <stdbool.h>
+#include <pthread.h>
+
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libvirt/libvirt.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <misc_util.h>
+#include <libcmpiutil/std_indication.h>
+#include <cs_util.h>
+
+#include "config.h"
+#include "infostore.h"
+
+typedef struct cb_info {
+ const CMPIContext *context;
+ const CMPIObjectPath *obj_path;
+} *cb_info_ptr;
+
+static const CMPIBroker *_BROKER;
+
+#define CAI_NUM_PLATFORMS 3
+enum CAI_PLATFORMS {CAI_XEN,
+ CAI_KVM,
+ CAI_LXC,
+};
+static int active_filters[CAI_NUM_PLATFORMS];
+
+static pthread_mutex_t cb_reg_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_alert_ind_props(const CMPIBroker *broker,
+ const char *prefix,
+ const CMPIContext *ctx,
+ CMPIInstance *ind)
+{
+ CMPIStatus s;
+ CMPIString *str = NULL;
+ CMPIUint16 val;
+ CMPIArray *array = NULL;
+ char *charsptr = NULL;
+ int rc;
+
+
+ //CMSetProperty(ind, "Description", &str, CMPI_string);
+
+
+ // val 1
+ val = 1;
+ CMSetProperty(ind, "AlertType", &val, CMPI_uint16);
+
+ str = CMNewString(broker, "Virtual guest crash", &s);
+ CMSetProperty(ind, "OtherAlertType", &str, CMPI_string);
+
+ val = 7;
+ CMSetProperty(ind, "PerceivedSeverity", &val, CMPI_uint16);
+
+ // val 48
+ val = 48;
+ CMSetProperty(ind, "ProbableCause", &val, CMPI_uint16);
+
+ //CMSetProperty(ind, "ProbableCauseDescription", &str,
CMPI_string);
+
+ // val 1
+ val = 1;
+ CMSetProperty(ind, "Trending", &val, CMPI_uint16);
+
+ // This is an array
+ // CMSetProperty(ind, "RecommendedActions", &str, CMPI_string);
+
+
+ // Must find how to fill it
+ //CMSetProperty(ind, "EventTime", &, CMPI_dateTime);
+
+ // Won't use it
+ //CMSetProperty(ind, "SystemCreationClassName", &str,
CMPI_string);
+
+ // Won't use it
+ // CMSetProperty(ind, "SystemName", &str, CMPI_string);
+
+ // Combine GuestCrashAlertIndication with prefix
+ rc = asprintf(&charsptr, "%s%s", prefix,
"_GuestCrashAlertIndication");
+ str = CMNewString(broker, charsptr, &s);
+ CMSetProperty(ind, "ProviderName", &str, CMPI_string);
+ free(charsptr);
+
+ str = CMNewString(broker, "DTMF", &s);
+ CMSetProperty(ind, "OwningEntity", &str, CMPI_string);
+
+ str = CMNewString(broker, "PLAT0002", &s);
+ CMSetProperty(ind, "MessageID", &str, CMPI_string);
+
+ //CMSetProperty(ind, "Message", &str, CMPI_string);
+
+ // This is an string array
+ array = CMNewArray(broker, 1, CMPI_stringA, &s);
+ str = CMNewString(broker,
+ "Virtual machine execution ended "
+ "unexpectly",
+ &s);
+ s = CMSetArrayElementAt(array, 0, &str, CMPI_string);
+ CMSetProperty(ind, "MessageArguments", &array, CMPI_string);
+}
+
+static CMPIStatus create_and_deliver_ind(const CMPIBroker *broker,
+ const CMPIContext *ctx,
+ struct ind_args *args)
+{
+ const char *ind_type_name = "GuestCrashAlertIndication";
+ CMPIObjectPath *ind_op;
+ CMPIInstance *ind;
+ CMPIStatus s;
+ char *prefix = NULL;
+
+ prefix = class_prefix_name(args->classname);
+
+ ind = get_typed_instance(broker,
+ prefix,
+ ind_type_name,
+ args->ns);
+
+ if (ind == NULL) {
+ cu_statusf(broker,
+ &s,
+ CMPI_RC_ERR_FAILED,
+ "Failed to create ind, type '%s:%s_%s'",
+ args->ns,
+ prefix,
+ ind_type_name);
+ goto out;
+ }
+
+ ind_op = CMGetObjectPath(ind, &s);
+ if (s.rc != CMPI_RC_OK) {
+ //CU_DEBUG("Failed to get ind_op. Error: '%s'",
s.msg);
+ goto out;
+ }
+ CMSetNameSpace(ind_op, args->ns);
+
+ set_alert_ind_props(broker, prefix, ctx, ind);
+
+ CU_DEBUG("Delivering Indication: %s",
+ CMGetCharPtr(CMObjectPathToString(ind_op, NULL)));
+
+ s = stdi_deliver(broker, ctx, args, ind);
+ if (s.rc == CMPI_RC_OK) {
+ CU_DEBUG("Indication delivered");
+ } else {
+ CU_DEBUG("Not delivered: %s", CMGetCharPtr(s.msg));
+ }
+
+ out:
+ free(prefix);
+
+ return s;
+}
+
+DECLARE_FILTER(xen_crashed, "Xen_GuestCrashAlertIndication");
+DECLARE_FILTER(kvm_crashed, "KVM_GuestCrashAlertIndication");
+
+static struct std_ind_filter *filters[] = {
+ &xen_crashed,
+ &kvm_crashed,
+ NULL,
+};
+
+static CMPIStatus raise_indication(const CMPIBroker *broker,
+ const CMPIContext *ctx,
+ const CMPIInstance *ind)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ CMPIObjectPath *ref = NULL;
+ struct std_indication_ctx *_ctx = NULL;
+ struct ind_args *args = NULL;
+
+ CU_DEBUG("Guest Crash Raise indication");
+
+ ref = CMGetObjectPath(ind, &s);
+ if (s.rc != CMPI_RC_OK) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unable to get a reference to the guest");
+ goto out;
+ }
+
+ /* FIXME: This is a Pegasus work around. Pegsus loses the namespace
+ when an ObjectPath is pulled from an instance */
+ if (STREQ(NAMESPACE(ref), ""))
+ CMSetNameSpace(ref, "root/virt");
+
+ /*s = get_domain_by_ref(broker, ref, &src_inst);
+ if (s.rc != CMPI_RC_OK || CMIsNullObject(src_inst))
+ goto out;*/
+
+ _ctx = malloc(sizeof(struct std_indication_ctx));
+ if (_ctx == NULL) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unable to allocate indication context");
+ goto out;
+ }
+
+ _ctx->brkr = broker;
+ _ctx->handler = NULL;
+ _ctx->filters = filters;
+ _ctx->enabled = true;
+
+ args = malloc(sizeof(struct ind_args));
+ if (args == NULL) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unable to allocate ind_args");
+ goto out;
+ }
+
+ args->ns = strdup(NAMESPACE(ref));
+ args->classname = strdup(CLASSNAME(ref));
+ args->_ctx = _ctx;
+
+
+ s = create_and_deliver_ind(broker, ctx, args);
+
+ if (s.rc != CMPI_RC_OK) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unable to generate indication");
+ }
+
+ out:
+ if (args != NULL)
+ stdi_free_ind_args(&args);
+
+ if (_ctx != NULL)
+ free(_ctx);
+
+ return s;
+}
+
+
+static void free_cb(void *opaque)
+{
+ cb_info_ptr cbinfo = NULL;
+
+ CU_DEBUG("Releasing memory from guest crash callback");
+
+ cbinfo = (cb_info_ptr)opaque;
+ free(cbinfo);
+}
+
+static char * inc_counter(virDomainPtr dom)
+{
+ struct infostore_ctx *store = NULL;
+ char *str = NULL;
+ uint64_t counter = 0;
+ bool ret = false;
+
+ store = infostore_open(dom);
+
+ if (store == NULL) {
+ CU_DEBUG("Could not open infostore");
+ goto out;
+ }
+
+ counter = infostore_get_u64(store, "EventID");
+
+ if (counter == 0)
+ CU_DEBUG("No EventID available. Creating...");
+
+ counter++;
+
+ if (asprintf(&str, "%llu", counter) < 0) {
+ CU_DEBUG("Could not alloc memory for counter");
+ goto out;
+ }
+
+ ret = infostore_set_u64(store, "EventID", counter);
+ if (!ret) {
+ CU_DEBUG("Could not save EventID to infostore");
+ free(str);
+ }
+
+ out:
+ if (!ret)
+ str = NULL;
+
+ infostore_close(store);
+
+ return str;
+}
+
+static void preset_alert_ind_props(CMPIInstance *ind, virDomainPtr dom)
+{
+ CMPIStatus s;
+ CMPIString *str = NULL;
+ char *dom_name = (char *)virDomainGetName(dom);
+ char *counter = NULL;
+
+ if (dom_name == NULL) {
+ CU_DEBUG("Could not retrieve name of guest responsible for "
+ "crash");
+ dom_name = "Guest name not available";
+ }
+
+ str = CMNewString(_BROKER, dom_name, &s);
+ CMSetProperty(ind, "AlertingManagedElement", &str, CMPI_string);
+
+ // This property must be unique, retrieve a counter from infostore
+ counter = inc_counter(dom);
+ if (counter == NULL) {
+ CU_DEBUG("Could not retrieve counter");
+ } else {
+ str = CMNewString(_BROKER, counter, &s);
+ CMSetProperty(ind, "EventID", &str, CMPI_string);
+ free(counter);
+ }
+}
+
+static int guest_crashed_cb(virConnectPtr conn,
+ virDomainPtr dom,
+ int event,
+ int detail,
+ void *opaque)
+{
+ char *type = NULL;
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ const char *ind_name = "GuestCrashedAlertIndication";
+ CMPIInstance *ind = NULL;
+ cb_info_ptr cbinfo = NULL;
+ const CMPIObjectPath *op = NULL;
+ const CMPIContext *context = NULL;
+
+ CU_DEBUG("Preparing GuestCrashedAlertIndication");
+
+ if (event != VIR_DOMAIN_EVENT_STOPPED_FAILED) {
+ CU_DEBUG("Event not monitored. Ignoring...");
+ return 0;
+ }
+
+ cbinfo = (cb_info_ptr)opaque;
+ op = cbinfo->obj_path;
+ context = cbinfo->context;
+
+ ind = get_typed_instance(_BROKER,
+ CLASSNAME(op),
+ ind_name,
+ NAMESPACE(op));
+
+ preset_alert_ind_props(ind, dom);
+
+ if (ind == NULL) {
+ CU_DEBUG("Failed to create ind '%s'", ind_name);
+ goto out;
+ }
+
+ type = get_typed_class(CLASSNAME(op), ind_name);
+
+ s = stdi_raise_indication(_BROKER,
+ context,
+ type,
+ NAMESPACE(op),
+ ind);
+
+ out:
+ free(type);
+
+ return s.rc != CMPI_RC_OK;
+}
+
+static int platform_from_class(const char *cn)
+{
+ if (STARTS_WITH(cn, "Xen"))
+ return CAI_XEN;
+ else if (STARTS_WITH(cn, "KVM"))
+ return CAI_KVM;
+ else if (STARTS_WITH(cn, "LXC"))
+ return CAI_LXC;
+ else
+ return -1;
+}
+
+static CMPIStatus ActivateFilter(CMPIIndicationMI* mi,
+ const CMPIContext* ctx,
+ const CMPISelectExp* se,
+ const char *ns,
+ const CMPIObjectPath* op,
+ CMPIBoolean first)
+{
+ virConnectPtr conn = NULL;
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ cb_info_ptr cbinfo = NULL;
+ int platform;
+ int ret = 0;
+
+ cbinfo = (cb_info_ptr)malloc(sizeof(struct cb_info));
+ cbinfo->context = ctx;
+ cbinfo->obj_path = op;
+
+ CU_DEBUG("ActivateFilter for %s", CLASSNAME(op));
+
+ if (CMIsNullObject(op)) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "No ObjectPath given");
+ goto out;
+ }
+
+ platform = platform_from_class(CLASSNAME(op));
+ if (platform < 0) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unknown platform");
+ goto out;
+ }
+
+ pthread_mutex_lock(&cb_reg_mutex);
+
+ active_filters[platform]++;
+
+ if (active_filters[platform] == 1) {
+ conn = connect_by_classname(_BROKER, CLASSNAME(op), &s);
+
+ CU_DEBUG("Registering callback function");
+ ret = virConnectDomainEventRegister(conn,
+ guest_crashed_cb,
+ (void *)cbinfo,
+ free_cb);
+ CU_DEBUG("ret val: %d\n", ret);
+ }
+
+ pthread_mutex_unlock(&cb_reg_mutex);
+
+ out:
+ return s;
+}
+
+static CMPIStatus DeActivateFilter(CMPIIndicationMI* mi,
+ const CMPIContext* ctx,
+ const CMPISelectExp* se,
+ const char *ns,
+ const CMPIObjectPath* op,
+ CMPIBoolean last)
+{
+ int platform;
+
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+
+ pthread_mutex_lock(&cb_reg_mutex);
+
+ platform = platform_from_class(CLASSNAME(op));
+ if (platform < 0) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unknown platform");
+ goto out;
+ }
+
+ if (active_filters[platform] == 1) {
+ // Unregister callback
+ }
+
+ active_filters[platform]--;
+
+ pthread_mutex_unlock(&cb_reg_mutex);
+
+ CU_DEBUG("DeActivateFilter for %s", CLASSNAME(op));
+
+ out:
+ return s;
+}
+
+static _EI_RTYPE EnableIndications(CMPIIndicationMI* mi,
+ const CMPIContext *ctx)
+{
+ CU_DEBUG("EnableIndications");
+
+ _EI_RET();
+
+}
+
+static _EI_RTYPE DisableIndications(CMPIIndicationMI* mi,
+ const CMPIContext *ctx)
+{
+ CU_DEBUG("DisableIndications");
+
+ _EI_RET();
+}
+
+
+
+static struct std_indication_handler csi = {
+ .raise_fn = raise_indication,
+ .trigger_fn = NULL,
+ .activate_fn = ActivateFilter,
+ .deactivate_fn = DeActivateFilter,
+ .enable_fn = EnableIndications,
+ .disable_fn = DisableIndications,
+};
+
+DEFAULT_IND_CLEANUP();
+DEFAULT_AF();
+DEFAULT_MP();
+
+STDI_IndicationMIStub(,
+ Virt_GuestCrashAlertIndicationProvider,
+ _BROKER,
+ libvirt_cim_init(),
+ &csi,
+ filters);
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */