]> granicus.if.org Git - icinga2/commitdiff
Implement config object sync
authorGunnar Beutner <gunnar@beutner.name>
Thu, 20 Aug 2015 14:43:03 +0000 (16:43 +0200)
committerMichael Friedrich <michael.friedrich@netways.de>
Thu, 17 Sep 2015 12:20:43 +0000 (14:20 +0200)
Adds object version.

refs #9927

32 files changed:
icinga-app/icinga.cpp
lib/base/application-version.cpp
lib/base/application.cpp
lib/base/application.hpp
lib/base/configobject.cpp
lib/base/configobject.ti
lib/cli/consolecommand.cpp
lib/cli/daemoncommand.cpp
lib/cli/troubleshootcommand.cpp
lib/compat/statusdatawriter.cpp
lib/config/configitem.cpp
lib/config/configitem.hpp
lib/config/configwriter.cpp
lib/config/configwriter.hpp
lib/config/expression.cpp
lib/config/vmops.hpp
lib/db_ido/dbconnection.cpp
lib/db_ido_mysql/idomysqlconnection.cpp
lib/db_ido_pgsql/idopgsqlconnection.cpp
lib/icinga/icingaapplication.cpp
lib/livestatus/statustable.cpp
lib/methods/icingachecktask.cpp
lib/remote/CMakeLists.txt
lib/remote/apilistener-configsync.cpp [new file with mode: 0644]
lib/remote/apilistener-filesync.cpp [moved from lib/remote/apilistener-sync.cpp with 100% similarity]
lib/remote/apilistener.hpp
lib/remote/configobjectutility.cpp
lib/remote/configobjectutility.hpp
lib/remote/createobjecthandler.cpp
lib/remote/httprequest.cpp
lib/remote/httpresponse.cpp
lib/remote/jsonrpcconnection.cpp

index 12601381ee321c8c64c5d796b306ba8d3e6bd547..4542577092cdb6fc6a946969f1cf140fd07a1e0f 100644 (file)
@@ -321,7 +321,7 @@ int Main(void)
 
                        std::cout << appName << " " << "- The Icinga 2 network monitoring daemon (version: "
                            << ConsoleColorTag(vm.count("version") ? Console_ForegroundRed : Console_Normal)
-                           << Application::GetVersion()
+                           << Application::GetAppVersion()
 #ifdef I2_DEBUG
                            << "; debug"
 #endif /* I2_DEBUG */
@@ -384,10 +384,10 @@ int Main(void)
                Logger::DisableTimestamp(true);
 #ifndef _WIN32
                if (command->GetImpersonationLevel() == ImpersonateRoot) {
-                       if (getuid() != 0) {
+                       /*if (getuid() != 0) {
                                Log(LogCritical, "cli", "This command must be run as root.");
                                return 0;
-                       }
+                       }*/
                } else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) {
                        String group = Application::GetRunAsGroup();
                        String user = Application::GetRunAsUser();
index c13166e7fc120eb334c977295fc981de808194cd..6bc51004d0712bc2eee44247186913f83bfb1cee 100644 (file)
@@ -22,7 +22,7 @@
 
 using namespace icinga;
 
-String Application::GetVersion(void)
+String Application::GetAppVersion(void)
 {
        return VERSION;
 }
index ec62ad083ebfd09d47838475ecdf78f63bba3afe..afa2e66a3a12f623b5f8093c7c02e630090a6512 100644 (file)
@@ -591,7 +591,7 @@ void Application::DisplayInfoMessage(std::ostream& os, bool skipVersion)
        os << "Application information:" << "\n";
 
        if (!skipVersion)
-               os << "  Application version: " << GetVersion() << "\n";
+               os << "  Application version: " << GetAppVersion() << "\n";
 
        os << "  Installation root: " << GetPrefixDir() << "\n"
           << "  Sysconf directory: " << GetSysconfDir() << "\n"
index fe6472dbc44655fd881051ad93c7d4d95489e8b2..eeb8f9c3b6239a9a79978f9ea040845083766ae0 100644 (file)
@@ -129,7 +129,7 @@ public:
 
        static ThreadPool& GetTP(void);
 
-       static String GetVersion(void);
+       static String GetAppVersion(void);
 
        static double GetStartTime(void);
        static void SetStartTime(double ts);
index 1d895676c06692d271daa7bbe731f3875b27d5d5..8713360682542035f6e35042d85ac498cc8f945c 100644 (file)
@@ -184,6 +184,7 @@ void ConfigObject::ModifyAttribute(const String& attr, const Value& value)
        ValidateField(fid, newValue, utils);
 
        SetField(fid, newValue);
+       SetVersion(GetVersion() + 1);
 
        if (updated_original_attributes)
                NotifyOriginalAttributes();
index b7f60cb0d0f9aae50dafd5308498dd0fe1b7178a..1e4a3f83f7eec28f99976990b4c6d1e142451da9 100644 (file)
@@ -94,6 +94,9 @@ abstract class ConfigObject : ConfigObjectBase
 
        [protected] bool state_loaded;
        Dictionary::Ptr original_attributes;
+       [state] int version {
+               default {{{ return 1; }}}
+       };
 };
 
 }
index 7ba81664a0209e2a1395c66e99cca54ccdec9817..cea3f884deb262e677ca3370fb6e412bb70ce91b 100644 (file)
@@ -186,7 +186,7 @@ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector<std::stri
                scriptFrame.Sandboxed = true;
        }
 
