diff options
author | Tomas Bzatek <tbzatek@redhat.com> | 2013-08-23 14:44:02 +0200 |
---|---|---|
committer | Tomas Bzatek <tbzatek@redhat.com> | 2013-10-15 15:23:49 +0200 |
commit | 144dcfc5a924ecba7f615064156f6a40247c39b2 (patch) | |
tree | e877b70f634e42603b5755213f6b2bac99bdd4fa | |
parent | 7584e2fb80a74b7e4db3b653937a2c6ee64a7400 (diff) | |
download | openlmi-providers-144dcfc5a924ecba7f615064156f6a40247c39b2.tar.gz openlmi-providers-144dcfc5a924ecba7f615064156f6a40247c39b2.tar.xz openlmi-providers-144dcfc5a924ecba7f615064156f6a40247c39b2.zip |
journald: Basic provider implementation
This is a fully functional basic implementation of the provider.
Maximum number of enumerated instances is limited, see the code.
TODO list: https://fedorahosted.org/openlmi/ticket/142
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | mof/60_LMI_Journald.mof | 64 | ||||
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/journald/90_LMI_Journald_Profile.mof.skel | 21 | ||||
-rw-r--r-- | src/journald/CMakeLists.txt | 55 | ||||
-rw-r--r-- | src/journald/LMI_JournalLogRecordProvider.c | 240 | ||||
-rw-r--r-- | src/journald/LMI_JournalMessageLogProvider.c | 338 | ||||
-rw-r--r-- | src/journald/LMI_JournalRecordInLogProvider.c | 273 | ||||
-rw-r--r-- | src/journald/README | 26 | ||||
-rwxr-xr-x | src/journald/cmpiLMI_Journald-cimprovagt | 21 | ||||
-rw-r--r-- | src/journald/instutil.c | 113 | ||||
-rw-r--r-- | src/journald/instutil.h | 31 | ||||
-rw-r--r-- | src/journald/journal.h | 37 |
13 files changed, 1224 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 546742e..351e66d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ option(WITH-LOGICALFILE "Build logical file provider" ON) option(WITH-REALMD "Build RealmD provider" ON) option(WITH-INDMANAGER "Build indication manager" ON) option(WITH-SOFTWARE "Build software provider" ON) +option(WITH-JOURNALD "Build journald provider" ON) # Set path to custom cmake modules set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) diff --git a/mof/60_LMI_Journald.mof b/mof/60_LMI_Journald.mof new file mode 100644 index 0000000..85dad2b --- /dev/null +++ b/mof/60_LMI_Journald.mof @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +[ Version("0.2.0"), Provider("cmpi:cmpiLMI_Journald") ] +class LMI_JournalMessageLog: CIM_MessageLog +{ + [ Override("CreationClassName"), Key ] + String CreationClassName; + + [ Override("Name"), Key] + String Name; +}; + +[ Version("0.2.0"), Provider("cmpi:cmpiLMI_Journald") ] +class LMI_JournalLogRecord: CIM_LogRecord +{ + [ Override("LogCreationClassName"), Key ] + String LogCreationClassName; + + [ Override("LogName"), Key ] + String LogName; + + [ Override("CreationClassName"), Key ] + String CreationClassName; + + [ Override("RecordID"), Key ] + String RecordID; + + [ Override("MessageTimestamp"), Key ] + datetime MessageTimestamp; + + String HostName; + + [ Override("DataFormat") ] + String DataFormat; +}; + +[ Version("0.2.0"), Provider("cmpi:cmpiLMI_Journald"), + Association ] +class LMI_JournalRecordInLog: CIM_RecordInLog +{ + [ Override("MessageLog"), Key ] + LMI_JournalMessageLog REF MessageLog; + + [ Override("LogRecord"), Key ] + LMI_JournalLogRecord REF LogRecord; +}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 589c845..5101e76 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,3 +55,7 @@ endif (WITH-INDMANAGER) if (WITH-SOFTWARE) add_subdirectory(software) endif (WITH-SOFTWARE) + +if (WITH-JOURNALD) + add_subdirectory(journald) +endif (WITH-JOURNALD) diff --git a/src/journald/90_LMI_Journald_Profile.mof.skel b/src/journald/90_LMI_Journald_Profile.mof.skel new file mode 100644 index 0000000..7c1fb68 --- /dev/null +++ b/src/journald/90_LMI_Journald_Profile.mof.skel @@ -0,0 +1,21 @@ +instance of PG_ProviderProfileCapabilities +{ + CapabilityID = "@CLASS@"; + + ProviderModuleName = "cmpiLMI_Journald"; + + ProviderName = "@CLASS@"; + + RegisteredProfile = 0; + + OtherRegisteredProfile = "OpenLMI-Journald"; + OtherProfileOrganization = "OpenLMI"; + + ProfileVersion = "@VERSION@"; + + RegisteredSubProfiles = { }; + + ConformingElements = { + "@CLASS@" + }; +}; diff --git a/src/journald/CMakeLists.txt b/src/journald/CMakeLists.txt new file mode 100644 index 0000000..7a4de06 --- /dev/null +++ b/src/journald/CMakeLists.txt @@ -0,0 +1,55 @@ +pkg_check_modules(GLIB2 glib-2.0 REQUIRED) +pkg_check_modules(SYSTEMD-JOURNAL libsystemd-journal REQUIRED) + +set(PROVIDER_NAME Journald) +set(LIBRARY_NAME cmpiLMI_${PROVIDER_NAME}) +set(MOF 60_LMI_Journald.mof) +set(CIMPROVAGT_SCRIPT cmpiLMI_${PROVIDER_NAME}-cimprovagt) + +set(provider_SRCS + instutil.c +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + +konkretcmpi_generate(${MOF} + CIM_PROVIDERS + CIM_HEADERS + CIM_CLASSES +) + +add_library(${LIBRARY_NAME} SHARED + ${provider_SRCS} + ${CIM_PROVIDERS} + ${CIM_HEADERS} +) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} + ${CMPI_INCLUDE_DIR} + ${GLIB2_INCLUDE_DIRS} + ${SYSTEMD-JOURNAL_INCLUDE_DIRS} + ) + +target_link_libraries(${LIBRARY_NAME} + openlmicommon + ${KONKRETCMPI_LIBRARIES} + ${GLIB2_LIBRARIES} + ${SYSTEMD-JOURNAL_LIBRARIES} + ) + +set(CIM_PROVIDERS_CLASSES "") +foreach(CIM_CLASS ${CIM_CLASSES}) + if(NOT ${CIM_CLASS} MATCHES "Indication") + set(CIM_PROVIDERS_CLASSES ${CIM_PROVIDERS_CLASSES} ${CIM_CLASS}) + endif(NOT ${CIM_CLASS} MATCHES "Indication") +endforeach(CIM_CLASS ${CIM_CLASSES}) + +set(TARGET_MOF "${CMAKE_BINARY_DIR}/mof/90_LMI_Journald_Profile.mof") +profile_mof_generate("90_LMI_Journald_Profile.mof.skel" "${TARGET_MOF}" "${CIM_PROVIDERS_CLASSES}") + +# Create registration file +cim_registration(${PROVIDER_NAME} ${LIBRARY_NAME} ${MOF} share/openlmi-providers) + +install(TARGETS ${LIBRARY_NAME} DESTINATION lib${LIB_SUFFIX}/cmpi/) +install(PROGRAMS ${CIMPROVAGT_SCRIPT} DESTINATION libexec/pegasus) +install(FILES ${TARGET_MOF} DESTINATION share/openlmi-providers/) diff --git a/src/journald/LMI_JournalLogRecordProvider.c b/src/journald/LMI_JournalLogRecordProvider.c new file mode 100644 index 0000000..812b4d2 --- /dev/null +++ b/src/journald/LMI_JournalLogRecordProvider.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +#include <konkret/konkret.h> +#include <cmpi/cmpimacs.h> +#include "LMI_JournalLogRecord.h" + +#include <errno.h> +#include <glib.h> +#include <systemd/sd-journal.h> + +#include "globals.h" +#include "journal.h" +#include "instutil.h" + + +static const CMPIBroker* _cb = NULL; +static sd_journal *journal_iter = NULL; + +static void LMI_JournalLogRecordInitialize() +{ + sd_journal *journal; + int r; + + r = sd_journal_open(&journal, 0); + if (r < 0) { + fprintf(stderr, "Error opening journal: %s\n", strerror(-r)); + return; + } + journal_iter = journal; +} + +static CMPIStatus LMI_JournalLogRecordCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + if (journal_iter != NULL) { + sd_journal_close(journal_iter); + journal_iter = NULL; + } + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalLogRecordEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + const char *ns = KNameSpace(cop); + sd_journal *journal; + int r; + LMI_JournalLogRecordRef log_record_ref; + unsigned long count = 0; + + /* Open our own journal instance to prevent losing cursor position in the global instance */ + r = sd_journal_open(&journal, 0); + if (r < 0) + KReturn2(_cb, ERR_FAILED, "Error opening journal: %s\n", strerror(-r)); + + r = sd_journal_seek_tail(journal); + if (r < 0) { + sd_journal_close(journal); + KReturn2(_cb, ERR_NOT_FOUND, "Failed to seek to the end of the journal: %s\n", strerror(-r)); + } + + SD_JOURNAL_FOREACH_BACKWARDS(journal) { + LMI_JournalLogRecordRef_Init(&log_record_ref, _cb, ns); + if (!create_LMI_JournalLogRecordRef(journal, &log_record_ref, _cb)) + continue; + + /* FYI: not testing ability to actually retrieve data, assuming further failures in subsequent calls */ + + KReturnObjectPath(cr, log_record_ref); + + /* Instance number limiter */ + count++; + if (JOURNAL_MAX_INSTANCES_NUM > 0 && count > JOURNAL_MAX_INSTANCES_NUM) + break; + } + sd_journal_close(journal); + + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalLogRecordEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus st; + CMPIEnumeration *e; + CMPIData cd; + CMPIInstance *in; + + if (!(e = _cb->bft->enumerateInstanceNames(_cb, cc, cop, &st))) + KReturn2(_cb, ERR_FAILED, "Unable to enumerate instances of LMI_JournalLogRecord"); + + while (CMHasNext(e, &st)) { + cd = CMGetNext(e, &st); + if (st.rc || cd.type != CMPI_ref) + KReturn2(_cb, ERR_FAILED, "Enumerate instances didn't returned list of references"); + in = _cb->bft->getInstance(_cb, cc, cd.value.ref, properties, &st); + if (st.rc) + KReturn2(_cb, ERR_FAILED, "Unable to get instance of LMI_JournalLogRecord"); + cr->ft->returnInstance(cr, in); + } + KReturn(OK); +} + +static CMPIStatus LMI_JournalLogRecordGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + LMI_JournalLogRecord log_record; + int r; + + LMI_JournalLogRecord_InitFromObjectPath(&log_record, _cb, cop); + + if (journal_iter == NULL) + KReturn2(_cb, ERR_FAILED, "Journal not open, possible failure during initialization\n"); + + r = sd_journal_seek_cursor(journal_iter, log_record.RecordID.chars); + if (r < 0) + KReturn2(_cb, ERR_NOT_FOUND, "Failed to seek to the requested position: %s\n", strerror(-r)); + + r = sd_journal_next(journal_iter); + if (r < 0) + KReturn2(_cb, ERR_FAILED, "Failed to seek next to the cursor: %s\n", strerror(-r)); + + r = create_LMI_JournalLogRecord(journal_iter, &log_record, _cb); + if (r <= 0) + KReturn2(_cb, ERR_FAILED, "Failed to create instance: %s\n", strerror(-r)); + + KReturnInstance(cr, log_record); + KReturn(OK); +} + +static CMPIStatus LMI_JournalLogRecordCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalLogRecordModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char** properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalLogRecordDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalLogRecordExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +CMInstanceMIStub( + LMI_JournalLogRecord, + LMI_JournalLogRecord, + _cb, + LMI_JournalLogRecordInitialize()) + +static CMPIStatus LMI_JournalLogRecordMethodCleanup( + CMPIMethodMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalLogRecordInvokeMethod( + CMPIMethodMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* meth, + const CMPIArgs* in, + CMPIArgs* out) +{ + return LMI_JournalLogRecord_DispatchMethod( + _cb, mi, cc, cr, cop, meth, in, out); +} + +CMMethodMIStub( + LMI_JournalLogRecord, + LMI_JournalLogRecord, + _cb, + LMI_JournalLogRecordInitialize()) + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_JournalLogRecord", + "LMI_JournalLogRecord", + "instance method") diff --git a/src/journald/LMI_JournalMessageLogProvider.c b/src/journald/LMI_JournalMessageLogProvider.c new file mode 100644 index 0000000..1a1ab02 --- /dev/null +++ b/src/journald/LMI_JournalMessageLogProvider.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +#include <konkret/konkret.h> +#include "LMI_JournalMessageLog.h" + +#include <systemd/sd-journal.h> + +#include "globals.h" +#include "journal.h" + + +static const CMPIBroker* _cb = NULL; + +static void LMI_JournalMessageLogInitialize() +{ +} + +static CMPIStatus LMI_JournalMessageLogCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalMessageLogEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_JournalMessageLogEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + LMI_JournalMessageLog message_log; + const char *ns = KNameSpace(cop); + sd_journal *journal; + int caps = 0; + uint64_t usec; + CMPIDateTime *date; + + /* TODO: split into several instances by open flags? */ + if (sd_journal_open(&journal, 0) >= 0) { + LMI_JournalMessageLog_Init(&message_log, _cb, ns); + LMI_JournalMessageLog_Set_CreationClassName(&message_log, LMI_JournalMessageLog_ClassName); + LMI_JournalMessageLog_Set_Name(&message_log, JOURNAL_MESSAGE_LOG_NAME); + + LMI_JournalMessageLog_Init_Capabilities(&message_log, 4); + LMI_JournalMessageLog_Set_Capabilities_Can_Move_Backward_in_Log(&message_log, caps++); + LMI_JournalMessageLog_Set_Capabilities_Variable_Formats_for_Records(&message_log, caps++); + LMI_JournalMessageLog_Set_Capabilities_Variable_Length_Records_Supported(&message_log, caps++); + LMI_JournalMessageLog_Set_Capabilities_Write_Record_Supported(&message_log, caps++); + + /* Optional: Time of last change */ + if (sd_journal_seek_tail(journal) >= 0 && + sd_journal_previous(journal) >= 0 && + sd_journal_get_realtime_usec(journal, &usec) >= 0) { + date = CMNewDateTimeFromBinary(_cb, usec, 0, NULL); + LMI_JournalMessageLog_Set_TimeOfLastChange(&message_log, date); + } + + sd_journal_close(journal); + KReturnInstance(cr, message_log); + } + + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalMessageLogGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_JournalMessageLogCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalMessageLogModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char** properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalMessageLogDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalMessageLogExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +CMInstanceMIStub( + LMI_JournalMessageLog, + LMI_JournalMessageLog, + _cb, + LMI_JournalMessageLogInitialize()) + +static CMPIStatus LMI_JournalMessageLogMethodCleanup( + CMPIMethodMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalMessageLogInvokeMethod( + CMPIMethodMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* meth, + const CMPIArgs* in, + CMPIArgs* out) +{ + return LMI_JournalMessageLog_DispatchMethod( + _cb, mi, cc, cr, cop, meth, in, out); +} + +CMMethodMIStub( + LMI_JournalMessageLog, + LMI_JournalMessageLog, + _cb, + LMI_JournalMessageLogInitialize()) + +KUint32 LMI_JournalMessageLog_RequestStateChange( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + const KUint16* RequestedState, + KRef* Job, + const KDateTime* TimeoutPeriod, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_ClearLog( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_PositionToFirstRecord( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + KString* IterationIdentifier, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_PositionAtRecord( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + KString* IterationIdentifier, + const KBoolean* MoveAbsolute, + KSint64* RecordNumber, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_GetRecord( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + KString* IterationIdentifier, + const KBoolean* PositionToNext, + KUint64* RecordNumber, + KUint8A* RecordData, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_DeleteRecord( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + KString* IterationIdentifier, + const KBoolean* PositionToNext, + KUint64* RecordNumber, + KUint8A* RecordData, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_WriteRecord( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + KString* IterationIdentifier, + const KBoolean* PositionToNext, + const KUint8A* RecordData, + KUint64* RecordNumber, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_CancelIteration( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + const KString* IterationIdentifier, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_FreezeLog( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + const KBoolean* Freeze, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_JournalMessageLog_FlagRecordForOverwrite( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_JournalMessageLogRef* self, + KString* IterationIdentifier, + const KBoolean* PositionToNext, + KUint64* RecordNumber, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_JournalMessageLog", + "LMI_JournalMessageLog", + "instance method") diff --git a/src/journald/LMI_JournalRecordInLogProvider.c b/src/journald/LMI_JournalRecordInLogProvider.c new file mode 100644 index 0000000..2e5241f --- /dev/null +++ b/src/journald/LMI_JournalRecordInLogProvider.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +#include <konkret/konkret.h> +#include "LMI_JournalRecordInLog.h" + +#include <systemd/sd-journal.h> + +#include "globals.h" +#include "journal.h" +#include "instutil.h" + +static const CMPIBroker* _cb; + +static void LMI_JournalRecordInLogInitialize() +{ +} + +static CMPIStatus LMI_JournalRecordInLogCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalRecordInLogEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_JournalRecordInLogEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + LMI_JournalRecordInLog record_in_log; + LMI_JournalMessageLogRef message_log_ref; + CMPIObjectPath *message_log_ref_op; + LMI_JournalLogRecordRef log_record_ref; + const char *ns = KNameSpace(cop); + sd_journal *journal; + int r; + CMPIStatus rc; + unsigned long count = 0; + + LMI_JournalMessageLogRef_Init(&message_log_ref, _cb, ns); + LMI_JournalMessageLogRef_Set_CreationClassName(&message_log_ref, LMI_JournalMessageLog_ClassName); + LMI_JournalMessageLogRef_Set_Name(&message_log_ref, JOURNAL_MESSAGE_LOG_NAME); + + message_log_ref_op = LMI_JournalMessageLogRef_ToObjectPath(&message_log_ref, &rc); + message_log_ref_op->ft->setClassName(message_log_ref_op, JOURNAL_MESSAGE_LOG_NAME); + + r = sd_journal_open(&journal, 0); + if (r < 0) + KReturn2(_cb, ERR_FAILED, "Error opening journal: %s\n", strerror(-r)); + + r = sd_journal_seek_tail(journal); + if (r < 0) { + sd_journal_close(journal); + KReturn2(_cb, ERR_NOT_FOUND, "Failed to seek to the end of the journal: %s\n", strerror(-r)); + } + + SD_JOURNAL_FOREACH_BACKWARDS(journal) { + LMI_JournalLogRecordRef_Init(&log_record_ref, _cb, ns); + if (!create_LMI_JournalLogRecordRef(journal, &log_record_ref, _cb)) + continue; + + LMI_JournalRecordInLog_Init(&record_in_log, _cb, ns); + LMI_JournalRecordInLog_SetObjectPath_MessageLog(&record_in_log, message_log_ref_op); + LMI_JournalRecordInLog_Set_LogRecord(&record_in_log, &log_record_ref); + + KReturnInstance(cr, record_in_log); + + /* Instance number limiter */ + count++; + if (JOURNAL_MAX_INSTANCES_NUM > 0 && count > JOURNAL_MAX_INSTANCES_NUM) + break; + } + sd_journal_close(journal); + + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalRecordInLogGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_JournalRecordInLogCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalRecordInLogModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char**properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalRecordInLogDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalRecordInLogExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_JournalRecordInLogAssociationCleanup( + CMPIAssociationMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_JournalRecordInLogAssociators( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* resultClass, + const char* role, + const char* resultRole, + const char** properties) +{ + return KDefaultAssociators( + _cb, + mi, + cc, + cr, + cop, + LMI_JournalRecordInLog_ClassName, + assocClass, + resultClass, + role, + resultRole, + properties); +} + +static CMPIStatus LMI_JournalRecordInLogAssociatorNames( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* resultClass, + const char* role, + const char* resultRole) +{ + return KDefaultAssociatorNames( + _cb, + mi, + cc, + cr, + cop, + LMI_JournalRecordInLog_ClassName, + assocClass, + resultClass, + role, + resultRole); +} + +static CMPIStatus LMI_JournalRecordInLogReferences( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* role, + const char** properties) +{ + return KDefaultReferences( + _cb, + mi, + cc, + cr, + cop, + LMI_JournalRecordInLog_ClassName, + assocClass, + role, + properties); +} + +static CMPIStatus LMI_JournalRecordInLogReferenceNames( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* role) +{ + return KDefaultReferenceNames( + _cb, + mi, + cc, + cr, + cop, + LMI_JournalRecordInLog_ClassName, + assocClass, + role); +} + +CMInstanceMIStub( + LMI_JournalRecordInLog, + LMI_JournalRecordInLog, + _cb, + LMI_JournalRecordInLogInitialize()) + +CMAssociationMIStub( + LMI_JournalRecordInLog, + LMI_JournalRecordInLog, + _cb, + LMI_JournalRecordInLogInitialize()) + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_JournalRecordInLog", + "LMI_JournalRecordInLog", + "instance association") diff --git a/src/journald/README b/src/journald/README new file mode 100644 index 0000000..0480766 --- /dev/null +++ b/src/journald/README @@ -0,0 +1,26 @@ += Description = + +The LMI_Journald provider exposes data stored in SystemD Journal service. See +http://www.freedesktop.org/wiki/Software/systemd/ for more information. + +For the moment, global journal is used, all journal files are mixed together. +This may change in the future. + +The CIM classes have been selected to be consistent with those used by +sblim-cmpi-syslog, for easy integration with existing tools. I haven't been able +to find a profile for CIM_LogRecord and CIM_MessageLog classes though. + +There's a related DMTF profile DSP1010 "Record Log Profile" which may be subject +to extension of this provider. + + +== Limiting number of instances enumerated == + +Testing the provider showed up an issue with enumeration of LMI_JournalLogRecord +instances. On the testing machine there was 199583 journal records, which is simply +too much for the CIMOM, exceeding limits of memory and resulting reply. + +An artificial limit has been set, currently to 1000 last records. This limit is +set by the JOURNAL_MAX_INSTANCES_NUM define in Journal.h source file. A solution +is being searched on how to deal with this issue in a nice way. For now take it +as a tail of the log. diff --git a/src/journald/cmpiLMI_Journald-cimprovagt b/src/journald/cmpiLMI_Journald-cimprovagt new file mode 100755 index 0000000..368c5b8 --- /dev/null +++ b/src/journald/cmpiLMI_Journald-cimprovagt @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Copyright (C) 2013 Red Hat, Inc. All rights reserved. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Authors: Tomas Bzatek <tbzatek@redhat.com> + +/usr/libexec/pegasus/cimprovagt "$@" diff --git a/src/journald/instutil.c b/src/journald/instutil.c new file mode 100644 index 0000000..2164aa9 --- /dev/null +++ b/src/journald/instutil.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +#include <errno.h> +#include <glib.h> + +#include "instutil.h" +#include "globals.h" +#include "journal.h" + +#include "LMI_JournalLogRecord.h" +#include "LMI_JournalMessageLog.h" + + +int create_LMI_JournalLogRecordRef(sd_journal *j, + LMI_JournalLogRecordRef *ref, + const CMPIBroker *_cb) +{ + char *cursor; + uint64_t usec; + CMPIDateTime *date; + + LMI_JournalLogRecordRef_Set_CreationClassName(ref, LMI_JournalLogRecord_ClassName); + LMI_JournalLogRecordRef_Set_LogCreationClassName(ref, LMI_JournalMessageLog_ClassName); + LMI_JournalLogRecordRef_Set_LogName(ref, JOURNAL_MESSAGE_LOG_NAME); + + /* Get stable cursor string */ + if (sd_journal_get_cursor(j, &cursor) < 0) + return 0; + LMI_JournalLogRecordRef_Set_RecordID(ref, cursor); + free(cursor); + + /* Get timestamp */ + if (sd_journal_get_realtime_usec(j, &usec) < 0) + return 0; + date = CMNewDateTimeFromBinary(_cb, usec, 0, NULL); + LMI_JournalLogRecordRef_Set_MessageTimestamp(ref, date); + + return 1; +} + +static int dup_journal_data( + sd_journal *j, + const char *key, + gchar **out) +{ + const char *d; + size_t l; + int r; + + *out = NULL; + r = sd_journal_get_data(j, key, (const void **) &d, &l); + if (r < 0) + return r; + if (l < strlen(key) + 1) + return -EBADMSG; + + *out = g_strndup(d + strlen(key) + 1, l - strlen(key) - 1); + if (*out == NULL) + return -EBADMSG; + + return 0; +} + +int create_LMI_JournalLogRecord(sd_journal *j, + LMI_JournalLogRecord *rec, + const CMPIBroker *_cb) +{ + int r; + uint64_t usec; + CMPIDateTime *date; + gchar *d; + + /* Set message */ + r = dup_journal_data(j, "MESSAGE", &d); + if (r < 0) + return r; + LMI_JournalLogRecord_Set_DataFormat(rec, d); + g_free(d); + + /* Set timestamp */ + r = sd_journal_get_realtime_usec(j, &usec); + if (r < 0) + return r; + date = CMNewDateTimeFromBinary(_cb, usec, 0, NULL); + LMI_JournalLogRecord_Set_MessageTimestamp(rec, date); + + /* Optional: hostname */ + r = dup_journal_data(j, "_HOSTNAME", &d); + if (r >= 0 && d != NULL && strlen(d) > 0) { + LMI_JournalLogRecord_Set_HostName(rec, d); + g_free(d); + } + + return 1; +} diff --git a/src/journald/instutil.h b/src/journald/instutil.h new file mode 100644 index 0000000..ef02aa1 --- /dev/null +++ b/src/journald/instutil.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +#ifndef INSTUTIL_H_ +#define INSTUTIL_H_ + +#include <systemd/sd-journal.h> + +#include "LMI_JournalLogRecord.h" + +int create_LMI_JournalLogRecordRef(sd_journal *j, LMI_JournalLogRecordRef *ref, const CMPIBroker *_cb); +int create_LMI_JournalLogRecord(sd_journal *j, LMI_JournalLogRecord *rec, const CMPIBroker *_cb); + +#endif /* INSTUTIL_H_ */ diff --git a/src/journald/journal.h b/src/journald/journal.h new file mode 100644 index 0000000..6f999ec --- /dev/null +++ b/src/journald/journal.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Tomas Bzatek <tbzatek@redhat.com> + */ + +#ifndef JOURNAL_H_ +#define JOURNAL_H_ + + +#define JOURNAL_MESSAGE_LOG_NAME "Journal" + + +/* Limit the number of LMI_JournalLogRecord instances enumerated */ + +/* Typical system carries hundreds of thousands of records making stress + * on the CIMOM itself and tools processing the XML reply. Accidental + * instance enumeration can lead to denial-of-service in extreme cases, + * so let's limit the total number of instances for now. */ +#define JOURNAL_MAX_INSTANCES_NUM 1000 /* Set to 0 to disable this feature */ + + +#endif /* JOURNAL_H_ */ |