Refactor the WorkQueue class to make error reporting easier

refs #7709
This commit is contained in:
Gunnar Beutner 2014-12-18 15:11:57 +01:00
parent c3cf7682b9
commit 873e294158
38 changed files with 277 additions and 466 deletions

View File

@ -205,8 +205,9 @@ int Main(void)
String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf"; String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf";
if (Utility::PathExists(initconfig)) { if (Utility::PathExists(initconfig)) {
ConfigCompilerContext::GetInstance()->Reset(); ScriptFrame frame;
ConfigCompiler::CompileFile(initconfig); Expression *expression = ConfigCompiler::CompileFile(initconfig);
expression->Evaluate(frame);
} }
#ifndef _WIN32 #ifndef _WIN32

View File

@ -27,7 +27,7 @@ set(base_SOURCES
convert.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp convert.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp
exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp logger.cpp logger.thpp exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp logger.cpp logger.thpp
netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp object-script.cpp primitivetype.cpp process.cpp netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp object-script.cpp primitivetype.cpp process.cpp
ringbuffer.cpp scripterror.cpp scriptframe.cpp scriptfunction.cpp scriptfunctionwrapper.cpp scriptglobal.cpp ringbuffer.cpp scriptframe.cpp scriptfunction.cpp scriptfunctionwrapper.cpp scriptglobal.cpp
scriptutils.cpp serializer.cpp socket.cpp stacktrace.cpp scriptutils.cpp serializer.cpp socket.cpp stacktrace.cpp
statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp string-script.cpp statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp string-script.cpp
sysloglogger.cpp sysloglogger.thpp tcpsocket.cpp thinmutex.cpp threadpool.cpp timer.cpp sysloglogger.cpp sysloglogger.thpp tcpsocket.cpp thinmutex.cpp threadpool.cpp timer.cpp

View File

@ -31,6 +31,7 @@
#include "base/initialize.hpp" #include "base/initialize.hpp"
#include "base/workqueue.hpp" #include "base/workqueue.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/application.hpp"
#include <fstream> #include <fstream>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/exception/errinfo_api_function.hpp> #include <boost/exception/errinfo_api_function.hpp>
@ -310,7 +311,7 @@ void DynamicObject::RestoreObjects(const String& filename, int attributeTypes)
unsigned long restored = 0; unsigned long restored = 0;
ParallelWorkQueue upq; WorkQueue upq(25000, Application::GetConcurrency());
String message; String message;
while (NetString::ReadStringFromStream(sfp, &message)) { while (NetString::ReadStringFromStream(sfp, &message)) {

View File

@ -22,7 +22,7 @@
#include "base/debug.hpp" #include "base/debug.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
using namespace icinga; using namespace icinga;

View File

@ -153,3 +153,24 @@ String icinga::DiagnosticInformation(boost::exception_ptr eptr)
return boost::diagnostic_information(eptr); return boost::diagnostic_information(eptr);
} }
ScriptError::ScriptError(const String& message)
: m_Message(message)
{ }
ScriptError::ScriptError(const String& message, const DebugInfo& di)
: m_Message(message), m_DebugInfo(di)
{ }
ScriptError::~ScriptError(void) throw()
{ }
const char *ScriptError::what(void) const throw()
{
return m_Message.CStr();
}
DebugInfo ScriptError::GetDebugInfo(void) const
{
return m_DebugInfo;
}

View File

@ -25,6 +25,7 @@
#include "base/stacktrace.hpp" #include "base/stacktrace.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/utility.hpp" #include "base/utility.hpp"
#include "base/debuginfo.hpp"
#include <sstream> #include <sstream>
#include <boost/exception/errinfo_api_function.hpp> #include <boost/exception/errinfo_api_function.hpp>
#include <boost/exception/errinfo_errno.hpp> #include <boost/exception/errinfo_errno.hpp>
@ -42,6 +43,25 @@ namespace icinga
class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception
{ }; { };
/*
* @ingroup base
*/
class I2_BASE_API ScriptError : virtual public user_error
{
public:
ScriptError(const String& message);
ScriptError(const String& message, const DebugInfo& di);
~ScriptError(void) throw();
virtual const char *what(void) const throw();
DebugInfo GetDebugInfo(void) const;
private:
String m_Message;
DebugInfo m_DebugInfo;
};
I2_BASE_API StackTrace *GetLastExceptionStack(void); I2_BASE_API StackTrace *GetLastExceptionStack(void);
I2_BASE_API void SetLastExceptionStack(const StackTrace& trace); I2_BASE_API void SetLastExceptionStack(const StackTrace& trace);
@ -58,9 +78,23 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace
{ {
std::ostringstream result; std::ostringstream result;
result << boost::diagnostic_information(ex); const user_error *uex = dynamic_cast<const user_error *>(&ex);
if (dynamic_cast<const user_error *>(&ex) == NULL) { String message = ex.what();
if (!uex || message.IsEmpty())
result << boost::diagnostic_information(ex);
else
result << "Error: " << message;
const ScriptError *dex = dynamic_cast<const ScriptError *>(&ex);
if (dex && !dex->GetDebugInfo().Path.IsEmpty()) {
result << "\nLocation:\n";
ShowCodeFragment(result, dex->GetDebugInfo());
}
if (!uex) {
if (boost::get_error_info<StackTraceErrorInfo>(ex) == NULL) { if (boost::get_error_info<StackTraceErrorInfo>(ex) == NULL) {
result << std::endl; result << std::endl;

View File

@ -1,45 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "base/scripterror.hpp"
#include <sstream>
using namespace icinga;
ScriptError::ScriptError(const String& message)
: m_Message(message)
{ }
ScriptError::ScriptError(const String& message, const DebugInfo& di)
: m_Message(message), m_DebugInfo(di)
{ }
ScriptError::~ScriptError(void) throw()
{ }
const char *ScriptError::what(void) const throw()
{
return m_Message.CStr();
}
DebugInfo ScriptError::GetDebugInfo(void) const
{
return m_DebugInfo;
}

View File

@ -1,51 +0,0 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef SCRIPTERROR_H
#define SCRIPTERROR_H
#include "base/i2-base.hpp"
#include "base/debuginfo.hpp"
#include "base/exception.hpp"
namespace icinga
{
/*
* @ingroup base
*/
class I2_BASE_API ScriptError : virtual public user_error
{
public:
ScriptError(const String& message);
ScriptError(const String& message, const DebugInfo& di);
~ScriptError(void) throw();
virtual const char *what(void) const throw();
DebugInfo GetDebugInfo(void) const;
private:
String m_Message;
DebugInfo m_DebugInfo;
};
}
#endif /* SCRIPTERROR_H */

View File

@ -26,7 +26,7 @@
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/dynamictype.hpp" #include "base/dynamictype.hpp"
#include "base/application.hpp" #include "base/application.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <algorithm> #include <algorithm>

View File

@ -22,16 +22,19 @@
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/application.hpp" #include "base/application.hpp"
#include "base/exception.hpp"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/thread/tss.hpp>
using namespace icinga; using namespace icinga;
int WorkQueue::m_NextID = 1; int WorkQueue::m_NextID = 1;
boost::thread_specific_ptr<WorkQueue *> l_ThreadWorkQueue;
WorkQueue::WorkQueue(size_t maxItems) WorkQueue::WorkQueue(size_t maxItems, int threadCount)
: m_ID(m_NextID++), m_MaxItems(maxItems), m_Stopped(false), : m_ID(m_NextID++), m_MaxItems(maxItems), m_ThreadCount(threadCount), m_Spawned(false), m_Stopped(false),
m_Processing(false), m_ExceptionCallback(WorkQueue::DefaultExceptionCallback) m_Processing(0)
{ {
m_StatusTimer = new Timer(); m_StatusTimer = new Timer();
m_StatusTimer->SetInterval(10); m_StatusTimer->SetInterval(10);
@ -45,46 +48,53 @@ WorkQueue::~WorkQueue(void)
} }
/** /**
* Enqueues a work item. Work items are guaranteed to be executed in the order * Enqueues a task. Tasks are guaranteed to be executed in the order
* they were enqueued in except when allowInterleaved is true in which case * they were enqueued in except if there is more than one worker thread or when
* the new work item might be run immediately if it's being enqueued from * allowInterleaved is true in which case the new task might be run
* within the WorkQueue thread. * immediately if it's being enqueued from within the WorkQueue thread.
*/ */
void WorkQueue::Enqueue(const WorkCallback& callback, bool allowInterleaved) void WorkQueue::Enqueue(const Task& task, bool allowInterleaved)
{ {
bool wq_thread = (boost::this_thread::get_id() == GetThreadId()); bool wq_thread = IsWorkerThread();
if (wq_thread && allowInterleaved) { if (wq_thread && allowInterleaved) {
callback(); task();
return; return;
} }
WorkItem item;
item.Callback = callback;
item.AllowInterleaved = allowInterleaved;
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
if (m_Thread.get_id() == boost::thread::id()) if (!m_Spawned) {
m_Thread = boost::thread(boost::bind(&WorkQueue::WorkerThreadProc, this)); for (int i = 0; i < m_ThreadCount; i++) {
m_Threads.create_thread(boost::bind(&WorkQueue::WorkerThreadProc, this));
}
m_Spawned = true;
}
if (!wq_thread) { if (!wq_thread) {
while (m_Items.size() >= m_MaxItems) while (m_Tasks.size() >= m_MaxItems)
m_CVFull.wait(lock); m_CVFull.wait(lock);
} }
m_Items.push_back(item); m_Tasks.push_back(task);
if (m_Items.size() == 1) if (m_Tasks.size() == 1)
m_CVEmpty.notify_all(); m_CVEmpty.notify_all();
} }
/**
* Waits until all currently enqueued tasks have completed. This only works reliably
* when no other thread is enqueuing new tasks when this method is called.
*
* @param stop Whether to stop the worker threads
*/
void WorkQueue::Join(bool stop) void WorkQueue::Join(bool stop)
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
while (m_Processing || !m_Items.empty()) while (m_Processing || !m_Tasks.empty())
m_CVStarved.wait(lock); m_CVStarved.wait(lock);
if (stop) { if (stop) {
@ -92,33 +102,73 @@ void WorkQueue::Join(bool stop)
m_CVEmpty.notify_all(); m_CVEmpty.notify_all();
lock.unlock(); lock.unlock();
if (m_Thread.joinable()) m_Threads.join_all();
m_Thread.join(); m_Spawned = false;
} }
} }
boost::thread::id WorkQueue::GetThreadId(void) const /**
* Checks whether the calling thread is one of the worker threads
* for this work queue.
*
* @returns true if called from one of the worker threads, false otherwise
*/
bool WorkQueue::IsWorkerThread(void) const
{ {
return m_Thread.get_id(); WorkQueue **pwq = l_ThreadWorkQueue.get();
if (!pwq)
return false;
return *pwq == this;
} }
void WorkQueue::SetExceptionCallback(const ExceptionCallback& callback) void WorkQueue::SetExceptionCallback(const ExceptionCallback& callback)
{ {
boost::mutex::scoped_lock lock(m_Mutex);
m_ExceptionCallback = callback; m_ExceptionCallback = callback;
} }
/**
* Checks whether any exceptions have occurred while executing tasks for this
* work queue. When a custom exception callback is set this method will always
* return false.
*/
bool WorkQueue::HasExceptions(void) const
{
boost::mutex::scoped_lock lock(m_Mutex);
return !m_Exceptions.empty();
}
/**
* Returns all exceptions which have occurred for tasks in this work queue. When a
* custom exception callback is set this method will always return an empty list.
*/
std::vector<boost::exception_ptr> WorkQueue::GetExceptions(void) const
{
boost::mutex::scoped_lock lock(m_Mutex);
return m_Exceptions;
}
void WorkQueue::ReportExceptions(const String& facility) const
{
std::vector<boost::exception_ptr> exceptions = GetExceptions();
BOOST_FOREACH(const boost::exception_ptr& eptr, exceptions) {
Log(LogCritical, facility)
<< DiagnosticInformation(eptr);
}
Log(LogCritical, facility)
<< exceptions.size() << " error" << (exceptions.size() != 1 ? "s" : "");
}
size_t WorkQueue::GetLength(void) size_t WorkQueue::GetLength(void)
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
return m_Items.size(); return m_Tasks.size();
}
void WorkQueue::DefaultExceptionCallback(boost::exception_ptr)
{
throw;
} }
void WorkQueue::StatusTimerHandler(void) void WorkQueue::StatusTimerHandler(void)
@ -126,7 +176,7 @@ void WorkQueue::StatusTimerHandler(void)
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
Log(LogNotice, "WorkQueue") Log(LogNotice, "WorkQueue")
<< "#" << m_ID << " items: " << m_Items.size(); << "#" << m_ID << " tasks: " << m_Tasks.size();
} }
void WorkQueue::WorkerThreadProc(void) void WorkQueue::WorkerThreadProc(void)
@ -135,67 +185,47 @@ void WorkQueue::WorkerThreadProc(void)
idbuf << "WQ #" << m_ID; idbuf << "WQ #" << m_ID;
Utility::SetThreadName(idbuf.str()); Utility::SetThreadName(idbuf.str());
l_ThreadWorkQueue.reset(new WorkQueue *(this));
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
for (;;) { for (;;) {
while (m_Items.empty() && !m_Stopped) while (m_Tasks.empty() && !m_Stopped)
m_CVEmpty.wait(lock); m_CVEmpty.wait(lock);
if (m_Stopped) if (m_Stopped)
break; break;
std::deque<WorkItem> items; if (m_Tasks.size() >= m_MaxItems)
m_Items.swap(items);
if (items.size() >= m_MaxItems)
m_CVFull.notify_all(); m_CVFull.notify_all();
m_Processing = true; Task task = m_Tasks.front();
m_Tasks.pop_front();
m_Processing++;
lock.unlock(); lock.unlock();
BOOST_FOREACH(WorkItem& wi, items) { try {
try { task();
wi.Callback(); } catch (const std::exception&) {
} lock.lock();
catch (const std::exception&) {
lock.lock();
ExceptionCallback callback = m_ExceptionCallback; if (!m_ExceptionCallback)
m_Exceptions.push_back(boost::current_exception());
lock.unlock(); lock.unlock();
callback(boost::current_exception()); if (m_ExceptionCallback)
} m_ExceptionCallback(boost::current_exception());
} }
lock.lock(); lock.lock();
m_Processing = false; m_Processing--;
m_CVStarved.notify_all(); if (m_Tasks.empty())
m_CVStarved.notify_all();
} }
} }
ParallelWorkQueue::ParallelWorkQueue(void)
: m_QueueCount(Application::GetConcurrency()),
m_Queues(new WorkQueue[m_QueueCount]),
m_Index(0)
{ }
ParallelWorkQueue::~ParallelWorkQueue(void)
{
delete[] m_Queues;
}
void ParallelWorkQueue::Enqueue(const boost::function<void(void)>& callback)
{
m_Index++;
m_Queues[m_Index % m_QueueCount].Enqueue(callback);
}
void ParallelWorkQueue::Join(void)
{
for (unsigned int i = 0; i < m_QueueCount; i++)
m_Queues[i].Join();
}

