]> granicus.if.org Git - icinga2/commitdiff
Implemented state retention.
authorGunnar Beutner <gunnar@beutner.name>
Tue, 24 Jul 2012 11:13:02 +0000 (13:13 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Tue, 24 Jul 2012 11:13:02 +0000 (13:13 +0200)
15 files changed:
base/base.vcxproj
base/base.vcxproj.filters
base/configobject.cpp
base/configobject.h
base/i2-base.h
base/netstring.cpp [moved from jsonrpc/netstring.cpp with 99% similarity]
base/netstring.h [moved from jsonrpc/netstring.h with 97% similarity]
base/variant.h
dyn/configcompiler.cpp
icinga.sln
icinga/icingaapplication.cpp
icinga/icingaapplication.h
jsonrpc/i2-jsonrpc.h
jsonrpc/jsonrpc.vcxproj
jsonrpc/jsonrpc.vcxproj.filters

index 7666a3368aec768537cec498bf766bb86a780187..3a93022b958279205711267a9eac4c09c2b25b73 100644 (file)
@@ -23,6 +23,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="logger.cpp" />
+    <ClCompile Include="netstring.cpp" />
     <ClCompile Include="object.cpp" />
     <ClCompile Include="objectmap.cpp" />
     <ClCompile Include="objectset.cpp" />
     <ClInclude Include="configobject.h" />
     <ClInclude Include="dictionary.h" />
     <ClInclude Include="event.h" />
+    <ClInclude Include="fifo.h" />
     <ClInclude Include="ioqueue.h" />
+    <ClInclude Include="netstring.h" />
     <ClInclude Include="scriptfunction.h" />
     <ClInclude Include="scripttask.h" />
     <ClInclude Include="logger.h" />
     <ClInclude Include="objectmap.h" />
     <ClInclude Include="objectset.h" />
     <ClInclude Include="exception.h" />
-    <ClInclude Include="fifo.h" />
     <ClInclude Include="i2-base.h" />
     <ClInclude Include="object.h" />
     <ClInclude Include="process.h" />
index fa329bab16c7f43190399220577ae554a70414b4..e4e5a5bad7a8de70338dc4faacab1bef3fb55eb3 100644 (file)
@@ -19,9 +19,6 @@
     <ClCompile Include="exception.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="fifo.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
     <ClCompile Include="object.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
     <ClCompile Include="i2-base.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
+    <ClCompile Include="fifo.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
+    <ClCompile Include="netstring.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="application.h">
     <ClInclude Include="exception.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="fifo.h">
-      <Filter>Headerdateien</Filter>
-    </ClInclude>
     <ClInclude Include="i2-base.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
     <ClInclude Include="ioqueue.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
+    <ClInclude Include="fifo.h">
+      <Filter>Headerdateien</Filter>
+    </ClInclude>
+    <ClInclude Include="netstring.h">
+      <Filter>Headerdateien</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="Quelldateien">
index 5647db12095d87212d5d580d1de8bc0b9483cc9b..6cc07e1d425b41f630e1ac548bdf13a255fcdb45 100644 (file)
 
 using namespace icinga;
 
+map<pair<string, string>, ConfigObject::Ptr> ConfigObject::m_RetainedObjects;
+
 ConfigObject::ConfigObject(Dictionary::Ptr properties, const ConfigObject::Set::Ptr& container)
        : m_Container(container ? container : GetAllObjects()),
        m_Properties(properties), m_Tags(boost::make_shared<Dictionary>())
-{ }
+{
+       /* restore the object's tags */
+       map<pair<string, string>, ConfigObject::Ptr>::iterator it;
+       it = m_RetainedObjects.find(make_pair(GetType(), GetName()));
+       if (it != m_RetainedObjects.end()) {
+               ConfigObject::Ptr retainedObject = it->second;
+               m_Tags = retainedObject->GetTags();
+               m_RetainedObjects.erase(it);
+       }
+}
 
-void ConfigObject::SetProperties(Dictionary::Ptr properties)
+void ConfigObject::SetProperties(const Dictionary::Ptr& properties)
 {
        m_Properties = properties;
 }
@@ -36,6 +47,11 @@ Dictionary::Ptr ConfigObject::GetProperties(void) const
        return m_Properties;
 }
 
