]> granicus.if.org Git - icinga2/commitdiff
Fine-grained locks (WIP, Part 9).
authorGunnar Beutner <gunnar.beutner@netways.de>
Sun, 24 Feb 2013 00:10:34 +0000 (01:10 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Sun, 24 Feb 2013 00:10:34 +0000 (01:10 +0100)
41 files changed:
components/checker/checkercomponent.cpp
components/compat/compatcomponent.cpp
components/compatido/compatidocomponent.cpp
components/delegation/delegationcomponent.cpp
components/demo/democomponent.cpp
components/notification/notificationcomponent.cpp
components/replication/replicationcomponent.cpp
icinga-app/icinga.cpp
lib/base/Makefile.am
lib/base/application.cpp
lib/base/application.h
lib/base/asynctask.h
lib/base/component.cpp
lib/base/component.h
lib/base/dictionary.cpp
lib/base/dictionary.h
lib/base/dynamicobject.cpp
lib/base/eventqueue.cpp
lib/base/i2-base.h
lib/base/object.h
lib/base/process-unix.cpp
lib/base/process.cpp
lib/base/process.h
lib/base/value.cpp
lib/base/value.h
lib/config/config_lexer.cc
lib/config/config_lexer.ll
lib/icinga/host.cpp
lib/icinga/host.h
lib/icinga/icingaapplication.cpp
lib/icinga/icingaapplication.h
lib/icinga/macroprocessor.cpp
lib/icinga/notification.cpp
lib/icinga/notification.h
lib/icinga/pluginchecktask.cpp
lib/icinga/pluginnotificationtask.cpp
lib/icinga/service-check.cpp
lib/icinga/service-notification.cpp
lib/icinga/service.cpp
lib/icinga/service.h
lib/remoting/endpointmanager.cpp

index e9136beb65894531663afca74085befb810c1813..565d52ad116ad377a82d1f8e6d74238d1b9323f1 100644 (file)
@@ -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)
 {
-       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);
 
@@ -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();
 }
-
index 5507b58018a78cb8e540ed2e120e7c98f4f8bbe9..0fc59f6ca9902705dde70310d0a48ea2b175e363 100644 (file)
@@ -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"
index 33c3dd5c7594f89578ae6838eb708f40fec2120c..69bf055ad29324e2ae562877e612110c51ba3d77 100644 (file)
@@ -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";
index 09836eb1ecc57550404ade8e4bbd72c4f21db729..1191bce94f13c5c930d93444f47842127fca117b 100644 (file)
@@ -22,7 +22,7 @@
 
 using namespace icinga;
 
-EXPORT_COMPONENT(delegation, DelegationComponent);
+REGISTER_COMPONENT("delegation", DelegationComponent);
 
 void DelegationComponent::Start(void)
 {
index 31b931c19a1d7ec908f6074c78ee816f169b2f9f..355f5014ce2420209b664abefd25c3dd0e15bc7a 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-EXPORT_COMPONENT(demo, DemoComponent);
+REGISTER_COMPONENT("demo", DemoComponent);
 
 /**
  * Starts the component.
index d6e5a9151ea1d24ba7daa4dc97beceedb34eb424..ae5178b52b58821f796fdfbaa0769afb77b6b598 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-EXPORT_COMPONENT(notification, NotificationComponent);
+REGISTER_COMPONENT("notification", NotificationComponent);
 
 /**
  * Starts the component.
index cb81abf990dcee2835e2f8d3053a968c8f380517..de1c1b4e014c74e7315ecb11f8f6bb94e2d19ba4 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-EXPORT_COMPONENT(replication, ReplicationComponent);
+REGISTER_COMPONENT("replication", ReplicationComponent);
 
 /**
  * Starts the component.
index 124c7d68f52ef062bb72dd89716372584e8d09d8..3445c762ede859f289c6800b528bfd198b862bcb 100644 (file)
@@ -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> >()) {
index 60ffcb8ccd7e6020f10c6c9402ef0c7e3f486f60..1f606540e37ee01813ff2982d50d2710d955f30c 100644 (file)
@@ -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 \
index 8cc0cc271546cdec80c489628db5f0c3fa787424..99453a992b06ae55023c3b2d53f6606394d6d6b5 100644 (file)
@@ -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;
 }
 
index bfeb4ef53d0066dfe601b2013790b7d4f535b092..dfb27e766fa14ddbedc10c2949bea1e5a3043e27 100644 (file)
@@ -84,6 +84,8 @@ public:
 protected:
        void RunEventLoop(void) const;
 
+       virtual void OnShutdown(void) = 0;
+
 private:
        static Application *m_Instance; /**< The application instance. */
 
index 0c1e9115a761f0140e7a3e65c268470f1039d905..af2f4ca8ab5a76590181aec056e2599032b1ad51 100644 (file)
@@ -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. */
index 86074b7c70a83f4919393e9e8b0737b798defb84..bc503d67b7780b49cdf84d94b2d141ad7fd07fe5 100644 (file)
@@ -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);
-
-       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;
 }
@@ -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;
+}
index 377342ac3e36c98864d5f73e010eca41723bbb28..003729da9c46fceb08252849c27f44edc7e85614 100644 (file)
@@ -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. */
-};
 
-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>)
 
 }
 