View File

@ -32,13 +32,7 @@
namespace icinga namespace icinga
{ {
typedef boost::function<void (void)> WorkCallback; typedef boost::function<void (void)> Task;
struct WorkItem
{
WorkCallback Callback;
bool AllowInterleaved;
};
/** /**
* A workqueue. * A workqueue.
@ -50,53 +44,43 @@ class I2_BASE_API WorkQueue
public: public:
typedef boost::function<void (boost::exception_ptr)> ExceptionCallback; typedef boost::function<void (boost::exception_ptr)> ExceptionCallback;
WorkQueue(size_t maxItems = 25000); WorkQueue(size_t maxItems = 25000, int threadCount = 1);
~WorkQueue(void); ~WorkQueue(void);
void Enqueue(const WorkCallback& callback, bool allowInterleaved = false); void Enqueue(const Task& task, bool allowInterleaved = false);
void Join(bool stop = false); void Join(bool stop = false);
boost::thread::id GetThreadId(void) const; bool IsWorkerThread(void) const;
size_t GetLength(void);
void SetExceptionCallback(const ExceptionCallback& callback); void SetExceptionCallback(const ExceptionCallback& callback);
size_t GetLength(void); bool HasExceptions(void) const;
std::vector<boost::exception_ptr> GetExceptions(void) const;
void ReportExceptions(const String& facility) const;
private: private:
int m_ID; int m_ID;
static int m_NextID; static int m_NextID;
int m_ThreadCount;
bool m_Spawned;
boost::mutex m_Mutex; mutable boost::mutex m_Mutex;
boost::condition_variable m_CVEmpty; boost::condition_variable m_CVEmpty;
boost::condition_variable m_CVFull; boost::condition_variable m_CVFull;
boost::condition_variable m_CVStarved; boost::condition_variable m_CVStarved;
boost::thread m_Thread; boost::thread_group m_Threads;
size_t m_MaxItems; size_t m_MaxItems;
bool m_Stopped; bool m_Stopped;
bool m_Processing; int m_Processing;
std::deque<WorkItem> m_Items; std::deque<Task> m_Tasks;
ExceptionCallback m_ExceptionCallback; ExceptionCallback m_ExceptionCallback;
std::vector<boost::exception_ptr> m_Exceptions;
Timer::Ptr m_StatusTimer; Timer::Ptr m_StatusTimer;
void WorkerThreadProc(void); void WorkerThreadProc(void);
void StatusTimerHandler(void); void StatusTimerHandler(void);
static void DefaultExceptionCallback(boost::exception_ptr exp);
};
class I2_BASE_API ParallelWorkQueue
{
public:
ParallelWorkQueue(void);
~ParallelWorkQueue(void);
void Enqueue(const boost::function<void(void)>& callback);
void Join(void);
private:
unsigned int m_QueueCount;
WorkQueue *m_Queues;
unsigned int m_Index;
}; };
} }

View File

@ -18,8 +18,8 @@
******************************************************************************/ ******************************************************************************/
#include "cli/daemoncommand.hpp" #include "cli/daemoncommand.hpp"
#include "config/configcompilercontext.hpp"
#include "config/configcompiler.hpp" #include "config/configcompiler.hpp"
#include "config/configcompilercontext.hpp"
#include "config/configitembuilder.hpp" #include "config/configitembuilder.hpp"
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/application.hpp" #include "base/application.hpp"
@ -60,16 +60,20 @@ static String LoadAppType(const String& typeSpec)
return typeSpec.SubStr(index + 1); return typeSpec.SubStr(index + 1);
} }
static void ExecuteExpression(Expression *expression) static bool ExecuteExpression(Expression *expression)
{ {
if (!expression)
return false;
try { try {
ScriptFrame frame; ScriptFrame frame;
expression->Evaluate(frame); expression->Evaluate(frame);
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); Log(LogCritical, "config", DiagnosticInformation(ex));
Application::Exit(EXIT_FAILURE);
} }
return true;
} }
static void IncludeZoneDirRecursive(const String& path) static void IncludeZoneDirRecursive(const String& path)
@ -95,22 +99,18 @@ static void IncludeNonLocalZone(const String& zonePath)
static bool LoadConfigFiles(const boost::program_options::variables_map& vm, const String& appType, static bool LoadConfigFiles(const boost::program_options::variables_map& vm, const String& appType,
const String& objectsFile = String(), const String& varsfile = String()) const String& objectsFile = String(), const String& varsfile = String())
{ {
ConfigCompilerContext::GetInstance()->Reset();
if (!objectsFile.IsEmpty()) if (!objectsFile.IsEmpty())
ConfigCompilerContext::GetInstance()->OpenObjectsFile(objectsFile); ConfigCompilerContext::GetInstance()->OpenObjectsFile(objectsFile);
if (vm.count("config") > 0) { if (vm.count("config") > 0) {
BOOST_FOREACH(const String& configPath, vm["config"].as<std::vector<std::string> >()) { BOOST_FOREACH(const String& configPath, vm["config"].as<std::vector<std::string> >()) {
Expression *expression = ConfigCompiler::CompileFile(configPath); Expression *expression = ConfigCompiler::CompileFile(configPath);
if (expression) ExecuteExpression(expression);
ExecuteExpression(expression);
delete expression; delete expression;
} }
} else if (!vm.count("no-config")) { } else if (!vm.count("no-config")) {
Expression *expression = ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf"); Expression *expression = ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
if (expression) ExecuteExpression(expression);
ExecuteExpression(expression);
delete expression; delete expression;
} }
@ -127,8 +127,7 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con
String name, fragment; String name, fragment;
BOOST_FOREACH(boost::tie(name, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) { BOOST_FOREACH(boost::tie(name, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) {
Expression *expression = ConfigCompiler::CompileText(name, fragment); Expression *expression = ConfigCompiler::CompileText(name, fragment);
if (expression) ExecuteExpression(expression);
ExecuteExpression(expression);
delete expression; delete expression;
} }
@ -138,42 +137,7 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con
ConfigItem::Ptr item = builder->Compile(); ConfigItem::Ptr item = builder->Compile();
item->Register(); item->Register();
bool result = ConfigItem::ValidateItems(); bool result = ConfigItem::CommitItems();
int warnings = 0, errors = 0;
BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
std::ostringstream locbuf;
ShowCodeFragment(locbuf, message.Location);
String location = locbuf.str();
String logmsg;
if (!location.IsEmpty())
logmsg = "Location:\n" + location;
logmsg += String("\nConfig ") + (message.Error ? "error" : "warning") + ": " + message.Text;
if (message.Error) {
Log(LogCritical, "config", logmsg);
errors++;
} else {
Log(LogWarning, "config", logmsg);
warnings++;
}
}
if (warnings > 0 || errors > 0) {
LogSeverity severity;
if (errors == 0)
severity = LogWarning;
else
severity = LogCritical;
Log(severity, "config")
<< errors << " errors, " << warnings << " warnings.";
}
if (!result) if (!result)
return false; return false;

View File

@ -19,7 +19,6 @@
#include "cli/replcommand.hpp" #include "cli/replcommand.hpp"
#include "config/configcompiler.hpp" #include "config/configcompiler.hpp"
#include "config/configcompilercontext.hpp"
#include "base/json.hpp" #include "base/json.hpp"
#include "base/console.hpp" #include "base/console.hpp"
#include "base/application.hpp" #include "base/application.hpp"
@ -132,22 +131,11 @@ int ReplCommand::Run(const po::variables_map& vm, const std::vector<std::string>
Expression *expr; Expression *expr;
try { try {
ConfigCompilerContext::GetInstance()->Reset();
lines[fileName] = line; lines[fileName] = line;
expr = ConfigCompiler::CompileText(fileName, line); expr = ConfigCompiler::CompileText(fileName, line);
bool has_errors = false; if (expr) {
BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
if (message.Error)
has_errors = true;
std::cout << (message.Error ? "Error" : "Warning") << ": " << message.Text << "\n";
}
if (expr && !has_errors) {
Value result = expr->Evaluate(frame); Value result = expr->Evaluate(frame);
std::cout << ConsoleColorTag(Console_ForegroundCyan); std::cout << ConsoleColorTag(Console_ForegroundCyan);
if (!result.IsObject() || result.IsObjectType<Array>() || result.IsObjectType<Dictionary>()) if (!result.IsObject() || result.IsObjectType<Array>() || result.IsObjectType<Dictionary>())

View File

@ -229,8 +229,6 @@ bool RepositoryUtility::AddObject(const String& name, const String& type, const
change->Set("command", "add"); change->Set("command", "add");
change->Set("attrs", attrs); change->Set("attrs", attrs);
ConfigCompilerContext::GetInstance()->Reset();
String fname, fragment; String fname, fragment;
BOOST_FOREACH(boost::tie(fname, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) { BOOST_FOREACH(boost::tie(fname, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) {
Expression *expression = ConfigCompiler::CompileText(fname, fragment); Expression *expression = ConfigCompiler::CompileText(fname, fragment);
@ -258,25 +256,13 @@ bool RepositoryUtility::AddObject(const String& name, const String& type, const
Object::Ptr object = dtype->Instantiate(); Object::Ptr object = dtype->Instantiate();
Deserialize(object, vattrs, false, FAConfig); Deserialize(object, vattrs, false, FAConfig);
RepositoryTypeRuleUtilities utils; try {
ctype->ValidateItem(name, object, DebugInfo(), &utils); RepositoryTypeRuleUtilities utils;
ctype->ValidateItem(name, object, DebugInfo(), &utils);
int warnings = 0, errors = 0; } catch (const ScriptError& ex) {
Log(LogCritical, "config", DiagnosticInformation(ex));
BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
String logmsg = String("Config ") + (message.Error ? "error" : "warning") + ": " + message.Text;
if (message.Error) {
Log(LogCritical, "config", logmsg);
errors++;
} else {
Log(LogWarning, "config", logmsg);
warnings++;
}
}
if (errors > 0)
return false; return false;
}
} }
if (CheckChangeExists(change)) { if (CheckChangeExists(change)) {

View File

@ -570,8 +570,8 @@ void CompatLogger::ValidateRotationMethod(const String& location, const CompatLo
if (rotation_method != "HOURLY" && rotation_method != "DAILY" && if (rotation_method != "HOURLY" && rotation_method != "DAILY" &&
rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") { rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Rotation method '" + rotation_method + "' is invalid."); location + ": Rotation method '" + rotation_method + "' is invalid.", GetDebugInfo()));
} }
} }

View File

@ -33,7 +33,7 @@
#include "base/utility.hpp" #include "base/utility.hpp"
#include "base/exception.hpp" #include "base/exception.hpp"
#include "base/dynamictype.hpp" #include "base/dynamictype.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>

View File

@ -27,39 +27,6 @@
using namespace icinga; using namespace icinga;
void ConfigCompilerContext::AddMessage(bool error, const String& message, const DebugInfo& di)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_Messages.push_back(ConfigCompilerMessage(error, message, di));
}
std::vector<ConfigCompilerMessage> ConfigCompilerContext::GetMessages(void) const
{
boost::mutex::scoped_lock lock(m_Mutex);
return m_Messages;
}
bool ConfigCompilerContext::HasErrors(void) const
{
boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const ConfigCompilerMessage& message, m_Messages) {
if (message.Error)
return true;
}
return false;
}
void ConfigCompilerContext::Reset(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_Messages.clear();
}
ConfigCompilerContext *ConfigCompilerContext::GetInstance(void) ConfigCompilerContext *ConfigCompilerContext::GetInstance(void)
{ {
return Singleton<ConfigCompilerContext>::GetInstance(); return Singleton<ConfigCompilerContext>::GetInstance();

View File

@ -47,12 +47,6 @@ struct I2_CONFIG_API ConfigCompilerMessage
class I2_CONFIG_API ConfigCompilerContext class I2_CONFIG_API ConfigCompilerContext
{ {
public: public:
void AddMessage(bool error, const String& message, const DebugInfo& di = DebugInfo());
std::vector<ConfigCompilerMessage> GetMessages(void) const;
bool HasErrors(void) const;
void Reset(void);
void OpenObjectsFile(const String& filename); void OpenObjectsFile(const String& filename);
void WriteObject(const Dictionary::Ptr& object); void WriteObject(const Dictionary::Ptr& object);
void FinishObjectsFile(void); void FinishObjectsFile(void);
@ -60,7 +54,6 @@ public:
static ConfigCompilerContext *GetInstance(void); static ConfigCompilerContext *GetInstance(void);
private: private:
std::vector<ConfigCompilerMessage> m_Messages;
String m_ObjectsPath; String m_ObjectsPath;
StdioStream::Ptr m_ObjectsFP; StdioStream::Ptr m_ObjectsFP;

View File

@ -34,7 +34,7 @@
#include "base/netstring.hpp" #include "base/netstring.hpp"
#include "base/serializer.hpp" #include "base/serializer.hpp"
#include "base/json.hpp" #include "base/json.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -163,16 +163,10 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard)
DebugHint debugHints; DebugHint debugHints;
try { ScriptFrame frame(dobj);
ScriptFrame frame(dobj); if (m_Scope)
if (m_Scope) m_Scope->CopyTo(frame.Locals);
m_Scope->CopyTo(frame.Locals); m_Expression->Evaluate(frame, &debugHints);
m_Expression->Evaluate(frame, &debugHints);
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
} catch (const std::exception& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
}
if (discard) if (discard)
m_Expression.reset(); m_Expression.reset();
@ -222,18 +216,9 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard)
ConfigType::Ptr ctype = ConfigType::GetByName(GetType()); ConfigType::Ptr ctype = ConfigType::GetByName(GetType());
if (!ctype) if (ctype)
ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'");
else {
TypeRuleUtilities utils; TypeRuleUtilities utils;
ctype->ValidateItem(GetName(), dobj, GetDebugInfo(), &utils);
try {
ctype->ValidateItem(GetName(), dobj, GetDebugInfo(), &utils);
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
} catch (const std::exception& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
}
} }
dobj->Register(); dobj->Register();
@ -287,7 +272,7 @@ ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
} }
} }
bool ConfigItem::CommitNewItems(ParallelWorkQueue& upq) bool ConfigItem::CommitNewItems(WorkQueue& upq)
{ {
typedef std::pair<ConfigItem::Ptr, bool> ItemPair; typedef std::pair<ConfigItem::Ptr, bool> ItemPair;
std::vector<ItemPair> items; std::vector<ItemPair> items;
@ -320,7 +305,7 @@ bool ConfigItem::CommitNewItems(ParallelWorkQueue& upq)
upq.Join(); upq.Join();
if (ConfigCompilerContext::GetInstance()->HasErrors()) if (upq.HasExceptions())
return false; return false;
std::vector<ConfigItem::Ptr> new_items; std::vector<ConfigItem::Ptr> new_items;
@ -340,22 +325,18 @@ bool ConfigItem::CommitNewItems(ParallelWorkQueue& upq)
return true; return true;
} }
bool ConfigItem::ValidateItems(void) bool ConfigItem::CommitItems(void)
{ {
ParallelWorkQueue upq; WorkQueue upq(25000, Application::GetConcurrency());
if (ConfigCompilerContext::GetInstance()->HasErrors())
return false;
Log(LogInformation, "ConfigItem", "Committing config items"); Log(LogInformation, "ConfigItem", "Committing config items");
if (!CommitNewItems(upq)) if (!CommitNewItems(upq)) {
upq.ReportExceptions("config");
return false; return false;
}
ApplyRule::CheckMatches(); ApplyRule::CheckMatches();
ApplyRule::DiscardRules();
ConfigItem::DiscardItems();
ConfigType::DiscardTypes(); ConfigType::DiscardTypes();
/* log stats for external parsers */ /* log stats for external parsers */
@ -366,14 +347,11 @@ bool ConfigItem::ValidateItems(void)
<< "Checked " << count << " " << type->GetName() << "(s)."; << "Checked " << count << " " << type->GetName() << "(s).";
} }
return !ConfigCompilerContext::GetInstance()->HasErrors(); return true;
} }
bool ConfigItem::ActivateItems(void) bool ConfigItem::ActivateItems(void)
{ {
if (ConfigCompilerContext::GetInstance()->HasErrors())
return false;
/* restore the previous program state */ /* restore the previous program state */
try { try {
DynamicObject::RestoreObjects(Application::GetStatePath()); DynamicObject::RestoreObjects(Application::GetStatePath());
@ -384,7 +362,7 @@ bool ConfigItem::ActivateItems(void)
Log(LogInformation, "ConfigItem", "Triggering Start signal for config items"); Log(LogInformation, "ConfigItem", "Triggering Start signal for config items");
ParallelWorkQueue upq; WorkQueue upq(25000, Application::GetConcurrency());
BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) { BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) { BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
@ -414,13 +392,6 @@ bool ConfigItem::ActivateItems(void)
return true; return true;
} }
void ConfigItem::DiscardItems(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_Items.clear();
}
std::vector<ConfigItem::Ptr> ConfigItem::GetItems(const String& type) std::vector<ConfigItem::Ptr> ConfigItem::GetItems(const String& type)
{ {
std::vector<ConfigItem::Ptr> items; std::vector<ConfigItem::Ptr> items;

View File

@ -64,9 +64,8 @@ public:
static ConfigItem::Ptr GetObject(const String& type, static ConfigItem::Ptr GetObject(const String& type,
const String& name); const String& name);
static bool ValidateItems(void); static bool CommitItems(void);
static bool ActivateItems(void); static bool ActivateItems(void);
static void DiscardItems(void);
static std::vector<ConfigItem::Ptr> GetItems(const String& type); static std::vector<ConfigItem::Ptr> GetItems(const String& type);
@ -96,7 +95,7 @@ private:
static ConfigItem::Ptr GetObjectUnlocked(const String& type, static ConfigItem::Ptr GetObjectUnlocked(const String& type,
const String& name); const String& name);
static bool CommitNewItems(ParallelWorkQueue& upq); static bool CommitNewItems(WorkQueue& upq);
}; };
} }

View File

@ -136,14 +136,14 @@ void ConfigType::ValidateAttribute(const String& key, const Value& value,
} }
if (overallResult == ValidationUnknownField) if (overallResult == ValidationUnknownField)
ConfigCompilerContext::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations)); BOOST_THROW_EXCEPTION(ScriptError("Unknown attribute: " + LocationToString(locations)));
else if (overallResult == ValidationInvalidType) { else if (overallResult == ValidationInvalidType) {
String message = "Invalid value: " + LocationToString(locations); String message = "Invalid value: " + LocationToString(locations);
if (!hint.IsEmpty()) if (!hint.IsEmpty())
message += ": " + hint; message += ": " + hint;
ConfigCompilerContext::GetInstance()->AddMessage(true, message); BOOST_THROW_EXCEPTION(ScriptError(message));
} }
if (!subRuleLists.empty() && value.IsObject() && !value.IsObjectType<Array>()) if (!subRuleLists.empty() && value.IsObject() && !value.IsObjectType<Array>())
@ -164,10 +164,8 @@ void ConfigType::ValidateObject(const Object::Ptr& object,
Value value = VMOps::GetField(object, require); Value value = VMOps::GetField(object, require);
if (value.IsEmpty() || (value.IsString() && static_cast<String>(value).IsEmpty())) { if (value.IsEmpty() || (value.IsString() && static_cast<String>(value).IsEmpty()))
ConfigCompilerContext::GetInstance()->AddMessage(true, BOOST_THROW_EXCEPTION(ScriptError("Required attribute is missing: " + LocationToString(locations)));
"Required attribute is missing: " + LocationToString(locations));
}
locations.pop_back(); locations.pop_back();
} }
@ -223,10 +221,8 @@ void ConfigType::ValidateArray(const Array::Ptr& array,
locations.push_back("Attribute '" + require + "'"); locations.push_back("Attribute '" + require + "'");
if (array->GetLength() < index) { if (array->GetLength() < index)
ConfigCompilerContext::GetInstance()->AddMessage(true, BOOST_THROW_EXCEPTION(ScriptError("Required array index is missing: " + LocationToString(locations)));
"Required array index is missing: " + LocationToString(locations));
}
locations.pop_back(); locations.pop_back();
} }

