<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" />
<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">
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;
}
return m_Properties;
}
+void ConfigObject::SetTags(const Dictionary::Ptr& tags)
+{
+ m_Tags = tags;
+}
+
Dictionary::Ptr ConfigObject::GetTags(void) const
{
return m_Tags;
time_t ConfigObject::GetCommitTimestamp(void) const
{
- long value = false;
+ long value = 0;
GetProperties()->Get("__tx", &value);
return value;
}
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;
+ }
+ }
+}
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>
return GetProperties()->Get(key, value);
}
+ void SetTags(const Dictionary::Ptr& tags);
Dictionary::Ptr GetTags(void) const;
template<typename T>
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);
using std::deque;
using std::stringstream;
+using std::istream;
using std::ostream;
+using std::ifstream;
using std::ofstream;
using std::exception;
#include "ringbuffer.h"
#include "timer.h"
#include "ioqueue.h"
+#include "netstring.h"
#include "fifo.h"
#include "socket.h"
#include "tcpsocket.h"
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
-#include "i2-jsonrpc.h"
+#include "i2-base.h"
using 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);
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);
}
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)
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);
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
*/
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));
return EXIT_SUCCESS;
}
+void IcingaApplication::RetentionTimerHandler(void) {
+ ConfigObject::DumpObjects("retention.dat");
+}
+
void IcingaApplication::NewComponentHandler(const ConfigObject::Ptr& object)
{
/* don't allow replicated config objects */
time_t m_StartTime;
+ Timer::Ptr m_RetentionTimer;
+
+ void RetentionTimerHandler(void);
+
void NewComponentHandler(const ConfigObject::Ptr& object);
void DeletedComponentHandler(const ConfigObject::Ptr& object);
#include "messagepart.h"
#include "requestmessage.h"
#include "responsemessage.h"
-#include "netstring.h"
#include "jsonrpcclient.h"
#include "jsonrpcserver.h"
<ClInclude Include="responsemessage.h" />
<ClInclude Include="jsonrpcserver.h" />
<ClInclude Include="messagepart.h" />
- <ClInclude Include="netstring.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="i2-jsonrpc.cpp">
<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>
<ClCompile Include="messagepart.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
- <ClCompile Include="netstring.cpp">
- <Filter>Quelldateien</Filter>
- </ClCompile>
<ClCompile Include="requestmessage.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClInclude Include="messagepart.h">
<Filter>Headerdateien</Filter>
</ClInclude>
- <ClInclude Include="netstring.h">
- <Filter>Headerdateien</Filter>
- </ClInclude>
<ClInclude Include="requestmessage.h">
<Filter>Headerdateien</Filter>
</ClInclude>