|
5 | 5 | #include "remote/configobjectutility.hpp"
|
6 | 6 | #include "remote/jsonrpc.hpp"
|
7 | 7 | #include "base/configtype.hpp"
|
8 |
| -#include "base/json.hpp" |
9 | 8 | #include "base/convert.hpp"
|
| 9 | +#include "base/dependencygraph.hpp" |
| 10 | +#include "base/json.hpp" |
10 | 11 | #include "config/vmops.hpp"
|
11 | 12 | #include "remote/configobjectslock.hpp"
|
12 | 13 | #include <fstream>
|
| 14 | +#include <unordered_set> |
13 | 15 |
|
14 | 16 | using namespace icinga;
|
15 | 17 |
|
@@ -393,6 +395,40 @@ void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const Mess
|
393 | 395 | }
|
394 | 396 | }
|
395 | 397 |
|
| 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 | +} |
396 | 432 |
|
397 | 433 | void ApiListener::DeleteConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
|
398 | 434 | const JsonRpcConnection::Ptr& client)
|
@@ -454,19 +490,17 @@ void ApiListener::SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient
|
454 | 490 | Log(LogInformation, "ApiListener")
|
455 | 491 | << "Syncing runtime objects to endpoint '" << endpoint->GetName() << "'.";
|
456 | 492 |
|
| 493 | + std::unordered_set<ConfigObject*> syncedObjects; |
457 | 494 | 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 | + } |
470 | 504 | }
|
471 | 505 | }
|
472 | 506 |
|
|
0 commit comments