config::HaveObjects: send config::WantObjects if not up-to-date

refs #8210
This commit is contained in:
Alexander A. Klimov 2020-09-08 11:55:02 +02:00
parent ee211daf76
commit 61586ed6f2
2 changed files with 129 additions and 0 deletions

View File

@ -14,6 +14,7 @@ using namespace icinga;
REGISTER_APIFUNCTION(UpdateObject, config, &ApiListener::ConfigUpdateObjectAPIHandler);
REGISTER_APIFUNCTION(DeleteObject, config, &ApiListener::ConfigDeleteObjectAPIHandler);
REGISTER_APIFUNCTION(HaveObjects, config, &ApiListener::ConfigHaveObjectsAPIHandler);
INITIALIZE_ONCE([]() {
ConfigObject::OnActiveChanged.connect(&ApiListener::ConfigUpdateObjectHandler);
@ -194,6 +195,133 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
return Empty;
}
Value ApiListener::ConfigHaveObjectsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
{
Log(LogNotice, "ApiListener")
<< "Received information about runtime objects: " << JsonEncode(params);
/* check permissions */
ApiListener::Ptr listener = ApiListener::GetInstance();
if (!listener)
return Empty;
Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint();
String identity = origin->FromClient->GetIdentity();
/* discard messages if the client is not configured on this node */
if (!endpoint) {
Log(LogNotice, "ApiListener")
<< "Discarding 'config have objects' message from '" << identity << "': Invalid endpoint origin (client not allowed).";
return Empty;
}
Zone::Ptr endpointZone = endpoint->GetZone();
/* discard messages if the sender is in a child zone */
if (!Zone::GetLocalZone()->IsChildOf(endpointZone)) {
Log(LogNotice, "ApiListener")
<< "Discarding 'config have objects' message"
<< " from '" << identity << "' (endpoint: '" << endpoint->GetName() << "', zone: '" << endpointZone->GetName()
<< "'). Sender is in a child zone.";
return Empty;
}
/* ignore messages if the endpoint does not accept config */
if (!listener->GetAcceptConfig()) {
Log(LogWarning, "ApiListener")
<< "Ignoring information about runtime objects"
<< " from '" << identity << "' (endpoint: '" << endpoint->GetName() << "', zone: '" << endpointZone->GetName()
<< "'). '" << listener->GetName() << "' does not accept config.";
return Empty;
}
Dictionary::Ptr versions (params->Get("versions"));
Dictionary::Ptr want = new Dictionary();
ObjectLock oLock (versions);
for (auto& kv : versions) {
auto type (Type::GetByName(kv.first));
if (!type) {
Log(LogWarning, "ApiListener")
<< "Bad object type in information about runtime objects from '"
<< identity << "': '" << kv.first << "'";
continue;
}
auto ctype (dynamic_cast<ConfigType*>(type.get()));
if (!ctype) {
Log(LogWarning, "ApiListener")
<< "Bad object type in information about runtime objects from '"
<< identity << "': '" << kv.first << "'";
continue;
}
Dictionary::Ptr perType (kv.second);
ObjectLock oLock (perType);
for (auto& kv : perType) {
auto object (ctype->GetObject(kv.first));
if (object && object->GetVersion() >= (double)kv.second) {
Log(LogNotice, "ApiListener")
<< "Compared to the information about runtime objects from '" << identity << "' the "
<< type->GetName() << " '" << object->GetName() << "' is up-to-date.";
continue;
}
Log(LogNotice, "ApiListener")
<< "Compared to the information about runtime objects from '" << identity << "' the " << type->GetName()
<< " '" << kv.first << "' is " << (object ? "outdated" : "missing") << ".";
Array::Ptr perType = want->Get(type->GetName());
if (!perType) {
perType = new Array();
want->Set(type->GetName(), perType);
}
perType->Add(kv.first);
}
}
if (!want->GetLength()) {
Log(LogNotice, "ApiListener")
<< "Compared to the information about runtime objects from '" << identity << "' everything is up-to-date.";
return Empty;
}
JsonRpcConnection::Ptr client;
for (auto& conn : endpoint->GetClients()) {
client = conn;
break;
}
if (!client) {
Log(LogNotice, "ApiListener")
<< "Compared to the information about runtime objects from '" << identity
<< "' not everything is up-to-date, but '" << identity << "' is not connected.";
return Empty;
}
Log(LogInformation, "ApiListener")
<< "Compared to the information about runtime objects from '" << identity
<< "' not everything is up-to-date. Requesting updates.";
client->SendMessage(new Dictionary({
{ "jsonrpc", "2.0" },
{ "method", "config::WantObjects" },
{ "params", new Dictionary({
{ "objects", want }
}) }
}));
return Empty;
}
Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
{
Log(LogNotice, "ApiListener")

View File

@ -91,6 +91,7 @@ public:
static void ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie);
static Value ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
static Value ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
static Value ConfigHaveObjectsAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
/* API config packages */
void SetActivePackageStage(const String& package, const String& stage);