From 95909d82fe2114939a135183930c90bf0ccdb647 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 12 Sep 2013 10:03:48 +0200 Subject: [PATCH] cluster: Implement authority checks. --- components/checker/checkercomponent.cpp | 5 +++ components/cluster/clustercomponent.cpp | 44 +++++++++++++++++++++++++ components/cluster/clustercomponent.h | 1 + components/cluster/endpoint.cpp | 22 +++++++++++++ components/cluster/endpoint.h | 6 ++++ lib/base/dynamicobject.cpp | 15 +++++++++ lib/base/dynamicobject.h | 6 ++++ lib/base/utility.cpp | 12 +++++++ lib/base/utility.h | 2 ++ lib/config/base-type.conf | 4 +++ 10 files changed, 117 insertions(+) diff --git a/components/checker/checkercomponent.cpp b/components/checker/checkercomponent.cpp index 6d9a14d8f..b31f53ce1 100644 --- a/components/checker/checkercomponent.cpp +++ b/components/checker/checkercomponent.cpp @@ -106,6 +106,11 @@ void CheckerComponent::CheckThreadProc(void) bool forced = service->GetForceNextCheck(); bool check = true; + if (!service->HasAuthority("checker")) { + Log(LogDebug, "checker", "Skipping check for service '" + service->GetName() + "': not authoritative"); + check = false; + } + if (!forced) { if (!service->GetEnableActiveChecks()) { Log(LogDebug, "checker", "Skipping check for service '" + service->GetName() + "': active checks are disabled"); diff --git a/components/cluster/clustercomponent.cpp b/components/cluster/clustercomponent.cpp index b170f48ee..8e175ad3b 100644 --- a/components/cluster/clustercomponent.cpp +++ b/components/cluster/clustercomponent.cpp @@ -85,6 +85,8 @@ void ClusterComponent::Start(void) Service::OnAcknowledgementSet.connect(boost::bind(&ClusterComponent::AcknowledgementSetHandler, this, _1, _2, _3, _4, _5, _6)); Service::OnAcknowledgementCleared.connect(boost::bind(&ClusterComponent::AcknowledgementClearedHandler, this, _1, _2)); + DynamicObject::OnCheckAuthority.connect(boost::bind(&ClusterComponent::CheckAuthorityHandler, this, _1, _2, _3)); + Endpoint::OnMessageReceived.connect(boost::bind(&ClusterComponent::MessageHandler, this, _1, _2)); } @@ -1119,6 +1121,48 @@ void ClusterComponent::MessageHandler(const Endpoint::Ptr& sender, const Diction } } +void ClusterComponent::CheckAuthorityHandler(const DynamicObject::Ptr& object, const String& type, bool& result) +{ + Array::Ptr authorities = object->GetAuthorities(); + std::vector endpoints; + + if ((type == "checker" && DynamicType::GetByName("CheckerComponent")) || + (type == "notification" && DynamicType::GetByName("NotificationComponent"))) + endpoints.push_back(GetIdentity()); + + BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects()) { + bool match = false; + + if (!endpoint->IsConnected()) + continue; + + if (authorities) { + BOOST_FOREACH(const String& authority, authorities) { + if (Utility::Match(authority, endpoint->GetName())) { + match = true; + + break; + } + } + } else { + match = true; + } + + if (match) + endpoints.push_back(endpoint->GetName()); + } + + std::sort(endpoints.begin(), endpoints.end()); + + String key = object->GetType()->GetName() + "\t" + object->GetName(); + unsigned long hash = Utility::SDBM(key); + unsigned long index = hash % endpoints.size(); + + Log(LogDebug, "cluster", "Authority for object '" + object->GetName() + "' of type '" + object->GetType()->GetName() + "' is '" + endpoints[index] + "'."); + + result = (endpoints[index] == GetIdentity()); +} + void ClusterComponent::InternalSerialize(const Dictionary::Ptr& bag, int attributeTypes) const { DynamicObject::InternalSerialize(bag, attributeTypes); diff --git a/components/cluster/clustercomponent.h b/components/cluster/clustercomponent.h index aebe68dd4..593044198 100644 --- a/components/cluster/clustercomponent.h +++ b/components/cluster/clustercomponent.h @@ -111,6 +111,7 @@ private: void AcknowledgementSetHandler(const Service::Ptr& service, const String& author, const String& comment, AcknowledgementType type, double expiry, const String& authority); void AcknowledgementClearedHandler(const Service::Ptr& service, const String& authority); void MessageHandler(const Endpoint::Ptr& sender, const Dictionary::Ptr& message); + void CheckAuthorityHandler(const DynamicObject::Ptr& object, const String& type, bool& result); }; } diff --git a/components/cluster/endpoint.cpp b/components/cluster/endpoint.cpp index efb08e847..a2785e99e 100644 --- a/components/cluster/endpoint.cpp +++ b/components/cluster/endpoint.cpp @@ -168,6 +168,26 @@ void Endpoint::SetRemoteLogPosition(double ts) m_RemoteLogPosition = ts; } +Dictionary::Ptr Endpoint::GetFeatures(void) const +{ + return m_Features; +} + +void Endpoint::SetFeatures(const Dictionary::Ptr& features) +{ + m_Features = features; +} + +bool Endpoint::HasFeature(const String& type) const +{ + Dictionary::Ptr features = GetFeatures(); + + if (!features) + return false; + + return features->Get(type); +} + void Endpoint::InternalSerialize(const Dictionary::Ptr& bag, int attributeTypes) const { DynamicObject::InternalSerialize(bag, attributeTypes); @@ -183,6 +203,7 @@ void Endpoint::InternalSerialize(const Dictionary::Ptr& bag, int attributeTypes) bag->Set("seen", m_Seen); bag->Set("local_log_position", m_LocalLogPosition); bag->Set("remote_log_position", m_RemoteLogPosition); + bag->Set("features", m_Features); } } @@ -201,5 +222,6 @@ void Endpoint::InternalDeserialize(const Dictionary::Ptr& bag, int attributeType m_Seen = bag->Get("seen"); m_LocalLogPosition = bag->Get("local_log_position"); m_RemoteLogPosition = bag->Get("remote_log_position"); + m_Features = bag->Get("features"); } } diff --git a/components/cluster/endpoint.h b/components/cluster/endpoint.h index 1830e1018..38a0b99d3 100644 --- a/components/cluster/endpoint.h +++ b/components/cluster/endpoint.h @@ -65,6 +65,11 @@ public: double GetRemoteLogPosition(void) const; void SetRemoteLogPosition(double ts); + Dictionary::Ptr GetFeatures(void) const; + void SetFeatures(const Dictionary::Ptr& features); + + bool HasFeature(const String& type) const; + protected: virtual void InternalSerialize(const Dictionary::Ptr& bag, int attributeTypes) const; virtual void InternalDeserialize(const Dictionary::Ptr& bag, int attributeTypes); @@ -80,6 +85,7 @@ private: double m_Seen; double m_LocalLogPosition; double m_RemoteLogPosition; + Dictionary::Ptr m_Features; void MessageThreadProc(const Stream::Ptr& stream); }; diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index ba8828788..ce99d26ce 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -41,6 +41,7 @@ using namespace icinga; boost::signals2::signal DynamicObject::OnStarted; boost::signals2::signal DynamicObject::OnStopped; boost::signals2::signal DynamicObject::OnStateChanged; +boost::signals2::signal DynamicObject::OnCheckAuthority; DynamicObject::DynamicObject(void) : m_Active(false) @@ -82,6 +83,7 @@ void DynamicObject::InternalSerialize(const Dictionary::Ptr& bag, int attributeT bag->Set("__type", m_Type); bag->Set("methods", m_Methods); bag->Set("custom", m_Custom); + bag->Set("authorities", m_Authorities); } bag->Set("extensions", m_Extensions); @@ -98,6 +100,7 @@ void DynamicObject::InternalDeserialize(const Dictionary::Ptr& bag, int attribut m_Type = bag->Get("__type"); m_Methods = bag->Get("methods"); m_Custom = bag->Get("custom"); + m_Authorities = bag->Get("authorities"); } m_Extensions = bag->Get("extensions"); @@ -118,6 +121,18 @@ bool DynamicObject::IsActive(void) const return m_Active; } +Array::Ptr DynamicObject::GetAuthorities(void) const +{ + return m_Authorities; +} + +bool DynamicObject::HasAuthority(const String& type) +{ + bool result = true; + OnCheckAuthority(GetSelf(), type, result); + return result; +} + void DynamicObject::SetExtension(const String& key, const Object::Ptr& object) { Dictionary::Ptr extensions = m_Extensions; diff --git a/lib/base/dynamicobject.h b/lib/base/dynamicobject.h index 44531289d..0849cae65 100644 --- a/lib/base/dynamicobject.h +++ b/lib/base/dynamicobject.h @@ -23,6 +23,7 @@ #include "base/i2-base.h" #include "base/object.h" #include "base/dictionary.h" +#include "base/array.h" #include #include #include @@ -62,6 +63,7 @@ public: static boost::signals2::signal OnStarted; static boost::signals2::signal OnStopped; static boost::signals2::signal OnStateChanged; + static boost::signals2::signal OnCheckAuthority; Value InvokeMethod(const String& method, const std::vector& arguments); @@ -70,6 +72,9 @@ public: bool IsActive(void) const; + Array::Ptr GetAuthorities(void) const; + bool HasAuthority(const String& type); + void SetExtension(const String& key, const Object::Ptr& object); Object::Ptr GetExtension(const String& key); void ClearExtension(const String& key); @@ -111,6 +116,7 @@ private: Dictionary::Ptr m_Extensions; Dictionary::Ptr m_Methods; Dictionary::Ptr m_Custom; + Array::Ptr m_Authorities; bool m_Active; diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 98511f919..e8e49b4d9 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -551,3 +551,15 @@ String Utility::GetThreadName(void) return *name; } + +unsigned long Utility::SDBM(const String& str) +{ + unsigned long hash = 0; + int c; + + BOOST_FOREACH(char c, str) { + hash = c + (hash << 6) + (hash << 16) - hash; + } + + return hash; +} diff --git a/lib/base/utility.h b/lib/base/utility.h index fa5439e1c..2befe3db2 100644 --- a/lib/base/utility.h +++ b/lib/base/utility.h @@ -95,6 +95,8 @@ public: static void SetThreadName(const String& name, bool os = true); static String GetThreadName(void); + static unsigned long SDBM(const String& str); + private: Utility(void); diff --git a/lib/config/base-type.conf b/lib/config/base-type.conf index e576ed5e9..f2826eca1 100644 --- a/lib/config/base-type.conf +++ b/lib/config/base-type.conf @@ -28,6 +28,10 @@ type DynamicObject { %attribute dictionary "custom" { %attribute string "*" + }, + + %attribute array "authorities" { + %attribute string "*" } }