using namespace icinga;
-ConfigObject::ConfigObject(Dictionary::Ptr properties)
- : m_Properties(properties), m_Tags(make_shared<Dictionary>())
+ConfigObject::ConfigObject(Dictionary::Ptr properties, const ConfigObject::Set::Ptr& container)
+ : m_Container(container ? container : GetAllObjects()),
+ m_Properties(properties), m_Tags(make_shared<Dictionary>())
{ }
-ConfigObject::ConfigObject(string type, string name)
- : m_Properties(make_shared<Dictionary>()), m_Tags(make_shared<Dictionary>())
+ConfigObject::ConfigObject(string type, string name, const ConfigObject::Set::Ptr& container)
+ : m_Container(container ? container : GetAllObjects()),
+ m_Properties(make_shared<Dictionary>()), m_Tags(make_shared<Dictionary>())
{
SetProperty("__type", type);
SetProperty("__name", name);
ConfigObject::Ptr dobj = GetObject(GetType(), GetName());
ConfigObject::Ptr self = static_pointer_cast<ConfigObject>(shared_from_this());
assert(!dobj || dobj == self);
- GetAllObjects()->CheckObject(self);
+ m_Container->CheckObject(self);
}
void ConfigObject::Unregister(void)
{
ConfigObject::Ptr self = static_pointer_cast<ConfigObject>(shared_from_this());
- GetAllObjects()->RemoveObject(self);
+ m_Container->RemoveObject(self);
}
ObjectSet<ConfigObject::Ptr>::Ptr ConfigObject::GetAllObjects(void)
ConfigObject::TMap::Range ConfigObject::GetObjects(string type)
{
return GetObjectsByType()->GetRange(type);
-}
\ No newline at end of file
+}
typedef ObjectMap<string, ConfigObject::Ptr> TMap;
typedef ObjectSet<ConfigObject::Ptr> Set;
- ConfigObject(Dictionary::Ptr properties);
- ConfigObject(string type, string name);
+ ConfigObject(Dictionary::Ptr properties, const Set::Ptr& container = Set::Ptr());
+ ConfigObject(string type, string name, const Set::Ptr& container = Set::Ptr());
void SetProperties(Dictionary::Ptr config);
Dictionary::Ptr GetProperties(void) const;
static function<bool (ConfigObject::Ptr)> MakeTypePredicate(string type);
private:
+ Set::Ptr m_Container;
Dictionary::Ptr m_Properties;
Dictionary::Ptr m_Tags;
params.SetProperty("type", object->GetType());
if (includeProperties)
- params.SetProperty("properties", object);
+ params.SetProperty("properties", object->GetProperties());
return msg;
}
bool ConfigRpcComponent::ShouldReplicateObject(const ConfigObject::Ptr& object)
{
- long replicate;
- if (!object->GetProperty("replicate", &replicate))
- return true;
- return (replicate != 0);
+ return (!object->IsLocal());
}
int ConfigRpcComponent::FetchObjectsHandler(const NewRequestEventArgs& ea)
m_ConfigObject = dobj;
- dobj->Commit();
+ if (dobj->IsAbstract())
+ dobj->Unregister();
+ else
+ dobj->Commit();
ConfigItem::Ptr ci = GetObject(GetType(), GetName());
ConfigItem::Ptr self = static_pointer_cast<ConfigItem>(shared_from_this());
local object component "demo" {
}
+
+object host "localhost" {
+
+}
+
+abstract object service "nagios-service" {
+ check_type = "nagios",
+
+ macros = {
+ plugindir = "/usr/local/icinga/libexec"
+ }
+}
+
+abstract object service "ping" inherits "nagios-service" {
+ check_type = "nagios",
+ check_command = "$plugindir$/check_ping -H $address$"
+}
+
+object service "localhost-ping" inherits "ping" {
+ host_name = "localhost",
+
+ macros += {
+ address = "localhost"
+ }
+}
\ No newline at end of file
--- /dev/null
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+map<string, CheckTask::Factory> CheckTask::m_Types;
+
+void CheckTask::RegisterType(string type, Factory factory)
+{
+ m_Types[type] = factory;
+}
+
+CheckTask::Ptr CheckTask::CreateTask(const Service& service)
+{
+ map<string, CheckTask::Factory>::iterator it;
+
+ it = m_Types.find(service.GetCheckType());
+
+ if (it == m_Types.end())
+ throw runtime_error("Invalid check type specified for service '" + service.GetName() + "'");
+
+ return it->second(service);
+}
--- /dev/null
+#ifndef CHECKTASK_H
+#define CHECKTASK_H
+
+namespace icinga
+{
+
+enum CheckState
+{
+ StateOK,
+ StateWarning,
+ StateCritical,
+ StateUnreachable,
+ StateUncheckable,
+ StateUnknown
+};
+
+struct CheckResult
+{
+ time_t StartTime;
+ time_t EndTime;
+
+ CheckState State;
+ string Output;
+ Dictionary::Ptr PerformanceData;
+};
+
+class CheckTask : public Object
+{
+public:
+ typedef shared_ptr<CheckTask> Ptr;
+ typedef weak_ptr<CheckTask> WeakPtr;
+
+ typedef function<CheckTask::Ptr(const Service&)> Factory;
+
+ virtual CheckResult Execute(void) const = 0;
+
+ static void RegisterType(string type, Factory factory);
+ static CheckTask::Ptr CreateTask(const Service& service);
+
+private:
+ static map<string, Factory> m_Types;
+};
+
+}
+
+#endif /* CHECKTASK_H */
--- /dev/null
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+string ConfigObjectAdapter::GetType(void) const
+{
+ return m_ConfigObject->GetType();
+}
+
+string ConfigObjectAdapter::GetName(void) const
+{
+ return m_ConfigObject->GetName();
+}
+
+bool ConfigObjectAdapter::IsLocal(void) const
+{
+ return m_ConfigObject->IsLocal();
+}
+
+ConfigObject::Ptr ConfigObjectAdapter::GetConfigObject() const
+{
+ return m_ConfigObject;
+}
--- /dev/null
+#ifndef CONFIGOBJECTADAPTER_H
+#define CONFIGOBJECTADAPTER_H
+
+namespace icinga
+{
+
+class I2_ICINGA_API ConfigObjectAdapter
+{
+public:
+ ConfigObjectAdapter(const ConfigObject::Ptr& configObject)
+ : m_ConfigObject(configObject)
+ { }
+
+ string GetType(void) const;
+ string GetName(void) const;
+
+ bool IsLocal(void) const;
+
+protected:
+ ConfigObject::Ptr GetConfigObject() const;
+
+private:
+ ConfigObject::Ptr m_ConfigObject;
+};
+
+}
+
+#endif /* CONFIGOBJECTADAPTER_H */
\ No newline at end of file
--- /dev/null
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+string Host::GetDisplayName(void) const
+{
+ string value;
+
+ if (GetConfigObject()->GetProperty("displayname", &value))
+ return value;
+
+ return GetName();
+}
+
+Host Host::GetByName(string name)
+{
+ ConfigObject::Ptr configObject = ConfigObject::GetObject("host", name);
+
+ if (!configObject)
+ throw invalid_argument("Host '" + name + "' does not exist.");
+
+ return Host(configObject);
+}
--- /dev/null
+#ifndef HOST_H
+#define HOST_H
+
+namespace icinga
+{
+
+class I2_ICINGA_API Host : public ConfigObjectAdapter
+{
+public:
+ Host(const ConfigObject::Ptr& configObject)
+ : ConfigObjectAdapter(configObject)
+ { }
+
+ static Host GetByName(string name);
+
+ string GetDisplayName(void) const;
+};
+
+}
+
+#endif /* HOST_H */
#include "icingaapplication.h"
#include "icingacomponent.h"
+#include "configobjectadapter.h"
+#include "host.h"
+#include "service.h"
+
+#include "macroprocessor.h"
+#include "checktask.h"
+#include "nagioschecktask.h"
+
#endif /* I2ICINGA_H */
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="checktask.cpp" />
+ <ClCompile Include="configobjectadapter.cpp" />
<ClCompile Include="endpoint.cpp" />
<ClCompile Include="endpointmanager.cpp" />
+ <ClCompile Include="host.cpp" />
<ClCompile Include="icingaapplication.cpp" />
<ClCompile Include="icingacomponent.cpp" />
<ClCompile Include="jsonrpcendpoint.cpp" />
+ <ClCompile Include="macroprocessor.cpp" />
+ <ClCompile Include="nagioschecktask.cpp" />
+ <ClCompile Include="service.cpp" />
<ClCompile Include="virtualendpoint.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="checktask.h" />
+ <ClInclude Include="configobjectadapter.h" />
<ClInclude Include="endpoint.h" />
<ClInclude Include="endpointmanager.h" />
+ <ClInclude Include="host.h" />
<ClInclude Include="i2-icinga.h" />
<ClInclude Include="icingaapplication.h" />
<ClInclude Include="icingacomponent.h" />
<ClInclude Include="jsonrpcendpoint.h" />
+ <ClInclude Include="macroprocessor.h" />
+ <ClInclude Include="nagioschecktask.h" />
+ <ClInclude Include="service.h" />
<ClInclude Include="virtualendpoint.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
m_EndpointManager->SetSSLContext(sslContext);
}
+ CheckTask::RegisterType("nagios", NagiosCheckTask::CreateTask);
+
+ ConfigObject::TMap::Range range = ConfigObject::GetObjects("service");
+
+ for (ConfigObject::TMap::Iterator it = range.first; it != range.second; it++) {
+ ConfigObject::Ptr obj = it->second;
+
+ Service svc = Service(obj);
+ CheckTask::Ptr ct = CheckTask::CreateTask(svc);
+ CheckResult cr = ct->Execute();
+ }
+
/* create the primary RPC listener */
string service = GetService();
if (!service.empty())
/* don't allow replicated config objects */
if (!object->IsLocal())
- return 0;
+ throw runtime_error("'component' objects must be 'local'");
string path;
if (!object->GetProperty("path", &path)) {
--- /dev/null
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+string MacroProcessor::ResolveMacros(string str, Dictionary::Ptr macros)
+{
+ string::size_type offset, pos_first, pos_second;
+
+ offset = 0;
+
+ while ((pos_first = str.find_first_of('$', offset)) != string::npos) {
+ pos_second = str.find_first_of('$', pos_first + 1);
+
+ if (pos_second == string::npos)
+ throw runtime_error("Closing $ not found in macro format string.");
+
+ string name = str.substr(pos_first + 1, pos_second - pos_first - 1);
+ string value;
+ if (!macros || !macros->GetProperty(name, &value))
+ throw runtime_error("Macro '" + name + "' is not defined.");
+
+ str.replace(pos_first, pos_second - pos_first + 1, value);
+
+ offset = pos_first + value.size();
+ }
+
+ return str;
+}
--- /dev/null
+#ifndef MACROPROCESSOR_H
+#define MACROPROCESSOR_H
+
+namespace icinga
+{
+
+class MacroProcessor
+{
+public:
+ static string ResolveMacros(string str, Dictionary::Ptr macros);
+};
+
+}
+
+#endif /* MACROPROCESSOR_H */
\ No newline at end of file
--- /dev/null
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+NagiosCheckTask::NagiosCheckTask(const Service& service)
+{
+ string checkCommand = service.GetCheckCommand();
+ m_Command = MacroProcessor::ResolveMacros(checkCommand, service.GetMacros());
+}
+
+CheckResult NagiosCheckTask::Execute(void) const
+{
+ CheckResult cr;
+ FILE *fp;
+
+ time(&cr.StartTime);
+
+ string command = m_Command + " 2>&1";
+
+#ifdef _MSC_VER
+ fp = _popen(command.c_str(), "r");
+#else /* _MSC_VER */
+ fp = popen(command.c_str(), "r");
+#endif /* _MSC_VER */
+
+ stringstream output;
+
+ while (!feof(fp)) {
+ char buffer[128];
+ size_t read = fread(buffer, 1, sizeof(buffer), fp);
+
+ if (read == 0)
+ break;
+
+ output << string(buffer, buffer + read);
+ }
+
+ cr.Output = output.str();
+
+ int status, exitstatus;
+#ifdef _MSC_VER
+ status = _pclose(fp);
+#else /* _MSC_VER */
+ status = pclose(fp);
+#endif /* _MSC_VER */
+
+#ifndef _MSC_VER
+ if (WIFEXITED(status)) {
+ exitcode = WEXITSTATUS(status);
+#else /* _MSC_VER */
+ exitstatus = status;
+#endif /* _MSC_VER */
+
+ switch (exitstatus) {
+ case 0:
+ cr.State = StateOK;
+ break;
+ case 1:
+ cr.State = StateWarning;
+ break;
+ case 2:
+ cr.State = StateCritical;
+ break;
+ default:
+ cr.State = StateUnknown;
+ break;
+ }
+#ifndef _MSC_VER
+ } else if (WIFSIGNALED(status)) {
+ cr.Output = "Process was terminated by signal " + WTERMSIG(status);
+ cr.Status = StateUnknown;
+ }
+#endif /* _MSC_VER */
+
+ time(&cr.EndTime);
+
+ return cr;
+}
+
+CheckTask::Ptr NagiosCheckTask::CreateTask(const Service& service)
+{
+ assert(service.GetCheckType() == "nagios");
+
+ return make_shared<NagiosCheckTask>(service);
+}
--- /dev/null
+#ifndef NAGIOSCHECKTASK_H
+#define NAGIOSCHECKTASK_H
+
+namespace icinga
+{
+
+class NagiosCheckTask : public CheckTask
+{
+public:
+ NagiosCheckTask(const Service& service);
+
+ virtual CheckResult Execute(void) const;
+
+ static CheckTask::Ptr CreateTask(const Service& service);
+
+private:
+ string m_Command;
+};
+
+}
+
+#endif /* NAGIOSCHECKTASK_H */
--- /dev/null
+#include "i2-icinga.h"
+
+using namespace icinga;
+
+string Service::GetDisplayName(void) const
+{
+ string value;
+
+ if (GetConfigObject()->GetProperty("displayname", &value))
+ return value;
+
+ return GetName();
+}
+
+Host Service::GetHost(void) const
+{
+ string hostname;
+ if (!GetConfigObject()->GetProperty("host_name", &hostname))
+ throw runtime_error("Service object is missing the 'host_name' property.");
+
+ return Host::GetByName(hostname);
+}
+
+Dictionary::Ptr Service::GetMacros(void) const
+{
+ Dictionary::Ptr macros;
+ GetConfigObject()->GetProperty("macros", ¯os);
+ return macros;
+}
+
+string Service::GetCheckType(void) const
+{
+ string value = "nagios";
+ GetConfigObject()->GetProperty("check_type", &value);
+ return value;
+}
+
+string Service::GetCheckCommand(void) const
+{
+ string value;
+ GetConfigObject()->GetProperty("check_command", &value);
+ return value;
+}
+
+long Service::GetMaxCheckAttempts(void) const
+{
+ long value = 1;
+ GetConfigObject()->GetProperty("max_check_attempts", &value);
+ return value;
+}
+
+long Service::GetCheckInterval(void) const
+{
+ long value = 1;
+ GetConfigObject()->GetProperty("check_interval", &value);
+ return value;
+}
+
+long Service::GetRetryInterval(void) const
+{
+ long value = 1;
+ GetConfigObject()->GetProperty("retry_interval", &value);
+ return value;
+}
--- /dev/null
+#ifndef SERVICE_H
+#define SERVICE_H
+
+namespace icinga
+{
+
+class I2_ICINGA_API Service : public ConfigObjectAdapter
+{
+public:
+ Service(const ConfigObject::Ptr& configObject)
+ : ConfigObjectAdapter(configObject)
+ { }
+
+ string GetDisplayName(void) const;
+ Host GetHost(void) const;
+ Dictionary::Ptr GetMacros(void) const;
+ string GetCheckType(void) const;
+ string GetCheckCommand(void) const;
+ long GetMaxCheckAttempts(void) const;
+ long GetCheckInterval(void) const;
+ long GetRetryInterval(void) const;
+};
+
+}
+
+#endif /* SERVICE_H */
\ No newline at end of file