diff --git a/components/checker/checkercomponent.cpp b/components/checker/checkercomponent.cpp index 2f53142dc..9859550f0 100644 --- a/components/checker/checkercomponent.cpp +++ b/components/checker/checkercomponent.cpp @@ -64,6 +64,8 @@ void CheckerComponent::OnConfigLoaded(void) { DynamicObject::OnStarted.connect(bind(&CheckerComponent::ObjectHandler, this, _1)); DynamicObject::OnStopped.connect(bind(&CheckerComponent::ObjectHandler, this, _1)); + DynamicObject::OnPaused.connect(bind(&CheckerComponent::ObjectHandler, this, _1)); + DynamicObject::OnResumed.connect(bind(&CheckerComponent::ObjectHandler, this, _1)); Checkable::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1)); } @@ -257,7 +259,7 @@ void CheckerComponent::ObjectHandler(const DynamicObject::Ptr& object) { boost::mutex::scoped_lock lock(m_Mutex); - if (object->IsActive() && same_zone) { + if (object->IsActive() && !object->IsPaused() && same_zone) { if (m_PendingCheckables.find(checkable) != m_PendingCheckables.end()) return; diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 286c80b6c..5b58dc77b 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -44,6 +44,8 @@ INITIALIZE_ONCE(&DynamicObject::StaticInitialize); boost::signals2::signal DynamicObject::OnStarted; boost::signals2::signal DynamicObject::OnStopped; +boost::signals2::signal DynamicObject::OnPaused; +boost::signals2::signal DynamicObject::OnResumed; boost::signals2::signal DynamicObject::OnStateChanged; boost::signals2::signal DynamicObject::OnVarsChanged; @@ -70,6 +72,11 @@ bool DynamicObject::IsActive(void) const return GetActive(); } +bool DynamicObject::IsPaused(void) const +{ + return GetPaused(); +} + void DynamicObject::SetExtension(const String& key, const Object::Ptr& object) { Dictionary::Ptr extensions = GetExtensions(); @@ -173,6 +180,33 @@ void DynamicObject::OnStateLoaded(void) /* Nothing to do here. */ } +void DynamicObject::Pause(void) +{ + SetPauseCalled(true); +} + +void DynamicObject::Resume(void) +{ + SetResumeCalled(true); +} + +void DynamicObject::SetAuthority(bool authority) +{ + if (authority && GetPaused()) { + SetResumeCalled(false); + Resume(); + ASSERT(GetResumeCalled()); + SetPaused(false); + OnResumed(GetSelf()); + } else if (!authority && !GetPaused()) { + SetPauseCalled(false); + Resume(); + ASSERT(GetPauseCalled()); + SetPaused(true); + OnPaused(GetSelf()); + } +} + Value DynamicObject::InvokeMethod(const String& method, const std::vector& arguments) { diff --git a/lib/base/dynamicobject.h b/lib/base/dynamicobject.h index 0dbf09f6b..9f9fcb269 100644 --- a/lib/base/dynamicobject.h +++ b/lib/base/dynamicobject.h @@ -77,6 +77,8 @@ public: static boost::signals2::signal OnStarted; static boost::signals2::signal OnStopped; + static boost::signals2::signal OnPaused; + static boost::signals2::signal OnResumed; static boost::signals2::signal OnStateChanged; static boost::signals2::signal OnVarsChanged; @@ -85,6 +87,7 @@ public: shared_ptr GetType(void) const; bool IsActive(void) const; + bool IsPaused(void) const; void SetExtension(const String& key, const Object::Ptr& object); Object::Ptr GetExtension(const String& key); @@ -102,10 +105,14 @@ public: void Activate(void); void Deactivate(void); + void SetAuthority(bool authority); virtual void Start(void); virtual void Stop(void); + virtual void Pause(void); + virtual void Resume(void); + virtual void OnConfigLoaded(void); virtual void OnStateLoaded(void); diff --git a/lib/base/dynamicobject.ti b/lib/base/dynamicobject.ti index 4f9fce254..1a7939cce 100644 --- a/lib/base/dynamicobject.ti +++ b/lib/base/dynamicobject.ti @@ -25,8 +25,11 @@ abstract class DynamicObject [config] Dictionary::Ptr methods; [config] Dictionary::Ptr vars (VarsRaw); [get_protected] bool active; + [get_protected] bool paused; [get_protected] bool start_called; [get_protected] bool stop_called; + [get_protected] bool pause_called; + [get_protected] bool resume_called; Dictionary::Ptr authority_info; [protected] Dictionary::Ptr extensions; diff --git a/lib/remote/CMakeLists.txt b/lib/remote/CMakeLists.txt index 9a8400dea..ed9fdc9fc 100644 --- a/lib/remote/CMakeLists.txt +++ b/lib/remote/CMakeLists.txt @@ -22,8 +22,9 @@ mkclass_target(zone.ti zone.th) mkembedconfig_target(remote-type.conf remote-type.cpp) add_library(remote SHARED - apiclient.cpp apifunction.cpp apilistener.cpp apilistener.th endpoint.cpp - endpoint.th jsonrpc.cpp messageorigin.cpp remote-type.cpp zone.cpp zone.th + apiclient.cpp apifunction.cpp apilistener.cpp apilistener.th authority.cpp + endpoint.cpp endpoint.th jsonrpc.cpp messageorigin.cpp remote-type.cpp + zone.cpp zone.th ) include_directories(${Boost_INCLUDE_DIRS}) diff --git a/lib/remote/authority.cpp b/lib/remote/authority.cpp new file mode 100644 index 000000000..12d8dc4ff --- /dev/null +++ b/lib/remote/authority.cpp @@ -0,0 +1,80 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "remote/zone.h" +#include "remote/apilistener.h" +#include "base/application.h" +#include "base/dynamictype.h" +#include "base/objectlock.h" +#include "base/utility.h" +#include "base/initialize.h" +#include "base/timer.h" +#include "base/logger_fwd.h" +#include "base/exception.h" + +using namespace icinga; + +static Timer::Ptr l_AuthorityTimer; + +static bool ObjectNameLessComparer(const DynamicObject::Ptr& a, const DynamicObject::Ptr& b) +{ + return a->GetName() < b->GetName(); +} + +static void AuthorityTimerHandler(void) +{ + ApiListener::Ptr listener = ApiListener::GetInstance(); + + if (!listener || !listener->IsActive()) + return; + + Zone::Ptr my_zone = Zone::GetLocalZone(); + Endpoint::Ptr my_endpoint = Endpoint::GetLocalEndpoint(); + + std::vector endpoints; + BOOST_FOREACH(const Endpoint::Ptr& endpoint, my_zone->GetEndpoints()) { + if (!endpoint->IsConnected() && endpoint != my_endpoint) + continue; + + endpoints.push_back(endpoint); + } + + std::sort(endpoints.begin(), endpoints.end(), ObjectNameLessComparer); + + BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) { + BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) { + Endpoint::Ptr endpoint = endpoints[Utility::SDBM(object->GetName()) % endpoints.size()]; + + if (endpoint == my_endpoint) + object->Resume(); + else + object->Pause(); + } + } +} + +static void StaticInitialize(void) +{ + l_AuthorityTimer = make_shared(); + l_AuthorityTimer->OnTimerExpired.connect(boost::bind(&AuthorityTimerHandler)); + l_AuthorityTimer->SetInterval(30); + l_AuthorityTimer->Start(); +} + +INITIALIZE_ONCE(StaticInitialize);