diff --git a/lib/base/array-script.cpp b/lib/base/array-script.cpp index 3f83dd934..c12585b1f 100644 --- a/lib/base/array-script.cpp +++ b/lib/base/array-script.cpp @@ -251,15 +251,7 @@ static Array::Ptr ArrayUnique() ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Array::Ptr self = static_cast(vframe->Self); REQUIRE_NOT_NULL(self); - - std::set result; - - ObjectLock olock(self); - for (const Value& item : self) { - result.insert(item); - } - - return Array::FromSet(result); + return self->Unique(); } static void ArrayFreeze() diff --git a/lib/base/array.cpp b/lib/base/array.cpp index ac2ade93e..30cf7eba3 100644 --- a/lib/base/array.cpp +++ b/lib/base/array.cpp @@ -305,6 +305,19 @@ String Array::ToString() const return msgbuf.str(); } +Array::Ptr Array::Unique() const +{ + std::set result; + + ObjectLock olock(this); + + for (const Value& item : m_Data) { + result.insert(item); + } + + return Array::FromSet(result); +} + void Array::Freeze() { ObjectLock olock(this); diff --git a/lib/base/array.hpp b/lib/base/array.hpp index 768cee131..62bcf7e2e 100644 --- a/lib/base/array.hpp +++ b/lib/base/array.hpp @@ -112,6 +112,7 @@ public: String ToString() const override; + Array::Ptr Unique() const; void Freeze(); Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; diff --git a/lib/icinga/hostgroup.cpp b/lib/icinga/hostgroup.cpp index da0e7b9ad..d0ca7b323 100644 --- a/lib/icinga/hostgroup.cpp +++ b/lib/icinga/hostgroup.cpp @@ -37,9 +37,9 @@ INITIALIZE_ONCE([]() { bool HostGroup::EvaluateObjectRule(const Host::Ptr& host, const ConfigItem::Ptr& group) { - String group_name = group->GetName(); + String groupName = group->GetName(); - CONTEXT("Evaluating rule for group '" + group_name + "'"); + CONTEXT("Evaluating rule for group '" + groupName + "'"); ScriptFrame frame(true); if (group->GetScope()) @@ -50,10 +50,12 @@ bool HostGroup::EvaluateObjectRule(const Host::Ptr& host, const ConfigItem::Ptr& return false; Log(LogDebug, "HostGroup") - << "Assigning membership for group '" << group_name << "' to host '" << host->GetName() << "'"; + << "Assigning membership for group '" << groupName << "' to host '" << host->GetName() << "'"; Array::Ptr groups = host->GetGroups(); - groups->Add(group_name); + + if (groups && !groups->Contains(groupName)) + groups->Add(groupName); return true; } diff --git a/lib/icinga/servicegroup.cpp b/lib/icinga/servicegroup.cpp index 555113259..2b99f4214 100644 --- a/lib/icinga/servicegroup.cpp +++ b/lib/icinga/servicegroup.cpp @@ -37,9 +37,9 @@ INITIALIZE_ONCE([]() { bool ServiceGroup::EvaluateObjectRule(const Service::Ptr& service, const ConfigItem::Ptr& group) { - String group_name = group->GetName(); + String groupName = group->GetName(); - CONTEXT("Evaluating rule for group '" + group_name + "'"); + CONTEXT("Evaluating rule for group '" + groupName + "'"); Host::Ptr host = service->GetHost(); @@ -53,10 +53,12 @@ bool ServiceGroup::EvaluateObjectRule(const Service::Ptr& service, const ConfigI return false; Log(LogDebug, "ServiceGroup") - << "Assigning membership for group '" << group_name << "' to service '" << service->GetName() << "'"; + << "Assigning membership for group '" << groupName << "' to service '" << service->GetName() << "'"; Array::Ptr groups = service->GetGroups(); - groups->Add(group_name); + + if (groups && !groups->Contains(groupName)) + groups->Add(groupName); return true; } diff --git a/lib/icinga/usergroup.cpp b/lib/icinga/usergroup.cpp index db8706729..8f2a4e7fc 100644 --- a/lib/icinga/usergroup.cpp +++ b/lib/icinga/usergroup.cpp @@ -37,9 +37,9 @@ INITIALIZE_ONCE([]() { bool UserGroup::EvaluateObjectRule(const User::Ptr& user, const ConfigItem::Ptr& group) { - String group_name = group->GetName(); + String groupName = group->GetName(); - CONTEXT("Evaluating rule for group '" + group_name + "'"); + CONTEXT("Evaluating rule for group '" + groupName + "'"); ScriptFrame frame(true); if (group->GetScope()) @@ -50,10 +50,12 @@ bool UserGroup::EvaluateObjectRule(const User::Ptr& user, const ConfigItem::Ptr& return false; Log(LogDebug, "UserGroup") - << "Assigning membership for group '" << group_name << "' to user '" << user->GetName() << "'"; + << "Assigning membership for group '" << groupName << "' to user '" << user->GetName() << "'"; Array::Ptr groups = user->GetGroups(); - groups->Add(group_name); + + if (groups && !groups->Contains(groupName)) + groups->Add(groupName); return true; } diff --git a/lib/remote/createobjecthandler.cpp b/lib/remote/createobjecthandler.cpp index e3646b3f3..a365ed664 100644 --- a/lib/remote/createobjecthandler.cpp +++ b/lib/remote/createobjecthandler.cpp @@ -71,6 +71,14 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r } } + /* Sanity checks for unique groups array. */ + if (attrs->Contains("groups")) { + Array::Ptr groups = attrs->Get("groups"); + + if (groups) + attrs->Set("groups", groups->Unique()); + } + Dictionary::Ptr result1 = new Dictionary(); String status; Array::Ptr errors = new Array(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5fce79833..29a16646f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -63,6 +63,7 @@ add_boost_test(base base_array/resize base_array/insert base_array/remove + base_array/unique base_array/foreach base_array/clone base_array/json diff --git a/test/base-array.cpp b/test/base-array.cpp index 86be0f510..74bbd692c 100644 --- a/test/base-array.cpp +++ b/test/base-array.cpp @@ -102,6 +102,27 @@ BOOST_AUTO_TEST_CASE(remove) BOOST_CHECK(array->GetLength() == 0); } +BOOST_AUTO_TEST_CASE(unique) +{ + Array::Ptr array = new Array(); + array->Add("group1"); + array->Add("group2"); + array->Add("group1"); + array->Add("group2"); + + Array::Ptr result; + + { + ObjectLock olock(array); + result = array->Unique(); + } + + BOOST_CHECK(result->GetLength() == 2); + result->Sort(); + + BOOST_CHECK(result->Get(0) == "group1"); + BOOST_CHECK(result->Get(1) == "group2"); +} BOOST_AUTO_TEST_CASE(foreach) { Array::Ptr array = new Array();