+void ConfigObject::SetTags(const Dictionary::Ptr& tags)
+{
+       m_Tags = tags;
+}
+
 Dictionary::Ptr ConfigObject::GetTags(void) const
 {
        return m_Tags;
@@ -88,7 +104,7 @@ void ConfigObject::SetCommitTimestamp(time_t ts)
 
 time_t ConfigObject::GetCommitTimestamp(void) const
 {
-       long value = false;
+       long value = 0;
        GetProperties()->Get("__tx", &value);
        return value;
 }
@@ -215,3 +231,89 @@ ScriptTask::Ptr ConfigObject::InvokeMethod(const string& method,
 
        return task;
 }
+
+void ConfigObject::DumpObjects(const string& filename)
+{
+       Logger::Write(LogInformation, "base", "Dumping program state to file '" + filename + "'");
+
+       ofstream fp;
+       fp.open(filename.c_str());
+
+       if (!fp)
+               throw runtime_error("Could not open retention.dat file");
+
+       FIFO::Ptr fifo = boost::make_shared<FIFO>();
+
+       BOOST_FOREACH(const ConfigObject::Ptr object, ConfigObject::GetAllObjects()) {
+               Dictionary::Ptr persistentObject = boost::make_shared<Dictionary>();
+
+               persistentObject->Set("properties", object->GetProperties());
+               persistentObject->Set("tags", object->GetTags());
+
+               Variant value = persistentObject;
+               string json = value.Serialize();
+
+               /* This is quite ugly, unfortunatelly Netstring requires an IOQueue object */
+               Netstring::WriteStringToIOQueue(fifo.get(), json);
+
+               size_t count;
+               while ((count = fifo->GetAvailableBytes()) > 0) {
+                       char buffer[1024];
+                       
+                       if (count > sizeof(buffer))
+                               count = sizeof(buffer);
+
+                       fifo->Read(buffer, count);
+                       fp.write(buffer, count);
+               }
+       }
+}
+
+void ConfigObject::RestoreObjects(const string& filename)
+{
+       assert(GetAllObjects()->Begin() == GetAllObjects()->End());
+
+       Logger::Write(LogInformation, "base", "Restoring program state from file '" + filename + "'");
+
+       std::ifstream fp;
+       fp.open(filename.c_str());
+
+       /* TODO: Fix this horrible mess. */
+       FIFO::Ptr fifo = boost::make_shared<FIFO>();
+       while (fp) {
+               char buffer[1024];
+
+               fp.read(buffer, sizeof(buffer));
+               fifo->Write(buffer, fp.gcount());
+       }
+
+       string message;
+       while (Netstring::ReadStringFromIOQueue(fifo.get(), &message)) {
+               Variant value = Variant::Deserialize(message);
+
+               if (!value.IsObjectType<Dictionary>())
+                       throw runtime_error("JSON objects in the retention file must be dictionaries.");
+
+               Dictionary::Ptr persistentObject = value;
+
+               Dictionary::Ptr properties;
+               if (!persistentObject->Get("properties", &properties))
+                       continue;
+
+               Dictionary::Ptr tags;
+               if (!persistentObject->Get("tags", &tags))
+                       continue;
+
+               ConfigObject::Ptr object = boost::make_shared<ConfigObject>(properties);
+
+               if (!object->GetSource().empty()) {
+                       /* restore replicated objects right away */
+                       object->SetTags(tags);
+                       object->Commit();
+               } else {
+                       /* keep non-replicated objects until another config object with
+                        * the same name is created (which is when we restore its tags) */
+                       m_RetainedObjects[make_pair(object->GetType(), object->GetName())] = object;
+               }
+       }
+}
index 647f902badfe6f7b4a14aaff90f141368c6f000b..ca51d9fc9a19eed229258e8ef0f4c22fb877ee67 100644 (file)
@@ -40,7 +40,7 @@ public:
 
        ConfigObject(Dictionary::Ptr properties, const Set::Ptr& container = Set::Ptr());
 
-       void SetProperties(Dictionary::Ptr config);
+       void SetProperties(const Dictionary::Ptr& config);
        Dictionary::Ptr GetProperties(void) const;
 
        template<typename T>
@@ -49,6 +49,7 @@ public:
                return GetProperties()->Get(key, value);
        }
 
+       void SetTags(const Dictionary::Ptr& tags);
        Dictionary::Ptr GetTags(void) const;
 
        template<typename T>
@@ -93,11 +94,16 @@ public:
 
        static function<bool (ConfigObject::Ptr)> MakeTypePredicate(string type);
 
+       static void DumpObjects(const string& filename);
+       static void RestoreObjects(const string& filename);
+
 private:
        Set::Ptr m_Container;
        Dictionary::Ptr m_Properties;
        Dictionary::Ptr m_Tags;
 
+       static map<pair<string, string>, ConfigObject::Ptr> m_RetainedObjects;
+
        void SetCommitTimestamp(time_t ts);
 
        static bool TypeAndNameGetter(const ConfigObject::Ptr& object, pair<string, string> *key);