index cd41e5ed3a65b91862044e3db3a320420821c393..6657959d2844a963e0c00b4ae0d04edfd46121de 100644 (file)
@@ -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.
  *
index fc5065eee7d9acccd814f807bc99f08539d083cf..d2921df22fbf9eace5ef0fb662bf9a154b66d771 100644 (file)
@@ -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)
index bf4e714f757d563afbfaa070ed7e778cd39343d5..3a985c7d6fca09f539a9682eb817355a83e9aa7c 100644 (file)
@@ -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)
index 55d8f7fce99f2174ee3752cbe0a23bb8dcfb8c37..8cb4864648817c0da44df902b2f25bf240f154f3 100644 (file)
@@ -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;
        }
 }
index 04e9684f97f5c8b01a2d7810f61327e27fd4d88b..ee80e4dfa601674716023af8185756f7cb45decf 100644 (file)
@@ -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"
index ce39a2b402c835ba3bd0670aee827546d11cd41b..923c208266a99169efbb3524222efd7f2f0ee54e 100644 (file)
@@ -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.
  *
index 9e852a765f844ec8d6b0497dae2191789dd31563..d7fdae54626274452bee30671400a4d6a2d10706 100644 (file)
@@ -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 */
index 7e9a08a6fccba8c1ed392b4f2a3dc116e74c9fd9..3197dcda2ebd2832ccaf3c336bc37f1c4eec70b1 100644 (file)
@@ -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();
index 018dc24ee6aa1ce7de360031de86c40e89a9ebd7..e141accff657dfada947d9e98c0d37b1b601cea7 100644 (file)
@@ -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);
index 60a85294820a6ef16e478832699addf632def254..d4a2486ae1d40ee3dd0c9afd30268f192cded982 100644 (file)
@@ -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.
  *
index 45ece754fcfd604c2841ed6a914a9f700e01681a..db84fc2ffc1701dd32870780aea3ad795b2de5c9 100644 (file)
@@ -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
index b00d99097240f347c1b7611d78a9cee8b9ccc0f1..eab6bbbaa2c237b4e60e59fca5baf9ebd3b17385 100644 (file)
@@ -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):
index bc1fd1dcd56493d699802c27992e7775080e6530..42666ecf9a2861917f56639d6ebfba92d28bb019 100644 (file)
@@ -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>{
index 581794b184bf2615a50b7d982b2a1cb75df339d5..095147b604befe6ee1e916143b8e0d5a4911798a 100644 (file)
@@ -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;
+
+       {
+               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;
 }
index 244232f09705e4b39968ebb240604d4f3db3a179..2308f1d23bcd5a4ebddb35803f69c3fba73f335c 100644 (file)
@@ -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;
index 96eda887dccb966c8ef0ab961e281f67589bbe45..73c36e3ebb3642fbf9148128f70c45c30dcab295 100644 (file)
@@ -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;
+}
index 3bf7a8a07f919c357d5d3bff6831ff32e3b4d0c6..fb294655be69591dc1df84558eb60f48cf931d3a 100644 (file)
@@ -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);
 };
 
 }
index 431843ddc5f2d9aa39fa19b5edd46244e2836b82..803fb21b61bd0f55e66f2457ddcd4173fc0e2b76 100644 (file)
@@ -88,5 +88,7 @@ Dictionary::Ptr MacroProcessor::MergeMacroDicts(const vector<Dictionary::Ptr>& d
                }
        }
 
+       result->Seal();
+
        return result;
 }
index 5d90a6d3521236f0e794f31a0c41022981ca5033..dd7d67e98eaaa9cb952ed6bd362c552bd02f956e 100644 (file)
@@ -70,24 +70,94 @@ Dictionary::Ptr Notification::GetMacros(void) const
        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)
index ef5e82dbf6174fd682655c2077aa3f405023f107..4aa16a1a2cef2b31fcde3c67273039672fa7c8e2 100644 (file)
@@ -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);
index c63560efb69002d64149101f1d57f773ef2a7799..6870ceb83e28b8f94f98dd871fb13cc233de9bbf 100644 (file)
@@ -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);
index c66671180fbfb2fef46558438e5cf8eee9aada68..4c0a35862abdcf7bad19e207539829ba696b300b 100644 (file)
@@ -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: 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);
index 3db70d3fdbe90ee8fe82e8745880ac1eef79d2e1..2f2759e97df2e7ce5845845fa5e405ad5c9fdb53 100644 (file)
@@ -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;
 
-       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;
 
@@ -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);
+
+}
index 6cc30550666c62f52bec087d051284b1c3e26e14..36ade2b666def32627353cf8b85f64a597d86b06 100644 (file)
@@ -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());
index 355df9899702413d42e92a150a6f44a87b2a3048..291e795174a4ad0e91450363ede8f228465ef6a6 100644 (file)
@@ -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;
 }
index 22da158187a716251c02749eac1b1aaa978abf1e..7dba9058ceda2b0f57b12a29ac761327172a25e6 100644 (file)
@@ -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 */
index 16cc00492bc183a7ea36fbcf01320cfc2f947f77..6ae387791da8bbb51063a8f8c110af584fd6fed6 100644 (file)
@@ -341,6 +341,8 @@ void EndpointManager::SubscriptionTimerHandler(void)
                }
        }
 
+       subscriptions->Seal();
+
        if (m_Endpoint)
                m_Endpoint->SetSubscriptions(subscriptions);
 }