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