summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Minar <miminar@redhat.com>2014-06-20 13:45:01 +0200
committerMichal Minar <miminar@redhat.com>2014-06-25 15:17:16 +0200
commit4c3452a2d4209edc1537b05cbba5725469f45cbf (patch)
tree3e5673019ca76584e1f0f5e4b1c59255fd4dc74c
parent0dcb115b4924bb19ee0b8650d3388d02ce4a7ff4 (diff)
downloadopenlmi-providers-4c3452a2d4209edc1537b05cbba5725469f45cbf.tar.gz
openlmi-providers-4c3452a2d4209edc1537b05cbba5725469f45cbf.tar.xz
openlmi-providers-4c3452a2d4209edc1537b05cbba5725469f45cbf.zip
openlmi: make sure computer system instance gets loaded
When broker is started with some indication subscriptions active, it immediately loads and starts corresponding providers that try to do their init functions. At this time it's not possible to query the broker for an instance of PG\_ComputerSystem though. Broker replies with NOT\_FOUND. This patch adds safe functions: lmi_get_computer_system_safe() lmi_get_system_name_safe() accepting current context. They make sure that computer system will be loaded even if the first attempt at init time failed. Following functions are now marked as deprecated: lmi_get_computer_system() lmi_get_system_name() Correct and ideal solution would be lazy evalution - load the computer system when it's needed for the first time, not before. This means: 1. `get_computer_system()` cleared away from init 2. `lmi_get_computer_system()` and `lmi_get_system_name()` accepting context and calling `get_computer_system()` to fetch it either from cache or from broker Unfortunately this would break libopenlmi's API.
-rw-r--r--src/libs/libopenlmi/openlmi.c180
-rw-r--r--src/libs/libopenlmi/openlmi.h37
2 files changed, 158 insertions, 59 deletions
diff --git a/src/libs/libopenlmi/openlmi.c b/src/libs/libopenlmi/openlmi.c
index 958a7ef..59c39c7 100644
--- a/src/libs/libopenlmi/openlmi.c
+++ b/src/libs/libopenlmi/openlmi.c
@@ -67,85 +67,135 @@ static ConfigEntry _toplevel_config_defaults[] = {
* Enumerate configured ComputerSystem class in order to obtain
* ComputerSystem ObjectPath and Hostname
*
- * @param cb CMPIBroker
+ * @note This call needs to be guarded with `_init_mutex`.
+ *
* @param ctx CMPIContext
+ * @param csop If not NULL, will be set with cached computer system.
+ * @param system_name If not NULL, will be set with cached system name.
* @retval true Success
* @retval false Failure
*/
-static bool get_computer_system(const CMPIBroker *cb, const CMPIContext *ctx)
+static bool get_computer_system(const CMPIContext *ctx,
+ CMPIObjectPath **csop,
+ const char **system_name)
{
- free(_system_name);
- _system_name = NULL;
- if (_computer_system != NULL) {
- CMRelease(_computer_system);
- _computer_system = NULL;
- }
-
- const char *class_name = lmi_get_system_creation_class_name();
- char *namespace = lmi_read_config("CIM", "Namespace");
CMPIStatus rc = { 0, NULL };
- CMPIObjectPath *op = CMNewObjectPath(cb, namespace, class_name, &rc);
- g_free (namespace);
- if (rc.rc != CMPI_RC_OK) {
- lmi_error("Unable to create object path: %s", rc.msg);
- return false;
- }
- CMPIEnumeration *en = CBEnumInstanceNames(cb, ctx, op, &rc);
- if (rc.rc != CMPI_RC_OK) {
- lmi_error("Unable to enumerate instance names of class %s", class_name);
- return false;
- }
-
- if (!CMHasNext(en, &rc)) {
- lmi_error("No instance of class %s exists", class_name);
- CMRelease(en);
- return false;
- }
- CMPIData data = CMGetNext(en, &rc);
- if (rc.rc != CMPI_RC_OK) {
- lmi_error("Unable to get instance name of class %s", class_name);
- CMRelease(en);
- return false;
- }
- if (data.type != CMPI_ref) {
- lmi_error("EnumInstanceNames didn't return CMPI_ref type, but %d", data.type);
+ const char *class_name;
+ char *namespace;
+ CMPIObjectPath *op;
+ CMPIEnumeration *en = NULL;
+
+ if (_system_name == NULL || _computer_system == NULL) {
+ lmi_debug("Caching computer system object path.");
+ if (_computer_system != NULL) {
+ CMRelease(_computer_system);
+ _computer_system = NULL;
+ }
+ free(_system_name);
+ _system_name = NULL;
+
+ class_name = lmi_get_system_creation_class_name();
+ namespace = lmi_read_config("CIM", "Namespace");
+ op = CMNewObjectPath(_cb, namespace, class_name, &rc);
+ g_free(namespace);
+ if (rc.rc != CMPI_RC_OK) {
+ lmi_error("Unable to create object path: %s", rc.msg);
+ goto err;
+ }
+ en = CBEnumInstanceNames(_cb, ctx, op, &rc);
+ if (rc.rc != CMPI_RC_OK) {
+ lmi_error("Unable to enumerate instance names of class %s",
+ class_name);
+ goto err;
+ }
+ if (!CMHasNext(en, &rc)) {
+ lmi_error("No instance of class %s exists", class_name);
+ goto err;
+ }
+ CMPIData data = CMGetNext(en, &rc);
+ if (rc.rc != CMPI_RC_OK) {
+ lmi_error("Unable to get instance name of class %s", class_name);
+ goto err;
+ }
+ if (data.type != CMPI_ref) {
+ lmi_error("EnumInstanceNames didn't return CMPI_ref type, but %d",
+ data.type);
+ goto err;
+ }
+ _computer_system = CMClone(data.value.ref, &rc);
+ if (rc.rc != CMPI_RC_OK) {
+ lmi_error("Unable to clone ComputerSystem object path");
+ goto err;
+ }
+ _system_name = strdup(CMGetCharPtr(
+ CMGetKey(_computer_system, "Name", NULL).value.string));
+ if (_system_name == NULL) {
+ lmi_error("Memory allocation failed");
+ goto err;
+ }
CMRelease(en);
- return false;
+ lmi_debug("Successfuly cached computer system.");
}
- _computer_system = CMClone(data.value.ref, &rc);
- if (rc.rc != CMPI_RC_OK) {
- lmi_error("Unable to clone ComputerSystem object path");
+
+ if (system_name != NULL)
+ *system_name = _system_name;
+ if (csop != NULL)
+ *csop = _computer_system;
+
+ return true;
+
+err:
+ if (en)
CMRelease(en);
- return false;
+ if (_computer_system != NULL) {
+ CMRelease(_computer_system);
+ _computer_system = NULL;
}
- _system_name = strdup(CMGetCharPtr(CMGetKey(_computer_system, "Name", &rc).value.string));
- CMRelease(en);
- return true;
+ return false;
}
-static bool lmi_is_this_system(const char *system_name)
+static bool lmi_is_this_system(const CMPIContext *ctx, const char *system_name)
{
- // TODO accept also aliases and FQDNs
- return strcmp(system_name, _system_name) == 0;
-}
+ const char *csn;
+ bool res = false;
+ pthread_mutex_lock(&_init_mutex);
+ if (get_computer_system(ctx, NULL, &csn))
+ // TODO accept also aliases and FQDNs
+ res = strcmp(system_name, csn) == 0;
+ pthread_mutex_unlock(&_init_mutex);
+
+ return res;
+}
CMPIObjectPath *lmi_get_computer_system(void)
{
return _computer_system;
}
-bool lmi_check_computer_system(const CMPIObjectPath *computer_system)
+CMPIObjectPath *lmi_get_computer_system_safe(const CMPIContext *ctx)
+{
+ CMPIObjectPath *csop = NULL;
+
+ pthread_mutex_lock(&_init_mutex);
+ get_computer_system(ctx, &csop, NULL);
+ pthread_mutex_unlock(&_init_mutex);
+
+ return csop;
+}
+
+bool lmi_check_computer_system(const CMPIContext *ctx,
+ const CMPIObjectPath *computer_system)
{
CMPIString *nsa = NULL;
CMPIString *nsb = NULL;
CMPIString *cls_name = NULL;
CMPIData data;
- CMPIObjectPath *our = lmi_get_computer_system();
+ CMPIObjectPath *our = lmi_get_computer_system_safe(ctx);
CMPIStatus status = {CMPI_RC_OK, NULL};
if (!our) {
- lmi_error("Memory allocation failed");
+ lmi_error("Failed to get computer system's object path.");
return false;
}
if (!(nsb = CMGetNameSpace(computer_system, NULL)))
@@ -187,7 +237,7 @@ bool lmi_check_computer_system(const CMPIObjectPath *computer_system)
lmi_warn("Missing Name property in computer system instance.");
return false;
}
- if (!lmi_is_this_system(CMGetCharsPtr(data.value.string, NULL))) {
+ if (!lmi_is_this_system(ctx, CMGetCharsPtr(data.value.string, NULL))) {
lmi_warn("Name \"%s\" of computer system do no match this system \"%s\".",
CMGetCharsPtr(data.value.string, NULL));
return false;
@@ -201,6 +251,17 @@ const char *lmi_get_system_name(void)
return _system_name;
}
+const char *lmi_get_system_name_safe(const CMPIContext *ctx)
+{
+ const char *csn = NULL;
+
+ pthread_mutex_lock(&_init_mutex);
+ get_computer_system(ctx, NULL, &csn);
+ pthread_mutex_unlock(&_init_mutex);
+
+ return csn;
+}
+
const char *lmi_get_system_creation_class_name(void)
{
if (_system_creation_class_name == NULL) {
@@ -352,10 +413,15 @@ void lmi_init(const char *provider, const CMPIBroker *cb,
// We might read different log config, reread it in next _log_debug call
_log_level = _LMI_DEBUG_NONE;
- // Read ComputerSystem instance
- if (_computer_system == NULL || _system_name == NULL) {
- get_computer_system(cb, ctx);
- }
+ // Read ComputerSystem instance. `_computer_system` and `_system_name` are
+ // expected to be initialized by deprecated functions
+ // `lmi_get_system_name()` and `lmi_get_computer_system()`. There is a
+ // valid case where `get_computer_system()` fails to fetch
+ // `CIM_ComputerSystem` instance. It happens at early init when indication
+ // subscriptions exist. Broker tries to initialize corresponding before it
+ // finishes its own initialization. At that time it's not possible to run
+ // any queries.
+ get_computer_system(ctx, NULL, NULL);
/*
* Ugly hack to prevent Pegasus from crashing on cleanup.
@@ -482,7 +548,7 @@ CMPIStatus lmi_check_required_properties(
if (CMIsNullValue(data)) {
lmi_return_with_chars(cb, CMPI_RC_ERR_FAILED, "%s is empty", csn_prop_name);
}
- if (strcmp(KChars(data.value.string), lmi_get_system_name()) != 0) {
+ if (strcmp(KChars(data.value.string), lmi_get_system_name_safe(ctx)) != 0) {
lmi_return_with_chars(cb, CMPI_RC_ERR_FAILED, "Wrong %s", csn_prop_name);
}
diff --git a/src/libs/libopenlmi/openlmi.h b/src/libs/libopenlmi/openlmi.h
index 7f2158b..799059d 100644
--- a/src/libs/libopenlmi/openlmi.h
+++ b/src/libs/libopenlmi/openlmi.h
@@ -67,7 +67,9 @@
#define LMI_MS_TO_DAYS(ms) ((ms) / 86400000000)
#define LMI_SECS_TO_MS(s) ((s) * 1000000)
-
+#define LMI_DEPRECATED G_DEPRECATED
+#define LMI_DEPRECATED_FOR G_DEPRECATED_FOR
+
typedef struct {
const char *group;
const char *key;
@@ -81,31 +83,62 @@ typedef struct {
* The instance is obtained by enumerating the configured ComputerSystem
* classname.
*
+ * @deprecated Please use lmi_get_computer_system_safe() instead.
+ *
* @warning Call lmi_init function before calling this function!
*
* @return CIM_ComputerSystem object path
*/
+LMI_DEPRECATED_FOR(lmi_get_computer_system_safe)
CMPIObjectPath *lmi_get_computer_system(void);
/**
+ * This function returns object path of an instance of CIM_ComputerSystem
+ * subclass.
+ *
+ * The instance is obtained by enumerating the configured ComputerSystem
+ * classname.
+ *
+ * @warning Call lmi_init function before calling this function!
+ *
+ * @return CIM_ComputerSystem object path
+ */
+CMPIObjectPath *lmi_get_computer_system_safe(const CMPIContext *ctx);
+
+/**
* Check object path of CIM_ComputerSystem.
*
* @return true, if the object path matches this computer system.
*/
-bool lmi_check_computer_system(const CMPIObjectPath *computer_system);
+bool lmi_check_computer_system(const CMPIContext *ctx,
+ const CMPIObjectPath *computer_system);
/**
* This function returns system name for the computer system
*
* @note Use this in the SystemName property of all provider created instances.
*
+ * @deprecated Please use lmi_get_system_name_safe() instead.
+ *
* @warning Call lmi_init function before calling this function!
*
* @return The scoping System's Name.
*/
+LMI_DEPRECATED_FOR(lmi_get_system_name_safe)
const char *lmi_get_system_name(void);
/**
+ * This function returns system name for the computer system
+ *
+ * @note Use this in the SystemName property of all provider created instances.
+ *
+ * @warning Call lmi_init function before calling this function!
+ *
+ * @return The scoping System's Name.
+ */
+const char *lmi_get_system_name_safe(const CMPIContext *ctx);
+
+/**
* This function returns system creation class name
*
* @note Use this in the SystemCreationClassName property of all provider