mirror of https://github.com/Icinga/icinga2.git
Make sure the updated config sync works with old versions of Icinga 2
refs #11014
This commit is contained in:
parent
c6be1c90aa
commit
b7a152ef48
|
@ -32,7 +32,7 @@ using namespace icinga;
|
||||||
|
|
||||||
REGISTER_APIFUNCTION(Update, config, &ApiListener::ConfigUpdateHandler);
|
REGISTER_APIFUNCTION(Update, config, &ApiListener::ConfigUpdateHandler);
|
||||||
|
|
||||||
void ApiListener::ConfigGlobHandler(Dictionary::Ptr& config, const String& path, const String& file)
|
void ApiListener::ConfigGlobHandler(ConfigDirInformation& config, const String& path, const String& file)
|
||||||
{
|
{
|
||||||
CONTEXT("Creating config update for file '" + file + "'");
|
CONTEXT("Creating config update for file '" + file + "'");
|
||||||
|
|
||||||
|
@ -44,20 +44,46 @@ void ApiListener::ConfigGlobHandler(Dictionary::Ptr& config, const String& path,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
|
String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
|
||||||
config->Set(file.SubStr(path.GetLength()), content);
|
|
||||||
|
Dictionary::Ptr update;
|
||||||
|
|
||||||
|
if (Utility::Match("*.conf", file))
|
||||||
|
update = config.UpdateV1;
|
||||||
|
else
|
||||||
|
update = config.UpdateV2;
|
||||||
|
|
||||||
|
update->Set(file.SubStr(path.GetLength()), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr ApiListener::LoadConfigDir(const String& dir)
|
Dictionary::Ptr ApiListener::MergeConfigUpdate(const ConfigDirInformation& config)
|
||||||
{
|
{
|
||||||
Dictionary::Ptr config = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
|
|
||||||
|
if (config.UpdateV1)
|
||||||
|
config.UpdateV1->CopyTo(result);
|
||||||
|
|
||||||
|
if (config.UpdateV2)
|
||||||
|
config.UpdateV2->CopyTo(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigDirInformation ApiListener::LoadConfigDir(const String& dir)
|
||||||
|
{
|
||||||
|
ConfigDirInformation config;
|
||||||
|
config.UpdateV1 = new Dictionary();
|
||||||
|
config.UpdateV2 = new Dictionary();
|
||||||
Utility::GlobRecursive(dir, "*", boost::bind(&ApiListener::ConfigGlobHandler, boost::ref(config), dir, _1), GlobFile);
|
Utility::GlobRecursive(dir, "*", boost::bind(&ApiListener::ConfigGlobHandler, boost::ref(config), dir, _1), GlobFile);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApiListener::UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictionary::Ptr& newConfig, const String& configDir, bool authoritative)
|
bool ApiListener::UpdateConfigDir(const ConfigDirInformation& oldConfigInfo, const ConfigDirInformation& newConfigInfo, const String& configDir, bool authoritative)
|
||||||
{
|
{
|
||||||
bool configChange = false;
|
bool configChange = false;
|
||||||
|
|
||||||
|
Dictionary::Ptr oldConfig = MergeConfigUpdate(oldConfigInfo);
|
||||||
|
Dictionary::Ptr newConfig = MergeConfigUpdate(newConfigInfo);
|
||||||
|
|
||||||
double oldTimestamp;
|
double oldTimestamp;
|
||||||
|
|
||||||
if (!oldConfig->Contains(".timestamp"))
|
if (!oldConfig->Contains(".timestamp"))
|
||||||
|
@ -125,29 +151,43 @@ bool ApiListener::UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictio
|
||||||
|
|
||||||
void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
|
void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
|
||||||
{
|
{
|
||||||
Dictionary::Ptr newConfig = new Dictionary();
|
ConfigDirInformation newConfigInfo;
|
||||||
BOOST_FOREACH(const ZoneFragment& zf, ConfigCompiler::GetZoneDirs(zone->GetName())) {
|
newConfigInfo.UpdateV1 = new Dictionary();
|
||||||
Dictionary::Ptr newConfigPart = LoadConfigDir(zf.Path);
|
newConfigInfo.UpdateV2 = new Dictionary();
|
||||||
|
|
||||||
ObjectLock olock(newConfigPart);
|
BOOST_FOREACH(const ZoneFragment& zf, ConfigCompiler::GetZoneDirs(zone->GetName())) {
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, newConfigPart) {
|
ConfigDirInformation newConfigPart = LoadConfigDir(zf.Path);
|
||||||
newConfig->Set("/" + zf.Tag + kv.first, kv.second);
|
|
||||||
|
{
|
||||||
|
ObjectLock olock(newConfigPart.UpdateV1);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, newConfigPart.UpdateV1) {
|
||||||
|
newConfigInfo.UpdateV1->Set("/" + zf.Tag + kv.first, kv.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ObjectLock olock(newConfigPart.UpdateV2);
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, newConfigPart.UpdateV2) {
|
||||||
|
newConfigInfo.UpdateV2->Set("/" + zf.Tag + kv.first, kv.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newConfig->GetLength() == 0)
|
int sumUpdates = newConfigInfo.UpdateV1->GetLength() + newConfigInfo.UpdateV2->GetLength();
|
||||||
|
|
||||||
|
if (sumUpdates == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
|
String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
|
||||||
|
|
||||||
Log(LogInformation, "ApiListener")
|
Log(LogInformation, "ApiListener")
|
||||||
<< "Copying " << newConfig->GetLength() << " zone configuration files for zone '" << zone->GetName() << "' to '" << oldDir << "'.";
|
<< "Copying " << sumUpdates << " zone configuration files for zone '" << zone->GetName() << "' to '" << oldDir << "'.";
|
||||||
|
|
||||||
Utility::MkDirP(oldDir, 0700);
|
Utility::MkDirP(oldDir, 0700);
|
||||||
|
|
||||||
Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
|
ConfigDirInformation oldConfigInfo = LoadConfigDir(oldDir);
|
||||||
|
|
||||||
UpdateConfigDir(oldConfig, newConfig, oldDir, true);
|
UpdateConfigDir(oldConfigInfo, newConfigInfo, oldDir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiListener::SyncZoneDirs(void) const
|
void ApiListener::SyncZoneDirs(void) const
|
||||||
|
@ -173,7 +213,8 @@ void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient)
|
||||||
if (!azone->IsChildOf(lzone))
|
if (!azone->IsChildOf(lzone))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Dictionary::Ptr configUpdate = new Dictionary();
|
Dictionary::Ptr configUpdateV1 = new Dictionary();
|
||||||
|
Dictionary::Ptr configUpdateV2 = new Dictionary();
|
||||||
|
|
||||||
String zonesDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
|
String zonesDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
|
||||||
|
|
||||||
|
@ -195,11 +236,14 @@ void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient)
|
||||||
<< "Syncing " << (zone->IsGlobal() ? "global " : "")
|
<< "Syncing " << (zone->IsGlobal() ? "global " : "")
|
||||||
<< "zone '" << zone->GetName() << "' to endpoint '" << endpoint->GetName() << "'.";
|
<< "zone '" << zone->GetName() << "' to endpoint '" << endpoint->GetName() << "'.";
|
||||||
|
|
||||||
configUpdate->Set(zone->GetName(), LoadConfigDir(zonesDir + "/" + zone->GetName()));
|
ConfigDirInformation config = LoadConfigDir(zonesDir + "/" + zone->GetName());
|
||||||
|
configUpdateV1->Set(zone->GetName(), config.UpdateV1);
|
||||||
|
configUpdateV2->Set(zone->GetName(), config.UpdateV2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr params = new Dictionary();
|
Dictionary::Ptr params = new Dictionary();
|
||||||
params->Set("update", configUpdate);
|
params->Set("update", configUpdateV1);
|
||||||
|
params->Set("update_v2", configUpdateV2);
|
||||||
|
|
||||||
Dictionary::Ptr message = new Dictionary();
|
Dictionary::Ptr message = new Dictionary();
|
||||||
message->Set("jsonrpc", "2.0");
|
message->Set("jsonrpc", "2.0");
|
||||||
|
@ -227,12 +271,13 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
|
||||||
return Empty;
|
return Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr update = params->Get("update");
|
Dictionary::Ptr updateV1 = params->Get("update");
|
||||||
|
Dictionary::Ptr updateV2 = params->Get("update_v2");
|
||||||
|
|
||||||
bool configChange = false;
|
bool configChange = false;
|
||||||
|
|
||||||
ObjectLock olock(update);
|
ObjectLock olock(updateV1);
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, update) {
|
BOOST_FOREACH(const Dictionary::Pair& kv, updateV1) {
|
||||||
Zone::Ptr zone = Zone::GetByName(kv.first);
|
Zone::Ptr zone = Zone::GetByName(kv.first);
|
||||||
|
|
||||||
if (!zone) {
|
if (!zone) {
|
||||||
|
@ -251,10 +296,16 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
|
||||||
|
|
||||||
Utility::MkDirP(oldDir, 0700);
|
Utility::MkDirP(oldDir, 0700);
|
||||||
|
|
||||||
Dictionary::Ptr newConfig = kv.second;
|
ConfigDirInformation newConfigInfo;
|
||||||
Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
|
newConfigInfo.UpdateV1 = kv.second;
|
||||||
|
|
||||||
if (UpdateConfigDir(oldConfig, newConfig, oldDir, false))
|
if (updateV2)
|
||||||
|
newConfigInfo.UpdateV2 = updateV2->Get(kv.first);
|
||||||
|
|
||||||
|
Dictionary::Ptr newConfig = kv.second;
|
||||||
|
ConfigDirInformation oldConfigInfo = LoadConfigDir(oldDir);
|
||||||
|
|
||||||
|
if (UpdateConfigDir(oldConfigInfo, newConfigInfo, oldDir, false))
|
||||||
configChange = true;
|
configChange = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,15 @@ namespace icinga
|
||||||
|
|
||||||
class JsonRpcConnection;
|
class JsonRpcConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup remote
|
||||||
|
*/
|
||||||
|
struct ConfigDirInformation
|
||||||
|
{
|
||||||
|
Dictionary::Ptr UpdateV1;
|
||||||
|
Dictionary::Ptr UpdateV2;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup remote
|
* @ingroup remote
|
||||||
*/
|
*/
|
||||||
|
@ -129,13 +138,14 @@ private:
|
||||||
void ReplayLog(const JsonRpcConnection::Ptr& client);
|
void ReplayLog(const JsonRpcConnection::Ptr& client);
|
||||||
|
|
||||||
/* filesync */
|
/* filesync */
|
||||||
static Dictionary::Ptr LoadConfigDir(const String& dir);
|
static ConfigDirInformation LoadConfigDir(const String& dir);
|
||||||
static bool UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictionary::Ptr& newConfig, const String& configDir, bool authoritative);
|
static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config);
|
||||||
|
static bool UpdateConfigDir(const ConfigDirInformation& oldConfig, const ConfigDirInformation& newConfig, const String& configDir, bool authoritative);
|
||||||
|
|
||||||
void SyncZoneDirs(void) const;
|
void SyncZoneDirs(void) const;
|
||||||
void SyncZoneDir(const Zone::Ptr& zone) const;
|
void SyncZoneDir(const Zone::Ptr& zone) const;
|
||||||
|
|
||||||
static void ConfigGlobHandler(Dictionary::Ptr& config, const String& path, const String& file);
|
static void ConfigGlobHandler(ConfigDirInformation& config, const String& path, const String& file);
|
||||||
void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient);
|
void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient);
|
||||||
|
|
||||||
/* configsync */
|
/* configsync */
|
||||||
|
|
Loading…
Reference in New Issue