summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadek Novacek <rnovacek@redhat.com>2013-09-18 08:00:08 +0200
committerRadek Novacek <rnovacek@redhat.com>2013-09-18 08:00:38 +0200
commite4d72c3b72f2f363ec556c5f0ec6d94bd4f038ed (patch)
treed50d5e7ba4d238725a48c97659a7c40e1131729a
parent87ac9c8b710ff016ac6db4311503a5b699b91c41 (diff)
downloadopenlmi-providers-e4d72c3b72f2f363ec556c5f0ec6d94bd4f038ed.tar.gz
openlmi-providers-e4d72c3b72f2f363ec556c5f0ec6d94bd4f038ed.tar.xz
openlmi-providers-e4d72c3b72f2f363ec556c5f0ec6d94bd4f038ed.zip
Introduce toplevel openlmi config file
Toplevel openlmi configuration file (/etc/openlmi/openlmi.conf) now contains common configuration options for all providers. Configuration for each provider could be overriden in provider-specific config (/etc/openlmi/$provider/$provider.conf). This patch also modify config file handling in python providers to include this config file. There is also support for C providers (in libopenlmicommon) for reading these config files and providing default configuration options.
-rw-r--r--CMakeLists.txt6
-rw-r--r--openlmi-providers.spec1
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/account/CMakeLists.txt3
-rw-r--r--src/openlmi.c160
-rw-r--r--src/openlmi.h35
-rw-r--r--src/python/lmi/base/BaseConfiguration.py40
7 files changed, 228 insertions, 22 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8bb4dd2..d3184e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,10 @@ else(CMAKE_SIZEOF_VOID_P EQUAL 4)
SET(LIB_SUFFIX 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 4)
+if(NOT SYSCONF_INSTALL_DIR)
+ set(SYSCONF_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/etc)
+endif(NOT SYSCONF_INSTALL_DIR)
+
option(WITH-FAN "Build fan provider" ON)
option(WITH-POWER "Build power provider" ON)
option(WITH-SERVICE "Build service provider" ON)
@@ -40,6 +44,8 @@ find_package(PkgConfig)
find_package(CMPI REQUIRED)
find_package(KonkretCMPI REQUIRED)
+pkg_check_modules(GLIB REQUIRED glib-2.0)
+
add_subdirectory(src)
add_subdirectory(mof)
add_subdirectory(tools)
diff --git a/openlmi-providers.spec b/openlmi-providers.spec
index f85faca..e3f1e68 100644
--- a/openlmi-providers.spec
+++ b/openlmi-providers.spec
@@ -312,6 +312,7 @@ cp -pr src/account/doc/build/html/* $RPM_BUILD_ROOT/%{_docdir}/%{name}/account/a
%files
%doc README COPYING
%dir %{_datadir}/%{name}
+%config(noreplace) %{_sysconfdir}/openlmi/openlmi.conf
%{_datadir}/%{name}/05_LMI_Qualifiers.mof
%{_datadir}/%{name}/30_LMI_Jobs.mof
%{_libdir}/libopenlmicommon.so.*
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a9dc85d..589c845 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,9 +1,11 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMPI_INCLUDE_DIR})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMPI_INCLUDE_DIR} ${GLIB_INCLUDE_DIRS})
add_library(openlmicommon SHARED
openlmi.c
)
+target_link_libraries(openlmicommon ${GLIB_LIBRARIES})
+
set(OPENLMICOMMON_VERSION_MAJOR 0)
set(OPENLMICOMMON_VERSION_MINOR 0)
set(OPENLMICOMMON_VERSION_PATCH 1)
@@ -16,6 +18,7 @@ install(TARGETS openlmicommon DESTINATION lib${LIB_SUFFIX})
install(FILES openlmi.h DESTINATION include/openlmi)
configure_file(openlmi.pc.in openlmi.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openlmi.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig)
+install(FILES openlmi.conf DESTINATION ${SYSCONF_INSTALL_DIR}/openlmi)
if (WITH-FAN)
add_subdirectory(fan)
diff --git a/src/account/CMakeLists.txt b/src/account/CMakeLists.txt
index a993094..021b5f2 100644
--- a/src/account/CMakeLists.txt
+++ b/src/account/CMakeLists.txt
@@ -41,8 +41,7 @@ endforeach(CIM_CLASS ${CIM_CLASSES})
set(TARGET_MOF "${CMAKE_BINARY_DIR}/mof/90_LMI_Account_Profile.mof")
profile_mof_generate("90_LMI_Account_Profile.mof.skel" "${TARGET_MOF}" "${CIM_PROVIDERS_CLASSES}")
-# Require GLib-2.0 and libuser
-pkg_check_modules(GLIB REQUIRED glib-2.0)
+# Require libuser
pkg_check_modules(LIBUSER REQUIRED libuser)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMPI_INCLUDE_DIR} ${GLIB_INCLUDE_DIRS} ${LIBUSER_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/src/indmanager)
diff --git a/src/openlmi.c b/src/openlmi.c
index 3b46f8d..ac539bd 100644
--- a/src/openlmi.c
+++ b/src/openlmi.c
@@ -22,17 +22,39 @@
#include <stdlib.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <cmpimacs.h>
+#include <glib.h>
static char *_fqdn = NULL;
static int _log_level = _LMI_DEBUG_DEBUG;
static const CMPIBroker *_cb = NULL;
-static char *_log_id = NULL;
+static char *_provider = NULL;
+
+// Storage for all keys from configuration files and default configuration option
+// Access needs to be mutexed
+static GKeyFile *_masterKeyFile = NULL;
+
+// Mutex for running lmi_init
+static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+// Cache for SystemCreationClassName
+static char *_system_creation_class_name = NULL;
+
+static ConfigEntry _toplevel_config_defaults[] = {
+ { "CIM", "Namespace", "root/cimv2" },
+ { "CIM", "SystemClassName", "Linux_ComputerSystem" },
+ { "LOG", "Level", "ERROR" },
+ { "LOG", "Stderr" , "false" }
+};
+
+#define TOPLEVEL_CONFIG_FILE "/etc/openlmi/openlmi.conf"
+#define PROVIDER_CONFIG_FILE "/etc/openlmi/%s/%s.conf"
/** Gets Fully Quantified Domain Name of the system
* @return FQDN (must be freed by the caller)
@@ -91,16 +113,140 @@ const char *lmi_get_system_name()
const char *lmi_get_system_creation_class_name()
{
- return "Linux_ComputerSystem";
+ if (_system_creation_class_name == NULL) {
+ if (_masterKeyFile == NULL) {
+ lmi_error("Configuration was not read, using default option");
+ return "Linux_ComputerSystem";
+ }
+ _system_creation_class_name = lmi_read_config("CIM", "SystemClassName");
+ if (_system_creation_class_name == NULL) {
+ // This shouldn't happen, SystemClassName should be at least
+ // in default config keys
+ return "Linux_ComputerSystem";
+ }
+ }
+ return _system_creation_class_name;
}
-void lmi_init_logging(const char *log_id, const CMPIBroker *cb)
+char *lmi_read_config(const char *group, const char *key)
+{
+ if (_masterKeyFile == NULL) {
+ lmi_warn("Attempted to read config file before calling lmi_init");
+ return NULL;
+ }
+ return g_key_file_get_string(_masterKeyFile, group, key, NULL);
+}
+
+GKeyFile *parse_config(const char *provider_name, const ConfigEntry *provider_config_defaults)
{
- if (_log_id != NULL) {
- free(_log_id);
+ GError *error = NULL;
+ char *providerconf;
+
+ // Get all configuration options to masterKeyFile
+ GKeyFile *masterKeyFile = g_key_file_new();
+
+ // Read top-level openlmi configuration
+ if (!g_key_file_load_from_file(masterKeyFile, TOPLEVEL_CONFIG_FILE, G_KEY_FILE_NONE, &error)) {
+ lmi_debug("Can't read openlmi top-level config file %s: %s", TOPLEVEL_CONFIG_FILE, error->message);
+ }
+
+ // Read provider-specific configuration
+ if (asprintf(&providerconf, PROVIDER_CONFIG_FILE, provider_name, provider_name) <= 0) {
+ lmi_error("Memory allocation failed");
+ g_key_file_free(masterKeyFile);
+ return NULL;
+ }
+ GKeyFile *providerKeyFile;
+ if ((providerKeyFile = g_key_file_new()) == NULL) {
+ lmi_error("Memory allocation failed");
+ g_key_file_free(masterKeyFile);
+ return NULL;
}
- _log_id = strdup(log_id);
+ if (!g_key_file_load_from_file(providerKeyFile, providerconf, G_KEY_FILE_NONE, &error)) {
+ lmi_debug("Can't read provider specific config file %s: %s", providerconf, error->message);
+ }
+
+ // Merge provider config to _masterKeyFile
+ gsize groups_len, keys_len, i, j;
+ gchar *v;
+ gchar **groups = g_key_file_get_groups(providerKeyFile, &groups_len), **keys;
+ if (groups != NULL) {
+ for (i = 0; i < groups_len; ++i) {
+ keys = g_key_file_get_keys(providerKeyFile, groups[i], &keys_len, &error);
+ for (j = 0; j < keys_len; ++j) {
+ v = g_key_file_get_value(providerKeyFile, groups[i], keys[j], &error);
+ g_key_file_set_value(masterKeyFile, groups[i], keys[j], v);
+ free(v);
+ }
+ g_strfreev(keys);
+ }
+ g_strfreev(groups);
+ }
+ g_key_file_free(providerKeyFile);
+
+ // Fill in default values where nothing gets read from config file.
+ // Provider-specific configs first
+ gsize len = 0;
+ if (provider_config_defaults != NULL) {
+ len = sizeof(provider_config_defaults) / sizeof(ConfigEntry);
+ }
+ for (i = 0; i < len; i++) {
+ if (!g_key_file_has_key(masterKeyFile,
+ provider_config_defaults[i].group,
+ provider_config_defaults[i].key, NULL)) {
+
+ g_key_file_set_value(masterKeyFile,
+ provider_config_defaults[i].group,
+ provider_config_defaults[i].key,
+ provider_config_defaults[i].value);
+ }
+ }
+
+ // Top-level configs
+ len = sizeof(_toplevel_config_defaults)/sizeof(ConfigEntry);
+ for (i = 0; i < len; i++) {
+ if (!g_key_file_has_key(masterKeyFile,
+ _toplevel_config_defaults[i].group,
+ _toplevel_config_defaults[i].key, NULL)) {
+
+ g_key_file_set_value(masterKeyFile,
+ _toplevel_config_defaults[i].group,
+ _toplevel_config_defaults[i].key,
+ _toplevel_config_defaults[i].value);
+ }
+ }
+ return masterKeyFile;
+}
+
+void lmi_init(const char *provider, const CMPIBroker *cb, const ConfigEntry *provider_config_defaults)
+{
+ pthread_mutex_lock(&_init_mutex);
+ // Broker can change between threads
_cb = cb;
+
+ // Provider should remain the same
+ if (_provider != NULL) {
+ if (strcmp(_provider, provider) != 0) {
+ lmi_error("lmi_init called twice with different provider (%s -> %s), "
+ "this shouldn't happen", _provider, provider);
+ free(_provider);
+ } else {
+ pthread_mutex_unlock(&_init_mutex);
+ return;
+ }
+ }
+ _provider = strdup(provider);
+ if (_masterKeyFile != NULL) {
+ g_key_file_free(_masterKeyFile);
+ }
+ // Read config only on first call of this function
+ _masterKeyFile = parse_config(provider, provider_config_defaults);
+ pthread_mutex_unlock(&_init_mutex);
+}
+
+void lmi_init_logging(const char *log_id, const CMPIBroker *cb)
+{
+ lmi_init(log_id, cb, NULL);
}
int lmi_log_level(void)
@@ -135,7 +281,7 @@ void _lmi_debug(int level, const char *file, int line, const char *format, ...)
rc.rc = CMPI_RC_OK;
if (_cb != NULL) {
// try to use standard CMPI logging
- rc = _cb->eft->trace(_cb, CMPI_LEV_INFO, _log_id, text, NULL);
+ rc = _cb->eft->trace(_cb, CMPI_LEV_INFO, _provider, text, NULL);
}
if (_cb == NULL || rc.rc != CMPI_RC_OK) {
diff --git a/src/openlmi.h b/src/openlmi.h
index 6ab4158..93778ce 100644
--- a/src/openlmi.h
+++ b/src/openlmi.h
@@ -23,6 +23,12 @@
#include <cmpidt.h>
+typedef struct {
+ const char *group;
+ const char *key;
+ const char *value;
+} ConfigEntry;
+
/**
* This function returns FQDN (fully qualified domain name) of the machine
*
@@ -43,6 +49,35 @@ const char *lmi_get_system_name();
const char *lmi_get_system_creation_class_name();
/**
+ * Initialize usage base openlmi tools like configuration file access,
+ * logging etc.
+ *
+ * @note You must call this function prior to getting any configuration option
+ * or usage of logging. lmi_get_system_creation_class_name requires that this
+ * function will be called first (SystemCreationClassName is read from config).
+ *
+ * This function is reentrant and thread safe, but it should be called always
+ * with same parameters
+ *
+ * @param provider Identification of the CIM provider (must be same as name of the
+ * configuration file)
+ * @param cb CMPIBroker
+ * @param provider_config_defaults Array of default config values for given provider
+ * NULL if there is no provider-specific configuration
+ */
+void lmi_init(const char *provider, const CMPIBroker *cb,
+ const ConfigEntry *provider_config_defaults);
+
+/**
+ * Reads string key out of configration files or default configration options.
+ *
+ * @param group Configration group
+ * @param key Configration key
+ * @return String value of the key or NULL if group/key is not found
+ */
+char *lmi_read_config(const char *group, const char *key);
+
+/**
* To use standard CIMOM logging facility, broker must be assigned. Without
* calling this function, logging will go to stderr.
*
diff --git a/src/python/lmi/base/BaseConfiguration.py b/src/python/lmi/base/BaseConfiguration.py
index 8790acf..275fc0f 100644
--- a/src/python/lmi/base/BaseConfiguration.py
+++ b/src/python/lmi/base/BaseConfiguration.py
@@ -72,9 +72,12 @@ class BaseConfiguration(Singleton):
There should be only one instance of this class.
"""
- CONFIG_DIRECTORY_TEMPLATE = '/etc/openlmi/%(provider_prefix)s/'
- CONFIG_FILE_PATH_TEMPLATE = \
- CONFIG_DIRECTORY_TEMPLATE + '%(provider_prefix)s.conf'
+ CONFIG_DIRECTORY_TEMPLATE_TOPLEVEL = '/etc/openlmi/'
+ CONFIG_DIRECTORY_TEMPLATE_PROVIDER = '/etc/openlmi/%(provider_prefix)s/'
+ CONFIG_FILE_PATH_TEMPLATE_TOPLEVEL = \
+ CONFIG_DIRECTORY_TEMPLATE_TOPLEVEL + 'openlmi.conf'
+ CONFIG_FILE_PATH_TEMPLATE_PROVIDER = \
+ CONFIG_DIRECTORY_TEMPLATE_PROVIDER + '%(provider_prefix)s.conf'
PERSISTENT_PATH_TEMPLATE = '/var/lib/openlmi-%(provider_prefix)s/'
SETTINGS_DIR = 'settings/'
@@ -106,11 +109,17 @@ class BaseConfiguration(Singleton):
return cls.DEFAULT_OPTIONS
@classmethod
- def config_directory(cls):
- """ Base directory with configuration settings. """
- return cls.CONFIG_DIRECTORY_TEMPLATE % {
+ def config_directory_toplevel(cls):
+ """ Base directory with toplevel configuration settings. """
+ return cls.CONFIG_DIRECTORY_TEMPLATE_TOPLEVEL
+
+ @classmethod
+ def config_directory_provider(cls):
+ """ Base directory with provider specific configuration settings. """
+ return cls.CONFIG_DIRECTORY_TEMPLATE_PROVIDER % {
'provider_prefix' : cls.provider_prefix() }
+
@classmethod
def persistent_path(cls):
""" Base directory with persistent settings. """
@@ -118,11 +127,17 @@ class BaseConfiguration(Singleton):
'provider_prefix': cls.provider_prefix() }
@classmethod
- def config_file_path(cls):
- """ File path of configuration file. """
- return cls.CONFIG_FILE_PATH_TEMPLATE % {
+ def config_file_path_toplevel(cls):
+ """ File path of toplevel configuration file. """
+ return cls.CONFIG_FILE_PATH_TEMPLATE_TOPLEVEL
+
+ @classmethod
+ def config_file_path_provider(cls):
+ """ File path of provider specific configuration file. """
+ return cls.CONFIG_FILE_PATH_TEMPLATE_PROVIDER % {
'provider_prefix' : cls.provider_prefix() }
+
@classmethod
def mandatory_sections(cls):
"""
@@ -163,10 +178,11 @@ class BaseConfiguration(Singleton):
def load(self):
"""
- Load configuration from config file path.
- The file does not need to exist.
+ Load configuration from config files. Provider specific options
+ overrides toplevel openlmi configuration.
+ The files do not need to exist.
"""
- self.config.read(self.config_file_path())
+ self.config.read([self.config_file_path_toplevel(), self.config_file_path_provider()])
for section in self.mandatory_sections():
if not self.config.has_section(section):
self.config.add_section(section)