-       std::cout << "Icinga (version: " << Application::GetVersion() << ")\n";
+       std::cout << "Icinga (version: " << Application::GetAppVersion() << ")\n";
 
        while (std::cin.good()) {
                String fileName = "<" + Convert::ToString(next_line) + ">";
index 7c9b6a625b32f4cb43c6c8caf2dd93755b071bdc..075b914749119ef28c81cc3446e99c561e30da4f 100644 (file)
@@ -209,7 +209,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
                Logger::DisableTimestamp(false);
 
        Log(LogInformation, "cli")
-           << "Icinga application loader (version: " << Application::GetVersion()
+           << "Icinga application loader (version: " << Application::GetAppVersion()
 #ifdef I2_DEBUG
            << "; debug"
 #endif /* I2_DEBUG */
index 8e63904d516351a18099d092eac7f766cc6d3cce..9a24051f313fabe11bbefc11fdb33b4333190172 100644 (file)
@@ -148,7 +148,7 @@ bool TroubleshootCommand::GeneralInfo(InfoLog& log, const boost::program_options
 
        //Application::DisplayInfoMessage() but formatted
        InfoLogLine(log)
-           << "\tApplication version: " << Application::GetVersion() << '\n'
+           << "\tApplication version: " << Application::GetAppVersion() << '\n'
            << "\tInstallation root: " << Application::GetPrefixDir() << '\n'
            << "\tSysconf directory: " << Application::GetSysconfDir() << '\n'
            << "\tRun directory: " << Application::GetRunDir() << '\n'
index 94f3e0477c828f359446147f212e7f8c2a219c77..af4b8a24c71028b8e64765700cf49ac6f2eb6758 100644 (file)
@@ -800,7 +800,7 @@ void StatusDataWriter::StatusTimerHandler(void)
 
        statusfp << "info {" "\n"
                    "\t" "created=" << Utility::GetTime() << "\n"
-                   "\t" "version=" << Application::GetVersion() << "\n"
+                   "\t" "version=" << Application::GetAppVersion() << "\n"
                    "\t" "}" "\n"
                    "\n";
 
index bd80809200abbe478427b16230b6e2776e51dfe4..3016752d7882b232bfbe8d6ffc092a05c932eec5 100644 (file)
@@ -115,6 +115,11 @@ Dictionary::Ptr ConfigItem::GetScope(void) const
        return m_Scope;
 }
 
+ConfigObject::Ptr ConfigItem::GetObject(void) const
+{
+       return m_Object;
+}
+
 /**
  * Retrieves the expression list for the configuration item.
  *
@@ -140,7 +145,7 @@ class DefaultValidationUtils : public ValidationUtils
 public:
        virtual bool ValidateName(const String& type, const String& name) const override
        {
-               return ConfigItem::GetObject(type, name) != ConfigItem::Ptr();
+               return ConfigItem::GetByTypeAndName(type, name) != ConfigItem::Ptr();
        }
 };
 
@@ -302,7 +307,7 @@ void ConfigItem::Unregister(void)
  * @param name The name of the ConfigItem that is to be looked up.
  * @returns The configuration item.
  */
-ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
+ConfigItem::Ptr ConfigItem::GetByTypeAndName(const String& type, const String& name)
 {
        boost::mutex::scoped_lock lock(m_Mutex);
 
index b69b828c469806f251147d511c81796c1d3ace6e..36b6264dff9f09107b844b7f546d2b548094cf4f 100644 (file)
@@ -61,7 +61,9 @@ public:
        DebugInfo GetDebugInfo(void) const;
        Dictionary::Ptr GetScope(void) const;
 
-       static ConfigItem::Ptr GetObject(const String& type,
+       ConfigObject::Ptr GetObject(void) const;
+       
+       static ConfigItem::Ptr GetByTypeAndName(const String& type,
            const String& name);
 
        static bool CommitItems(WorkQueue& upq);
index a113ad5ac946b6895d706f992816671c77ffb806..26dfe822a67694360b2a732bae613e408aa57eea 100644 (file)
 
 using namespace icinga;
 
-ConfigWriter::ConfigWriter(const String& fileName)
-    : m_FP(fileName.CStr(), std::ofstream::out | std::ostream::trunc)
-{ }
-
-void ConfigWriter::EmitBoolean(bool val)
+void ConfigWriter::EmitBoolean(std::ostream& fp, bool val)
 {
-       m_FP << (val ? "true" : "false");
+       fp << (val ? "true" : "false");
 }
 
-void ConfigWriter::EmitNumber(double val)
+void ConfigWriter::EmitNumber(std::ostream& fp, double val)
 {
-       m_FP << val;
+       fp << val;
 }
 
-void ConfigWriter::EmitString(const String& val)
+void ConfigWriter::EmitString(std::ostream& fp, const String& val)
 {
-       m_FP << "\"" << EscapeIcingaString(val) << "\"";
+       fp << "\"" << EscapeIcingaString(val) << "\"";
 }
 
-void ConfigWriter::EmitEmpty(void)
+void ConfigWriter::EmitEmpty(std::ostream& fp)
 {
-       m_FP << "null";
+       fp << "null";
 }
 
-void ConfigWriter::EmitArray(const Array::Ptr& val)
+void ConfigWriter::EmitArray(std::ostream& fp, const Array::Ptr& val)
 {
-       m_FP << "[ ";
-       EmitArrayItems(val);
-       m_FP << " ]";
+       fp << "[ ";
+       EmitArrayItems(fp, val);
+       fp << " ]";
 }
 
-void ConfigWriter::EmitArrayItems(const Array::Ptr& val)
+void ConfigWriter::EmitArrayItems(std::ostream& fp, const Array::Ptr& val)
 {
        bool first = true;
 
@@ -70,80 +66,82 @@ void ConfigWriter::EmitArrayItems(const Array::Ptr& val)
                if (first)
                        first = false;
                else
-                       m_FP << ", ";
+                       fp << ", ";
 
-               EmitValue(0, item);
+               EmitValue(fp, 0, item);
        }
 }
 
-void ConfigWriter::EmitScope(int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports)
+void ConfigWriter::EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports)
 {
-       m_FP << "{";
+       fp << "{";
 
        if (imports && imports->GetLength() > 0) {
                ObjectLock xlock(imports);
                BOOST_FOREACH(const Value& import, imports) {
-                       m_FP << "\n";
-                       EmitIndent(indentLevel);
-                       m_FP << "import \"" << import << "\"";
+                       fp << "\n";
+                       EmitIndent(fp, indentLevel);
+                       fp << "import \"" << import << "\"";
                }
 
-               m_FP << "\n";
+               fp << "\n";
        }
 
-       ObjectLock olock(val);
-       BOOST_FOREACH(const Dictionary::Pair& kv, val) {
-               m_FP << "\n";
-               EmitIndent(indentLevel);
-               
-               std::vector<String> tokens;
-               boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
-               
-               EmitIdentifier(tokens[0], true);
-               
-               for (std::vector<String>::size_type i = 1; i < tokens.size(); i++) {
-                       m_FP << "[";
-                       EmitString(tokens[i]);
-                       m_FP << "]";
+       if (val) {
+               ObjectLock olock(val);
+               BOOST_FOREACH(const Dictionary::Pair& kv, val) {
+                       fp << "\n";
+                       EmitIndent(fp, indentLevel);
+                       
+                       std::vector<String> tokens;
+                       boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
+                       
+                       EmitIdentifier(fp, tokens[0], true);
+                       
+                       for (std::vector<String>::size_type i = 1; i < tokens.size(); i++) {
+                               fp << "[";
+                               EmitString(fp, tokens[i]);
+                               fp << "]";
+                       }
+                       
+                       fp << " = ";
+                       EmitValue(fp, indentLevel + 1, kv.second);
                }
-               
-               m_FP << " = ";
-               EmitValue(indentLevel + 1, kv.second);
        }
 
-       m_FP << "\n";
-       EmitIndent(indentLevel - 1);
-       m_FP << "}";
+       fp << "\n";
+       EmitIndent(fp, indentLevel - 1);
+       fp << "}";
 }
 
-void ConfigWriter::EmitValue(int indentLevel, const Value& val)
+void ConfigWriter::EmitValue(std::ostream& fp, int indentLevel, const Value& val)
 {
        if (val.IsObjectType<Array>())
-               EmitArray(val);
+               EmitArray(fp, val);
        else if (val.IsObjectType<Dictionary>())
-               EmitScope(indentLevel, val);
+               EmitScope(fp, indentLevel, val);
        else if (val.IsString())
-               EmitString(val);
+               EmitString(fp, val);
        else if (val.IsNumber())
-               EmitNumber(val);
+               EmitNumber(fp, val);
        else if (val.IsBoolean())
-               EmitBoolean(val);
+               EmitBoolean(fp, val);
        else if (val.IsEmpty())
-               EmitEmpty();
+               EmitEmpty(fp);
 }
 
-void ConfigWriter::EmitRaw(const String& val)
+void ConfigWriter::EmitRaw(std::ostream& fp, const String& val)
 {
-       m_FP << val;
+       fp << val;
 }
 
-void ConfigWriter::EmitIndent(int indentLevel)
+void ConfigWriter::EmitIndent(std::ostream& fp, int indentLevel)
 {
        for (int i = 0; i < indentLevel; i++)
-               m_FP << "\t";
+               fp << "\t";
 }
 
-void ConfigWriter::EmitIdentifier(const String& identifier, bool inAssignment)
+void ConfigWriter::EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment)
 {
        static std::set<String> keywords;
        if (keywords.empty()) {
@@ -152,46 +150,46 @@ void ConfigWriter::EmitIdentifier(const String& identifier, bool inAssignment)
        }
 
        if (keywords.find(identifier) != keywords.end()) {
-               m_FP << "@" << identifier;
+               fp << "@" << identifier;
                return;
        }
 
        boost::regex expr("^[a-zA-Z_][a-zA-Z0-9\\_]*$");
        boost::smatch what;
        if (boost::regex_search(identifier.GetData(), what, expr))
-               m_FP << identifier;
+               fp << identifier;
        else if (inAssignment)
-               EmitString(identifier);
+               EmitString(fp, identifier);
        else
                BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid identifier"));
 }
 
-void ConfigWriter::EmitConfigItem(const String& type, const String& name, bool isTemplate,
+void ConfigWriter::EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate,
     const Array::Ptr& imports, const Dictionary::Ptr& attrs)
 {
        if (isTemplate)
-               m_FP << "template ";
+               fp << "template ";
        else
-               m_FP << "object ";
+               fp << "object ";
 
-       EmitIdentifier(type, false);
-       m_FP << " ";
-       EmitString(name);
-       m_FP << " ";
-       EmitScope(1, attrs, imports);
+       EmitIdentifier(fp, type, false);
+       fp << " ";
+       EmitString(fp, name);
+       fp << " ";
+       EmitScope(fp, 1, attrs, imports);
 }
 
-void ConfigWriter::EmitComment(const String& text)
+void ConfigWriter::EmitComment(std::ostream& fp, const String& text)
 {
-       m_FP << "/* " << text << " */\n";
+       fp << "/* " << text << " */\n";
 }
 
-void ConfigWriter::EmitFunctionCall(const String& name, const Array::Ptr& arguments)
+void ConfigWriter::EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments)
 {
-       EmitIdentifier(name, false);
-       m_FP << "(";
-       EmitArrayItems(arguments);
-       m_FP << ")";
+       EmitIdentifier(fp, name, false);
+       fp << "(";
+       EmitArrayItems(fp, arguments);
+       fp << ")";
 }
 
 String ConfigWriter::EscapeIcingaString(const String& str)
index 325ee53cdb49a1c73b11dc6ba5787b6e1149c60d..c7fa1bb8ee38d5ab8b3089616729cec24ed9ce61 100644 (file)
@@ -34,34 +34,30 @@ namespace icinga
  *
  * @ingroup config
  */
-class I2_CONFIG_API ConfigWriter : public Object
+class I2_CONFIG_API ConfigWriter
 {
 public:
-       DECLARE_PTR_TYPEDEFS(ConfigWriter);
+       static void EmitBoolean(std::ostream& fp, bool val);
+       static void EmitNumber(std::ostream& fp, double val);
+       static void EmitString(std::ostream& fp, const String& val);
+       static void EmitEmpty(std::ostream& fp);
+       static void EmitArray(std::ostream& fp, const Array::Ptr& val);
+       static void EmitArrayItems(std::ostream& fp, const Array::Ptr& val);
+       static void EmitDictionary(std::ostream& fp, const Dictionary::Ptr& val);
+       static void EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports = Array::Ptr());
+       static void EmitValue(std::ostream& fp, int indentLevel, const Value& val);
+       static void EmitRaw(std::ostream& fp, const String& val);
+       static void EmitIndent(std::ostream& fp, int indentLevel);
 
-       ConfigWriter(const String& fileName);
-
-       void EmitBoolean(bool val);
-       void EmitNumber(double val);
-       void EmitString(const String& val);
-       void EmitEmpty(void);
-       void EmitArray(const Array::Ptr& val);
-       void EmitArrayItems(const Array::Ptr& val);
-       void EmitDictionary(const Dictionary::Ptr& val);
-       void EmitScope(int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports = Array::Ptr());
-       void EmitValue(int indentLevel, const Value& val);
-       void EmitRaw(const String& val);
-       void EmitIndent(int indentLevel);
-
-       void EmitIdentifier(const String& identifier, bool inAssignment);
-       void EmitConfigItem(const String& type, const String& name, bool isTemplate,
+       static void EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment);
+       static void EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate,
            const Array::Ptr& imports, const Dictionary::Ptr& attrs);
 
-       void EmitComment(const String& text);
-       void EmitFunctionCall(const String& name, const Array::Ptr& arguments);
+       static void EmitComment(std::ostream& fp, const String& text);
+       static void EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments);
 
 private:
-       std::ofstream m_FP;
+       ConfigWriter(void);
 
        static String EscapeIcingaString(const String& str);
 };
index fcee207770c1848c4df2c5c3f9fbef0db26fd6a9..773a871a71bbfa32f012aa71947fe5141ee3d47d 100644 (file)
@@ -724,7 +724,7 @@ ExpressionResult ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhi
        if (!name.IsString())
                BOOST_THROW_EXCEPTION(ScriptError("Template/object name must be a string", m_DebugInfo));
 
-       ConfigItem::Ptr item = ConfigItem::GetObject(type, name);
+       ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, name);
 
        if (!item)
                BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo));
index f342ac0c4c801f86a6a011084d806e94421fc1e4..e4cde9f2669273023a32b1123c6ab30dd95872a4 100644 (file)
@@ -131,7 +131,7 @@ public:
                }
 
                if (!checkName.IsEmpty()) {
-                       ConfigItem::Ptr oldItem = ConfigItem::GetObject(type, checkName);
+                       ConfigItem::Ptr oldItem = ConfigItem::GetByTypeAndName(type, checkName);
 
                        if (oldItem) {
                                std::ostringstream msgbuf;
index 986995b1852f29a198873ff8de38014b12ffbecb..eca07b8027dba70b423c17bda4a601d73b856f8b 100644 (file)
@@ -141,7 +141,7 @@ void DbConnection::ProgramStatusHandler(void)
 
        query2.Fields = new Dictionary();
        query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
-       query2.Fields->Set("program_version", Application::GetVersion());
+       query2.Fields->Set("program_version", Application::GetAppVersion());
        query2.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
        query2.Fields->Set("program_start_time", DbValue::FromTimestamp(Application::GetStartTime()));
        query2.Fields->Set("is_currently_running", 1);
index 9071f81e5ba74ba7a0cd391698505308b6c7a2ca..7e9c2c1b82e22c29f1d26b374769e04eb80c6533 100644 (file)
@@ -331,7 +331,7 @@ void IdoMysqlConnection::Reconnect(void)
        /* record connection */
        Query("INSERT INTO " + GetTablePrefix() + "conninfo " +
            "(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES ("
-           + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), 'icinga2 db_ido_mysql', '" + Escape(Application::GetVersion())
+           + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), 'icinga2 db_ido_mysql', '" + Escape(Application::GetAppVersion())
            + "', '" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())");
 
        /* clear config tables for the initial config dump */