View File

@ -24,7 +24,7 @@
#include "base/json.hpp" #include "base/json.hpp"
#include "base/object.hpp" #include "base/object.hpp"
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include "base/scriptglobal.hpp" #include "base/scriptglobal.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/exception_ptr.hpp> #include <boost/exception_ptr.hpp>

View File

@ -25,7 +25,7 @@
#include "base/array.hpp" #include "base/array.hpp"
#include "base/dictionary.hpp" #include "base/dictionary.hpp"
#include "base/scriptfunction.hpp" #include "base/scriptfunction.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include "base/scriptframe.hpp" #include "base/scriptframe.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>

View File

@ -30,7 +30,7 @@
#include "base/dictionary.hpp" #include "base/dictionary.hpp"
#include "base/scriptfunction.hpp" #include "base/scriptfunction.hpp"
#include "base/scriptglobal.hpp" #include "base/scriptglobal.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>

View File

@ -424,7 +424,7 @@ void DbConnection::PrepareDatabase(void)
void DbConnection::ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object) void DbConnection::ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object)
{ {
if (object->GetFailoverTimeout() < 60) { if (object->GetFailoverTimeout() < 60) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Failover timeout minimum is 60s."); location + ": Failover timeout minimum is 60s.", GetDebugInfo()));
} }
} }

