Skip to content

Commit 4e08adc

Browse files
authored
Merge pull request #10161 from Icinga/authBYhost-10157
ApiListener::UpdateObjectAuthority(): distribute auth. by object's host
2 parents 215af2b + b1e08ba commit 4e08adc

File tree

4 files changed

+37
-18
lines changed

4 files changed

+37
-18
lines changed

doc/19-technical-concepts.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -633,15 +633,12 @@ The algorithm works like this:
633633
* Set the authority (true or false)
634634

635635
The object authority calculation works "offline" without any message exchange.
636-
Each instance alculates the SDBM hash of the config object name, puts that in contrast
637-
modulo the connected endpoints size.
638-
This index is used to lookup the corresponding endpoint in the connected endpoints array,
639-
including the local endpoint. Whether the local endpoint is equal to the selected endpoint,
640-
or not, this sets the authority to `true` or `false`.
641-
642-
```cpp
643-
authority = endpoints[Utility::SDBM(object->GetName()) % endpoints.size()] == my_endpoint;
644-
```
636+
Each instance calculates the SDBM hash of the config object name. However, for objects bound to some
637+
host, i.e. the object name is composed of `<host_name>!<object_name>`, the SDBM hash is calculated based
638+
on the host name only instead of the full object name. That way, each child object like services, downtimes,
639+
etc. will be assigned to the same endpoint as the host object itself. The resulting hash modulo (`%`) the number of
640+
connected endpoints produces the index of the endpoint which is authoritative for this config object. If the
641+
endpoint at this index is equal to the local endpoint, the authority is set to `true`, otherwise it is set to `false`.
645642

646643
`ConfigObject::SetAuthority(bool authority)` triggers the following events:
647644

lib/remote/apilistener-authority.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void ApiListener::UpdateObjectAuthority()
2525

2626
std::vector<Endpoint::Ptr> endpoints;
2727
Endpoint::Ptr my_endpoint;
28+
int hostChildrenInheritObjectAuthority = 0;
2829

2930
if (my_zone) {
3031
my_endpoint = Endpoint::GetLocalEndpoint();
@@ -38,6 +39,10 @@ void ApiListener::UpdateObjectAuthority()
3839
continue;
3940

4041
endpoints.push_back(endpoint);
42+
43+
if (endpoint == my_endpoint || endpoint->GetCapabilities() & static_cast<uint_fast64_t>(ApiCapabilities::HostChildrenInheritObjectAuthority)) {
44+
++hostChildrenInheritObjectAuthority;
45+
}
4146
}
4247

4348
double startTime = Application::GetStartTime();
@@ -65,10 +70,24 @@ void ApiListener::UpdateObjectAuthority()
6570

6671
bool authority;
6772

68-
if (!my_zone)
73+
if (my_zone) {
74+
auto name (object->GetName());
75+
76+
// If all endpoints know this algorithm, we can use it.
77+
if (hostChildrenInheritObjectAuthority == endpoints.size()) {
78+
auto exclamation (name.FindFirstOf('!'));
79+
80+
// Pin child objects of hosts (HOST!...) to the same endpoint as the host.
81+
// This reduces cross-object action latency withing the same host.
82+
if (exclamation != String::NPos) {
83+
name.erase(name.Begin() + exclamation, name.End());
84+
}
85+
}
86+
87+
authority = endpoints[Utility::SDBM(name) % endpoints.size()] == my_endpoint;
88+
} else {
6989
authority = true;
70-
else
71-
authority = endpoints[Utility::SDBM(object->GetName()) % endpoints.size()] == my_endpoint;
90+
}
7291

7392
#ifdef I2_DEBUG
7493
// //Enable on demand, causes heavy logging on each run.

lib/remote/apilistener.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -640,10 +640,6 @@ static const auto l_AppVersionInt (([]() -> unsigned long {
640640
+ boost::lexical_cast<unsigned long>(match[3].str());
641641
})());
642642

643-
static const auto l_MyCapabilities (
644-
(uint_fast64_t)ApiCapabilities::ExecuteArbitraryCommand | (uint_fast64_t)ApiCapabilities::IfwApiCheckCommand
645-
);
646-
647643
/**
648644
* Processes a new client connection.
649645
*
@@ -774,7 +770,7 @@ void ApiListener::NewClientHandlerInternal(
774770
{ "method", "icinga::Hello" },
775771
{ "params", new Dictionary({
776772
{ "version", (double)l_AppVersionInt },
777-
{ "capabilities", (double)l_MyCapabilities }
773+
{ "capabilities", (double)ApiCapabilities::MyCapabilities }
778774
}) }
779775
}), yc);
780776

@@ -813,7 +809,7 @@ void ApiListener::NewClientHandlerInternal(
813809
{ "method", "icinga::Hello" },
814810
{ "params", new Dictionary({
815811
{ "version", (double)l_AppVersionInt },
816-
{ "capabilities", (double)l_MyCapabilities }
812+
{ "capabilities", (double)ApiCapabilities::MyCapabilities }
817813
}) }
818814
}), yc);
819815

@@ -1801,6 +1797,10 @@ Value ApiListener::HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dicti
18011797
endpoint->SetIcingaVersion(nodeVersion);
18021798
endpoint->SetCapabilities((double)params->Get("capabilities"));
18031799

1800+
if (endpoint->GetZone() == Zone::GetLocalZone()) {
1801+
UpdateObjectAuthority();
1802+
}
1803+
18041804
if (nodeVersion == 0u) {
18051805
nodeVersion = 21200;
18061806
}

lib/remote/apilistener.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ enum class ApiCapabilities : uint_fast64_t
7070
{
7171
ExecuteArbitraryCommand = 1u << 0u,
7272
IfwApiCheckCommand = 1u << 1u,
73+
HostChildrenInheritObjectAuthority = 1u << 2u,
74+
75+
MyCapabilities = ExecuteArbitraryCommand | IfwApiCheckCommand | HostChildrenInheritObjectAuthority
7376
};
7477

7578
/**

0 commit comments

Comments
 (0)