index 8b28930c9622fa0f3edf50db92c535911c5b3558..c9e171bf2a016cc8d59c8587d7537b21faf3ae9c 100644 (file)
@@ -323,7 +323,7 @@ void IdoPgsqlConnection::Reconnect(void)
                /* record connection */
                Query("INSERT INTO " + GetTablePrefix() + "conninfo " +
                    "(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES ("
-                   + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), E'icinga2 db_ido_pgsql', E'" + Escape(Application::GetVersion())
+                   + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), E'icinga2 db_ido_pgsql', E'" + Escape(Application::GetAppVersion())
                    + "', E'" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())");
 
                /* clear config tables for the initial config dump */
index 77d330dcf01b7b53770c0f10f2da31ce3ec01432..bba902fbb98b288d9c727eef19c4dc79c0404a6b 100644 (file)
@@ -81,7 +81,7 @@ void IcingaApplication::StatsFunc(const Dictionary::Ptr& status, const Array::Pt
                stats->Set("enable_perfdata", icingaapplication->GetEnablePerfdata());
                stats->Set("pid", Utility::GetPid());
                stats->Set("program_start", Application::GetStartTime());
-               stats->Set("version", Application::GetVersion());
+               stats->Set("version", Application::GetAppVersion());
 
                nodes->Set(icingaapplication->GetName(), stats);
        }
