mirror of https://github.com/Icinga/icinga2.git
parent
9e29936b8f
commit
40ac05c182
|
@ -1288,6 +1288,7 @@ params | Dictionary
|
|||
|
||||
Key | Type | Description
|
||||
---------------------|-------------|------------------
|
||||
capabilities | Number | Bitmask, see `lib/remote/apilistener.hpp`.
|
||||
version | Number | Icinga 2 version, e.g. 21300 for v2.13.0.
|
||||
|
||||
##### Functions
|
||||
|
|
|
@ -821,11 +821,11 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object,
|
|||
std::set<Endpoint::Ptr> endpoints = zone->GetEndpoints();
|
||||
|
||||
for (const Endpoint::Ptr& childEndpoint : endpoints) {
|
||||
if (childEndpoint->GetIcingaVersion() < 21300) {
|
||||
if (!(childEndpoint->GetCapabilities() & (uint_fast64_t)ApiCapabilities::ExecuteArbitraryCommand)) {
|
||||
/* Update execution */
|
||||
double now = Utility::GetTime();
|
||||
pending_execution->Set("exit", 126);
|
||||
pending_execution->Set("output", "Endpoint '" + childEndpoint->GetName() + "' has version < 2.13.");
|
||||
pending_execution->Set("output", "Endpoint '" + childEndpoint->GetName() + "' doesn't support executing arbitrary commands.");
|
||||
pending_execution->Set("start", now);
|
||||
pending_execution->Set("end", now);
|
||||
pending_execution->Remove("pending");
|
||||
|
|
|
@ -641,7 +641,7 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin,
|
|||
std::set<Endpoint::Ptr> endpoints = zone->GetEndpoints();
|
||||
|
||||
for (const Endpoint::Ptr &childEndpoint : endpoints) {
|
||||
if (childEndpoint->GetIcingaVersion() < 21300) {
|
||||
if (!(childEndpoint->GetCapabilities() & (uint_fast64_t)ApiCapabilities::ExecuteArbitraryCommand)) {
|
||||
double now = Utility::GetTime();
|
||||
Dictionary::Ptr executedParams = new Dictionary();
|
||||
executedParams->Set("execution", params->Get("source"));
|
||||
|
@ -650,7 +650,7 @@ Value ClusterEvents::ExecuteCommandAPIHandler(const MessageOrigin::Ptr& origin,
|
|||
executedParams->Set("service", params->Get("service"));
|
||||
executedParams->Set("exit", 126);
|
||||
executedParams->Set("output",
|
||||
"Endpoint '" + childEndpoint->GetName() + "' has version < 2.13.");
|
||||
"Endpoint '" + childEndpoint->GetName() + "' doesn't support executing arbitrary commands.");
|
||||
executedParams->Set("start", now);
|
||||
executedParams->Set("end", now);
|
||||
|
||||
|
|
|
@ -522,6 +522,8 @@ static const auto l_AppVersionInt (([]() -> unsigned long {
|
|||
+ boost::lexical_cast<unsigned long>(match[3].str());
|
||||
})());
|
||||
|
||||
static const auto l_MyCapabilities (ApiCapabilities::ExecuteArbitraryCommand);
|
||||
|
||||
/**
|
||||
* Processes a new client connection.
|
||||
*
|
||||
|
@ -667,7 +669,8 @@ void ApiListener::NewClientHandlerInternal(
|
|||
{ "jsonrpc", "2.0" },
|
||||
{ "method", "icinga::Hello" },
|
||||
{ "params", new Dictionary({
|
||||
{ "version", (double)l_AppVersionInt }
|
||||
{ "version", (double)l_AppVersionInt },
|
||||
{ "capabilities", (double)l_MyCapabilities }
|
||||
}) }
|
||||
}), yc);
|
||||
|
||||
|
@ -705,7 +708,8 @@ void ApiListener::NewClientHandlerInternal(
|
|||
{ "jsonrpc", "2.0" },
|
||||
{ "method", "icinga::Hello" },
|
||||
{ "params", new Dictionary({
|
||||
{ "version", (double)l_AppVersionInt }
|
||||
{ "version", (double)l_AppVersionInt },
|
||||
{ "capabilities", (double)l_MyCapabilities }
|
||||
}) }
|
||||
}), yc);
|
||||
|
||||
|
@ -1643,6 +1647,7 @@ Value ApiListener::HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dicti
|
|||
|
||||
if (endpoint) {
|
||||
endpoint->SetIcingaVersion((double)params->Get("version"));
|
||||
endpoint->SetCapabilities((double)params->Get("capabilities"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
|
||||
namespace icinga
|
||||
|
@ -38,6 +39,35 @@ struct ConfigDirInformation
|
|||
Dictionary::Ptr Checksums;
|
||||
};
|
||||
|
||||
/**
|
||||
* If the version reported by icinga::Hello is not enough to tell whether
|
||||
* the peer has a specific capability, add the latter to this bitmask.
|
||||
*
|
||||
* Note that due to the capability exchange via JSON-RPC and the state storage via JSON
|
||||
* the bitmask numbers are stored in IEEE 754 64-bit floats.
|
||||
* The latter have 53 digit bits which limit the bitmask.
|
||||
* Not to run out of bits:
|
||||
*
|
||||
* Once all Icinga versions which don't have a specific capability are completely EOL,
|
||||
* remove the respective capability checks and assume the peer has the capability.
|
||||
* Once all Icinga versions which still check for the capability are completely EOL,
|
||||
* remove the respective bit from icinga::Hello.
|
||||
* Once all Icinga versions which still have the respective bit in icinga::Hello
|
||||
* are completely EOL, remove the bit here.
|
||||
* Once all Icinga versions which still have the respective bit here
|
||||
* are completely EOL, feel free to re-use the bit.
|
||||
*
|
||||
* completely EOL = not supported, even if an important customer of us used it and
|
||||
* not expected to appear in a multi-level cluster, e.g. a 4 level cluster with
|
||||
* v2.11 -> v2.10 -> v2.9 -> v2.8 - v2.7 isn't here
|
||||
*
|
||||
* @ingroup remote
|
||||
*/
|
||||
enum class ApiCapabilities : uint_fast64_t
|
||||
{
|
||||
ExecuteArbitraryCommand = 1u
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup remote
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
||||
|
||||
#include "base/configobject.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
library remote;
|
||||
|
||||
|
@ -24,6 +25,9 @@ class Endpoint : ConfigObject
|
|||
[state] "unsigned long" icinga_version {
|
||||
default {{{ return 0; }}}
|
||||
};
|
||||
[state] uint_fast64_t capabilities {
|
||||
default {{{ return 0; }}}
|
||||
};
|
||||
|
||||
[no_user_modify] bool connecting;
|
||||
[no_user_modify] bool syncing;
|
||||
|
|
Loading…
Reference in New Issue