mirror of https://github.com/Icinga/icinga2.git
Merge pull request #7584 from Icinga/bugfix/cluster-sync-checksums-timestamps
Cluster Config Sync: Check the timestamp prior to config file checksums for changes
This commit is contained in:
commit
3b49c10d0a
|
@ -229,6 +229,56 @@ void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient)
|
||||||
aclient->SendMessage(message);
|
aclient->SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool CompareTimestampsConfigChange(const Dictionary::Ptr& productionConfig, const Dictionary::Ptr& receivedConfig,
|
||||||
|
const String& stageConfigZoneDir)
|
||||||
|
{
|
||||||
|
double productionTimestamp;
|
||||||
|
double receivedTimestamp;
|
||||||
|
|
||||||
|
// Missing production timestamp means that something really broke. Always trigger a config change then.
|
||||||
|
if (!productionConfig->Contains("/.timestamp"))
|
||||||
|
productionTimestamp = 0;
|
||||||
|
else
|
||||||
|
productionTimestamp = productionConfig->Get("/.timestamp");
|
||||||
|
|
||||||
|
// Missing received config timestamp means that something really broke. Always trigger a config change then.
|
||||||
|
if (!receivedConfig->Contains("/.timestamp"))
|
||||||
|
receivedTimestamp = Utility::GetTime() + 10;
|
||||||
|
else
|
||||||
|
receivedTimestamp = receivedConfig->Get("/.timestamp");
|
||||||
|
|
||||||
|
bool configChange;
|
||||||
|
|
||||||
|
// Skip update if our configuration files are more recent.
|
||||||
|
if (productionTimestamp >= receivedTimestamp) {
|
||||||
|
|
||||||
|
Log(LogInformation, "ApiListener")
|
||||||
|
<< "Our production configuration is more recent than the received configuration update."
|
||||||
|
<< " Ignoring configuration file update for path '" << stageConfigZoneDir << "'. Current timestamp '"
|
||||||
|
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", productionTimestamp) << "' ("
|
||||||
|
<< std::fixed << std::setprecision(6) << productionTimestamp
|
||||||
|
<< ") >= received timestamp '"
|
||||||
|
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", receivedTimestamp) << "' ("
|
||||||
|
<< receivedTimestamp << ").";
|
||||||
|
|
||||||
|
configChange = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
configChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the .timestamp file inside the staging directory.
|
||||||
|
String tsPath = stageConfigZoneDir + "/.timestamp";
|
||||||
|
|
||||||
|
if (!Utility::PathExists(tsPath)) {
|
||||||
|
std::ofstream fp(tsPath.CStr(), std::ofstream::out | std::ostream::trunc);
|
||||||
|
fp << std::fixed << receivedTimestamp;
|
||||||
|
fp.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return configChange;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registered handler when a new config::Update message is received.
|
* Registered handler when a new config::Update message is received.
|
||||||
*
|
*
|
||||||
|
@ -360,11 +410,13 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
|
||||||
if (checksums) {
|
if (checksums) {
|
||||||
Log(LogInformation, "ApiListener")
|
Log(LogInformation, "ApiListener")
|
||||||
<< "Received configuration for zone '" << zoneName << "' from endpoint '"
|
<< "Received configuration for zone '" << zoneName << "' from endpoint '"
|
||||||
<< fromEndpointName << "'. Comparing the checksums.";
|
<< fromEndpointName << "'. Comparing the timestamp and checksums.";
|
||||||
|
|
||||||
|
if (CompareTimestampsConfigChange(productionConfig, newConfig, stageConfigZoneDir)) {
|
||||||
|
|
||||||
// TODO: Do this earlier in hello-handshakes?
|
|
||||||
if (CheckConfigChange(productionConfigInfo, newConfigInfo))
|
if (CheckConfigChange(productionConfigInfo, newConfigInfo))
|
||||||
configChange = true;
|
configChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Fallback to timestamp handling when the parent endpoint didn't send checks.
|
/* Fallback to timestamp handling when the parent endpoint didn't send checks.
|
||||||
|
@ -377,33 +429,7 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
|
||||||
<< "Received configuration update without checksums from parent endpoint "
|
<< "Received configuration update without checksums from parent endpoint "
|
||||||
<< fromEndpointName << ". This behaviour is deprecated. Please upgrade the parent endpoint to 2.11+";
|
<< fromEndpointName << ". This behaviour is deprecated. Please upgrade the parent endpoint to 2.11+";
|
||||||
|
|
||||||
double productionTimestamp;
|
if (CompareTimestampsConfigChange(productionConfig, newConfig, stageConfigZoneDir)) {
|
||||||
|
|
||||||
if (!productionConfig->Contains("/.timestamp"))
|
|
||||||
productionTimestamp = 0;
|
|
||||||
else
|
|
||||||
productionTimestamp = productionConfig->Get("/.timestamp");
|
|
||||||
|
|
||||||
double newTimestamp;
|
|
||||||
|
|
||||||
if (!newConfig->Contains("/.timestamp"))
|
|
||||||
newTimestamp = Utility::GetTime();
|
|
||||||
else
|
|
||||||
newTimestamp = newConfig->Get("/.timestamp");
|
|
||||||
|
|
||||||
// Skip update if our configuration files are more recent.
|
|
||||||
if (productionTimestamp >= newTimestamp) {
|
|
||||||
|
|
||||||
Log(LogInformation, "ApiListener")
|
|
||||||
<< "Our configuration is more recent than the received configuration update."
|
|
||||||
<< " Ignoring configuration file update for path '" << stageConfigZoneDir << "'. Current timestamp '"
|
|
||||||
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", productionTimestamp) << "' ("
|
|
||||||
<< std::fixed << std::setprecision(6) << productionTimestamp
|
|
||||||
<< ") >= received timestamp '"
|
|
||||||
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", newTimestamp) << "' ("
|
|
||||||
<< newTimestamp << ").";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
configChange = true;
|
configChange = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,14 +446,6 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the .timestamp file.
|
|
||||||
String tsPath = stageConfigZoneDir + "/.timestamp";
|
|
||||||
if (!Utility::PathExists(tsPath)) {
|
|
||||||
std::ofstream fp(tsPath.CStr(), std::ofstream::out | std::ostream::trunc);
|
|
||||||
fp << std::fixed << newTimestamp;
|
|
||||||
fp.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump the received configuration for this zone into the stage directory.
|
// Dump the received configuration for this zone into the stage directory.
|
||||||
|
@ -507,7 +525,7 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
|
||||||
} else {
|
} else {
|
||||||
Log(LogInformation, "ApiListener")
|
Log(LogInformation, "ApiListener")
|
||||||
<< "Received configuration updates (" << count << ") from endpoint '" << fromEndpointName
|
<< "Received configuration updates (" << count << ") from endpoint '" << fromEndpointName
|
||||||
<< "' are equal to production, not triggering reload.";
|
<< "' do not qualify for production, not triggering reload.";
|
||||||
}
|
}
|
||||||
|
|
||||||
return Empty;
|
return Empty;
|
||||||
|
|
Loading…
Reference in New Issue