@@ -139,30 +139,33 @@ void IcingaApplication::OnShutdown(void)
        DumpProgramState();
 }
 
-static void PersistModAttrHelper(const ConfigWriter::Ptr& cw, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
+static void PersistModAttrHelper(std::ofstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
 {
        if (object != previousObject) {
-               if (previousObject)
-                       cw->EmitRaw("}\n\n");
+               if (previousObject) {
+                       ConfigWriter::EmitRaw(fp, "\tobj.version = ");
+                       ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
+                       ConfigWriter::EmitRaw(fp, "\n}\n\n");
+               }
 
-               cw->EmitRaw("var obj = ");
+               ConfigWriter::EmitRaw(fp, "var obj = ");
 
                Array::Ptr args1 = new Array();
                args1->Add(object->GetReflectionType()->GetName());
                args1->Add(object->GetName());
-               cw->EmitFunctionCall("get_object", args1);
+               ConfigWriter::EmitFunctionCall(fp, "get_object", args1);
 
-               cw->EmitRaw("\nif (obj) {\n");
+               ConfigWriter::EmitRaw(fp, "\nif (obj) {\n");
        }
 
-       cw->EmitRaw("\tobj.");
+       ConfigWriter::EmitRaw(fp, "\tobj.");
 
        Array::Ptr args2 = new Array();
        args2->Add(attr);
        args2->Add(value);
-       cw->EmitFunctionCall("modify_attribute", args2);
+       ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2);
 
-       cw->EmitRaw("\n");
+       ConfigWriter::EmitRaw(fp, "\n");
 
        previousObject = object;
 }
@@ -171,12 +174,16 @@ void IcingaApplication::DumpProgramState(void)
 {
        ConfigObject::DumpObjects(GetStatePath());
 
-       ConfigWriter::Ptr cw = new ConfigWriter(GetModAttrPath());
+       String path = GetModAttrPath();
+       std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc);
        ConfigObject::Ptr previousObject;
-       ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, cw, boost::ref(previousObject), _1, _2, _3));
+       ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, boost::ref(fp), boost::ref(previousObject), _1, _2, _3));
 
-       if (previousObject)
-               cw->EmitRaw("\n}\n");
+       if (previousObject) {
+               ConfigWriter::EmitRaw(fp, "\tobj.version = ");
+               ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
+               ConfigWriter::EmitRaw(fp, "\n}\n");
+       }
 }
 
 IcingaApplication::Ptr IcingaApplication::GetInstance(void)
index 1bcd6c305be7efeec4a3855dc657884fc36d3742..fea0c82daaad798aecc16e91471fb54398df5644 100644 (file)
@@ -217,12 +217,12 @@ Value StatusTable::NumServicesAccessor(const Value&)
 
 Value StatusTable::ProgramVersionAccessor(const Value&)
 {
-       return Application::GetVersion();
+       return Application::GetAppVersion();
 }
 
 Value StatusTable::LivestatusVersionAccessor(const Value&)
 {
-       return Application::GetVersion();
+       return Application::GetAppVersion();
 }
 
 Value StatusTable::LivestatusActiveConnectionsAccessor(const Value&)
index 5e2643db9da1388637c74e4b06545b43cfe0507b..fef332c0ce0321f57c799b9c69f4357f2a845a3d 100644 (file)
@@ -97,7 +97,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& service, const CheckResul
        perfdata->Add(new PerfdataValue("num_hosts_acknowledged", hs.hosts_acknowledged));
 
        cr->SetOutput("Icinga 2 has been running for " + Utility::FormatDuration(uptime) +
-           ". Version: " + Application::GetVersion());
+           ". Version: " + Application::GetAppVersion());
        cr->SetPerformanceData(perfdata);
        cr->SetState(ServiceOK);
 
