mirror of https://github.com/Icinga/icinga2.git
Refactored Application class to use DynamicObject as a base class.
This commit is contained in:
parent
8b87e30197
commit
160219f4d3
|
@ -18,13 +18,14 @@
|
|||
******************************************************************************/
|
||||
|
||||
#include "i2-base.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <ltdl.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
Application::Ptr Application::m_Instance;
|
||||
Application *Application::m_Instance = NULL;
|
||||
bool Application::m_ShuttingDown = false;
|
||||
bool Application::m_Debugging = false;
|
||||
boost::thread::id Application::m_MainThreadID;
|
||||
|
@ -32,9 +33,12 @@ boost::thread::id Application::m_MainThreadID;
|
|||
/**
|
||||
* Constructor for the Application class.
|
||||
*/
|
||||
Application::Application(void)
|
||||
: m_PidFile(NULL)
|
||||
Application::Application(const Dictionary::Ptr& serializedUpdate)
|
||||
: DynamicObject(serializedUpdate), m_PidFile(NULL)
|
||||
{
|
||||
if (!IsLocal())
|
||||
throw_exception(runtime_error("Application objects must be local."));
|
||||
|
||||
#ifdef _WIN32
|
||||
/* disable GUI-based error messages for LoadLibrary() */
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
@ -42,8 +46,6 @@ Application::Application(void)
|
|||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
|
||||
throw_exception(Win32Exception("WSAStartup failed", WSAGetLastError()));
|
||||
#else /* _WIN32 */
|
||||
lt_dlinit();
|
||||
#endif /* _WIN32 */
|
||||
|
||||
char *debugging = getenv("_DEBUG");
|
||||
|
@ -53,6 +55,9 @@ Application::Application(void)
|
|||
if (IsDebuggerPresent())
|
||||
m_Debugging = true;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
assert(m_Instance == NULL);
|
||||
m_Instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,6 +65,8 @@ Application::Application(void)
|
|||
*/
|
||||
Application::~Application(void)
|
||||
{
|
||||
m_Instance = NULL;
|
||||
|
||||
m_ShuttingDown = true;
|
||||
|
||||
DynamicObject::DeactivateObjects();
|
||||
|
@ -78,7 +85,10 @@ Application::~Application(void)
|
|||
*/
|
||||
Application::Ptr Application::GetInstance(void)
|
||||
{
|
||||
return m_Instance;
|
||||
if (m_Instance)
|
||||
return m_Instance->GetSelf();
|
||||
else
|
||||
return Application::Ptr();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,20 +140,14 @@ void Application::Shutdown(void)
|
|||
/**
|
||||
* Retrieves the full path of the executable.
|
||||
*
|
||||
* @param argv0 The first command-line argument.
|
||||
* @returns The path.
|
||||
*/
|
||||
String Application::GetExePath(void) const
|
||||
String Application::GetExePath(const String& argv0)
|
||||
{
|
||||
static String result;
|
||||
|
||||
if (!result.IsEmpty())
|
||||
return result;
|
||||
|
||||
String executablePath;
|
||||
|
||||
#ifndef _WIN32
|
||||
String argv0 = m_Arguments[0];
|
||||
|
||||
char buffer[MAXPATHLEN];
|
||||
if (getcwd(buffer, sizeof(buffer)) == NULL)
|
||||
throw_exception(PosixException("getcwd failed", errno));
|
||||
|
@ -189,17 +193,15 @@ String Application::GetExePath(void) const
|
|||
if (realpath(executablePath.CStr(), buffer) == NULL)
|
||||
throw_exception(PosixException("realpath failed", errno));
|
||||
|
||||
result = buffer;
|
||||
return buffer;
|
||||
#else /* _WIN32 */
|
||||
char FullExePath[MAXPATHLEN];
|
||||
|
||||
if (!GetModuleFileName(NULL, FullExePath, sizeof(FullExePath)))
|
||||
throw_exception(Win32Exception("GetModuleFileName() failed", GetLastError()));
|
||||
|
||||
result = FullExePath;
|
||||
return FullExePath;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,6 +219,11 @@ bool Application::IsMainThread(void)
|
|||
return (boost::this_thread::get_id() == m_MainThreadID);
|
||||
}
|
||||
|
||||
void Application::SetMainThread(void)
|
||||
{
|
||||
m_MainThreadID = boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* Signal handler for SIGINT. Prepares the application for cleanly
|
||||
|
@ -270,12 +277,6 @@ int Application::Run(int argc, char **argv)
|
|||
{
|
||||
int result;
|
||||
|
||||
assert(!Application::m_Instance);
|
||||
|
||||
m_MainThreadID = boost::this_thread::get_id();
|
||||
|
||||
Application::m_Instance = GetSelf();
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
|
@ -294,28 +295,24 @@ int Application::Run(int argc, char **argv)
|
|||
|
||||
DynamicObject::BeginTx();
|
||||
|
||||
if (IsDebugging()) {
|
||||
try {
|
||||
result = Main(m_Arguments);
|
||||
|
||||
Application::m_Instance.reset();
|
||||
} else {
|
||||
try {
|
||||
result = Main(m_Arguments);
|
||||
DynamicObject::FinishTx();
|
||||
DynamicObject::DeactivateObjects();
|
||||
|
||||
Application::m_Instance.reset();
|
||||
} catch (const exception& ex) {
|
||||
Application::m_Instance.reset();
|
||||
assert(m_Instance == NULL);
|
||||
} catch (const exception& ex) {
|
||||
Logger::Write(LogCritical, "base", "---");
|
||||
Logger::Write(LogCritical, "base", "Exception: " + Utility::GetTypeName(typeid(ex)));
|
||||
Logger::Write(LogCritical, "base", "Message: " + String(ex.what()));
|
||||
|
||||
Logger::Write(LogCritical, "base", "---");
|
||||
Logger::Write(LogCritical, "base", "Exception: " + Utility::GetTypeName(typeid(ex)));
|
||||
Logger::Write(LogCritical, "base", "Message: " + String(ex.what()));
|
||||
if (IsDebugging())
|
||||
throw;
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
DynamicObject::FinishTx();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,12 @@ class Component;
|
|||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class I2_BASE_API Application : public Object {
|
||||
class I2_BASE_API Application : public DynamicObject {
|
||||
public:
|
||||
typedef shared_ptr<Application> Ptr;
|
||||
typedef weak_ptr<Application> WeakPtr;
|
||||
|
||||
Application(void);
|
||||
Application(const Dictionary::Ptr& serializedUpdate);
|
||||
~Application(void);
|
||||
|
||||
static Application::Ptr GetInstance(void);
|
||||
|
@ -48,16 +48,18 @@ public:
|
|||
static bool IsDebugging(void);
|
||||
|
||||
static bool IsMainThread(void);
|
||||
static void SetMainThread(void);
|
||||
|
||||
void UpdatePidFile(const String& filename);
|
||||
void ClosePidFile(void);
|
||||
|
||||
static String GetExePath(const String& argv0);
|
||||
|
||||
protected:
|
||||
void RunEventLoop(void);
|
||||
String GetExePath(void) const;
|
||||
|
||||
private:
|
||||
static Application::Ptr m_Instance; /**< The application instance. */
|
||||
static Application *m_Instance; /**< The application instance. */
|
||||
|
||||
static bool m_ShuttingDown; /**< Whether the application is in the process of
|
||||
shutting down. */
|
||||
|
|
|
@ -473,6 +473,11 @@ DynamicObject::ClassMap& DynamicObject::GetClasses(void)
|
|||
return classes;
|
||||
}
|
||||
|
||||
bool DynamicObject::ClassExists(const String& name)
|
||||
{
|
||||
return (GetClasses().find(name) != GetClasses().end());
|
||||
}
|
||||
|
||||
void DynamicObject::RegisterClass(const String& type, DynamicObject::Factory factory)
|
||||
{
|
||||
if (GetObjects(type).first != GetObjects(type).second)
|
||||
|
|
|
@ -151,7 +151,8 @@ class RegisterClassHelper
|
|||
public:
|
||||
RegisterClassHelper(const String& name, DynamicObject::Factory factory)
|
||||
{
|
||||
DynamicObject::RegisterClass(name, factory);
|
||||
if (!DynamicObject::ClassExists(name))
|
||||
DynamicObject::RegisterClass(name, factory);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -110,13 +110,20 @@ LogSeverity Logger::GetMinSeverity(void) const
|
|||
*/
|
||||
void Logger::ForwardLogEntry(const LogEntry& entry)
|
||||
{
|
||||
bool processed = false;
|
||||
|
||||
DynamicObject::Ptr object;
|
||||
BOOST_FOREACH(tie(tuples::ignore, object), DynamicObject::GetObjects("Logger")) {
|
||||
Logger::Ptr logger = dynamic_pointer_cast<Logger>(object);
|
||||
|
||||
if (entry.Severity >= logger->GetMinSeverity())
|
||||
logger->m_Impl->ProcessLogEntry(entry);
|
||||
|
||||
processed = true;
|
||||
}
|
||||
|
||||
if (!processed && entry.Severity >= LogInformation)
|
||||
StreamLogger::ProcessLogEntry(std::cout, entry);
|
||||
}
|
||||
|
||||
String Logger::SeverityToString(LogSeverity severity)
|
||||
|
|
|
@ -49,9 +49,10 @@ void StreamLogger::OpenFile(const String& filename)
|
|||
/**
|
||||
* Processes a log entry and outputs it to a stream.
|
||||
*
|
||||
* @param stream The output stream.
|
||||
* @param entry The log entry.
|
||||
*/
|
||||
void StreamLogger::ProcessLogEntry(const LogEntry& entry)
|
||||
void StreamLogger::ProcessLogEntry(std::ostream& stream, const LogEntry& entry)
|
||||
{
|
||||
char timestamp[100];
|
||||
|
||||
|
@ -60,7 +61,18 @@ void StreamLogger::ProcessLogEntry(const LogEntry& entry)
|
|||
|
||||
strftime(timestamp, sizeof(timestamp), "%Y/%m/%d %H:%M:%S", &tmnow);
|
||||
|
||||
*m_Stream << "[" << timestamp << "] "
|
||||
stream << "[" << timestamp << "] "
|
||||
<< Logger::SeverityToString(entry.Severity) << "/" << entry.Facility << ": "
|
||||
<< entry.Message << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a log entry and outputs it to a stream.
|
||||
*
|
||||
* @param entry The log entry.
|
||||
*/
|
||||
void StreamLogger::ProcessLogEntry(const LogEntry& entry)
|
||||
{
|
||||
ProcessLogEntry(*m_Stream, entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ public:
|
|||
~StreamLogger(void);
|
||||
|
||||
void OpenFile(const String& filename);
|
||||
|
||||
static void ProcessLogEntry(std::ostream& stream, const LogEntry& entry);
|
||||
|
||||
protected:
|
||||
virtual void ProcessLogEntry(const LogEntry& entry);
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include <i2-icinga.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include "icinga-version.h"
|
||||
# define ICINGA_VERSION GIT_MESSAGE
|
||||
|
||||
# include <ltdl.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
|
@ -38,6 +41,48 @@ int main(int argc, char **argv)
|
|||
LTDL_SET_PRELOADED_SYMBOLS();
|
||||
#endif /* _WIN32 */
|
||||
|
||||
IcingaApplication::Ptr instance = boost::make_shared<IcingaApplication>();
|
||||
return instance->Run(argc, argv);
|
||||
#ifndef _WIN32
|
||||
lt_dlinit();
|
||||
#endif /* _WIN32 */
|
||||
|
||||
Application::SetMainThread();
|
||||
|
||||
#ifdef _WIN32
|
||||
Logger::Write(LogInformation, "icinga", "Icinga application loader");
|
||||
#else /* _WIN32 */
|
||||
Logger::Write(LogInformation, "icinga", "Icinga application loader (version: " ICINGA_VERSION ")");
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (argc < 3 || strcmp(argv[1], "-c") != 0) {
|
||||
stringstream msgbuf;
|
||||
msgbuf << "Syntax: " << argv[0] << " -c <config-file> ...";
|
||||
Logger::Write(LogInformation, "base", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
String configFile = argv[2];
|
||||
|
||||
String componentDirectory = Utility::DirName(Application::GetExePath(argv[0])) + "/../lib/icinga2";
|
||||
Component::AddSearchDir(componentDirectory);
|
||||
|
||||
DynamicObject::BeginTx();
|
||||
|
||||
/* load config file */
|
||||
vector<ConfigItem::Ptr> configItems = ConfigCompiler::CompileFile(configFile);
|
||||
|
||||
Logger::Write(LogInformation, "icinga", "Executing config items...");
|
||||
|
||||
BOOST_FOREACH(const ConfigItem::Ptr& item, configItems) {
|
||||
item->Commit();
|
||||
}
|
||||
|
||||
DynamicObject::FinishTx();
|
||||
|
||||
Application::Ptr app = Application::GetInstance();
|
||||
|
||||
if (!app)
|
||||
throw_exception(runtime_error("Configuration must create an Application object."));
|
||||
|
||||
return app->Run(argc - 2, &(argv[2]));
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,25 @@ using namespace icinga;
|
|||
const String IcingaApplication::DefaultPidPath = "icinga.pid";
|
||||
const String IcingaApplication::DefaultStatePath = "icinga.state";
|
||||
|
||||
IcingaApplication::IcingaApplication(void)
|
||||
{ }
|
||||
IcingaApplication::IcingaApplication(const Dictionary::Ptr& serializedUpdate)
|
||||
: Application(serializedUpdate)
|
||||
{
|
||||
/* load cibsync config component */
|
||||
ConfigItemBuilder::Ptr cibsyncComponentConfig = boost::make_shared<ConfigItemBuilder>();
|
||||
cibsyncComponentConfig->SetType("Component");
|
||||
cibsyncComponentConfig->SetName("cibsync");
|
||||
cibsyncComponentConfig->SetLocal(true);
|
||||
cibsyncComponentConfig->Compile()->Commit();
|
||||
cibsyncComponentConfig.reset();
|
||||
|
||||
/* load convenience config component */
|
||||
ConfigItemBuilder::Ptr convenienceComponentConfig = boost::make_shared<ConfigItemBuilder>();
|
||||
convenienceComponentConfig->SetType("Component");
|
||||
convenienceComponentConfig->SetName("convenience");
|
||||
convenienceComponentConfig->SetLocal(true);
|
||||
convenienceComponentConfig->Compile()->Commit();
|
||||
convenienceComponentConfig.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the Icinga application.
|
||||
|
@ -42,26 +59,13 @@ IcingaApplication::IcingaApplication(void)
|
|||
*/
|
||||
int IcingaApplication::Main(const vector<String>& args)
|
||||
{
|
||||
/* create console logger */
|
||||
ConfigItemBuilder::Ptr consoleLogConfig = boost::make_shared<ConfigItemBuilder>();
|
||||
consoleLogConfig->SetType("Logger");
|
||||
consoleLogConfig->SetName("console");
|
||||
consoleLogConfig->SetLocal(true);
|
||||
consoleLogConfig->AddExpression("type", OperatorSet, "console");
|
||||
consoleLogConfig->Compile()->Commit();
|
||||
consoleLogConfig.reset();
|
||||
|
||||
#ifdef _WIN32
|
||||
Logger::Write(LogInformation, "icinga", "Icinga component loader");
|
||||
#else /* _WIN32 */
|
||||
Logger::Write(LogInformation, "icinga", "Icinga component loader (version: " ICINGA_VERSION ")");
|
||||
#endif /* _WIN32 */
|
||||
Logger::Write(LogInformation, "icinga", "In IcingaApplication::Main()");
|
||||
|
||||
m_StartTime = Utility::GetTime();
|
||||
|
||||
if (args.size() < 2) {
|
||||
if (args.size() == 1 && args[0] == "--help") {
|
||||
stringstream msgbuf;
|
||||
msgbuf << "Syntax: " << args[0] << " [-S] [-L logfile] [-d] [--] <config-file>";
|
||||
msgbuf << "Syntax: " << args[0] << " ... -d";
|
||||
Logger::Write(LogInformation, "icinga", msgbuf.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -92,68 +96,24 @@ int IcingaApplication::Main(const vector<String>& args)
|
|||
throw_exception(invalid_argument("Unknown option: " + arg));
|
||||
}
|
||||
}
|
||||
|
||||
configFile = arg;
|
||||
|
||||
if (it + 1 != args.end())
|
||||
throw_exception(invalid_argument("Trailing command line arguments after config filename."));
|
||||
}
|
||||
|
||||
if (configFile.IsEmpty())
|
||||
throw_exception(invalid_argument("No config file was specified on the command line."));
|
||||
m_CertificateFile = Get("cert");
|
||||
m_CAFile = Get("ca");
|
||||
m_Node = Get("node");
|
||||
m_Service = Get("service");
|
||||
|
||||
String componentDirectory = Utility::DirName(GetExePath()) + "/../lib/icinga2";
|
||||
Component::AddSearchDir(componentDirectory);
|
||||
|
||||
/* load cibsync config component */
|
||||
ConfigItemBuilder::Ptr cibsyncComponentConfig = boost::make_shared<ConfigItemBuilder>();
|
||||
cibsyncComponentConfig->SetType("Component");
|
||||
cibsyncComponentConfig->SetName("cibsync");
|
||||
cibsyncComponentConfig->SetLocal(true);
|
||||
cibsyncComponentConfig->Compile()->Commit();
|
||||
cibsyncComponentConfig.reset();
|
||||
|
||||
/* load convenience config component */
|
||||
ConfigItemBuilder::Ptr convenienceComponentConfig = boost::make_shared<ConfigItemBuilder>();
|
||||
convenienceComponentConfig->SetType("Component");
|
||||
convenienceComponentConfig->SetName("convenience");
|
||||
convenienceComponentConfig->SetLocal(true);
|
||||
convenienceComponentConfig->Compile()->Commit();
|
||||
convenienceComponentConfig.reset();
|
||||
|
||||
/* load config file */
|
||||
vector<ConfigItem::Ptr> configItems = ConfigCompiler::CompileFile(configFile);
|
||||
|
||||
Logger::Write(LogInformation, "icinga", "Executing config items...");
|
||||
|
||||
BOOST_FOREACH(const ConfigItem::Ptr& item, configItems) {
|
||||
item->Commit();
|
||||
}
|
||||
|
||||
DynamicObject::Ptr icingaConfig = DynamicObject::GetObject("Application", "icinga");
|
||||
|
||||
if (!icingaConfig)
|
||||
throw_exception(runtime_error("Configuration must contain an 'Application' object named 'icinga'."));
|
||||
|
||||
if (!icingaConfig->IsLocal())
|
||||
throw_exception(runtime_error("'icinga' application object must be 'local'."));
|
||||
|
||||
m_CertificateFile = icingaConfig->Get("cert");
|
||||
m_CAFile = icingaConfig->Get("ca");
|
||||
m_Node = icingaConfig->Get("node");
|
||||
m_Service = icingaConfig->Get("service");
|
||||
|
||||
m_PidPath = icingaConfig->Get("pidpath");
|
||||
m_PidPath = Get("pidpath");
|
||||
if (m_PidPath.IsEmpty())
|
||||
m_PidPath = DefaultPidPath;
|
||||
|
||||
m_StatePath = icingaConfig->Get("statepath");
|
||||
m_StatePath = Get("statepath");
|
||||
if (m_StatePath.IsEmpty())
|
||||
m_StatePath = DefaultStatePath;
|
||||
|
||||
m_Macros = icingaConfig->Get("macros");
|
||||
m_Macros = Get("macros");
|
||||
|
||||
String logpath = icingaConfig->Get("logpath");
|
||||
String logpath = Get("logpath");
|
||||
if (!logpath.IsEmpty()) {
|
||||
ConfigItemBuilder::Ptr fileLogConfig = boost::make_shared<ConfigItemBuilder>();
|
||||
fileLogConfig->SetType("Logger");
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
typedef shared_ptr<IcingaApplication> Ptr;
|
||||
typedef weak_ptr<IcingaApplication> WeakPtr;
|
||||
|
||||
IcingaApplication(void);
|
||||
IcingaApplication(const Dictionary::Ptr& serializedUpdate);
|
||||
|
||||
int Main(const vector<String>& args);
|
||||
|
||||
|
@ -69,6 +69,8 @@ private:
|
|||
void DumpProgramState(void);
|
||||
};
|
||||
|
||||
REGISTER_CLASS(IcingaApplication);
|
||||
|
||||
}
|
||||
|
||||
#endif /* ICINGAAPPLICATION_H */
|
||||
|
|
Loading…
Reference in New Issue