diff --git a/components/compat/Makefile.am b/components/compat/Makefile.am index 70638ce99..a974fae35 100644 --- a/components/compat/Makefile.am +++ b/components/compat/Makefile.am @@ -10,6 +10,8 @@ EXTRA_DIST = \ $(top_builddir)/tools/mkembedconfig $< $@ libcompat_la_SOURCES = \ + checkresultreader.cpp \ + checkresultreader.h \ compatcomponent.cpp \ compatcomponent.h \ compatlog.cpp \ diff --git a/components/compat/checkresultreader.cpp b/components/compat/checkresultreader.cpp new file mode 100644 index 000000000..3e580cf8a --- /dev/null +++ b/components/compat/checkresultreader.cpp @@ -0,0 +1,150 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "compat/checkresultreader.h" +#include "icinga/service.h" +#include "icinga/pluginchecktask.h" +#include "base/dynamictype.h" +#include "base/objectlock.h" +#include "base/logger_fwd.h" +#include "base/convert.h" +#include "base/application.h" +#include +#include + +using namespace icinga; + +REGISTER_TYPE(CheckResultReader); + +CheckResultReader::CheckResultReader(const Dictionary::Ptr& properties) + : DynamicObject(properties) +{ + RegisterAttribute("spool_dir", Attribute_Config, &m_SpoolDir); +} + +/** + * @threadsafety Always. + */ +void CheckResultReader::Start(void) +{ + m_ReadTimer = boost::make_shared(); + m_ReadTimer->OnTimerExpired.connect(boost::bind(&CheckResultReader::ReadTimerHandler, this)); + m_ReadTimer->SetInterval(5); + m_ReadTimer->Start(); +} + +/** + * @threadsafety Always. + */ +CheckResultReader::Ptr CheckResultReader::GetByName(const String& name) +{ + DynamicObject::Ptr configObject = DynamicObject::GetObject("CheckResultReader", name); + + return dynamic_pointer_cast(configObject); +} + +/** + * @threadsafety Always. + */ +String CheckResultReader::GetSpoolDir(void) const +{ + if (!m_SpoolDir.IsEmpty()) + return m_SpoolDir; + else + return Application::GetLocalStateDir() + "/lib/icinga2/spool/checkresults/"; +} + +/** + * @threadsafety Always. + */ +void CheckResultReader::ReadTimerHandler(void) const +{ + Utility::Glob(GetSpoolDir() + "/c??????.ok", boost::bind(&CheckResultReader::ProcessCheckResultFile, this, _1)); +} + +void CheckResultReader::ProcessCheckResultFile(const String& path) const +{ + String crfile = String(path.Begin(), path.End() - 3); /* Remove the ".ok" extension. */ + + std::ifstream fp; + fp.exceptions(std::ifstream::badbit); + fp.open(crfile.CStr()); + + std::map attrs; + + while (fp.good()) { + std::string line; + std::getline(fp, line); + + if (line.empty() || line[0] == '#') + continue; /* Ignore comments and empty lines. */ + + int pos = line.find_first_of('='); + + if (pos == std::string::npos) + continue; /* Ignore invalid lines. */ + + String key = line.substr(0, pos); + String value = line.substr(pos + 1); + + attrs[key] = value; + } + + /* Remove the checkresult files. */ + (void)unlink(path.CStr()); + (void)unlink(crfile.CStr()); + + Host::Ptr host = Host::GetByName(attrs["host_name"]); + + if (!host) { + Log(LogWarning, "compat", "Ignoring checkresult file for host '" + attrs["host_name"] + + "': Host does not exist."); + + return; + } + + Service::Ptr service = host->GetServiceByShortName(attrs["service_description"]); + + if (!service) { + Log(LogWarning, "compat", "Ignoring checkresult file for host '" + attrs["host_name"] + + "', service '" + attrs["service_description"] + "': Service does not exist."); + + return; + } + + Dictionary::Ptr result = PluginCheckTask::ParseCheckOutput(attrs["output"]); + result->Set("state", PluginCheckTask::ExitStatusToState(Convert::ToLong(attrs["return_code"]))); + result->Set("execution_start", Convert::ToDouble(attrs["start_time"])); + result->Set("execution_end", Convert::ToDouble(attrs["finish_time"])); + result->Set("active", 1); + + service->ProcessCheckResult(result); + + Log(LogDebug, "compat", "Processed checkresult file for host '" + attrs["host_name"] + + "', service '" + attrs["service_description"] + "'"); + + { + ObjectLock olock(service); + + /* Reschedule the next check. The side effect of this is that for as long + * as we receive check result files for a service we won't execute any + * active checks. */ + service->SetNextCheck(Utility::GetTime() + service->GetCheckInterval()); + } +} diff --git a/components/compat/checkresultreader.h b/components/compat/checkresultreader.h new file mode 100644 index 000000000..2b6695f6d --- /dev/null +++ b/components/compat/checkresultreader.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef CHECKRESULTREADER_H +#define CHECKRESULTREADER_H + +#include "remoting/endpoint.h" +#include "base/dynamicobject.h" +#include "base/timer.h" +#include + +namespace icinga +{ + +/** + * An Icinga checkresult reader. + * + * @ingroup compat + */ +class CheckResultReader : public DynamicObject +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + CheckResultReader(const Dictionary::Ptr& properties); + + static CheckResultReader::Ptr GetByName(const String& name); + + String GetSpoolDir(void) const; + +protected: + virtual void Start(void); + +private: + Attribute m_SpoolDir; + + Timer::Ptr m_ReadTimer; + void ReadTimerHandler(void) const; + void ProcessCheckResultFile(const String& path) const; +}; + +} + +#endif /* CHECKRESULTREADER_H */ diff --git a/components/compat/compat-type.conf b/components/compat/compat-type.conf index cbffdac5d..83e56f4f5 100644 --- a/components/compat/compat-type.conf +++ b/components/compat/compat-type.conf @@ -27,3 +27,7 @@ type CompatLog { %attribute string "path_prefix", %attribute number "rotation_interval" } + +type CheckResultReader { + %attribute string "spool_dir" +} diff --git a/components/compat/compatlog.h b/components/compat/compatlog.h index db2310f4d..5ac710484 100644 --- a/components/compat/compatlog.h +++ b/components/compat/compatlog.h @@ -20,7 +20,6 @@ #ifndef COMPATLOG_H #define COMPATLOG_H -#include "icinga/i2-icinga.h" #include "remoting/endpoint.h" #include "base/dynamicobject.h" #include "base/timer.h" @@ -34,7 +33,7 @@ namespace icinga * * @ingroup compat */ -class I2_ICINGA_API CompatLog : public DynamicObject +class CompatLog : public DynamicObject { public: typedef shared_ptr Ptr; diff --git a/lib/icinga/service-check.cpp b/lib/icinga/service-check.cpp index 64603cef8..0e0b444bf 100644 --- a/lib/icinga/service-check.cpp +++ b/lib/icinga/service-check.cpp @@ -409,6 +409,20 @@ void Service::SetForceNextCheck(bool forced) */ void Service::ProcessCheckResult(const Dictionary::Ptr& cr) { + double now = Utility::GetTime(); + + if (!cr->Contains("schedule_start")) + cr->Set("schedule_start", now); + + if (!cr->Contains("schedule_end")) + cr->Set("schedule_end", now); + + if (!cr->Contains("execution_start")) + cr->Set("execution_start", now); + + if (!cr->Contains("execution_end")) + cr->Set("execution_end", now); + bool reachable = IsReachable(); Host::Ptr host = GetHost(); @@ -467,8 +481,6 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr) int state = cr->Get("state"); SetState(static_cast(state)); - double now = Utility::GetTime(); - if (old_state != GetState()) { SetLastStateChange(now); diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index 1b14e8860..fe1590a71 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -475,7 +475,7 @@ Dictionary::Ptr Service::CalculateDynamicMacros(const Dictionary::Ptr& crOverrid macros->Set("SERVICEOUTPUT", cr->Get("output")); macros->Set("SERVICEPERFDATA", cr->Get("performance_data_raw")); - macros->Set("LASTSERVICECHECK", (long)cr->Get("schedule_start")); + macros->Set("LASTSERVICECHECK", (long)cr->Get("execution_end")); } macros->Seal();