index f52c39b7ead7aacd4fbf18399181ef84c737b2db..8e90966a4bf16d3f75bdce5468a2a743932034e3 100644 (file)
@@ -22,8 +22,8 @@ mkclass_target(zone.ti zone.tcpp zone.thpp)
 
 set(remote_SOURCES
   actionshandler.cpp apiaction.cpp
-  apifunction.cpp apilistener.cpp apilistener.thpp apilistener-sync.cpp
-  apiuser.cpp apiuser.thpp authority.cpp base64.cpp 
+  apifunction.cpp apilistener.cpp apilistener.thpp apilistener-configsync.cpp 
+  apilistener-filesync.cpp apiuser.cpp apiuser.thpp authority.cpp base64.cpp 
   configfileshandler.cpp configpackageshandler.cpp configpackageutility.cpp configobjectutility.cpp
   configstageshandler.cpp createobjecthandler.cpp deleteobjecthandler.cpp
   endpoint.cpp endpoint.thpp filterutility.cpp
diff --git a/lib/remote/apilistener-configsync.cpp b/lib/remote/apilistener-configsync.cpp
new file mode 100644 (file)
index 0000000..c3c44fd
--- /dev/null
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "remote/apilistener.hpp"
+#include "remote/apifunction.hpp"
+#include "remote/configobjectutility.hpp"
+#include "remote/jsonrpc.hpp"
+#include "base/configtype.hpp"
+#include "base/json.hpp"
+#include <fstream>
+
+using namespace icinga;
+
+INITIALIZE_ONCE(&ApiListener::StaticInitialize);
+
+REGISTER_APIFUNCTION(UpdateObject, config, &ApiListener::ConfigUpdateObjectAPIHandler);
+REGISTER_APIFUNCTION(DeleteObject, config, &ApiListener::ConfigDeleteObjectAPIHandler);
+
+
+void ApiListener::StaticInitialize(void)
+{
+       ConfigObject::OnActiveChanged.connect(&ApiListener::ConfigUpdateObjectHandler);
+       ConfigObject::OnVersionChanged.connect(&ApiListener::ConfigUpdateObjectHandler);
+}
+
+void ApiListener::ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie)
+{
+       ApiListener::Ptr listener = ApiListener::GetInstance();
+
+       if (!listener)
+               return;
+
+       if (object->IsActive()) {
+               /* Sync object config */
+               listener->UpdateConfigObject(object, cookie);
+       } else {
+               /* Delete object */
+       }
+}
+
+Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
+{
+       Log(LogWarning, "ApiListener")
+           << "Received update for object: " << JsonEncode(params);
+
+       ConfigType::Ptr dtype = ConfigType::GetByName(params->Get("type"));
+
+       if (!dtype) {
+               Log(LogCritical, "ApiListener")
+                   << "Config type '" << params->Get("type") << "' does not exist.";
+               return Empty;
+       }
+
+       ConfigObject::Ptr object = dtype->GetObject(params->Get("name"));
+
+       if (!object) {
+               Array::Ptr errors = new Array();
+               if (!ConfigObjectUtility::CreateObject(Type::GetByName(params->Get("type")),
+                   params->Get("name"), params->Get("config"), errors)) {
+                       Log(LogCritical, "ApiListener", "Could not create object:");
+
+                       ObjectLock olock(errors);
+                       BOOST_FOREACH(const String& error, errors) {
+                               Log(LogCritical, "ApiListener", error);
+                       }
+               }
+
+               //TODO-MA: modified attributes, same version
+       }
+
+       return Empty;
+}
+
+Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
+{
+       return Empty;
+}
+
+void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
+    const JsonRpcConnection::Ptr& client)
+{
+       if (object->GetPackage() != "_api")
+               return;
+
+       Dictionary::Ptr message = new Dictionary();
+       message->Set("jsonrpc", "2.0");
+       message->Set("method", "config::UpdateObject");
+
+       Dictionary::Ptr params = new Dictionary();
+       params->Set("name", object->GetName());
+       params->Set("type", object->GetType()->GetName());
+       params->Set("version", object->GetVersion());
+
+       String file = ConfigObjectUtility::GetObjectConfigPath(object->GetReflectionType(), object->GetName());
+
+       std::ifstream fp(file.CStr(), std::ifstream::binary);
+       if (!fp)
+               return;
+
+       String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
+       params->Set("config", content);
+
+       Dictionary::Ptr original_attributes = object->GetOriginalAttributes();
+       Dictionary::Ptr modified_attributes = new Dictionary();
+
+       if (original_attributes) {
+               ObjectLock olock(original_attributes);
+               BOOST_FOREACH(const Dictionary::Pair& kv, original_attributes) {
+                       int fid = object->GetReflectionType()->GetFieldId(kv.first);
+                       //TODO-MA: vars.os
+                       Value value = static_cast<Object::Ptr>(object)->GetField(fid);
+                       modified_attributes->Set(kv.first, value);
+               }
+       }
+
+       params->Set("modified_attributes", modified_attributes);
+
+       message->Set("params", params);
+
+       Log(LogWarning, "ApiListener")
+           << "Sent update for object: " << JsonEncode(params);
+
+       if (client)
+               JsonRpc::SendMessage(client->GetStream(), message);
+       else
+               RelayMessage(origin, object, message, false);
+}
index 4990b410181a9aaf03ee1e4b78f25a27016a7b80..a9a4dadb2bd48d48a004f1ffc0469b6445a97bff 100644 (file)
@@ -46,6 +46,8 @@ public:
        DECLARE_OBJECT(ApiListener);
        DECLARE_OBJECTNAME(ApiListener);
 
+       static void StaticInitialize(void);
+       
        static boost::signals2::signal<void(bool)> OnMasterChanged;
 
        ApiListener(void);
@@ -73,8 +75,14 @@ public:
        void RemoveHttpClient(const HttpServerConnection::Ptr& aclient);
        std::set<HttpServerConnection::Ptr> GetHttpClients(void) const;
 
+       /* filesync */
        static Value ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