View File

@ -115,7 +115,7 @@ void IdoMysqlConnection::ExceptionHandler(boost::exception_ptr exp)
void IdoMysqlConnection::AssertOnWorkQueue(void) void IdoMysqlConnection::AssertOnWorkQueue(void)
{ {
ASSERT(boost::this_thread::get_id() == m_QueryQueue.GetThreadId()); ASSERT(m_QueryQueue.IsWorkerThread());
} }
void IdoMysqlConnection::Disconnect(void) void IdoMysqlConnection::Disconnect(void)

View File

@ -116,7 +116,7 @@ void IdoPgsqlConnection::ExceptionHandler(boost::exception_ptr exp)
void IdoPgsqlConnection::AssertOnWorkQueue(void) void IdoPgsqlConnection::AssertOnWorkQueue(void)
{ {
ASSERT(boost::this_thread::get_id() == m_QueryQueue.GetThreadId()); ASSERT(m_QueryQueue.IsWorkerThread());
} }
void IdoPgsqlConnection::Disconnect(void) void IdoPgsqlConnection::Disconnect(void)

View File

@ -270,7 +270,7 @@ Endpoint::Ptr Checkable::GetCommandEndpoint(void) const
void Checkable::ValidateCheckInterval(const String& location, const Checkable::Ptr& object) void Checkable::ValidateCheckInterval(const String& location, const Checkable::Ptr& object)
{ {
if (object->GetCheckInterval() <= 0) { if (object->GetCheckInterval() <= 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": check_interval must be greater than 0."); location + ": check_interval must be greater than 0.", GetDebugInfo()));
} }
} }

