mirror of https://github.com/Icinga/icinga2.git
Fine-grained locks (WIP, Part 9).
This commit is contained in:
parent
404b1807e6
commit
2ef255b9f6
|
@ -21,7 +21,7 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
EXPORT_COMPONENT(checker, CheckerComponent);
|
||||
REGISTER_COMPONENT("checker", CheckerComponent);
|
||||
|
||||
void CheckerComponent::Start(void)
|
||||
{
|
||||
|
@ -59,12 +59,9 @@ void CheckerComponent::Stop(void)
|
|||
|
||||
void CheckerComponent::CheckThreadProc(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_Mutex);
|
||||
|
||||
for (;;) {
|
||||
vector<Service::Ptr> services;
|
||||
Service::Ptr service;
|
||||
|
||||
boost::mutex::scoped_lock lock(m_Mutex);
|
||||
|
||||
typedef nth_index<ServiceSet, 1>::type CheckTimeView;
|
||||
CheckTimeView& idx = boost::get<1>(m_IdleServices);
|
||||
|
||||
|
@ -75,7 +72,7 @@ void CheckerComponent::CheckThreadProc(void)
|
|||
break;
|
||||
|
||||
CheckTimeView::iterator it = idx.begin();
|
||||
service = it->lock();
|
||||
Service::Ptr service = it->lock();
|
||||
|
||||
if (!service) {
|
||||
idx.erase(it);
|
||||
|
@ -131,20 +128,16 @@ void CheckerComponent::CheckThreadProc(void)
|
|||
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);
|
||||
|
@ -217,4 +210,3 @@ void CheckerComponent::NextCheckChangedHandler(const Service::Ptr& service)
|
|||
idx.insert(service);
|
||||
m_CV.notify_all();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
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
|
||||
|
@ -91,7 +91,7 @@ String CompatComponent::GetCommandPath(void) const
|
|||
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);
|
||||
|
@ -323,11 +323,10 @@ void CompatComponent::DumpServiceStatusAttrs(ofstream& fp, const Service::Ptr& s
|
|||
{
|
||||
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;
|
||||
|
||||
{
|
||||
|
@ -335,21 +334,16 @@ void CompatComponent::DumpServiceStatusAttrs(ofstream& fp, const Service::Ptr& s
|
|||
|
||||
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;
|
||||
|
||||
|
@ -370,10 +364,10 @@ void CompatComponent::DumpServiceStatusAttrs(ofstream& fp, const Service::Ptr& s
|
|||
<< "\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"
|
||||
|
@ -518,7 +512,8 @@ void CompatComponent::StatusTimerHandler(void)
|
|||
<< "\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"
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
EXPORT_COMPONENT(compatido, CompatIdoComponent);
|
||||
REGISTER_COMPONENT("compatido", CompatIdoComponent);
|
||||
|
||||
const String CompatIdoComponent::DefaultSocketAddress = "127.0.0.1";
|
||||
const String CompatIdoComponent::DefaultSocketPort = "5668";
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
EXPORT_COMPONENT(delegation, DelegationComponent);
|
||||
REGISTER_COMPONENT("delegation", DelegationComponent);
|
||||
|
||||
void DelegationComponent::Start(void)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
EXPORT_COMPONENT(demo, DemoComponent);
|
||||
REGISTER_COMPONENT("demo", DemoComponent);
|
||||
|
||||
/**
|
||||
* Starts the component.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
EXPORT_COMPONENT(notification, NotificationComponent);
|
||||
REGISTER_COMPONENT("notification", NotificationComponent);
|
||||
|
||||
/**
|
||||
* Starts the component.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
EXPORT_COMPONENT(replication, ReplicationComponent);
|
||||
REGISTER_COMPONENT("replication", ReplicationComponent);
|
||||
|
||||
/**
|
||||
* Starts the component.
|
||||
|
|
|
@ -210,7 +210,7 @@ int main(int argc, char **argv)
|
|||
|
||||
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> >()) {
|
||||
|
|
|
@ -34,6 +34,8 @@ libbase_la_SOURCES = \
|
|||
netstring.h \
|
||||
object.cpp \
|
||||
object.h \
|
||||
objectlock.cpp \
|
||||
objectlock.h \
|
||||
process.cpp \
|
||||
process-unix.cpp \
|
||||
process-windows.cpp \
|
||||
|
|
|
@ -120,8 +120,12 @@ void Application::ProfileTimerHandler(void)
|
|||
|
||||
void Application::ShutdownTimerHandler(void)
|
||||
{
|
||||
if (m_ShuttingDown)
|
||||
if (m_ShuttingDown) {
|
||||
Application::GetInstance()->OnShutdown();
|
||||
DynamicObject::DeactivateObjects();
|
||||
GetEQ().Stop();
|
||||
m_ShuttingDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -424,8 +428,6 @@ int Application::Run(void)
|
|||
|
||||
result = Main();
|
||||
|
||||
DynamicObject::DeactivateObjects();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,8 @@ public:
|
|||
protected:
|
||||
void RunEventLoop(void) const;
|
||||
|
||||
virtual void OnShutdown(void) = 0;
|
||||
|
||||
private:
|
||||
static Application *m_Instance; /**< The application instance. */
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,6 +166,18 @@ private:
|
|||
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. */
|
||||
|
|
|
@ -23,6 +23,8 @@ using namespace icinga;
|
|||
|
||||
REGISTER_TYPE(Component, NULL);
|
||||
|
||||
map<String, Component::Factory> Component::m_Factories;
|
||||
|
||||
/**
|
||||
* Constructor for the component class.
|
||||
*/
|
||||
|
@ -32,51 +34,20 @@ Component::Component(const Dictionary::Ptr& properties)
|
|||
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);
|
||||
(void) Utility::LoadIcingaLibrary(GetName(), true);
|
||||
|
||||
CreateComponentFunction pCreateComponent;
|
||||
map<String, Factory>::iterator it;
|
||||
it = m_Factories.find(GetName());
|
||||
|
||||
#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 */
|
||||
if (it == m_Factories.end())
|
||||
BOOST_THROW_EXCEPTION(invalid_argument("Unknown component: " + GetName()));
|
||||
|
||||
IComponent::Ptr impl;
|
||||
IComponent::Ptr impl = it->second();
|
||||
|
||||
try {
|
||||
if (pCreateComponent == NULL)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Loadable module does not contain "
|
||||
"CreateComponent function"));
|
||||
|
||||
/* pCreateComponent returns a raw pointer which we must wrap in a shared_ptr */
|
||||
impl = IComponent::Ptr(pCreateComponent());
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -142,3 +113,11 @@ void IComponent::Stop(void)
|
|||
{
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ public:
|
|||
typedef shared_ptr<Component> Ptr;
|
||||
typedef weak_ptr<Component> WeakPtr;
|
||||
|
||||
typedef function<IComponent::Ptr (void)> Factory;
|
||||
|
||||
Component(const Dictionary::Ptr& properties);
|
||||
~Component(void);
|
||||
|
||||
|
@ -66,30 +68,43 @@ public:
|
|||
|
||||
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. */
|
||||
|
||||
static map<String, Factory> m_Factories;
|
||||
};
|
||||
|
||||
typedef IComponent *(*CreateComponentFunction)(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
# define SYM_CREATECOMPONENT(component) CreateComponent
|
||||
#else /* _WIN32 */
|
||||
# define SYM_CREATECOMPONENT(component) component ## _LTX_CreateComponent
|
||||
#endif /* _WIN32 */
|
||||
/**
|
||||
* Helper class for registering Component implementation classes.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class RegisterComponentHelper
|
||||
{
|
||||
public:
|
||||
RegisterComponentHelper(const String& name, const Component::Factory& factory)
|
||||
{
|
||||
Component::Register(name, factory);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the loader function for a component.
|
||||
* Factory function for IComponent-based 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(); \
|
||||
}
|
||||
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>)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,13 @@ struct DictionaryKeyLessComparer
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for the Dictionary class.
|
||||
*/
|
||||
Dictionary::Dictionary(void)
|
||||
: m_Sealed(false)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Restrieves a value from a dictionary.
|
||||
*
|
||||
|
@ -98,6 +105,8 @@ void Dictionary::Set(const String& key, const Value& value)
|
|||
{
|
||||
ObjectLock olock(this);
|
||||
|
||||
assert(!m_Sealed);
|
||||
|
||||
if (value.IsEmpty()) {
|
||||
Remove(key);
|
||||
return;
|
||||
|
@ -213,6 +222,15 @@ void Dictionary::Remove(Dictionary::Iterator it)
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -39,11 +39,14 @@ public:
|
|||
*/
|
||||
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);
|
||||
|
@ -60,6 +63,7 @@ public:
|
|||
|
||||
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)
|
||||
|
|
|
@ -122,6 +122,8 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
|
|||
attrs->Set(it->first, attr);
|
||||
}
|
||||
|
||||
attrs->Seal();
|
||||
|
||||
Dictionary::Ptr update = boost::make_shared<Dictionary>();
|
||||
update->Set("attrs", attrs);
|
||||
|
||||
|
@ -130,6 +132,8 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
|
|||
else if (attrs->GetLength() == 0)
|
||||
return Dictionary::Ptr();
|
||||
|
||||
update->Seal();
|
||||
|
||||
return update;
|
||||
}
|
||||
|
||||
|
@ -243,8 +247,12 @@ void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
|
|||
* 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
|
||||
|
@ -496,7 +504,7 @@ void DynamicObject::RestoreObjects(const String& filename)
|
|||
|
||||
stringstream msgbuf;
|
||||
msgbuf << "Restored " << restored << " objects";
|
||||
Logger::Write(LogDebug, "base", msgbuf.str());
|
||||
Logger::Write(LogInformation, "base", msgbuf.str());
|
||||
}
|
||||
|
||||
void DynamicObject::DeactivateObjects(void)
|
||||
|
|
|
@ -81,7 +81,7 @@ void EventQueue::QueueThreadProc(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);
|
||||
|
@ -94,7 +94,7 @@ void EventQueue::QueueThreadProc(void)
|
|||
|
||||
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());
|
||||
|
@ -118,7 +118,7 @@ void EventQueue::Post(const EventQueue::Callback& callback)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,6 +190,7 @@ namespace signals2 = boost::signals2;
|
|||
#include "qstring.h"
|
||||
#include "utility.h"
|
||||
#include "object.h"
|
||||
#include "objectlock.h"
|
||||
#include "exception.h"
|
||||
#include "eventqueue.h"
|
||||
#include "value.h"
|
||||
|
|
|
@ -106,38 +106,6 @@ private:
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
using namespace icinga;
|
||||
|
||||
int Process::m_TaskFd;
|
||||
Timer::Ptr Process::m_StatusTimer;
|
||||
extern char **environ;
|
||||
|
||||
void Process::Initialize(void)
|
||||
|
@ -37,7 +38,7 @@ 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]);
|
||||
|
@ -59,6 +60,11 @@ void Process::Initialize(void)
|
|||
}
|
||||
|
||||
(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)
|
||||
|
@ -314,4 +320,12 @@ bool Process::RunTask(void)
|
|||
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 */
|
||||
|
|
|
@ -24,7 +24,6 @@ using namespace icinga;
|
|||
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)
|
||||
|
@ -66,18 +65,9 @@ vector<String> Process::SplitCommand(const Value& command)
|
|||
|
||||
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();
|
||||
|
|
|
@ -69,10 +69,11 @@ private:
|
|||
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);
|
||||
|
@ -83,6 +84,8 @@ private:
|
|||
static void WorkerThreadProc(void);
|
||||
#else /* _WIN32 */
|
||||
static void WorkerThreadProc(int taskFd);
|
||||
|
||||
static void StatusTimerHandler(void);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
void InitTask(void);
|
||||
|
|
|
@ -54,6 +54,38 @@ bool Value::IsObject(void) const
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -85,27 +85,8 @@ public:
|
|||
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
|
||||
|
|
|
@ -386,7 +386,7 @@ static yyconst flex_int16_t yy_accept[193] =
|
|||
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,
|
||||
|
@ -793,6 +793,10 @@ int yyget_lineno (yyscan_t yyscanner );
|
|||
|
||||
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 );
|
||||
|
@ -948,7 +952,7 @@ YY_DECL
|
|||
|
||||
lex_buf string_buf;
|
||||
|
||||
#line 952 "config_lexer.cc"
|
||||
#line 956 "config_lexer.cc"
|
||||
|
||||
yylval = yylval_param;
|
||||
|
||||
|
@ -1377,7 +1381,7 @@ YY_RULE_SETUP
|
|||
#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):
|
||||
|
|
|
@ -173,7 +173,7 @@ static void lb_append_char(lex_buf *lb, char new_char)
|
|||
"*" /* ignore star */
|
||||
}
|
||||
|
||||
\/\/[^\n]+ /* ignore C++-style comments */
|
||||
\/\/[^\n]* /* ignore C++-style comments */
|
||||
[ \t\r\n]+ /* ignore whitespace */
|
||||
|
||||
<INITIAL>{
|
||||
|
|
|
@ -288,6 +288,8 @@ void Host::UpdateSlaveServices(void)
|
|||
}
|
||||
}
|
||||
|
||||
newServices->Seal();
|
||||
|
||||
Set("slave_services", newServices);
|
||||
}
|
||||
|
||||
|
@ -479,23 +481,69 @@ set<Service::Ptr> Host::GetParentServices(void) const
|
|||
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;
|
||||
|
||||
Service::Ptr hostcheck = GetHostCheckService();
|
||||
{
|
||||
ObjectLock olock(self);
|
||||
|
||||
if (hostcheck) {
|
||||
macros->Set("HOSTSTATEID", 99);
|
||||
macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hostcheck->GetStateType()));
|
||||
macros->Set("HOSTATTEMPT", hostcheck->GetCurrentCheckAttempt());
|
||||
macros->Set("MAXHOSTATTEMPT", hostcheck->GetMaxCheckAttempts());
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
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;
|
||||
|
|
|
@ -72,14 +72,20 @@ int IcingaApplication::Main(void)
|
|||
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -142,3 +148,12 @@ shared_ptr<SSL_CTX> IcingaApplication::GetSSLContext(void) const
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ public:
|
|||
|
||||
double GetStartTime(void) const;
|
||||
|
||||
static Dictionary::Ptr CalculateDynamicMacros(const IcingaApplication::Ptr& self);
|
||||
|
||||
private:
|
||||
shared_ptr<SSL_CTX> m_SSLContext;
|
||||
|
||||
|
@ -59,6 +61,8 @@ private:
|
|||
Timer::Ptr m_RetentionTimer;
|
||||
|
||||
void DumpProgramState(void);
|
||||
|
||||
virtual void OnShutdown(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -88,5 +88,7 @@ Dictionary::Ptr MacroProcessor::MergeMacroDicts(const vector<Dictionary::Ptr>& d
|
|||
}
|
||||
}
|
||||
|
||||
result->Seal();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -70,24 +70,94 @@ Dictionary::Ptr Notification::GetMacros(void) const
|
|||
return Get("macros");
|
||||
}
|
||||
|
||||
void Notification::SendNotification(NotificationType type)
|
||||
String Notification::NotificationTypeToString(NotificationType type)
|
||||
{
|
||||
vector<Value> arguments;
|
||||
arguments.push_back(static_cast<Notification::Ptr>(GetSelf()));
|
||||
arguments.push_back(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";
|
||||
}
|
||||
}
|
||||
|
||||
ScriptTask::Ptr task = MakeMethodTask("notify", arguments);
|
||||
void Notification::BeginExecuteNotification(const Notification::Ptr& self, NotificationType type)
|
||||
{
|
||||
|
||||
if (!task) {
|
||||
Logger::Write(LogWarning, "icinga", "Notification object '" + GetName() + "' doesn't have a 'notify' method.");
|
||||
vector<Dictionary::Ptr> macroDicts;
|
||||
|
||||
return;
|
||||
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();
|
||||
}
|
||||
|
||||
/* We need to keep the task object alive until the completion handler is called. */
|
||||
m_Tasks.insert(task);
|
||||
Host::Ptr host;
|
||||
String service_name;
|
||||
|
||||
task->Start(boost::bind(&Notification::NotificationCompletedHandler, this, _1));
|
||||
{
|
||||
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(self);
|
||||
arguments.push_back(macros);
|
||||
arguments.push_back(type);
|
||||
|
||||
ScriptTask::Ptr task;
|
||||
|
||||
{
|
||||
ObjectLock olock(self);
|
||||
task = self->MakeMethodTask("notify", arguments);
|
||||
|
||||
if (!task) {
|
||||
Logger::Write(LogWarning, "icinga", "Notification object '" + self->GetName() + "' doesn't have a 'notify' method.");
|
||||
|
||||
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, self, _1));
|
||||
}
|
||||
|
||||
void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
|
||||
|
|
|
@ -34,7 +34,8 @@ enum NotificationType
|
|||
NotificationDowntimeEnd,
|
||||
NotificationDowntimeRemoved,
|
||||
NotificationCustom,
|
||||
NotificationStateChange
|
||||
NotificationProblem,
|
||||
NotificationRecovery
|
||||
};
|
||||
|
||||
class Service;
|
||||
|
@ -60,7 +61,9 @@ public:
|
|||
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);
|
||||
|
|
|
@ -32,37 +32,19 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
|
|||
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);
|
||||
|
|
|
@ -37,49 +37,30 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const vecto
|
|||
BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Notification target must be specified."));
|
||||
|
||||
if (arguments.size() < 2)
|
||||
BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Macros must be specified."));
|
||||
|
||||
if (arguments.size() < 3)
|
||||
BOOST_THROW_EXCEPTION(invalid_argument("Missing argument: Notification type must be specified."));
|
||||
|
||||
if (!arguments[0].IsObjectType<Notification>())
|
||||
BOOST_THROW_EXCEPTION(invalid_argument("Argument must be a service."));
|
||||
Notification::Ptr notification = arguments[0];
|
||||
Dictionary::Ptr macros = arguments[1];
|
||||
NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[2]));
|
||||
|
||||
NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[1]));
|
||||
|
||||
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);
|
||||
|
|
|
@ -287,6 +287,7 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
|
|||
ServiceState old_state = GetState();
|
||||
ServiceStateType old_stateType = GetStateType();
|
||||
bool hardChange = false;
|
||||
bool recovery;
|
||||
|
||||
long attempt = GetCurrentCheckAttempt();
|
||||
|
||||
|
@ -298,6 +299,7 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
|
|||
SetStateType(StateTypeHard);
|
||||
|
||||
attempt = 1;
|
||||
recovery = true;
|
||||
} else {
|
||||
if (attempt >= GetMaxCheckAttempts()) {
|
||||
SetStateType(StateTypeHard);
|
||||
|
@ -307,6 +309,8 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
|
|||
SetStateType(StateTypeSoft);
|
||||
attempt++;
|
||||
}
|
||||
|
||||
recovery = false;
|
||||
}
|
||||
|
||||
SetCurrentCheckAttempt(attempt);
|
||||
|
@ -353,19 +357,19 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
|
|||
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;
|
||||
|
@ -375,22 +379,22 @@ String Service::StateToString(ServiceState state)
|
|||
{
|
||||
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;
|
||||
|
@ -399,9 +403,9 @@ ServiceStateType Service::StateTypeFromString(const String& type)
|
|||
String Service::StateTypeToString(ServiceStateType type)
|
||||
{
|
||||
if (type == StateTypeSoft)
|
||||
return "soft";
|
||||
return "SOFT";
|
||||
else
|
||||
return "hard";
|
||||
return "HARD";
|
||||
}
|
||||
|
||||
bool Service::IsAllowedChecker(const String& checker) const
|
||||
|
@ -420,10 +424,14 @@ 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();
|
||||
|
||||
|
@ -431,28 +439,59 @@ void Service::BeginExecuteCheck(const function<void (void)>& 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 = MakeMethodTask("check", arguments);
|
||||
Set("current_task", task);
|
||||
ScriptTask::Ptr task;
|
||||
|
||||
task->Start(boost::bind(&Service::CheckCompletedHandler, this, scheduleInfo, _1, callback));
|
||||
{
|
||||
ObjectLock olock(self);
|
||||
task = self->MakeMethodTask("check", arguments);
|
||||
self->Set("current_task", task);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -481,32 +520,43 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& scheduleInfo,
|
|||
|
||||
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();
|
||||
}
|
||||
|
@ -551,3 +601,40 @@ void Service::UpdateStatistics(const Dictionary::Ptr& cr)
|
|||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ void Service::SendNotifications(NotificationType type)
|
|||
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());
|
||||
|
|
|
@ -76,10 +76,10 @@ String Service::GetDisplayName(void) const
|
|||
{
|
||||
String value = Get("display_name");
|
||||
|
||||
if (!value.IsEmpty())
|
||||
return value;
|
||||
if (value.IsEmpty())
|
||||
return GetShortName();
|
||||
|
||||
return GetName();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -330,27 +330,36 @@ set<Service::Ptr> Service::GetParentServices(void) const
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
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;
|
||||
|
@ -171,9 +171,12 @@ public:
|
|||
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);
|
||||
|
||||
|
@ -252,7 +255,7 @@ protected:
|
|||
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 */
|
||||
|
|
|
@ -341,6 +341,8 @@ void EndpointManager::SubscriptionTimerHandler(void)
|
|||
}
|
||||
}
|
||||
|
||||
subscriptions->Seal();
|
||||
|
||||
if (m_Endpoint)
|
||||
m_Endpoint->SetSubscriptions(subscriptions);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue