]> granicus.if.org Git - icinga2/commitdiff
Make sure the updated config sync works with old versions of Icinga 2
authorGunnar Beutner <gunnar@beutner.name>
Tue, 26 Jan 2016 09:46:27 +0000 (10:46 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Tue, 26 Jan 2016 09:46:27 +0000 (10:46 +0100)
refs #11014

lib/remote/apilistener-filesync.cpp
lib/remote/apilistener.hpp

index bc1d1110282ffea5ddce9ab45790c90f209b4292..dcb9af9b09ec616a3030ccc40facc62b2b4d50d9 100644 (file)
@@ -32,7 +32,7 @@ using namespace icinga;
 
 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 + "'");
 
@@ -44,20 +44,46 @@ void ApiListener::ConfigGlobHandler(Dictionary::Ptr& config, const String& path,
                return;
 
        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::MergeConfigUpdate(const ConfigDirInformation& config)
+{
+       Dictionary::Ptr result = new Dictionary();
+
+       if (config.UpdateV1)
+               config.UpdateV1->CopyTo(result);
+
+       if (config.UpdateV2)
+               config.UpdateV2->CopyTo(result);
+
+       return result;
 }
 
-Dictionary::Ptr ApiListener::LoadConfigDir(const String& dir)
+ConfigDirInformation ApiListener::LoadConfigDir(const String& dir)
 {
-       Dictionary::Ptr config = new Dictionary();
+       ConfigDirInformation config;
+       config.UpdateV1 = new Dictionary();
+       config.UpdateV2 = new Dictionary();
        Utility::GlobRecursive(dir, "*", boost::bind(&ApiListener::ConfigGlobHandler, boost::ref(config), dir, _1), GlobFile);
        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;
 
+       Dictionary::Ptr oldConfig = MergeConfigUpdate(oldConfigInfo);
+       Dictionary::Ptr newConfig = MergeConfigUpdate(newConfigInfo);
+
        double oldTimestamp;
 
        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
 {
-       Dictionary::Ptr newConfig = new Dictionary();
+       ConfigDirInformation newConfigInfo;
+       newConfigInfo.UpdateV1 = new Dictionary();
+       newConfigInfo.UpdateV2 = new Dictionary();
+
        BOOST_FOREACH(const ZoneFragment& zf, ConfigCompiler::GetZoneDirs(zone->GetName())) {
-               Dictionary::Ptr newConfigPart = LoadConfigDir(zf.Path);
+               ConfigDirInformation newConfigPart = LoadConfigDir(zf.Path);
 
-               ObjectLock olock(newConfigPart);
-               BOOST_FOREACH(const Dictionary::Pair& kv, newConfigPart) {
-                       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;
 
        String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
 
        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);
 
-       Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
+       ConfigDirInformation oldConfigInfo = LoadConfigDir(oldDir);
 
-       UpdateConfigDir(oldConfig, newConfig, oldDir, true);
+       UpdateConfigDir(oldConfigInfo, newConfigInfo, oldDir, true);
 }
 
 void ApiListener::SyncZoneDirs(void) const
@@ -173,7 +213,8 @@ void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient)
        if (!azone->IsChildOf(lzone))
                return;
 
-       Dictionary::Ptr configUpdate = new Dictionary();
+       Dictionary::Ptr configUpdateV1 = new Dictionary();
+       Dictionary::Ptr configUpdateV2 = new Dictionary();
 
        String zonesDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
 
@@ -190,11 +231,14 @@ void ApiListener::SendConfigUpdate(const JsonRpcConnection::Ptr& aclient)
                    << "Syncing " << (zone->IsGlobal() ? "global " : "")
                    << "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();
-       params->Set("update", configUpdate);
+       params->Set("update", configUpdateV1);
+       params->Set("update_v2", configUpdateV2);
 
        Dictionary::Ptr message = new Dictionary();
        message->Set("jsonrpc", "2.0");
@@ -222,12 +266,13 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
                return Empty;
        }
 
-       Dictionary::Ptr update = params->Get("update");
+       Dictionary::Ptr updateV1 = params->Get("update");
+       Dictionary::Ptr updateV2 = params->Get("update_v2");
 
        bool configChange = false;
 
-       ObjectLock olock(update);
-       BOOST_FOREACH(const Dictionary::Pair& kv, update) {
+       ObjectLock olock(updateV1);
+       BOOST_FOREACH(const Dictionary::Pair& kv, updateV1) {
                Zone::Ptr zone = Zone::GetByName(kv.first);
 
                if (!zone) {
@@ -246,10 +291,16 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
 
                Utility::MkDirP(oldDir, 0700);
 
+               ConfigDirInformation newConfigInfo;
+               newConfigInfo.UpdateV1 = kv.second;
+
+               if (updateV2)
+                       newConfigInfo.UpdateV2 = updateV2->Get(kv.first);
+
                Dictionary::Ptr newConfig = kv.second;
-               Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
+               ConfigDirInformation oldConfigInfo = LoadConfigDir(oldDir);
 
-               if (UpdateConfigDir(oldConfig, newConfig, oldDir, false))
+               if (UpdateConfigDir(oldConfigInfo, newConfigInfo, oldDir, false))
                        configChange = true;
        }
 
index f5fa65b80681e271af3471c71bfc8d75fb503e2c..3b02a3bb032f1f9a636eeaa6da5bcce1e3f7f61e 100644 (file)
@@ -37,6 +37,15 @@ namespace icinga
 
 class JsonRpcConnection;
 
+/**
+ * @ingroup remote
+ */
+struct ConfigDirInformation
+{
+       Dictionary::Ptr UpdateV1;
+       Dictionary::Ptr UpdateV2;
+};
+
 /**
 * @ingroup remote
 */
@@ -129,13 +138,14 @@ private:
        void ReplayLog(const JsonRpcConnection::Ptr& client);
 
        /* filesync */
-       static Dictionary::Ptr LoadConfigDir(const String& dir);
-       static bool UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictionary::Ptr& newConfig, const String& configDir, bool authoritative);
+       static ConfigDirInformation LoadConfigDir(const String& dir);
+       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 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);
 
        /* configsync */