View File

@ -47,8 +47,8 @@ void Command::SetModifiedAttributes(int flags, const MessageOrigin& origin)
void Command::ValidateAttributes(const String& location, const Command::Ptr& object) void Command::ValidateAttributes(const String& location, const Command::Ptr& object)
{ {
if (object->GetArguments() != Empty && !object->GetCommandLine().IsObjectType<Array>()) { if (object->GetArguments() != Empty && !object->GetCommandLine().IsObjectType<Array>()) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Attribute 'command' must be an array if the 'arguments' attribute is set."); location + ": Attribute 'command' must be an array if the 'arguments' attribute is set.", GetDebugInfo()));
} }
} }

View File

@ -27,7 +27,7 @@
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/workqueue.hpp" #include "base/workqueue.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
@ -150,12 +150,8 @@ void Dependency::EvaluateApplyRules(const Host::Ptr& host)
if (rule.GetTargetType() != "Host") if (rule.GetTargetType() != "Host")
continue; continue;
try { if (EvaluateApplyRule(host, rule))
if (EvaluateApplyRule(host, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }
@ -167,11 +163,7 @@ void Dependency::EvaluateApplyRules(const Service::Ptr& service)
if (rule.GetTargetType() != "Service") if (rule.GetTargetType() != "Service")
continue; continue;
try { if (EvaluateApplyRule(service, rule))
if (EvaluateApplyRule(service, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }

View File

@ -208,12 +208,12 @@ void Dependency::ValidateFilters(const String& location, const Dependency::Ptr&
int sfilter = FilterArrayToInt(object->GetStates(), 0); int sfilter = FilterArrayToInt(object->GetStates(), 0);
if (object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { if (object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid for host dependency."); location + ": State filter is invalid for host dependency.", GetDebugInfo()));
} }
if (!object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { if (!object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid for service dependency."); location + ": State filter is invalid for service dependency.", GetDebugInfo()));
} }
} }

View File

@ -23,7 +23,7 @@
#include "icinga/pluginutility.hpp" #include "icinga/pluginutility.hpp"
#include "icinga/scheduleddowntime.hpp" #include "icinga/scheduleddowntime.hpp"
#include "config/configcompilercontext.hpp" #include "config/configcompilercontext.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/utility.hpp" #include "base/utility.hpp"

View File

@ -27,7 +27,7 @@
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/workqueue.hpp" #include "base/workqueue.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
@ -150,12 +150,8 @@ void Notification::EvaluateApplyRules(const Host::Ptr& host)
if (rule.GetTargetType() != "Host") if (rule.GetTargetType() != "Host")
continue; continue;
try { if (EvaluateApplyRule(host, rule))
if (EvaluateApplyRule(host, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }
@ -167,11 +163,7 @@ void Notification::EvaluateApplyRules(const Service::Ptr& service)
if (rule.GetTargetType() != "Service") if (rule.GetTargetType() != "Service")
continue; continue;
try { if (EvaluateApplyRule(service, rule))
if (EvaluateApplyRule(service, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }

View File

@ -501,13 +501,13 @@ void Notification::ValidateFilters(const String& location, const Notification::P
int sfilter = FilterArrayToInt(object->GetStates(), 0); int sfilter = FilterArrayToInt(object->GetStates(), 0);
if (object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { if (object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid."); location + ": State filter is invalid.", GetDebugInfo()));
} }
if (!object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { if (!object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid."); location + ": State filter is invalid.", GetDebugInfo()));
} }
int tfilter = FilterArrayToInt(object->GetTypes(), 0); int tfilter = FilterArrayToInt(object->GetTypes(), 0);
@ -515,8 +515,8 @@ void Notification::ValidateFilters(const String& location, const Notification::P
if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved | if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery | 1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery |
1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) { 1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Type filter is invalid."); location + ": Type filter is invalid.", GetDebugInfo()));
} }
} }

View File

@ -26,7 +26,7 @@
#include "base/dynamictype.hpp" #include "base/dynamictype.hpp"
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
@ -148,12 +148,8 @@ void ScheduledDowntime::EvaluateApplyRules(const Host::Ptr& host)
if (rule.GetTargetType() != "Host") if (rule.GetTargetType() != "Host")
continue; continue;
try { if (EvaluateApplyRule(host, rule))
if (EvaluateApplyRule(host, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }
@ -165,11 +161,7 @@ void ScheduledDowntime::EvaluateApplyRules(const Service::Ptr& service)
if (rule.GetTargetType() != "Service") if (rule.GetTargetType() != "Service")
continue; continue;
try { if (EvaluateApplyRule(service, rule))
if (EvaluateApplyRule(service, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }

View File

@ -26,7 +26,7 @@
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/workqueue.hpp" #include "base/workqueue.hpp"
#include "base/scripterror.hpp" #include "base/exception.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
@ -133,11 +133,7 @@ void Service::EvaluateApplyRules(const Host::Ptr& host)
BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Service")) { BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Service")) {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
try { if (EvaluateApplyRule(host, rule))
if (EvaluateApplyRule(host, rule)) rule.AddMatch();
rule.AddMatch();
} catch (const ScriptError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
}
} }
} }

View File

@ -106,8 +106,8 @@ void User::ValidateFilters(const String& location, const Dictionary::Ptr& attrs)
int sfilter = FilterArrayToInt(attrs->Get("states"), 0); int sfilter = FilterArrayToInt(attrs->Get("states"), 0);
if ((sfilter & ~(StateFilterUp | StateFilterDown | StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { if ((sfilter & ~(StateFilterUp | StateFilterDown | StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": State filter is invalid."); location + ": State filter is invalid.", GetDebugInfo()));
} }
int tfilter = FilterArrayToInt(attrs->Get("types"), 0); int tfilter = FilterArrayToInt(attrs->Get("types"), 0);
@ -115,8 +115,8 @@ void User::ValidateFilters(const String& location, const Dictionary::Ptr& attrs)
if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved | if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery | 1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery |
1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) { 1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Type filter is invalid."); location + ": Type filter is invalid.", GetDebugInfo()));
} }
} }

View File

@ -188,7 +188,7 @@ void LivestatusListener::ValidateSocketType(const String& location, const Livest
String socket_type = object->GetSocketType(); String socket_type = object->GetSocketType();
if (socket_type != "unix" && socket_type != "tcp") { if (socket_type != "unix" && socket_type != "tcp") {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " +
location + ": Socket type '" + socket_type + "' is invalid."); location + ": Socket type '" + socket_type + "' is invalid.", GetDebugInfo()));
} }
} }