diff --git a/base/base.vcxproj b/base/base.vcxproj
index 7666a3368..3a93022b9 100644
--- a/base/base.vcxproj
+++ b/base/base.vcxproj
@@ -23,6 +23,7 @@
Create
+
@@ -51,14 +52,15 @@
+
+
-
diff --git a/base/base.vcxproj.filters b/base/base.vcxproj.filters
index fa329bab1..e4e5a5bad 100644
--- a/base/base.vcxproj.filters
+++ b/base/base.vcxproj.filters
@@ -19,9 +19,6 @@
Quelldateien
-
- Quelldateien
-
Quelldateien
@@ -88,6 +85,12 @@
Quelldateien
+
+ Quelldateien
+
+
+ Quelldateien
+
@@ -111,9 +114,6 @@
Headerdateien
-
- Headerdateien
-
Headerdateien
@@ -183,6 +183,12 @@
Headerdateien
+
+ Headerdateien
+
+
+ Headerdateien
+
diff --git a/base/configobject.cpp b/base/configobject.cpp
index 5647db120..6cc07e1d4 100644
--- a/base/configobject.cpp
+++ b/base/configobject.cpp
@@ -21,12 +21,23 @@
using namespace icinga;
+map, 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())
-{ }
+{
+ /* restore the object's tags */
+ map, 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();
+
+ BOOST_FOREACH(const ConfigObject::Ptr object, ConfigObject::GetAllObjects()) {
+ Dictionary::Ptr persistentObject = boost::make_shared();
+
+ 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();
+ 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())
+ 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(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;
+ }
+ }
+}
diff --git a/base/configobject.h b/base/configobject.h
index 647f902ba..ca51d9fc9 100644
--- a/base/configobject.h
+++ b/base/configobject.h
@@ -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
@@ -49,6 +49,7 @@ public:
return GetProperties()->Get(key, value);
}
+ void SetTags(const Dictionary::Ptr& tags);
Dictionary::Ptr GetTags(void) const;
template
@@ -93,11 +94,16 @@ public:
static function 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, ConfigObject::Ptr> m_RetainedObjects;
+
void SetCommitTimestamp(time_t ts);
static bool TypeAndNameGetter(const ConfigObject::Ptr& object, pair *key);
diff --git a/base/i2-base.h b/base/i2-base.h
index 99e3991ca..ffea13021 100644
--- a/base/i2-base.h
+++ b/base/i2-base.h
@@ -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"
diff --git a/jsonrpc/netstring.cpp b/base/netstring.cpp
similarity index 99%
rename from jsonrpc/netstring.cpp
rename to base/netstring.cpp
index c6dc83573..9f09b7f78 100644
--- a/jsonrpc/netstring.cpp
+++ b/base/netstring.cpp
@@ -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;
diff --git a/jsonrpc/netstring.h b/base/netstring.h
similarity index 97%
rename from jsonrpc/netstring.h
rename to base/netstring.h
index 5cf1eea8f..35d5b8681 100644
--- a/jsonrpc/netstring.h
+++ b/base/netstring.h
@@ -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);
diff --git a/base/variant.h b/base/variant.h
index 4f0a4f956..a5c091295 100644
--- a/base/variant.h
+++ b/base/variant.h
@@ -75,7 +75,12 @@ public:
operator long(void) const
{
if (m_Value.type() != typeid(long)) {
- return boost::lexical_cast(m_Value);
+ if (m_Value.type() == typeid(double)) {
+ // TODO: log this?
+ return boost::get(m_Value);
+ } else {
+ return boost::lexical_cast(m_Value);
+ }
} else {
return boost::get(m_Value);
}
@@ -109,6 +114,9 @@ public:
template
operator shared_ptr(void) const
{
+ if (IsEmpty())
+ return shared_ptr();
+
shared_ptr object = dynamic_pointer_cast(boost::get(m_Value));
if (!object)
diff --git a/dyn/configcompiler.cpp b/dyn/configcompiler.cpp
index 85aa98a2a..b3d60ba72 100644
--- a/dyn/configcompiler.cpp
+++ b/dyn/configcompiler.cpp
@@ -74,7 +74,7 @@ vector 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);
diff --git a/icinga.sln b/icinga.sln
index fe869e5d2..0c71daecf 100644
--- a/icinga.sln
+++ b/icinga.sln
@@ -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
diff --git a/icinga/icingaapplication.cpp b/icinga/icingaapplication.cpp
index 21d1132e0..2ade8c2d2 100644
--- a/icinga/icingaapplication.cpp
+++ b/icinga/icingaapplication.cpp
@@ -42,6 +42,14 @@ IcingaApplication::IcingaApplication(void)
*/
int IcingaApplication::Main(const vector& args)
{
+ /* restore the previous program state */
+ ConfigObject::RestoreObjects("retention.dat");
+
+ m_RetentionTimer = boost::make_shared();
+ 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::GetAllObjects(), ConfigObject::MakeTypePredicate("log"));
logObjects->OnObjectAdded.connect(boost::bind(&IcingaApplication::NewLogHandler, this, _2));
@@ -213,6 +221,10 @@ int IcingaApplication::Main(const vector& 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 */
diff --git a/icinga/icingaapplication.h b/icinga/icingaapplication.h
index dc40af147..d8f5a9540 100644
--- a/icinga/icingaapplication.h
+++ b/icinga/icingaapplication.h
@@ -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);
diff --git a/jsonrpc/i2-jsonrpc.h b/jsonrpc/i2-jsonrpc.h
index e7fcc15b5..d4d6df787 100644
--- a/jsonrpc/i2-jsonrpc.h
+++ b/jsonrpc/i2-jsonrpc.h
@@ -39,7 +39,6 @@
#include "messagepart.h"
#include "requestmessage.h"
#include "responsemessage.h"
-#include "netstring.h"
#include "jsonrpcclient.h"
#include "jsonrpcserver.h"
diff --git a/jsonrpc/jsonrpc.vcxproj b/jsonrpc/jsonrpc.vcxproj
index 095152f4e..e59e37dbd 100644
--- a/jsonrpc/jsonrpc.vcxproj
+++ b/jsonrpc/jsonrpc.vcxproj
@@ -17,7 +17,6 @@
-
@@ -29,7 +28,6 @@
-
{8DD52FAC-ECEE-48C2-B266-E7C47ED485F8}
diff --git a/jsonrpc/jsonrpc.vcxproj.filters b/jsonrpc/jsonrpc.vcxproj.filters
index f2a1ea9d0..8012b7ba5 100644
--- a/jsonrpc/jsonrpc.vcxproj.filters
+++ b/jsonrpc/jsonrpc.vcxproj.filters
@@ -13,9 +13,6 @@
Quelldateien
-
- Quelldateien
-
Quelldateien
@@ -36,9 +33,6 @@
Headerdateien
-
- Headerdateien
-
Headerdateien