-
+       
+       /* configsync */
+       static void ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie);
+       static Value ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
+       static Value ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
+       
        static Value HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
 protected:
        virtual void OnConfigLoaded(void) override;
@@ -121,6 +129,9 @@ private:
        static bool IsConfigMaster(const Zone::Ptr& zone);
        static void ConfigGlobHandler(Dictionary::Ptr& config, const String& path, const String& file);
        void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient);
+       
+       void UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
+           const JsonRpcConnection::Ptr& client = JsonRpcConnection::Ptr());
 };
 
 }
index 0ce87e89e1cac0f6907dd6ca4c356ec6ed1b2c07..e59868a74edbcde8e47ae69d03cb61adb17182b2 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "remote/configobjectutility.hpp"
 #include "remote/configpackageutility.hpp"
-#include "config/configitembuilder.hpp"
+#include "config/configcompiler.hpp"
 #include "config/configitem.hpp"
 #include "config/configwriter.hpp"
 #include "base/exception.hpp"
@@ -37,13 +37,22 @@ String ConfigObjectUtility::GetConfigDir(void)
            ConfigPackageUtility::GetActiveStage("_api");
 }
 
+String ConfigObjectUtility::GetObjectConfigPath(const Type::Ptr& type, const String& fullName)
+{
+       String typeDir = type->GetPluralName();
+       boost::algorithm::to_lower(typeDir);
+
+       return GetConfigDir() + "/conf.d/" + typeDir +
+           "/" + EscapeName(fullName) + ".conf";
+}
+
 String ConfigObjectUtility::EscapeName(const String& name)
 {
        return Utility::EscapeString(name, "<>:\"/\\|?*", true);
 }
 
-bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName,
-    const Array::Ptr& templates, const Dictionary::Ptr& attrs, const Array::Ptr& errors)
+String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const String& fullName,
+    const Array::Ptr& templates, const Dictionary::Ptr& attrs)
 {
        NameComposer *nc = dynamic_cast<NameComposer *>(type.get());
        Dictionary::Ptr nameParts;
@@ -55,48 +64,47 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
        } else
                name = fullName;
 
-       ConfigItemBuilder::Ptr builder = new ConfigItemBuilder();
-       builder->SetType(type->GetName());
-       builder->SetName(name);
-       builder->SetScope(ScriptGlobal::GetGlobals());
-       builder->SetPackage("_api");
-
-       if (templates) {
-               ObjectLock olock(templates);
-               BOOST_FOREACH(const String& tmpl, templates) {
-                       ImportExpression *expr = new ImportExpression(MakeLiteral(tmpl));
-                       builder->AddExpression(expr);
-               }
-       }
+       Dictionary::Ptr allAttrs = new Dictionary();
 
-       if (nameParts) {
-               ObjectLock olock(nameParts);
-               BOOST_FOREACH(const Dictionary::Pair& kv, nameParts) {
-                       SetExpression *expr = new SetExpression(MakeIndexer(ScopeThis, kv.first), OpSetLiteral, MakeLiteral(kv.second));
-                       builder->AddExpression(expr);
-               }
-       }
+       if (attrs)
+               attrs->CopyTo(allAttrs);
 
-       if (attrs) {
-               ObjectLock olock(attrs);
-               BOOST_FOREACH(const Dictionary::Pair& kv, attrs) {
-                       std::vector<String> tokens;
-                       boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
-                       
-                       Expression *expr = new GetScopeExpression(ScopeThis);
-                       
-                       BOOST_FOREACH(const String& val, tokens) {
-                               expr = new IndexerExpression(expr, MakeLiteral(val));
-                       }
-                       
-                       SetExpression *aexpr = new SetExpression(expr, OpSetLiteral, MakeLiteral(kv.second));
-                       builder->AddExpression(aexpr);
-               }
+       if (nameParts)
+               nameParts->CopyTo(allAttrs);
+
+       allAttrs->Remove("name");
+
+       std::ostringstream config;
+       ConfigWriter::EmitConfigItem(config, type->GetName(), name, false, templates, allAttrs);
+       ConfigWriter::EmitRaw(config, "\n");
+
+       return config.str();
+}
+
+bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName,
+    const String& config, const Array::Ptr& errors)
+{
+       if (!ConfigPackageUtility::PackageExists("_api")) {
+               ConfigPackageUtility::CreatePackage("_api");
+
+               String stage = ConfigPackageUtility::CreateStage("_api");
+               ConfigPackageUtility::ActivateStage("_api", stage);
        }
-       
+
+       String path = GetObjectConfigPath(type, fullName);
+       Utility::MkDirP(Utility::DirName(path), 0700);
+
+       std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc);
+       fp << config;
+       fp.close();
+
+       Expression *expr = ConfigCompiler::CompileFile(path, String(), "_api");
+
        try {
-               ConfigItem::Ptr item = builder->Compile();
-               item->Register();
+               ScriptFrame frame;
+               expr->Evaluate(frame);
+               delete expr;
+               expr = NULL;
 
                WorkQueue upq;
 
@@ -106,43 +114,18 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
                                        errors->Add(DiagnosticInformation(ex));
                                }
                        }
-                       
+
                        return false;
                }
        } catch (const std::exception& ex) {
+               delete expr;
+
                if (errors)
                        errors->Add(DiagnosticInformation(ex));
-                       
+
                return false;
        }