index 99e3991caae4c7aad16820ba71807aa7c7ff5e47..ffea1302106143d07b919377ffdcafc03835d10d 100644 (file)
@@ -100,7 +100,9 @@ using std::pair;
 using std::deque;
 
 using std::stringstream;
+using std::istream;
 using std::ostream;
+using std::ifstream;
 using std::ofstream;
 
 using std::exception;
@@ -171,6 +173,7 @@ namespace tuples = boost::tuples;
 #include "ringbuffer.h"
 #include "timer.h"
 #include "ioqueue.h"
+#include "netstring.h"
 #include "fifo.h"
 #include "socket.h"
 #include "tcpsocket.h"
similarity index 99%
rename from jsonrpc/netstring.cpp
rename to base/netstring.cpp
index c6dc8357371a1b23c8c7d6d649f9c30d1fe3b377..9f09b7f7877b7da64c44caccecd9a63603855371 100644 (file)
@@ -17,7 +17,7 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
  ******************************************************************************/
 
-#include "i2-jsonrpc.h"
+#include "i2-base.h"
 
 using namespace icinga;
 
similarity index 97%
rename from jsonrpc/netstring.h
rename to base/netstring.h
index 5cf1eea8fd73fed9f680fd081f06628089887f69..35d5b868134a600c0d495340ce2c2f5e178797f4 100644 (file)
@@ -28,9 +28,9 @@ namespace icinga
  *
  * @see http://cr.yp.to/proto/netstrings.txt
  *
- * @ingroup jsonrpc
+ * @ingroup base
  */
