From 873e2941585c07d452fa7d543d992a437c7353f3 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 18 Dec 2014 15:11:57 +0100 Subject: [PATCH] Refactor the WorkQueue class to make error reporting easier refs #7709 --- icinga-app/icinga.cpp | 5 +- lib/base/CMakeLists.txt | 2 +- lib/base/dynamicobject.cpp | 3 +- lib/base/dynamictype.cpp | 2 +- lib/base/exception.cpp | 21 +++ lib/base/exception.hpp | 38 ++++- lib/base/scripterror.cpp | 45 ------ lib/base/scripterror.hpp | 51 ------- lib/base/scriptutils.cpp | 2 +- lib/base/workqueue.cpp | 176 ++++++++++++++---------- lib/base/workqueue.hpp | 48 +++---- lib/cli/daemoncommand.cpp | 62 ++------- lib/cli/replcommand.cpp | 14 +- lib/cli/repositoryutility.cpp | 26 +--- lib/compat/compatlogger.cpp | 4 +- lib/config/config_parser.yy | 2 +- lib/config/configcompilercontext.cpp | 33 ----- lib/config/configcompilercontext.hpp | 7 - lib/config/configitem.cpp | 61 +++----- lib/config/configitem.hpp | 5 +- lib/config/configtype.cpp | 16 +-- lib/config/expression.cpp | 2 +- lib/config/expression.hpp | 2 +- lib/config/vmops.hpp | 2 +- lib/db_ido/dbconnection.cpp | 4 +- lib/db_ido_mysql/idomysqlconnection.cpp | 2 +- lib/db_ido_pgsql/idopgsqlconnection.cpp | 2 +- lib/icinga/checkable.cpp | 4 +- lib/icinga/command.cpp | 4 +- lib/icinga/dependency-apply.cpp | 18 +-- lib/icinga/dependency.cpp | 8 +- lib/icinga/host.cpp | 2 +- lib/icinga/notification-apply.cpp | 18 +-- lib/icinga/notification.cpp | 12 +- lib/icinga/scheduleddowntime-apply.cpp | 18 +-- lib/icinga/service-apply.cpp | 10 +- lib/icinga/user.cpp | 8 +- lib/livestatus/livestatuslistener.cpp | 4 +- 38 files changed, 277 insertions(+), 466 deletions(-) delete mode 100644 lib/base/scripterror.cpp delete mode 100644 lib/base/scripterror.hpp diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index b060a39d9..1c360f52d 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -205,8 +205,9 @@ int Main(void) String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf"; if (Utility::PathExists(initconfig)) { - ConfigCompilerContext::GetInstance()->Reset(); - ConfigCompiler::CompileFile(initconfig); + ScriptFrame frame; + Expression *expression = ConfigCompiler::CompileFile(initconfig); + expression->Evaluate(frame); } #ifndef _WIN32 diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index c1ca8dfae..87b5f10b0 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -27,7 +27,7 @@ set(base_SOURCES 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 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 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 diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 38b7acb96..552b7e915 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -31,6 +31,7 @@ #include "base/initialize.hpp" #include "base/workqueue.hpp" #include "base/context.hpp" +#include "base/application.hpp" #include #include #include @@ -310,7 +311,7 @@ void DynamicObject::RestoreObjects(const String& filename, int attributeTypes) unsigned long restored = 0; - ParallelWorkQueue upq; + WorkQueue upq(25000, Application::GetConcurrency()); String message; while (NetString::ReadStringFromStream(sfp, &message)) { diff --git a/lib/base/dynamictype.cpp b/lib/base/dynamictype.cpp index 1f9d0868f..976899748 100644 --- a/lib/base/dynamictype.cpp +++ b/lib/base/dynamictype.cpp @@ -22,7 +22,7 @@ #include "base/debug.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" using namespace icinga; diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index a2a9c6a9b..a694b18ce 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -153,3 +153,24 @@ String icinga::DiagnosticInformation(boost::exception_ptr 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; +} + diff --git a/lib/base/exception.hpp b/lib/base/exception.hpp index 431422bd5..64d662e10 100644 --- a/lib/base/exception.hpp +++ b/lib/base/exception.hpp @@ -25,6 +25,7 @@ #include "base/stacktrace.hpp" #include "base/context.hpp" #include "base/utility.hpp" +#include "base/debuginfo.hpp" #include #include #include @@ -42,6 +43,25 @@ namespace icinga 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 void SetLastExceptionStack(const StackTrace& trace); @@ -58,9 +78,23 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace { std::ostringstream result; - result << boost::diagnostic_information(ex); + const user_error *uex = dynamic_cast(&ex); - if (dynamic_cast(&ex) == NULL) { + String message = ex.what(); + + if (!uex || message.IsEmpty()) + result << boost::diagnostic_information(ex); + else + result << "Error: " << message; + + const ScriptError *dex = dynamic_cast(&ex); + + if (dex && !dex->GetDebugInfo().Path.IsEmpty()) { + result << "\nLocation:\n"; + ShowCodeFragment(result, dex->GetDebugInfo()); + } + + if (!uex) { if (boost::get_error_info(ex) == NULL) { result << std::endl; diff --git a/lib/base/scripterror.cpp b/lib/base/scripterror.cpp deleted file mode 100644 index 02a3fd1fb..000000000 --- a/lib/base/scripterror.cpp +++ /dev/null @@ -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 - -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; -} - diff --git a/lib/base/scripterror.hpp b/lib/base/scripterror.hpp deleted file mode 100644 index a92573040..000000000 --- a/lib/base/scripterror.hpp +++ /dev/null @@ -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 */ diff --git a/lib/base/scriptutils.cpp b/lib/base/scriptutils.cpp index 8f3722d1e..441faab8e 100644 --- a/lib/base/scriptutils.cpp +++ b/lib/base/scriptutils.cpp @@ -26,7 +26,7 @@ #include "base/objectlock.hpp" #include "base/dynamictype.hpp" #include "base/application.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include #include #include diff --git a/lib/base/workqueue.cpp b/lib/base/workqueue.cpp index 0450493b5..1d2bfeea4 100644 --- a/lib/base/workqueue.cpp +++ b/lib/base/workqueue.cpp @@ -22,16 +22,19 @@ #include "base/logger.hpp" #include "base/convert.hpp" #include "base/application.hpp" +#include "base/exception.hpp" #include #include +#include using namespace icinga; int WorkQueue::m_NextID = 1; +boost::thread_specific_ptr l_ThreadWorkQueue; -WorkQueue::WorkQueue(size_t maxItems) - : m_ID(m_NextID++), m_MaxItems(maxItems), m_Stopped(false), - m_Processing(false), m_ExceptionCallback(WorkQueue::DefaultExceptionCallback) +WorkQueue::WorkQueue(size_t maxItems, int threadCount) + : m_ID(m_NextID++), m_MaxItems(maxItems), m_ThreadCount(threadCount), m_Spawned(false), m_Stopped(false), + m_Processing(0) { m_StatusTimer = new Timer(); 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 - * they were enqueued in except when allowInterleaved is true in which case - * the new work item might be run immediately if it's being enqueued from - * within the WorkQueue thread. + * Enqueues a task. Tasks are guaranteed to be executed in the order + * they were enqueued in except if there is more than one worker thread or when + * allowInterleaved is true in which case the new task might be run + * 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) { - callback(); + task(); return; } - WorkItem item; - item.Callback = callback; - item.AllowInterleaved = allowInterleaved; - boost::mutex::scoped_lock lock(m_Mutex); - if (m_Thread.get_id() == boost::thread::id()) - m_Thread = boost::thread(boost::bind(&WorkQueue::WorkerThreadProc, this)); + if (!m_Spawned) { + for (int i = 0; i < m_ThreadCount; i++) { + m_Threads.create_thread(boost::bind(&WorkQueue::WorkerThreadProc, this)); + } + + m_Spawned = true; + } if (!wq_thread) { - while (m_Items.size() >= m_MaxItems) + while (m_Tasks.size() >= m_MaxItems) 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(); } +/** + * 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) { boost::mutex::scoped_lock lock(m_Mutex); - while (m_Processing || !m_Items.empty()) + while (m_Processing || !m_Tasks.empty()) m_CVStarved.wait(lock); if (stop) { @@ -92,33 +102,73 @@ void WorkQueue::Join(bool stop) m_CVEmpty.notify_all(); lock.unlock(); - if (m_Thread.joinable()) - m_Thread.join(); + m_Threads.join_all(); + 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) { - boost::mutex::scoped_lock lock(m_Mutex); - 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 WorkQueue::GetExceptions(void) const +{ + boost::mutex::scoped_lock lock(m_Mutex); + + return m_Exceptions; +} + +void WorkQueue::ReportExceptions(const String& facility) const +{ + std::vector 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) { boost::mutex::scoped_lock lock(m_Mutex); - return m_Items.size(); -} - -void WorkQueue::DefaultExceptionCallback(boost::exception_ptr) -{ - throw; + return m_Tasks.size(); } void WorkQueue::StatusTimerHandler(void) @@ -126,7 +176,7 @@ void WorkQueue::StatusTimerHandler(void) boost::mutex::scoped_lock lock(m_Mutex); Log(LogNotice, "WorkQueue") - << "#" << m_ID << " items: " << m_Items.size(); + << "#" << m_ID << " tasks: " << m_Tasks.size(); } void WorkQueue::WorkerThreadProc(void) @@ -135,67 +185,47 @@ void WorkQueue::WorkerThreadProc(void) idbuf << "WQ #" << m_ID; Utility::SetThreadName(idbuf.str()); + l_ThreadWorkQueue.reset(new WorkQueue *(this)); + boost::mutex::scoped_lock lock(m_Mutex); for (;;) { - while (m_Items.empty() && !m_Stopped) + while (m_Tasks.empty() && !m_Stopped) m_CVEmpty.wait(lock); if (m_Stopped) break; - std::deque items; - m_Items.swap(items); - - if (items.size() >= m_MaxItems) + if (m_Tasks.size() >= m_MaxItems) m_CVFull.notify_all(); - m_Processing = true; + Task task = m_Tasks.front(); + m_Tasks.pop_front(); + + m_Processing++; lock.unlock(); - BOOST_FOREACH(WorkItem& wi, items) { - try { - wi.Callback(); - } - catch (const std::exception&) { - lock.lock(); + try { + task(); + } 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(); - 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& 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(); -} diff --git a/lib/base/workqueue.hpp b/lib/base/workqueue.hpp index 9970c945a..5d6263952 100644 --- a/lib/base/workqueue.hpp +++ b/lib/base/workqueue.hpp @@ -32,13 +32,7 @@ namespace icinga { -typedef boost::function WorkCallback; - -struct WorkItem -{ - WorkCallback Callback; - bool AllowInterleaved; -}; +typedef boost::function Task; /** * A workqueue. @@ -50,53 +44,43 @@ class I2_BASE_API WorkQueue public: typedef boost::function ExceptionCallback; - WorkQueue(size_t maxItems = 25000); + WorkQueue(size_t maxItems = 25000, int threadCount = 1); ~WorkQueue(void); - void Enqueue(const WorkCallback& callback, bool allowInterleaved = false); + void Enqueue(const Task& task, bool allowInterleaved = 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); - size_t GetLength(void); + bool HasExceptions(void) const; + std::vector GetExceptions(void) const; + void ReportExceptions(const String& facility) const; private: int m_ID; 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_CVFull; boost::condition_variable m_CVStarved; - boost::thread m_Thread; + boost::thread_group m_Threads; size_t m_MaxItems; bool m_Stopped; - bool m_Processing; - std::deque m_Items; + int m_Processing; + std::deque m_Tasks; ExceptionCallback m_ExceptionCallback; + std::vector m_Exceptions; Timer::Ptr m_StatusTimer; void WorkerThreadProc(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& callback); - void Join(void); - -private: - unsigned int m_QueueCount; - WorkQueue *m_Queues; - unsigned int m_Index; }; } diff --git a/lib/cli/daemoncommand.cpp b/lib/cli/daemoncommand.cpp index 255e9d457..1ef46a639 100644 --- a/lib/cli/daemoncommand.cpp +++ b/lib/cli/daemoncommand.cpp @@ -18,8 +18,8 @@ ******************************************************************************/ #include "cli/daemoncommand.hpp" -#include "config/configcompilercontext.hpp" #include "config/configcompiler.hpp" +#include "config/configcompilercontext.hpp" #include "config/configitembuilder.hpp" #include "base/logger.hpp" #include "base/application.hpp" @@ -60,16 +60,20 @@ static String LoadAppType(const String& typeSpec) return typeSpec.SubStr(index + 1); } -static void ExecuteExpression(Expression *expression) +static bool ExecuteExpression(Expression *expression) { + if (!expression) + return false; + try { ScriptFrame frame; expression->Evaluate(frame); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); } 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) @@ -95,22 +99,18 @@ static void IncludeNonLocalZone(const String& zonePath) static bool LoadConfigFiles(const boost::program_options::variables_map& vm, const String& appType, const String& objectsFile = String(), const String& varsfile = String()) { - ConfigCompilerContext::GetInstance()->Reset(); - if (!objectsFile.IsEmpty()) ConfigCompilerContext::GetInstance()->OpenObjectsFile(objectsFile); if (vm.count("config") > 0) { BOOST_FOREACH(const String& configPath, vm["config"].as >()) { Expression *expression = ConfigCompiler::CompileFile(configPath); - if (expression) - ExecuteExpression(expression); + ExecuteExpression(expression); delete expression; } } else if (!vm.count("no-config")) { Expression *expression = ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf"); - if (expression) - ExecuteExpression(expression); + ExecuteExpression(expression); delete expression; } @@ -127,8 +127,7 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con String name, fragment; BOOST_FOREACH(boost::tie(name, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) { Expression *expression = ConfigCompiler::CompileText(name, fragment); - if (expression) - ExecuteExpression(expression); + ExecuteExpression(expression); delete expression; } @@ -138,42 +137,7 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con ConfigItem::Ptr item = builder->Compile(); item->Register(); - bool result = ConfigItem::ValidateItems(); - - 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."; - } + bool result = ConfigItem::CommitItems(); if (!result) return false; diff --git a/lib/cli/replcommand.cpp b/lib/cli/replcommand.cpp index a5b134489..55443ff8b 100644 --- a/lib/cli/replcommand.cpp +++ b/lib/cli/replcommand.cpp @@ -19,7 +19,6 @@ #include "cli/replcommand.hpp" #include "config/configcompiler.hpp" -#include "config/configcompilercontext.hpp" #include "base/json.hpp" #include "base/console.hpp" #include "base/application.hpp" @@ -132,22 +131,11 @@ int ReplCommand::Run(const po::variables_map& vm, const std::vector Expression *expr; try { - ConfigCompilerContext::GetInstance()->Reset(); - lines[fileName] = line; expr = ConfigCompiler::CompileText(fileName, line); - bool has_errors = false; - - 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) { + if (expr) { Value result = expr->Evaluate(frame); std::cout << ConsoleColorTag(Console_ForegroundCyan); if (!result.IsObject() || result.IsObjectType() || result.IsObjectType()) diff --git a/lib/cli/repositoryutility.cpp b/lib/cli/repositoryutility.cpp index ad35bf409..f1d55201e 100644 --- a/lib/cli/repositoryutility.cpp +++ b/lib/cli/repositoryutility.cpp @@ -229,8 +229,6 @@ bool RepositoryUtility::AddObject(const String& name, const String& type, const change->Set("command", "add"); change->Set("attrs", attrs); - ConfigCompilerContext::GetInstance()->Reset(); - String fname, fragment; BOOST_FOREACH(boost::tie(fname, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) { 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(); Deserialize(object, vattrs, false, FAConfig); - RepositoryTypeRuleUtilities utils; - ctype->ValidateItem(name, object, DebugInfo(), &utils); - - int warnings = 0, errors = 0; - - 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) + try { + RepositoryTypeRuleUtilities utils; + ctype->ValidateItem(name, object, DebugInfo(), &utils); + } catch (const ScriptError& ex) { + Log(LogCritical, "config", DiagnosticInformation(ex)); return false; + } } if (CheckChangeExists(change)) { diff --git a/lib/compat/compatlogger.cpp b/lib/compat/compatlogger.cpp index e92d80b30..8b318bad8 100644 --- a/lib/compat/compatlogger.cpp +++ b/lib/compat/compatlogger.cpp @@ -570,8 +570,8 @@ void CompatLogger::ValidateRotationMethod(const String& location, const CompatLo if (rotation_method != "HOURLY" && rotation_method != "DAILY" && rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": Rotation method '" + rotation_method + "' is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": Rotation method '" + rotation_method + "' is invalid.", GetDebugInfo())); } } diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 38dc2b22c..b422c18bb 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -33,7 +33,7 @@ #include "base/utility.hpp" #include "base/exception.hpp" #include "base/dynamictype.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include #include #include diff --git a/lib/config/configcompilercontext.cpp b/lib/config/configcompilercontext.cpp index 6ac45a97a..3a4fb531d 100644 --- a/lib/config/configcompilercontext.cpp +++ b/lib/config/configcompilercontext.cpp @@ -27,39 +27,6 @@ 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 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) { return Singleton::GetInstance(); diff --git a/lib/config/configcompilercontext.hpp b/lib/config/configcompilercontext.hpp index 84091ba2f..f51a2ba79 100644 --- a/lib/config/configcompilercontext.hpp +++ b/lib/config/configcompilercontext.hpp @@ -47,12 +47,6 @@ struct I2_CONFIG_API ConfigCompilerMessage class I2_CONFIG_API ConfigCompilerContext { public: - void AddMessage(bool error, const String& message, const DebugInfo& di = DebugInfo()); - std::vector GetMessages(void) const; - bool HasErrors(void) const; - - void Reset(void); - void OpenObjectsFile(const String& filename); void WriteObject(const Dictionary::Ptr& object); void FinishObjectsFile(void); @@ -60,7 +54,6 @@ public: static ConfigCompilerContext *GetInstance(void); private: - std::vector m_Messages; String m_ObjectsPath; StdioStream::Ptr m_ObjectsFP; diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index d71e370d3..b358dd417 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -34,7 +34,7 @@ #include "base/netstring.hpp" #include "base/serializer.hpp" #include "base/json.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include #include #include @@ -163,16 +163,10 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard) DebugHint debugHints; - try { - ScriptFrame frame(dobj); - if (m_Scope) - m_Scope->CopyTo(frame.Locals); - 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)); - } + ScriptFrame frame(dobj); + if (m_Scope) + m_Scope->CopyTo(frame.Locals); + m_Expression->Evaluate(frame, &debugHints); if (discard) m_Expression.reset(); @@ -222,18 +216,9 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard) ConfigType::Ptr ctype = ConfigType::GetByName(GetType()); - if (!ctype) - ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'"); - else { + if (ctype) TypeRuleUtilities 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)); - } + ctype->ValidateItem(GetName(), dobj, GetDebugInfo(), &utils); } 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 ItemPair; std::vector items; @@ -320,7 +305,7 @@ bool ConfigItem::CommitNewItems(ParallelWorkQueue& upq) upq.Join(); - if (ConfigCompilerContext::GetInstance()->HasErrors()) + if (upq.HasExceptions()) return false; std::vector new_items; @@ -340,22 +325,18 @@ bool ConfigItem::CommitNewItems(ParallelWorkQueue& upq) return true; } -bool ConfigItem::ValidateItems(void) +bool ConfigItem::CommitItems(void) { - ParallelWorkQueue upq; - - if (ConfigCompilerContext::GetInstance()->HasErrors()) - return false; + WorkQueue upq(25000, Application::GetConcurrency()); Log(LogInformation, "ConfigItem", "Committing config items"); - if (!CommitNewItems(upq)) + if (!CommitNewItems(upq)) { + upq.ReportExceptions("config"); return false; + } ApplyRule::CheckMatches(); - ApplyRule::DiscardRules(); - - ConfigItem::DiscardItems(); ConfigType::DiscardTypes(); /* log stats for external parsers */ @@ -366,14 +347,11 @@ bool ConfigItem::ValidateItems(void) << "Checked " << count << " " << type->GetName() << "(s)."; } - return !ConfigCompilerContext::GetInstance()->HasErrors(); + return true; } bool ConfigItem::ActivateItems(void) { - if (ConfigCompilerContext::GetInstance()->HasErrors()) - return false; - /* restore the previous program state */ try { DynamicObject::RestoreObjects(Application::GetStatePath()); @@ -384,7 +362,7 @@ bool ConfigItem::ActivateItems(void) 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 DynamicObject::Ptr& object, type->GetObjects()) { @@ -414,13 +392,6 @@ bool ConfigItem::ActivateItems(void) return true; } -void ConfigItem::DiscardItems(void) -{ - boost::mutex::scoped_lock lock(m_Mutex); - - m_Items.clear(); -} - std::vector ConfigItem::GetItems(const String& type) { std::vector items; diff --git a/lib/config/configitem.hpp b/lib/config/configitem.hpp index 538b9d89d..a31def4f6 100644 --- a/lib/config/configitem.hpp +++ b/lib/config/configitem.hpp @@ -64,9 +64,8 @@ public: static ConfigItem::Ptr GetObject(const String& type, const String& name); - static bool ValidateItems(void); + static bool CommitItems(void); static bool ActivateItems(void); - static void DiscardItems(void); static std::vector GetItems(const String& type); @@ -96,7 +95,7 @@ private: static ConfigItem::Ptr GetObjectUnlocked(const String& type, const String& name); - static bool CommitNewItems(ParallelWorkQueue& upq); + static bool CommitNewItems(WorkQueue& upq); }; } diff --git a/lib/config/configtype.cpp b/lib/config/configtype.cpp index 1c20b49ba..19dfdecdc 100644 --- a/lib/config/configtype.cpp +++ b/lib/config/configtype.cpp @@ -136,14 +136,14 @@ void ConfigType::ValidateAttribute(const String& key, const Value& value, } if (overallResult == ValidationUnknownField) - ConfigCompilerContext::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations)); + BOOST_THROW_EXCEPTION(ScriptError("Unknown attribute: " + LocationToString(locations))); else if (overallResult == ValidationInvalidType) { String message = "Invalid value: " + LocationToString(locations); if (!hint.IsEmpty()) message += ": " + hint; - ConfigCompilerContext::GetInstance()->AddMessage(true, message); + BOOST_THROW_EXCEPTION(ScriptError(message)); } if (!subRuleLists.empty() && value.IsObject() && !value.IsObjectType()) @@ -164,10 +164,8 @@ void ConfigType::ValidateObject(const Object::Ptr& object, Value value = VMOps::GetField(object, require); - if (value.IsEmpty() || (value.IsString() && static_cast(value).IsEmpty())) { - ConfigCompilerContext::GetInstance()->AddMessage(true, - "Required attribute is missing: " + LocationToString(locations)); - } + if (value.IsEmpty() || (value.IsString() && static_cast(value).IsEmpty())) + BOOST_THROW_EXCEPTION(ScriptError("Required attribute is missing: " + LocationToString(locations))); locations.pop_back(); } @@ -223,10 +221,8 @@ void ConfigType::ValidateArray(const Array::Ptr& array, locations.push_back("Attribute '" + require + "'"); - if (array->GetLength() < index) { - ConfigCompilerContext::GetInstance()->AddMessage(true, - "Required array index is missing: " + LocationToString(locations)); - } + if (array->GetLength() < index) + BOOST_THROW_EXCEPTION(ScriptError("Required array index is missing: " + LocationToString(locations))); locations.pop_back(); } diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 3b4c7c77e..1ff32298c 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -24,7 +24,7 @@ #include "base/json.hpp" #include "base/object.hpp" #include "base/logger.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include "base/scriptglobal.hpp" #include #include diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 7165658b1..6948d1cca 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -25,7 +25,7 @@ #include "base/array.hpp" #include "base/dictionary.hpp" #include "base/scriptfunction.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include "base/scriptframe.hpp" #include "base/convert.hpp" #include diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 48d0f5b48..f89f7c1e5 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -30,7 +30,7 @@ #include "base/dictionary.hpp" #include "base/scriptfunction.hpp" #include "base/scriptglobal.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include "base/convert.hpp" #include "base/objectlock.hpp" #include diff --git a/lib/db_ido/dbconnection.cpp b/lib/db_ido/dbconnection.cpp index d754505f2..9eee40f3c 100644 --- a/lib/db_ido/dbconnection.cpp +++ b/lib/db_ido/dbconnection.cpp @@ -424,7 +424,7 @@ void DbConnection::PrepareDatabase(void) void DbConnection::ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object) { if (object->GetFailoverTimeout() < 60) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": Failover timeout minimum is 60s."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": Failover timeout minimum is 60s.", GetDebugInfo())); } } diff --git a/lib/db_ido_mysql/idomysqlconnection.cpp b/lib/db_ido_mysql/idomysqlconnection.cpp index 69461ebce..7f85ad776 100644 --- a/lib/db_ido_mysql/idomysqlconnection.cpp +++ b/lib/db_ido_mysql/idomysqlconnection.cpp @@ -115,7 +115,7 @@ void IdoMysqlConnection::ExceptionHandler(boost::exception_ptr exp) void IdoMysqlConnection::AssertOnWorkQueue(void) { - ASSERT(boost::this_thread::get_id() == m_QueryQueue.GetThreadId()); + ASSERT(m_QueryQueue.IsWorkerThread()); } void IdoMysqlConnection::Disconnect(void) diff --git a/lib/db_ido_pgsql/idopgsqlconnection.cpp b/lib/db_ido_pgsql/idopgsqlconnection.cpp index 045adfe98..1c8653ac5 100644 --- a/lib/db_ido_pgsql/idopgsqlconnection.cpp +++ b/lib/db_ido_pgsql/idopgsqlconnection.cpp @@ -116,7 +116,7 @@ void IdoPgsqlConnection::ExceptionHandler(boost::exception_ptr exp) void IdoPgsqlConnection::AssertOnWorkQueue(void) { - ASSERT(boost::this_thread::get_id() == m_QueryQueue.GetThreadId()); + ASSERT(m_QueryQueue.IsWorkerThread()); } void IdoPgsqlConnection::Disconnect(void) diff --git a/lib/icinga/checkable.cpp b/lib/icinga/checkable.cpp index c8f65ea9b..e6a475351 100644 --- a/lib/icinga/checkable.cpp +++ b/lib/icinga/checkable.cpp @@ -270,7 +270,7 @@ Endpoint::Ptr Checkable::GetCommandEndpoint(void) const void Checkable::ValidateCheckInterval(const String& location, const Checkable::Ptr& object) { if (object->GetCheckInterval() <= 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": check_interval must be greater than 0."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": check_interval must be greater than 0.", GetDebugInfo())); } } diff --git a/lib/icinga/command.cpp b/lib/icinga/command.cpp index 947fcf3b8..538330759 100644 --- a/lib/icinga/command.cpp +++ b/lib/icinga/command.cpp @@ -47,8 +47,8 @@ void Command::SetModifiedAttributes(int flags, const MessageOrigin& origin) void Command::ValidateAttributes(const String& location, const Command::Ptr& object) { if (object->GetArguments() != Empty && !object->GetCommandLine().IsObjectType()) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": Attribute 'command' must be an array if the 'arguments' attribute is set."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": Attribute 'command' must be an array if the 'arguments' attribute is set.", GetDebugInfo())); } } diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 8dd0ace17..82cd6e578 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -27,7 +27,7 @@ #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include using namespace icinga; @@ -150,12 +150,8 @@ void Dependency::EvaluateApplyRules(const Host::Ptr& host) if (rule.GetTargetType() != "Host") continue; - try { - if (EvaluateApplyRule(host, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(host, rule)) + rule.AddMatch(); } } @@ -167,11 +163,7 @@ void Dependency::EvaluateApplyRules(const Service::Ptr& service) if (rule.GetTargetType() != "Service") continue; - try { - if (EvaluateApplyRule(service, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(service, rule)) + rule.AddMatch(); } } diff --git a/lib/icinga/dependency.cpp b/lib/icinga/dependency.cpp index 4bafab4e1..bbd20d392 100644 --- a/lib/icinga/dependency.cpp +++ b/lib/icinga/dependency.cpp @@ -208,12 +208,12 @@ void Dependency::ValidateFilters(const String& location, const Dependency::Ptr& int sfilter = FilterArrayToInt(object->GetStates(), 0); if (object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": State filter is invalid for host dependency."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": State filter is invalid for host dependency.", GetDebugInfo())); } if (!object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": State filter is invalid for service dependency."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": State filter is invalid for service dependency.", GetDebugInfo())); } } diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index c87d1674d..2f4e5a341 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -23,7 +23,7 @@ #include "icinga/pluginutility.hpp" #include "icinga/scheduleddowntime.hpp" #include "config/configcompilercontext.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include "base/objectlock.hpp" #include "base/convert.hpp" #include "base/utility.hpp" diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index f7fd494cd..01d3f4e1b 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -27,7 +27,7 @@ #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include using namespace icinga; @@ -150,12 +150,8 @@ void Notification::EvaluateApplyRules(const Host::Ptr& host) if (rule.GetTargetType() != "Host") continue; - try { - if (EvaluateApplyRule(host, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(host, rule)) + rule.AddMatch(); } } @@ -167,11 +163,7 @@ void Notification::EvaluateApplyRules(const Service::Ptr& service) if (rule.GetTargetType() != "Service") continue; - try { - if (EvaluateApplyRule(service, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(service, rule)) + rule.AddMatch(); } } diff --git a/lib/icinga/notification.cpp b/lib/icinga/notification.cpp index 8239fa39f..c9326f2a9 100644 --- a/lib/icinga/notification.cpp +++ b/lib/icinga/notification.cpp @@ -501,13 +501,13 @@ void Notification::ValidateFilters(const String& location, const Notification::P int sfilter = FilterArrayToInt(object->GetStates(), 0); if (object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": State filter is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": State filter is invalid.", GetDebugInfo())); } if (!object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": State filter is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": State filter is invalid.", GetDebugInfo())); } 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 | 1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery | 1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": Type filter is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": Type filter is invalid.", GetDebugInfo())); } } diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index 71114c0e0..b288b1864 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -26,7 +26,7 @@ #include "base/dynamictype.hpp" #include "base/logger.hpp" #include "base/context.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include using namespace icinga; @@ -148,12 +148,8 @@ void ScheduledDowntime::EvaluateApplyRules(const Host::Ptr& host) if (rule.GetTargetType() != "Host") continue; - try { - if (EvaluateApplyRule(host, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(host, rule)) + rule.AddMatch(); } } @@ -165,11 +161,7 @@ void ScheduledDowntime::EvaluateApplyRules(const Service::Ptr& service) if (rule.GetTargetType() != "Service") continue; - try { - if (EvaluateApplyRule(service, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(service, rule)) + rule.AddMatch(); } } diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index d7be39235..1276e90aa 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -26,7 +26,7 @@ #include "base/logger.hpp" #include "base/context.hpp" #include "base/workqueue.hpp" -#include "base/scripterror.hpp" +#include "base/exception.hpp" #include using namespace icinga; @@ -133,11 +133,7 @@ void Service::EvaluateApplyRules(const Host::Ptr& host) BOOST_FOREACH(ApplyRule& rule, ApplyRule::GetRules("Service")) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); - try { - if (EvaluateApplyRule(host, rule)) - rule.AddMatch(); - } catch (const ScriptError& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); - } + if (EvaluateApplyRule(host, rule)) + rule.AddMatch(); } } diff --git a/lib/icinga/user.cpp b/lib/icinga/user.cpp index 098992bf0..0e7b6374b 100644 --- a/lib/icinga/user.cpp +++ b/lib/icinga/user.cpp @@ -106,8 +106,8 @@ void User::ValidateFilters(const String& location, const Dictionary::Ptr& attrs) int sfilter = FilterArrayToInt(attrs->Get("states"), 0); if ((sfilter & ~(StateFilterUp | StateFilterDown | StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": State filter is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": State filter is invalid.", GetDebugInfo())); } 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 | 1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery | 1 << NotificationFlappingStart | 1 << NotificationFlappingEnd)) != 0) { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": Type filter is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": Type filter is invalid.", GetDebugInfo())); } } diff --git a/lib/livestatus/livestatuslistener.cpp b/lib/livestatus/livestatuslistener.cpp index 5a595adec..b38472ada 100644 --- a/lib/livestatus/livestatuslistener.cpp +++ b/lib/livestatus/livestatuslistener.cpp @@ -188,7 +188,7 @@ void LivestatusListener::ValidateSocketType(const String& location, const Livest String socket_type = object->GetSocketType(); if (socket_type != "unix" && socket_type != "tcp") { - ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + - location + ": Socket type '" + socket_type + "' is invalid."); + BOOST_THROW_EXCEPTION(ScriptError("Validation failed for " + + location + ": Socket type '" + socket_type + "' is invalid.", GetDebugInfo())); } }