-       
-       if (!ConfigPackageUtility::PackageExists("_api")) {
-               ConfigPackageUtility::CreatePackage("_api");
-       
-               String stage = ConfigPackageUtility::CreateStage("_api");
-               ConfigPackageUtility::ActivateStage("_api", stage);
-       } 
-       
-       String typeDir = type->GetPluralName();
-       boost::algorithm::to_lower(typeDir);
-       
-       String path = GetConfigDir() + "/conf.d/" + typeDir;
-       Utility::MkDirP(path, 0700);
-
-       path += "/" + EscapeName(fullName) + ".conf";
-       
-       Dictionary::Ptr allAttrs = new Dictionary();
-       attrs->CopyTo(allAttrs);
-
-       if (nameParts)
-               nameParts->CopyTo(allAttrs);
 
-       allAttrs->Remove("name");
-
-       ConfigWriter::Ptr cw = new ConfigWriter(path);
-       cw->EmitConfigItem(type->GetName(), name, false, templates, allAttrs);
-       cw->EmitRaw("\n");
-       
        return true;
 }
 
@@ -168,7 +151,7 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
 
        Type::Ptr type = object->GetReflectionType();
 
-       ConfigItem::Ptr item = ConfigItem::GetObject(type->GetName(), object->GetName());
+       ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type->GetName(), object->GetName());
 
        try {
                object->Deactivate();
@@ -181,16 +164,12 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
        } catch (const std::exception& ex) {
                if (errors)
                        errors->Add(DiagnosticInformation(ex));
-                       
+
                return false;
        }
 
-       String typeDir = type->GetPluralName();
-       boost::algorithm::to_lower(typeDir);
-       
-       String path = GetConfigDir() + "/conf.d/" + typeDir +
-           "/" + EscapeName(object->GetName()) + ".conf";
-       
+       String path = GetObjectConfigPath(object->GetReflectionType(), object->GetName());
+
        if (Utility::PathExists(path)) {
                if (unlink(path.CStr()) < 0) {
                        BOOST_THROW_EXCEPTION(posix_error()
index f52ec8f7de33154dbb5912f1ff5ea2e67a949878..a8ff679222541c56c6e1be3267b33e7f086d0962 100644 (file)
@@ -39,10 +39,13 @@ class I2_REMOTE_API ConfigObjectUtility
 
 public:
        static String GetConfigDir(void);
+       static String GetObjectConfigPath(const Type::Ptr& type, const String& fullName);
        
+       static String CreateObjectConfig(const Type::Ptr& type, const String& fullName,
+            const Array::Ptr& templates, const Dictionary::Ptr& attrs);
+            
        static bool CreateObject(const Type::Ptr& type, const String& fullName,
-           const Array::Ptr& templates, const Dictionary::Ptr& attrs,
-           const Array::Ptr& errors);
+            const String& config, const Array::Ptr& errors);
            
        static bool DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors);
        
index 28fdc4385aa5cd15e0fd81f7291ad024c70bb73b..7e22e85fb7199757e9ae8152150b2a5e0727c3bf 100644 (file)
@@ -52,7 +52,9 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
        String status;
        Array::Ptr errors = new Array();
        
-       if (!ConfigObjectUtility::CreateObject(type, name, templates, attrs, errors)) {
+       String config = ConfigObjectUtility::CreateObjectConfig(type, name, templates, attrs);
+       
+       if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) {
                result1->Set("errors", errors);
                code = 500;
                status = "Object could not be created.";
index 28634563fdeec16471de4b4394d52301dd2d9c60..c2c8f116f77d02eb6919a52021be4cda97de9fee 100644 (file)
@@ -171,7 +171,7 @@ void HttpRequest::FinishHeaders(void)
        }
 
        if (m_State == HttpRequestHeaders) {
-               AddHeader("User-Agent", "Icinga/" + Application::GetVersion());
+               AddHeader("User-Agent", "Icinga/" + Application::GetAppVersion());
 
                if (ProtocolVersion == HttpVersion11)
                        AddHeader("Transfer-Encoding", "chunked");
index fdd5d663dc2d82f37df964d10e30a7eccad30734..f3fe6a790f0800d7ccabfd3a7497c95683d39f5b 100644 (file)
@@ -65,7 +65,7 @@ void HttpResponse::FinishHeaders(void)
                if (m_Request.ProtocolVersion == HttpVersion11)
                        AddHeader("Transfer-Encoding", "chunked");
  
-               AddHeader("Server", "Icinga/" + Application::GetVersion());
+               AddHeader("Server", "Icinga/" + Application::GetAppVersion());
                m_Stream->Write("\r\n", 2);
                m_State = HttpResponseBody;
        }
index 6d67e10e6253647fe5fd69242aa58109abebb3fa..7a0be8a5df4229c65d0f076749cb530fef84c250 100644 (file)
@@ -104,8 +104,6 @@ void JsonRpcConnection::SendMessageSync(const Dictionary::Ptr& message)
                std::ostringstream info;
                info << "Error while sending JSON-RPC message for identity '" << m_Identity << "'";
                Log(LogWarning, "JsonRpcConnection")
-                   << info.str();
-               Log(LogDebug, "JsonRpcConnection")
                    << info.str() << "\n" << DiagnosticInformation(ex);
 
                Disconnect();
@@ -181,8 +179,6 @@ bool JsonRpcConnection::ProcessMessage(void)
                std::ostringstream info;
                info << "Error while processing message for identity '" << m_Identity << "'";
                Log(LogWarning, "JsonRpcConnection")
-                   << info.str();
-               Log(LogDebug, "JsonRpcConnection")
                    << info.str() << "\n" << DiagnosticInformation(ex);
        }