-class I2_JSONRPC_API Netstring
+class I2_BASE_API Netstring
 {
 public:
        static bool ReadStringFromIOQueue(IOQueue *queue, string *message);
index 4f0a4f956ec2c804f5e7ba44ce70af0b98547d43..a5c091295bd1359d4e2d43b8ffa89c70bd3a1b09 100644 (file)
@@ -75,7 +75,12 @@ public:
        operator long(void) const
        {
                if (m_Value.type() != typeid(long)) {
-                       return boost::lexical_cast<long>(m_Value);
+                       if (m_Value.type() == typeid(double)) {
+                               // TODO: log this?
+                               return boost::get<double>(m_Value);
+                       } else {
+                               return boost::lexical_cast<long>(m_Value);
+                       }
                } else {
                        return boost::get<long>(m_Value);
                }
@@ -109,6 +114,9 @@ public:
        template<typename T>
        operator shared_ptr<T>(void) const
        {
+               if (IsEmpty())
+                       return shared_ptr<T>();
+
                shared_ptr<T> object = dynamic_pointer_cast<T>(boost::get<Object::Ptr>(m_Value));
 
                if (!object)
index 85aa98a2acc2dc69a8d5d4f31b8a09a33716e6b7..b3d60ba72510063daa21e2a738ba564af627503e 100644 (file)
@@ -74,7 +74,7 @@ vector<ConfigItem::Ptr> ConfigCompiler::CompileFile(const string& path)
        ifstream stream;
        stream.open(path.c_str(), ifstream::in);
 
-       if (!stream.good())
+       if (!stream)
                throw_exception(invalid_argument("Could not open config file: " + path));
 
        Logger::Write(LogInformation, "dyn", "Compiling config file: " + path);
index fe869e5d21c6717fa3a7365a9a2327404e73cacd..0c71daecf8c4eb5c99255d8d6735853ae1cadfbb 100644 (file)
@@ -169,13 +169,13 @@ Global
                HideSolutionNode = FALSE
        EndGlobalSection
        GlobalSection(NestedProjects) = preSolution
-               {EAD41628-BB96-4F99-9070-8A9676801295} = {4A1773FD-DDED-4952-8700-C898E890554A}
                {2E6C1133-730F-4875-A72C-B455B1DD4C5C} = {4A1773FD-DDED-4952-8700-C898E890554A}
+               {EAD41628-BB96-4F99-9070-8A9676801295} = {4A1773FD-DDED-4952-8700-C898E890554A}
+               {38CE81CC-2660-4EF0-A936-4A337591DA3E} = {4A1773FD-DDED-4952-8700-C898E890554A}
                {17C93245-8C20-4316-9573-1AE41D918C10} = {4A1773FD-DDED-4952-8700-C898E890554A}
+               {704DDD8E-9E6D-4C22-80BD-6DE10F3A5E1C} = {4A1773FD-DDED-4952-8700-C898E890554A}
+               {2BD1C70C-43DB-4F44-B66B-67CF5C7044AA} = {4A1773FD-DDED-4952-8700-C898E890554A}
                {D02A349B-BAF7-41FB-86FF-B05BA05FE578} = {4A1773FD-DDED-4952-8700-C898E890554A}
                {E58F1DA7-B723-412B-B2B7-7FF58E2A944E} = {4A1773FD-DDED-4952-8700-C898E890554A}
-               {2BD1C70C-43DB-4F44-B66B-67CF5C7044AA} = {4A1773FD-DDED-4952-8700-C898E890554A}
-               {704DDD8E-9E6D-4C22-80BD-6DE10F3A5E1C} = {4A1773FD-DDED-4952-8700-C898E890554A}
-               {38CE81CC-2660-4EF0-A936-4A337591DA3E} = {4A1773FD-DDED-4952-8700-C898E890554A}
        EndGlobalSection
 EndGlobal
index 21d1132e0bd89dbb553e91fff8f91eec1bccbc21..2ade8c2d2c64800c58865046fc34d04e3ef14678 100644 (file)
@@ -42,6 +42,14 @@ IcingaApplication::IcingaApplication(void)
  */
 int IcingaApplication::Main(const vector<string>& args)
 {
+       /* restore the previous program state */
+       ConfigObject::RestoreObjects("retention.dat");
+
+       m_RetentionTimer = boost::make_shared<Timer>();
+       m_RetentionTimer->SetInterval(60);
+       m_RetentionTimer->OnTimerExpired.connect(boost::bind(&IcingaApplication::RetentionTimerHandler, this));
+       m_RetentionTimer->Start();
+
        /* register handler for 'log' config objects */
        static ConfigObject::Set::Ptr logObjects = boost::make_shared<ConfigObject::Set>(ConfigObject::GetAllObjects(), ConfigObject::MakeTypePredicate("log"));
        logObjects->OnObjectAdded.connect(boost::bind(&IcingaApplication::NewLogHandler, this, _2));
@@ -213,6 +221,10 @@ int IcingaApplication::Main(const vector<string>& args)
        return EXIT_SUCCESS;
 }
 
+void IcingaApplication::RetentionTimerHandler(void) {
+       ConfigObject::DumpObjects("retention.dat");
+}
+
 void IcingaApplication::NewComponentHandler(const ConfigObject::Ptr& object)
 {
        /* don't allow replicated config objects */
index dc40af1473feef784990c54261c2f6a3c536b274..d8f5a9540fd65b7d676124e8d1c8e0d3aba83942 100644 (file)
@@ -61,6 +61,10 @@ private:
 
        time_t m_StartTime;
 
+       Timer::Ptr m_RetentionTimer;
+
+       void RetentionTimerHandler(void);
+
        void NewComponentHandler(const ConfigObject::Ptr& object);
        void DeletedComponentHandler(const ConfigObject::Ptr& object);
 
index e7fcc15b56912dbe0dd8549a197d23ab56bdea53..d4d6df787558152e01202616f55dbd86c3160a06 100644 (file)
@@ -39,7 +39,6 @@
 #include "messagepart.h"
 #include "requestmessage.h"
 #include "responsemessage.h"
-#include "netstring.h"
 #include "jsonrpcclient.h"
 #include "jsonrpcserver.h"
 
index 095152f4e34f4c45a02b3f41481b5ad35984b5ac..e59e37dbd35dce1338acd986e1d969c8da320be1 100644 (file)
@@ -17,7 +17,6 @@
     <ClInclude Include="responsemessage.h" />
     <ClInclude Include="jsonrpcserver.h" />
     <ClInclude Include="messagepart.h" />
-    <ClInclude Include="netstring.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="i2-jsonrpc.cpp">
@@ -29,7 +28,6 @@
     <ClCompile Include="responsemessage.cpp" />
     <ClCompile Include="jsonrpcserver.cpp" />
     <ClCompile Include="messagepart.cpp" />
-    <ClCompile Include="netstring.cpp" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{8DD52FAC-ECEE-48C2-B266-E7C47ED485F8}</ProjectGuid>
index f2a1ea9d0734d8e903257f0a165fb843bcc3a8f7..8012b7ba554fc2d612870791afaa19ddfa4f592d 100644 (file)
@@ -13,9 +13,6 @@
     <ClCompile Include="messagepart.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="netstring.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
     <ClCompile Include="requestmessage.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
@@ -36,9 +33,6 @@
     <ClInclude Include="messagepart.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="netstring.h">
-      <Filter>Headerdateien</Filter>
-    </ClInclude>
     <ClInclude Include="requestmessage.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>