mirror of https://github.com/Icinga/icinga2.git
Implemented state retention.
This commit is contained in:
parent
44b3de76c9
commit
709cd36e83
|
@ -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" />
|
||||
|
@ -51,14 +52,15 @@
|
|||
<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" />
|
||||
|
|
|
@ -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>
|
||||
|
@ -88,6 +85,12 @@
|
|||
<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">
|
||||
|
@ -111,9 +114,6 @@
|
|||
<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>
|
||||
|
@ -183,6 +183,12 @@
|
|||
<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">
|
||||
|
|
|
@ -21,12 +21,23 @@
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -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);
|
|
@ -75,7 +75,12 @@ public:
|
|||
operator long(void) const
|
||||
{
|
||||
if (m_Value.type() != typeid(long)) {
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "messagepart.h"
|
||||
#include "requestmessage.h"
|
||||
#include "responsemessage.h"
|
||||
#include "netstring.h"
|
||||
#include "jsonrpcclient.h"
|
||||
#include "jsonrpcserver.h"
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue