using namespace icinga;
-EXPORT_COMPONENT(checker, CheckerComponent);
+REGISTER_COMPONENT("checker", CheckerComponent);
void CheckerComponent::Start(void)
{
void CheckerComponent::CheckThreadProc(void)
{
- for (;;) {
- vector<Service::Ptr> services;
- Service::Ptr service;
-
- boost::mutex::scoped_lock lock(m_Mutex);
+ boost::mutex::scoped_lock lock(m_Mutex);
+ for (;;) {
typedef nth_index<ServiceSet, 1>::type CheckTimeView;
CheckTimeView& idx = boost::get<1>(m_IdleServices);
break;
CheckTimeView::iterator it = idx.begin();
- service = it->lock();
+ Service::Ptr service = it->lock();
if (!service) {
idx.erase(it);
m_IdleServices.erase(service);
m_PendingServices.insert(service);
- double rwait = service->GetNextCheck() - Utility::GetTime();
-
- if (rwait < -5)
- Logger::Write(LogWarning, "checker", "Check delayed: " + Convert::ToString(-rwait));
-
try {
- service->BeginExecuteCheck(boost::bind(&CheckerComponent::CheckCompletedHandler, this, service));
+ olock.Unlock();
+ Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, this, service));
} catch (const exception& ex) {
+ olock.Lock();
Logger::Write(LogCritical, "checker", "Exception occured while checking service '" + service->GetName() + "': " + diagnostic_information(ex));
}
}
}
-
void CheckerComponent::CheckCompletedHandler(const Service::Ptr& service)
{
boost::mutex::scoped_lock lock(m_Mutex);
idx.insert(service);
m_CV.notify_all();
}
-
using namespace icinga;
-EXPORT_COMPONENT(compat, CompatComponent);
+REGISTER_COMPONENT("compat", CompatComponent);
/**
* Hint: The reason why we're using "\n" rather than std::endl is because
void CompatComponent::Start(void)
{
m_StatusTimer = boost::make_shared<Timer>();
- m_StatusTimer->SetInterval(60);
+ m_StatusTimer->SetInterval(15);
m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this));
m_StatusTimer->Start();
m_StatusTimer->Reschedule(0);
{
String output;
String perfdata;
- double schedule_start = -1, schedule_end = -1;
- double execution_start = -1, execution_end = -1;
+ double schedule_end = -1;
Dictionary::Ptr cr;
- int state;
+ int state, state_type;
Host::Ptr host;
{
cr = service->GetLastCheckResult();
state = service->GetState();
+ state_type = service->GetStateType();
host = service->GetHost();
}
if (cr) {
output = cr->Get("output");
- schedule_start = cr->Get("schedule_start");
schedule_end = cr->Get("schedule_end");
- execution_start = cr->Get("execution_start");
- execution_end = cr->Get("execution_end");
perfdata = cr->Get("performance_data_raw");
}
- double execution_time = (execution_end - execution_start);
- double latency = (schedule_end - schedule_start) - execution_time;
-
if (state > StateUnknown)
state = StateUnknown;
<< "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n"
<< "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n"
<< "\t" << "should_be_scheduled=1" << "\n"
- << "\t" << "check_execution_time=" << execution_time << "\n"
- << "\t" << "check_latency=" << latency << "\n"
+ << "\t" << "check_execution_time=" << Service::CalculateExecutionTime(cr) << "\n"
+ << "\t" << "check_latency=" << Service::CalculateLatency(cr) << "\n"
<< "\t" << "current_state=" << state << "\n"
- << "\t" << "state_type=" << service->GetStateType() << "\n"
+ << "\t" << "state_type=" << state_type << "\n"
<< "\t" << "plugin_output=" << output << "\n"
<< "\t" << "performance_data=" << perfdata << "\n"
<< "\t" << "last_check=" << schedule_end << "\n"
<< "\t" << "passive_host_checks_enabled=0" << "\n"
<< "\t" << "check_service_freshness=0" << "\n"
<< "\t" << "check_host_freshness=0" << "\n"
- << "\t" << "enable_flap_detection=1" << "\n"
+ << "\t" << "enable_notifications=1" << "\n"
+ << "\t" << "enable_flap_detection=0" << "\n"
<< "\t" << "enable_failure_prediction=0" << "\n"
<< "\t" << "active_scheduled_service_check_stats=" << CIB::GetActiveChecksStatistics(60) << "," << CIB::GetActiveChecksStatistics(5 * 60) << "," << CIB::GetActiveChecksStatistics(15 * 60) << "\n"
<< "\t" << "passive_service_check_stats=" << CIB::GetPassiveChecksStatistics(60) << "," << CIB::GetPassiveChecksStatistics(5 * 60) << "," << CIB::GetPassiveChecksStatistics(15 * 60) << "\n"
using namespace icinga;
-EXPORT_COMPONENT(compatido, CompatIdoComponent);
+REGISTER_COMPONENT("compatido", CompatIdoComponent);
const String CompatIdoComponent::DefaultSocketAddress = "127.0.0.1";
const String CompatIdoComponent::DefaultSocketPort = "5668";
using namespace icinga;
-EXPORT_COMPONENT(delegation, DelegationComponent);
+REGISTER_COMPONENT("delegation", DelegationComponent);
void DelegationComponent::Start(void)
{
using namespace icinga;
-EXPORT_COMPONENT(demo, DemoComponent);
+REGISTER_COMPONENT("demo", DemoComponent);
/**
* Starts the component.
using namespace icinga;
-EXPORT_COMPONENT(notification, NotificationComponent);
+REGISTER_COMPONENT("notification", NotificationComponent);
/**
* Starts the component.
using namespace icinga;
-EXPORT_COMPONENT(replication, ReplicationComponent);
+REGISTER_COMPONENT("replication", ReplicationComponent);
/**
* Starts the component.
Component::AddSearchDir(Application::GetPkgLibDir());
- Utility::LoadIcingaLibrary("icinga", false);
+ (void) Utility::LoadIcingaLibrary("icinga", false);
if (g_AppParams.count("library")) {
BOOST_FOREACH(const String& libraryName, g_AppParams["library"].as<vector<String> >()) {
netstring.h \
object.cpp \
object.h \
+ objectlock.cpp \
+ objectlock.h \
process.cpp \
process-unix.cpp \
process-windows.cpp \
void Application::ShutdownTimerHandler(void)
{
- if (m_ShuttingDown)
+ if (m_ShuttingDown) {
+ Application::GetInstance()->OnShutdown();
+ DynamicObject::DeactivateObjects();
GetEQ().Stop();
+ m_ShuttingDown = false;
+ }
}
/**
result = Main();
- DynamicObject::DeactivateObjects();
-
return result;
}
protected:
void RunEventLoop(void) const;
+ virtual void OnShutdown(void) = 0;
+
private:
static Application *m_Instance; /**< The application instance. */
void Start(const CompletionCallback& completionCallback = CompletionCallback())
{
m_CompletionCallback = completionCallback;
- Utility::QueueAsyncCallback(boost::bind(&AsyncTask<TClass, TResult>::Run, this));
+ Utility::QueueAsyncCallback(boost::bind(&AsyncTask<TClass, TResult>::RunInternal, this));
}
/**
Utility::QueueAsyncCallback(boost::bind(callback, GetSelf()));
}
+ /**
+ * Calls the Run() method and catches exceptions.
+ */
+ void RunInternal(void)
+ {
+ try {
+ Run();
+ } catch (const exception& ex) {
+ FinishException(boost::current_exception());
+ }
+ }
+
mutable boost::mutex m_Mutex;
boost::condition_variable m_CV;
CompletionCallback m_CompletionCallback; /**< The completion callback. */
REGISTER_TYPE(Component, NULL);
+map<String, Component::Factory> Component::m_Factories;
+
/**
* Constructor for the component class.
*/
if (!IsLocal())
BOOST_THROW_EXCEPTION(runtime_error("Component objects must be local."));
-#ifdef _WIN32
- HMODULE
-#else /* _WIN32 */
- lt_dlhandle
-#endif /* _WIN32 */
- hModule;
-
Logger::Write(LogInformation, "base", "Loading component '" + GetName() + "'");
- hModule = Utility::LoadIcingaLibrary(GetName(), true);
-
- CreateComponentFunction pCreateComponent;
-
-#ifdef _WIN32
- pCreateComponent = reinterpret_cast<CreateComponentFunction>(GetProcAddress(hModule,
- "CreateComponent"));
-#else /* _WIN32 */
-# ifdef __GNUC__
- /* suppress compiler warning for void * cast */
- __extension__
-# endif
- pCreateComponent = reinterpret_cast<CreateComponentFunction>(lt_dlsym(hModule,
- "CreateComponent"));
-#endif /* _WIN32 */
+ (void) Utility::LoadIcingaLibrary(GetName(), true);
- IComponent::Ptr impl;
+ map<String, Factory>::iterator it;
+ it = m_Factories.find(GetName());
- try {
- if (pCreateComponent == NULL)
- BOOST_THROW_EXCEPTION(runtime_error("Loadable module does not contain "
- "CreateComponent function"));
+ if (it == m_Factories.end())
+ BOOST_THROW_EXCEPTION(invalid_argument("Unknown component: " + GetName()));
- /* pCreateComponent returns a raw pointer which we must wrap in a shared_ptr */
- impl = IComponent::Ptr(pCreateComponent());
+ IComponent::Ptr impl = it->second();
- if (!impl)
- BOOST_THROW_EXCEPTION(runtime_error("CreateComponent function returned NULL."));
- } catch (...) {
-#ifdef _WIN32
- FreeLibrary(hModule);
-#else /* _WIN32 */
- lt_dlclose(hModule);
-#endif /* _WIN32 */
- throw;
- }
+ if (!impl)
+ BOOST_THROW_EXCEPTION(runtime_error("Component factory returned NULL."));
m_Impl = impl;
}
{
/* Nothing to do in the default implementation. */
}
+
+/**
+ * Registers a component factory.
+ */
+void Component::Register(const String& name, const Component::Factory& factory)
+{
+ m_Factories[name] = factory;
+}
typedef shared_ptr<Component> Ptr;
typedef weak_ptr<Component> WeakPtr;
+ typedef function<IComponent::Ptr (void)> Factory;
+
Component(const Dictionary::Ptr& properties);
~Component(void);
static void AddSearchDir(const String& componentDirectory);
+ static void Register(const String& name, const Factory& factory);
+
private:
IComponent::Ptr m_Impl; /**< The implementation object for this
component. */
-};
-typedef IComponent *(*CreateComponentFunction)(void);
-
-#ifdef _WIN32
-# define SYM_CREATECOMPONENT(component) CreateComponent
-#else /* _WIN32 */
-# define SYM_CREATECOMPONENT(component) component ## _LTX_CreateComponent
-#endif /* _WIN32 */
+ static map<String, Factory> m_Factories;
+};
/**
- * Implements the loader function for a component.
+ * Helper class for registering Component implementation classes.
*
- * @param component The name of the component.
- * @param klass The component class.
+ * @ingroup base
*/
-#define EXPORT_COMPONENT(component, klass) \
- extern "C" I2_EXPORT icinga::IComponent *SYM_CREATECOMPONENT(component)(void) \
- { \
- return new klass(); \
+class RegisterComponentHelper
+{
+public:
+ RegisterComponentHelper(const String& name, const Component::Factory& factory)
+ {
+ Component::Register(name, factory);
}
+};
+
+/**
+ * Factory function for IComponent-based classes.
+ *
+ * @ingroup base
+ */
+template<typename T>
+IComponent::Ptr ComponentFactory(void)
+{
+ return boost::make_shared<T>();
+}
+
+
+#define REGISTER_COMPONENT(name, klass) \
+ static RegisterComponentHelper g_RegisterSF_ ## type(name, ComponentFactory<klass>)
}
}
};
+/**
+ * Constructor for the Dictionary class.
+ */
+Dictionary::Dictionary(void)
+ : m_Sealed(false)
+{ }
+
/**
* Restrieves a value from a dictionary.
*
{
ObjectLock olock(this);
+ assert(!m_Sealed);
+
if (value.IsEmpty()) {
Remove(key);
return;
m_Data.erase(it);
}
+/**
+ * Marks the dictionary as read-only. Attempting to modify a sealed
+ * dictionary is an error.
+ */
+void Dictionary::Seal(void)
+{
+ m_Sealed = true;
+}
+
/**
* Makes a shallow copy of a dictionary.
*
*/
typedef map<String, Value>::iterator Iterator;
+ Dictionary(void);
+
Value Get(const char *key) const;
Value Get(const String& key) const;
void Set(const String& key, const Value& value);
String Add(const Value& value);
bool Contains(const String& key) const;
+ void Seal(void);
Iterator Begin(void);
Iterator End(void);
private:
map<String, Value> m_Data; /**< The data for the dictionary. */
+ bool m_Sealed; /**< Whether the dictionary is read-only. */
};
inline Dictionary::Iterator range_begin(Dictionary::Ptr x)
attrs->Set(it->first, attr);
}
+ attrs->Seal();
+
Dictionary::Ptr update = boost::make_shared<Dictionary>();
update->Set("attrs", attrs);
else if (attrs->GetLength() == 0)
return Dictionary::Ptr();
+ update->Seal();
+
return update;
}
* object to the list of modified objects later on if we can't
* do it here. */
- boost::mutex::scoped_lock lock(m_TransactionMutex);
- m_ModifiedObjects.insert(GetSelf());
+ DynamicObject::Ptr self = GetSelf();
+
+ {
+ boost::mutex::scoped_lock lock(m_TransactionMutex);
+ m_ModifiedObjects.insert(self);
+ }
}
/* Use insert() rather than [] so we don't overwrite
stringstream msgbuf;
msgbuf << "Restored " << restored << " objects";
- Logger::Write(LogDebug, "base", msgbuf.str());
+ Logger::Write(LogInformation, "base", msgbuf.str());
}
void DynamicObject::DeactivateObjects(void)
while (m_Events.empty() && !m_Stopped)
m_CV.wait(lock);
- if (m_Stopped)
+ if (m_Events.empty() && m_Stopped)
break;
events.swap(m_Events);
double et = Utility::GetTime();
- if (et - st > 1.0) {
+ if (et - st > 0.25) {
stringstream msgbuf;
msgbuf << "Event call took " << et - st << " seconds.";
Logger::Write(LogWarning, "base", msgbuf.str());
int pending = m_Events.size();
double now = Utility::GetTime();
if (pending > 1000 && now - m_LastReport > 5) {
- Logger::Write(LogWarning, "base", "More than 1000 pending events: " + Convert::ToString(pending));
+ Logger::Write(LogCritical, "base", "More than 1000 pending events: " + Convert::ToString(pending));
m_LastReport = now;
}
}
#include "qstring.h"
#include "utility.h"
#include "object.h"
+#include "objectlock.h"
#include "exception.h"
#include "eventqueue.h"
#include "value.h"
mutable recursive_mutex m_Mutex;
};
-/**
- * A scoped lock for Objects.
- */
-struct ObjectLock {
-public:
- ObjectLock(void)
- : m_Lock()
- { }
-
- ObjectLock(const Object::Ptr& object)
- : m_Lock()
- {
- if (object)
- m_Lock = recursive_mutex::scoped_lock(object->GetMutex());
- }
-
- ObjectLock(const Object *object)
- : m_Lock()
- {
- if (object)
- m_Lock = recursive_mutex::scoped_lock(object->GetMutex());
- }
-
- void Unlock(void)
- {
- m_Lock = recursive_mutex::scoped_lock();
- }
-
-private:
- recursive_mutex::scoped_lock m_Lock;
-};
-
/**
* Compares a weak pointer with a raw pointer.
*
using namespace icinga;
int Process::m_TaskFd;
+Timer::Ptr Process::m_StatusTimer;
extern char **environ;
void Process::Initialize(void)
if (pipe(fds) < 0)
BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
- /* Don't bother setting fds[1] to clo-exec as we'll only
+ /* Don't bother setting fds[0] to clo-exec as we'll only
* use it in the following dup() call. */
Utility::SetCloExec(fds[1]);
}
(void) close(fds[0]);
+
+ m_StatusTimer = boost::make_shared<Timer>();
+ m_StatusTimer->OnTimerExpired.connect(boost::bind(&Process::StatusTimerHandler));
+ m_StatusTimer->SetInterval(5);
+ m_StatusTimer->Start();
}
void Process::WorkerThreadProc(int taskFd)
return false;
}
+void Process::StatusTimerHandler(void)
+{
+ boost::mutex::scoped_lock lock(m_Mutex);
+ if (m_Tasks.size() > 50)
+ Logger::Write(LogCritical, "base", "More than 50 waiting Process tasks: " +
+ Convert::ToString(m_Tasks.size()));
+}
+
#endif /* _WIN32 */
boost::once_flag Process::m_ThreadOnce = BOOST_ONCE_INIT;
boost::mutex Process::m_Mutex;
deque<Process::Ptr> Process::m_Tasks;
-double Process::m_LastReport = 0;
Process::Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment)
: AsyncTask<Process, ProcessResult>(), m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment)
void Process::Run(void)
{
- int count;
-
{
boost::mutex::scoped_lock lock(m_Mutex);
m_Tasks.push_back(GetSelf());
- count = m_Tasks.size();
- }
-
- if (count > 50 && Utility::GetTime() - m_LastReport > 5) {
- Logger::Write(LogInformation, "base", "More than 50 pending Process tasks: " +
- Convert::ToString(count));
- m_LastReport = Utility::GetTime();
}
NotifyWorker();
virtual void Run(void);
static boost::mutex m_Mutex;
- static double m_LastReport;
static deque<Process::Ptr> m_Tasks;
#ifndef _WIN32
static int m_TaskFd;
+
+ static Timer::Ptr m_StatusTimer;
#endif /* _WIN32 */
static void NotifyWorker(void);
static void WorkerThreadProc(void);
#else /* _WIN32 */
static void WorkerThreadProc(int taskFd);
+
+ static void StatusTimerHandler(void);
#endif /* _WIN32 */
void InitTask(void);
return !IsEmpty() && (m_Value.type() == typeid(Object::Ptr));
}
+Value::operator double(void) const
+{
+ if (m_Value.type() != typeid(double)) {
+ return boost::lexical_cast<double>(m_Value);
+ } else {
+ return boost::get<double>(m_Value);
+ }
+}
+
+Value::operator String(void) const
+{
+ Object *object;
+ double integral, fractional;
+
+ switch (GetType()) {
+ case ValueEmpty:
+ return String();
+ case ValueNumber:
+ fractional = modf(boost::get<double>(m_Value), &integral);
+
+ if (fractional != 0)
+ return boost::lexical_cast<String>(m_Value);
+ else
+ return boost::lexical_cast<String>((long)integral);
+ case ValueString:
+ return boost::get<String>(m_Value);
+ case ValueObject:
+ object = boost::get<Object::Ptr>(m_Value).get();
+ return "Object of type '" + Utility::GetTypeName(typeid(*object)) + "'";
+ }
+}
+
/**
* Converts a JSON object into a variant.
*
m_Value = object;
}
- operator double(void) const
- {
- if (m_Value.type() != typeid(double)) {
- return boost::lexical_cast<double>(m_Value);
- } else {
- return boost::get<double>(m_Value);
- }
- }
-
- operator String(void) const
- {
- if (IsEmpty())
- return String();
-
- if (m_Value.type() != typeid(String)) {
- String result = boost::lexical_cast<String>(m_Value);
- m_Value = result;
- }
-
- return boost::get<String>(m_Value);
- }
+ operator double(void) const;
+ operator String(void) const;
template<typename T>
operator shared_ptr<T>(void) const
54, 49, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 54, 18, 19, 12, 3, 2, 55,
15, 15, 21, 0, 0, 0, 0, 0, 42, 52,
- 50, 48, 51, 16, 0, 53, 0, 45, 46, 47,
+ 50, 48, 51, 16, 20, 53, 0, 45, 46, 47,
0, 43, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 0, 18, 17, 12,
11, 4, 5, 9, 10, 6, 8, 7, 0, 0,
void yyset_lineno (int line_number ,yyscan_t yyscanner );
+int yyget_column (yyscan_t yyscanner );
+
+void yyset_column (int column_no ,yyscan_t yyscanner );
+
YYSTYPE * yyget_lval (yyscan_t yyscanner );
void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
lex_buf string_buf;
-#line 952 "config_lexer.cc"
+#line 956 "config_lexer.cc"
yylval = yylval_param;
#line 216 "config_lexer.ll"
ECHO;
YY_BREAK
-#line 1381 "config_lexer.cc"
+#line 1385 "config_lexer.cc"
case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(C_COMMENT):
case YY_STATE_EOF(STRING):
"*" /* ignore star */
}
-\/\/[^\n]+ /* ignore C++-style comments */
+\/\/[^\n]* /* ignore C++-style comments */
[ \t\r\n]+ /* ignore whitespace */
<INITIAL>{
}
}
+ newServices->Seal();
+
Set("slave_services", newServices);
}
return parents;
}
-Dictionary::Ptr Host::CalculateDynamicMacros(void) const
+Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self)
{
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
- macros->Set("HOSTNAME", GetName());
- macros->Set("HOSTALIAS", GetName());
- macros->Set("HOSTDISPLAYNAME", GetDisplayName());
- macros->Set("HOSTSTATE", "DERP");
+ Service::Ptr hc;
+
+ {
+ ObjectLock olock(self);
+
+ macros->Set("HOSTNAME", self->GetName());
+ macros->Set("HOSTDISPLAYNAME", self->GetDisplayName());
+ macros->Set("HOSTALIAS", self->GetName());
+
+ hc = self->GetHostCheckService();
+ }
+
+ bool reachable = Host::IsReachable(self);
+
+ Dictionary::Ptr cr;
+
+ if (hc) {
+ ObjectLock olock(hc);
+
+ String state;
+ int stateid;
+
+ switch (hc->GetState()) {
+ case StateOK:
+ case StateWarning:
+ state = "UP";
+ stateid = 0;
+ break;
+ default:
+ state = "DOWN";
+ stateid = 1;
+ break;
+ }
+
+ if (!reachable) {
+ state = "UNREACHABLE";
+ stateid = 2;
+ }
- Service::Ptr hostcheck = GetHostCheckService();
+ macros->Set("HOSTSTATE", state);
+ macros->Set("HOSTSTATEID", stateid);
+ macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hc->GetStateType()));
+ macros->Set("HOSTATTEMPT", hc->GetCurrentCheckAttempt());
+ macros->Set("MAXHOSTATTEMPT", hc->GetMaxCheckAttempts());
- if (hostcheck) {
- macros->Set("HOSTSTATEID", 99);
- macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hostcheck->GetStateType()));
- macros->Set("HOSTATTEMPT", hostcheck->GetCurrentCheckAttempt());
- macros->Set("MAXHOSTATTEMPT", hostcheck->GetMaxCheckAttempts());
+ cr = hc->GetLastCheckResult();
}
+ if (cr) {
+ macros->Set("HOSTLATENCY", Service::CalculateLatency(cr));
+ macros->Set("HOSTEXECUTIONTIME", Service::CalculateExecutionTime(cr));
+
+ ObjectLock olock(cr);
+
+ macros->Set("HOSTOUTPUT", cr->Get("output"));
+ macros->Set("HOSTPERFDATA", cr->Get("performance_data_raw"));
+ }
+
+ macros->Seal();
+
return macros;
}
Dictionary::Ptr GetServiceDependencies(void) const;
String GetHostCheck(void) const;
- Dictionary::Ptr CalculateDynamicMacros(void) const;
+ static Dictionary::Ptr CalculateDynamicMacros(const Host::Ptr& self);
shared_ptr<Service> GetHostCheckService(void) const;
set<Host::Ptr> GetParentHosts(void) const;
RunEventLoop();
- DumpProgramState();
-
Logger::Write(LogInformation, "icinga", "Icinga has shut down.");
return EXIT_SUCCESS;
}
-void IcingaApplication::DumpProgramState(void) {
+void IcingaApplication::OnShutdown(void)
+{
+ m_RetentionTimer->Stop();
+
+ DumpProgramState();
+}
+
+void IcingaApplication::DumpProgramState(void)
+{
DynamicObject::DumpObjects(GetStatePath());
}
{
return m_SSLContext;
}
+
+Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(const IcingaApplication::Ptr& self)
+{
+ Dictionary::Ptr macros = boost::make_shared<Dictionary>();
+
+ macros->Set("TIMET", (long)Utility::GetTime());
+
+ return macros;
+}
double GetStartTime(void) const;
+ static Dictionary::Ptr CalculateDynamicMacros(const IcingaApplication::Ptr& self);
+
private:
shared_ptr<SSL_CTX> m_SSLContext;
Timer::Ptr m_RetentionTimer;
void DumpProgramState(void);
+
+ virtual void OnShutdown(void);
};
}
}
}
+ result->Seal();
+
return result;
}
return Get("macros");
}
-void Notification::SendNotification(NotificationType type)
+String Notification::NotificationTypeToString(NotificationType type)
{
+ switch (type) {
+ case NotificationDowntimeStart:
+ return "DOWNTIMESTART";
+ case NotificationDowntimeEnd:
+ return "DOWNTIMEEND";
+ case NotificationDowntimeRemoved:
+ return "DOWNTIMECANCELLED";
+ case NotificationCustom:
+ return "DOWNTIMECUSTOM";
+ case NotificationProblem:
+ return "PROBLEM";
+ case NotificationRecovery:
+ return "RECOVERY";
+ default:
+ return "UNKNOWN_NOTIFICATION";
+ }
+}
+
+void Notification::BeginExecuteNotification(const Notification::Ptr& self, NotificationType type)
+{
+
+ vector<Dictionary::Ptr> macroDicts;
+
+ Dictionary::Ptr notificationMacros = boost::make_shared<Dictionary>();
+ notificationMacros->Set("NOTIFICATIONTYPE", NotificationTypeToString(type));
+ macroDicts.push_back(notificationMacros);
+
+ Service::Ptr service;
+
+ {
+ ObjectLock olock(self);
+ macroDicts.push_back(self->GetMacros());
+ service = self->GetService();
+ }
+
+ Host::Ptr host;
+ String service_name;
+
+ {
+ ObjectLock olock(service);
+ macroDicts.push_back(service->GetMacros());
+ service_name = service->GetName();
+ host = service->GetHost();
+ }
+
+ macroDicts.push_back(Service::CalculateDynamicMacros(service));
+
+ {
+ ObjectLock olock(host);
+ macroDicts.push_back(host->GetMacros());
+ macroDicts.push_back(Host::CalculateDynamicMacros(host));
+ }
+
+ IcingaApplication::Ptr app = IcingaApplication::GetInstance();
+
+ {
+ ObjectLock olock(app);
+ macroDicts.push_back(app->GetMacros());
+ }
+
+ macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
+
+ Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
+
vector<Value> arguments;
- arguments.push_back(static_cast<Notification::Ptr>(GetSelf()));
+ arguments.push_back(self);
+ arguments.push_back(macros);
arguments.push_back(type);
- ScriptTask::Ptr task = MakeMethodTask("notify", arguments);
+ ScriptTask::Ptr task;
- if (!task) {
- Logger::Write(LogWarning, "icinga", "Notification object '" + GetName() + "' doesn't have a 'notify' method.");
+ {
+ ObjectLock olock(self);
+ task = self->MakeMethodTask("notify", arguments);
- return;
- }
+ if (!task) {
+ Logger::Write(LogWarning, "icinga", "Notification object '" + self->GetName() + "' doesn't have a 'notify' method.");
- /* We need to keep the task object alive until the completion handler is called. */
- m_Tasks.insert(task);
+ return;
+ }
+
+ /* We need to keep the task object alive until the completion handler is called. */
+ self->m_Tasks.insert(task);
+ }
- task->Start(boost::bind(&Notification::NotificationCompletedHandler, this, _1));
+ task->Start(boost::bind(&Notification::NotificationCompletedHandler, self, _1));
}
void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
NotificationDowntimeEnd,
NotificationDowntimeRemoved,
NotificationCustom,
- NotificationStateChange
+ NotificationProblem,
+ NotificationRecovery
};
class Service;
Value GetNotificationCommand(void) const;
Dictionary::Ptr GetMacros(void) const;
- void SendNotification(NotificationType type);
+ static void BeginExecuteNotification(const Notification::Ptr& self, NotificationType type);
+
+ static String NotificationTypeToString(NotificationType type);
protected:
void OnAttributeChanged(const String& name, const Value& oldValue);
if (arguments.size() < 1)
BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Service must be specified."));
- Value vservice = arguments[0];
- if (!vservice.IsObjectType<Service>())
- BOOST_THROW_EXCEPTION(invalid_argument("Argument must be a service."));
+ if (arguments.size() < 2)
+ BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Macros must be specified."));
+
+ Service::Ptr service = arguments[0];
+ Dictionary::Ptr macros = arguments[1];
- vector<Dictionary::Ptr> macroDicts;
Value raw_command;
- Host::Ptr host;
{
- Service::Ptr service = vservice;
ObjectLock olock(service);
- macroDicts.push_back(service->GetMacros());
- macroDicts.push_back(service->CalculateDynamicMacros());
raw_command = service->GetCheckCommand();
- host = service->GetHost();
- }
-
- {
- ObjectLock olock(host);
- macroDicts.push_back(host->GetMacros());
- macroDicts.push_back(host->CalculateDynamicMacros());
}
- {
- IcingaApplication::Ptr app = IcingaApplication::GetInstance();
- ObjectLock olock(app);
- macroDicts.push_back(app->GetMacros());
- }
-
- Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
-
Value command = MacroProcessor::ResolveMacros(raw_command, macros);
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros);
BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Notification target must be specified."));
if (arguments.size() < 2)
- BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Notification type must be specified."));
+ BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Macros must be specified."));
- if (!arguments[0].IsObjectType<Notification>())
- BOOST_THROW_EXCEPTION(invalid_argument("Argument must be a service."));
+ if (arguments.size() < 3)
+ BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Notification type must be specified."));
- NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[1]));
+ Notification::Ptr notification = arguments[0];
+ Dictionary::Ptr macros = arguments[1];
+ NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[2]));
- vector<Dictionary::Ptr> macroDicts;
Value raw_command;
- Service::Ptr service;
- Host::Ptr host;
String service_name;
+ Service::Ptr service;
{
- Notification::Ptr notification = arguments[0];
ObjectLock olock(notification);
- macroDicts.push_back(notification->GetMacros());
raw_command = notification->GetNotificationCommand();
service = notification->GetService();
}
{
ObjectLock olock(service);
- macroDicts.push_back(service->GetMacros());
- macroDicts.push_back(service->CalculateDynamicMacros());
service_name = service->GetName();
- host = service->GetHost();
}
- {
- ObjectLock olock(host);
- macroDicts.push_back(host->GetMacros());
- macroDicts.push_back(host->CalculateDynamicMacros());
- }
-
- {
- IcingaApplication::Ptr app = IcingaApplication::GetInstance();
- ObjectLock olock(app);
- macroDicts.push_back(app->GetMacros());
- }
-
- Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
-
Value command = MacroProcessor::ResolveMacros(raw_command, macros);
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros);
ServiceState old_state = GetState();
ServiceStateType old_stateType = GetStateType();
bool hardChange = false;
+ bool recovery;
long attempt = GetCurrentCheckAttempt();
SetStateType(StateTypeHard);
attempt = 1;
+ recovery = true;
} else {
if (attempt >= GetMaxCheckAttempts()) {
SetStateType(StateTypeHard);
SetStateType(StateTypeSoft);
attempt++;
}
+
+ recovery = false;
}
SetCurrentCheckAttempt(attempt);
Flush();
if (IsReachable(GetSelf()) && !IsInDowntime() && !IsAcknowledged())
- RequestNotifications(NotificationStateChange);
+ RequestNotifications(recovery ? NotificationRecovery : NotificationProblem);
}
}
ServiceState Service::StateFromString(const String& state)
{
- if (state == "ok")
+ if (state == "OK")
return StateOK;
- else if (state == "warning")
+ else if (state == "WARNING")
return StateWarning;
- else if (state == "critical")
+ else if (state == "CRITICAL")
return StateCritical;
- else if (state == "uncheckable")
+ else if (state == "UNCHECKABLE")
return StateUncheckable;
else
return StateUnknown;
{
switch (state) {
case StateOK:
- return "ok";
+ return "OK";
case StateWarning:
- return "warning";
+ return "WARNING";
case StateCritical:
- return "critical";
+ return "CRITICAL";
case StateUncheckable:
- return "uncheckable";
+ return "UNCHECKABLE";
case StateUnknown:
default:
- return "unknown";
+ return "UNKNOWN";
}
}
ServiceStateType Service::StateTypeFromString(const String& type)
{
- if (type == "soft")
+ if (type == "SOFT")
return StateTypeSoft;
else
return StateTypeHard;
String Service::StateTypeToString(ServiceStateType type)
{
if (type == StateTypeSoft)
- return "soft";
+ return "SOFT";
else
- return "hard";
+ return "HARD";
}
bool Service::IsAllowedChecker(const String& checker) const
return false;
}
-void Service::BeginExecuteCheck(const function<void (void)>& callback)
+void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (void)>& callback)
{
+ ObjectLock slock(self);
+
/* don't run another check if there is one pending */
- if (!Get("current_task").IsEmpty()) {
+ if (!self->Get("current_task").IsEmpty()) {
+ slock.Unlock();
+
/* we need to call the callback anyway */
callback();
}
/* keep track of scheduling info in case the check type doesn't provide its own information */
- Dictionary::Ptr scheduleInfo = boost::make_shared<Dictionary>();
- scheduleInfo->Set("schedule_start", GetNextCheck());
- scheduleInfo->Set("execution_start", Utility::GetTime());
+ Dictionary::Ptr checkInfo = boost::make_shared<Dictionary>();
+ checkInfo->Set("schedule_start", self->GetNextCheck());
+ checkInfo->Set("execution_start", Utility::GetTime());
+
+ vector<Dictionary::Ptr> macroDicts;
+ macroDicts.push_back(self->GetMacros());
+ macroDicts.push_back(Service::CalculateDynamicMacros(self));
+
+ Value raw_command = self->GetCheckCommand();
+
+ Host::Ptr host = self->GetHost();
+
+ slock.Unlock();
+
+ {
+ ObjectLock olock(host);
+ macroDicts.push_back(host->GetMacros());
+ macroDicts.push_back(Host::CalculateDynamicMacros(host));
+ }
+
+ IcingaApplication::Ptr app = IcingaApplication::GetInstance();
+
+ {
+ ObjectLock olock(app);
+ macroDicts.push_back(app->GetMacros());
+ }
+
+ macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
+
+ Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
+
+ checkInfo->Set("macros", macros);
vector<Value> arguments;
- arguments.push_back(static_cast<Service::Ptr>(GetSelf()));
+ arguments.push_back(self);
+ arguments.push_back(macros);
+
+ ScriptTask::Ptr task;
- ScriptTask::Ptr task = MakeMethodTask("check", arguments);
- Set("current_task", task);
+ {
+ ObjectLock olock(self);
+ task = self->MakeMethodTask("check", arguments);
+ self->Set("current_task", task);
+ }
- task->Start(boost::bind(&Service::CheckCompletedHandler, this, scheduleInfo, _1, callback));
+ task->Start(boost::bind(&Service::CheckCompletedHandler, self, checkInfo, _1, callback));
}
-void Service::CheckCompletedHandler(const Dictionary::Ptr& scheduleInfo,
+void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
const ScriptTask::Ptr& task, const function<void (void)>& callback)
{
- ObjectLock olock(this);
-
- Set("current_task", Empty);
-
- scheduleInfo->Set("execution_end", Utility::GetTime());
- scheduleInfo->Set("schedule_end", Utility::GetTime());
+ checkInfo->Set("execution_end", Utility::GetTime());
+ checkInfo->Set("schedule_end", Utility::GetTime());
Dictionary::Ptr result;
if (result) {
if (!result->Contains("schedule_start"))
- result->Set("schedule_start", scheduleInfo->Get("schedule_start"));
+ result->Set("schedule_start", checkInfo->Get("schedule_start"));
if (!result->Contains("schedule_end"))
- result->Set("schedule_end", scheduleInfo->Get("schedule_end"));
+ result->Set("schedule_end", checkInfo->Get("schedule_end"));
if (!result->Contains("execution_start"))
- result->Set("execution_start", scheduleInfo->Get("execution_start"));
+ result->Set("execution_start", checkInfo->Get("execution_start"));
if (!result->Contains("execution_end"))
- result->Set("execution_end", scheduleInfo->Get("execution_end"));
+ result->Set("execution_end", checkInfo->Get("execution_end"));
+
+ if (!result->Contains("macros"))
+ result->Set("macros", checkInfo->Get("macros"));
if (!result->Contains("active"))
result->Set("active", 1);
- if (!result->Contains("checker"))
- result->Set("checker", EndpointManager::GetInstance()->GetIdentity());
+ if (!result->Contains("checker")) {
+ EndpointManager::Ptr em = EndpointManager::GetInstance();
+ ObjectLock olock(em);
- ProcessCheckResult(result);
+ result->Set("checker", em->GetIdentity());
+ }
}
- /* figure out when the next check is for this service; the call to
- * ApplyCheckResult() should've already done this but lets do it again
- * just in case there was no check result. */
- UpdateNextCheck();
+ {
+ ObjectLock olock(this);
+ if (result)
+ ProcessCheckResult(result);
- olock.Unlock();
+ Set("current_task", Empty);
+
+ /* figure out when the next check is for this service; the call to
+ * ApplyCheckResult() should've already done this but lets do it again
+ * just in case there was no check result. */
+ UpdateNextCheck();
+ }
callback();
}
else
CIB::UpdatePassiveChecksStatistics(ts, 1);
}
+
+double Service::CalculateExecutionTime(const Dictionary::Ptr& cr)
+{
+ ObjectLock olock(cr);
+
+ double execution_start = 0, execution_end = 0;
+
+ if (cr) {
+ ObjectLock olock(cr);
+
+ if (!cr->Contains("execution_start") || !cr->Contains("execution_end"))
+ return 0;
+
+ execution_start = cr->Get("execution_start");
+ execution_end = cr->Get("execution_end");
+ }
+
+ return (execution_end - execution_start);
+}
+
+double Service::CalculateLatency(const Dictionary::Ptr& cr)
+{
+ double schedule_start = 0, schedule_end = 0;
+
+ if (cr) {
+ ObjectLock olock(cr);
+
+ if (!cr->Contains("schedule_start") || !cr->Contains("schedule_end"))
+ return 0;
+
+ schedule_start = cr->Get("schedule_start");
+ schedule_end = cr->Get("schedule_end");
+ }
+
+ return (schedule_end - schedule_start) - CalculateExecutionTime(cr);
+
+}
Logger::Write(LogInformation, "icinga", "Service '" + GetName() + "' does not have any notifications.");
BOOST_FOREACH(const Notification::Ptr& notification, notifications) {
- notification->SendNotification(type);
+ Notification::BeginExecuteNotification(notification, type);
}
SetLastNotification(Utility::GetTime());
{
String value = Get("display_name");
- if (!value.IsEmpty())
- return value;
+ if (value.IsEmpty())
+ return GetShortName();
- return GetName();
+ return value;
}
/**
return parents;
}
-Dictionary::Ptr Service::CalculateDynamicMacros(void) const
+Dictionary::Ptr Service::CalculateDynamicMacros(const Service::Ptr& self)
{
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
- macros->Set("SERVICEDESC", GetShortName());
- macros->Set("SERVICEDISPLAYNAME", GetDisplayName());
- macros->Set("SERVICESTATE", StateToString(GetState()));
- macros->Set("SERVICESTATEID", GetState());
- macros->Set("SERVICESTATETYPE", StateTypeToString(GetStateType()));
- macros->Set("SERVICEATTEMPT", GetCurrentCheckAttempt());
- macros->Set("MAXSERVICEATTEMPT", GetMaxCheckAttempts());
+ Dictionary::Ptr cr;
- Dictionary::Ptr cr = GetLastCheckResult();
+ {
+ ObjectLock olock(self);
+ macros->Set("SERVICEDESC", self->GetShortName());
+ macros->Set("SERVICEDISPLAYNAME", self->GetDisplayName());
+ macros->Set("SERVICESTATE", StateToString(self->GetState()));
+ macros->Set("SERVICESTATEID", self->GetState());
+ macros->Set("SERVICESTATETYPE", StateTypeToString(self->GetStateType()));
+ macros->Set("SERVICEATTEMPT", self->GetCurrentCheckAttempt());
+ macros->Set("MAXSERVICEATTEMPT", self->GetMaxCheckAttempts());
+
+ cr = self->GetLastCheckResult();
+ }
if (cr) {
+ macros->Set("SERVICELATENCY", Service::CalculateLatency(cr));
+ macros->Set("SERVICEEXECUTIONTIME", Service::CalculateExecutionTime(cr));
+
+ ObjectLock olock(cr);
+
macros->Set("SERVICEOUTPUT", cr->Get("output"));
macros->Set("SERVICEPERFDATA", cr->Get("performance_data_raw"));
- } else {
- macros->Set("SERVICEOUTPUT", "");
- macros->Set("SERVICEPERFDATA", "");
}
+ macros->Seal();
+
return macros;
}
Dictionary::Ptr GetGroups(void) const;
String GetShortName(void) const;
- Dictionary::Ptr CalculateDynamicMacros(void) const;
+ static Dictionary::Ptr CalculateDynamicMacros(const Service::Ptr& self);
set<Host::Ptr> GetParentHosts(void) const;
set<Service::Ptr> GetParentServices(void) const;
void ApplyCheckResult(const Dictionary::Ptr& cr);
static void UpdateStatistics(const Dictionary::Ptr& cr);
- void BeginExecuteCheck(const function<void (void)>& callback);
+ static void BeginExecuteCheck(const Service::Ptr& self, const function<void (void)>& callback);
void ProcessCheckResult(const Dictionary::Ptr& cr);
+ static double CalculateExecutionTime(const Dictionary::Ptr& cr);
+ static double CalculateLatency(const Dictionary::Ptr& cr);
+
static ServiceState StateFromString(const String& state);
static String StateToString(ServiceState state);
virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private:
- void CheckCompletedHandler(const Dictionary::Ptr& scheduleInfo,
+ void CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
const ScriptTask::Ptr& task, const function<void (void)>& callback);
/* Downtimes */
}
}
+ subscriptions->Seal();
+
if (m_Endpoint)
m_Endpoint->SetSubscriptions(subscriptions);
}