Skip to content

Commit acd7195

Browse files
committed
ApiListener: Sync runtime configs in order
1 parent e55a78f commit acd7195

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

lib/remote/apilistener-configsync.cpp

+47-13
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
#include "remote/configobjectutility.hpp"
66
#include "remote/jsonrpc.hpp"
77
#include "base/configtype.hpp"
8-
#include "base/json.hpp"
98
#include "base/convert.hpp"
9+
#include "base/dependencygraph.hpp"
10+
#include "base/json.hpp"
1011
#include "config/vmops.hpp"
1112
#include "remote/configobjectslock.hpp"
1213
#include <fstream>
14+
#include <unordered_set>
1315

1416
using namespace icinga;
1517

@@ -393,6 +395,40 @@ void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const Mess
393395
}
394396
}
395397

398+
/**
399+
* Syncs the specified object and its direct and indirect parents to the provided client
400+
* in topological order of their dependency graph recursively.
401+
*
402+
* Objects that the client does not have access to are skipped without going through their dependency graph.
403+
*
404+
* Please do not use this method to forward remote generated cluster updates; it should only be used to
405+
* send local updates to that specific non-nullptr client.
406+
*
407+
* @param object The config object you want to sync.
408+
* @param azone The zone of the client you want to send the update to.
409+
* @param client The JsonRpc client you send the update to.
410+
* @param syncedObjects Used to cache the already synced objects.
411+
*/
412+
void ApiListener::UpdateConfigObjectWithParents(const ConfigObject::Ptr& object, const Zone::Ptr& azone,
413+
const JsonRpcConnection::Ptr& client, std::unordered_set<ConfigObject*>& syncedObjects)
414+
{
415+
if (syncedObjects.find(object.get()) != syncedObjects.end()) {
416+
return;
417+
}
418+
419+
/* don't sync objects for non-matching parent-child zones */
420+
if (!azone->CanAccessObject(object)) {
421+
return;
422+
}
423+
syncedObjects.emplace(object.get());
424+
425+
for (const auto& parent : DependencyGraph::GetParents(object)) {
426+
UpdateConfigObjectWithParents(parent, azone, client, syncedObjects);
427+
}
428+
429+
/* send the config object to the connected client */
430+
UpdateConfigObject(object, nullptr, client);
431+
}
396432

397433
void ApiListener::DeleteConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
398434
const JsonRpcConnection::Ptr& client)
@@ -454,19 +490,17 @@ void ApiListener::SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient
454490
Log(LogInformation, "ApiListener")
455491
<< "Syncing runtime objects to endpoint '" << endpoint->GetName() << "'.";
456492

493+
std::unordered_set<ConfigObject*> syncedObjects;
457494
for (const Type::Ptr& type : Type::GetAllTypes()) {
458-
auto *dtype = dynamic_cast<ConfigType *>(type.get());
459-
460-
if (!dtype)
461-
continue;
462-
463-
for (const ConfigObject::Ptr& object : dtype->GetObjects()) {
464-
/* don't sync objects for non-matching parent-child zones */
465-
if (!azone->CanAccessObject(object))
466-
continue;
467-
468-
/* send the config object to the connected client */
469-
UpdateConfigObject(object, nullptr, aclient);
495+
if (auto *ctype = dynamic_cast<ConfigType *>(type.get())) {
496+
for (const auto& object : ctype->GetObjects()) {
497+
// All objects must be synced sorted by their dependency graph.
498+
// Otherwise, downtimes/comments etc. might get synced before their respective Checkables, which will
499+
// result in comments and downtimes being ignored by the other endpoint since it does not yet know
500+
// about their checkables. Given that the runtime config updates event does not trigger a reload on the
501+
// remote endpoint, these objects won't be synced again until the next reload.
502+
UpdateConfigObjectWithParents(object, azone, aclient, syncedObjects);
503+
}
470504
}
471505
}
472506

lib/remote/apilistener.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ class ApiListener final : public ObjectImpl<ApiListener>
247247
/* configsync */
248248
void UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
249249
const JsonRpcConnection::Ptr& client = nullptr);
250+
void UpdateConfigObjectWithParents(const ConfigObject::Ptr& object, const Zone::Ptr& azone,
251+
const JsonRpcConnection::Ptr& client, std::unordered_set<ConfigObject*>& syncedObjects);
250252
void DeleteConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
251253
const JsonRpcConnection::Ptr& client = nullptr);
252254
void SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient);

0 commit comments

Comments
 (0)