static Timer::Ptr g_ReloadConfigTimer;
#endif /* _WIN32 */
-static bool LoadConfigFiles(void)
+static bool LoadConfigFiles(bool validateOnly)
{
- set<ConfigItem::Ptr> allItems;
+ ConfigCompilerContext context;
- try {
- BOOST_FOREACH(const String& configPath, g_AppParams["config"].as<vector<String> >()) {
- vector<ConfigItem::Ptr> items;
- vector<ConfigType::Ptr> types;
+ ConfigCompilerContext::SetContext(&context);
+
+ BOOST_FOREACH(const String& configPath, g_AppParams["config"].as<vector<String> >()) {
+ ConfigCompiler::CompileFile(configPath);
+ }
- ConfigCompiler::CompileFile(configPath, &items, &types);
+ ConfigCompilerContext::SetContext(NULL);
- Logger::Write(LogInformation, "icinga-app", "Registering config types...");
- BOOST_FOREACH(const ConfigType::Ptr& type, types) {
- type->Commit();
- }
+ context.Validate();
+
+ bool hasError = false;
+
+ BOOST_FOREACH(const ConfigCompilerError& error, context.GetErrors()) {
+ if (error.Warning) {
+ Logger::Write(LogWarning, "icinga-app", "Config warning: " + error.Message);
+ } else {
+ hasError = true;
+ Logger::Write(LogCritical, "icinga-app", "Config error: " + error.Message);
+ }
+ }
- Logger::Write(LogInformation, "icinga-app", "Executing config items...");
- BOOST_FOREACH(const ConfigItem::Ptr& item, items) {
- item->Commit();
- }
+ if (hasError)
+ return false;
- Logger::Write(LogInformation, "icinga-app", "Validating config items...");
+/* Logger::Write(LogInformation, "icinga-app", "Validating config items...");
DynamicType::Ptr type;
BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) {
ConfigType::Ptr ctype = ConfigType::GetByName(type->GetName());
BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) {
ctype->ValidateObject(object);
}
- }
+ }*/
- std::copy(items.begin(), items.end(), std::inserter(allItems, allItems.begin()));
- }
+ context.ActivateItems();
- BOOST_FOREACH(const ConfigItem::WeakPtr& witem, g_ConfigItems) {
- ConfigItem::Ptr item = witem.lock();
+ BOOST_FOREACH(const ConfigItem::WeakPtr& witem, g_ConfigItems) {
+ ConfigItem::Ptr item = witem.lock();
- /* Ignore this item if it's not active anymore */
- if (!item || ConfigItem::GetObject(item->GetType(), item->GetName()) != item)
- continue;
+ /* Ignore this item if it's not active anymore */
+ if (!item || ConfigItem::GetObject(item->GetType(), item->GetName()) != item)
+ continue;
- /* Remove the object if it's not in the list of current items */
- if (allItems.find(item) == allItems.end())
- item->Unregister();
- }
+ item->Unregister();
+ }
- g_ConfigItems.clear();
- std::copy(allItems.begin(), allItems.end(), std::back_inserter(g_ConfigItems));
+ g_ConfigItems.clear();
- return true;
- } catch (const exception& ex) {
- Logger::Write(LogCritical, "icinga-app", "Configuration error: " + String(ex.what()));
- return false;
- }
+ vector<ConfigItem::Ptr> items = context.GetItems();
+ std::copy(items.begin(), items.end(), std::back_inserter(g_ConfigItems));
+ return true;
}
#ifndef _WIN32
{
if (g_ReloadConfig) {
Logger::Write(LogInformation, "icinga-app", "Received SIGHUP. Reloading config files.");
- LoadConfigFiles();
+ LoadConfigFiles(false);
g_ReloadConfig = false;
}
}
DynamicObject::BeginTx();
- if (!LoadConfigFiles())
+ bool validateOnly = g_AppParams.count("validate");
+
+ if (!LoadConfigFiles(validateOnly))
return EXIT_FAILURE;
DynamicObject::FinishTx();
+ if (validateOnly) {
+ Logger::Write(LogInformation, "icinga-app", "Terminating as requested by --validate.");
+ return EXIT_SUCCESS;
+ }
+
Application::Ptr app = Application::GetInstance();
if (!app)
throw_exception(runtime_error("Configuration must create an Application object."));
- if (g_AppParams.count("validate")) {
- Logger::Write(LogInformation, "icinga-app", "Terminating as requested by --validate.");
- return EXIT_SUCCESS;
- }
-
if (g_AppParams.count("daemonize")) {
Logger::Write(LogInformation, "icinga", "Daemonizing.");
Utility::Daemonize();
char *jsonString;
- if (Application::GetInstance()->IsDebugging())
+ if (Application::IsDebugging())
jsonString = cJSON_Print(json);
else
jsonString = cJSON_PrintUnformatted(json);
libconfig_la_SOURCES = \
configcompiler.cpp \
configcompiler.h \
+ configcompilercontext.cpp \
+ configcompilercontext.h \
config_lexer.ll \
config_parser.yy \
i2-config.h \
</ItemGroup>
<ItemGroup>
<ClInclude Include="configcompiler.h" />
+ <ClInclude Include="configcompilercontext.h" />
<ClInclude Include="configitem.h" />
<ClInclude Include="configitembuilder.h" />
<ClInclude Include="configtype.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="configcompiler.cpp" />
+ <ClCompile Include="configcompilercontext.cpp" />
<ClCompile Include="configitem.cpp" />
<ClCompile Include="configitembuilder.cpp" />
<ClCompile Include="configtype.cpp" />
void ConfigCompiler::Compile(void)
{
- yyparse(this);
+ assert(ConfigCompilerContext::GetContext() != NULL);
+
+ try {
+ yyparse(this);
+ } catch (const exception& ex) {
+ ConfigCompilerContext::GetContext()->AddError(false, ex.what());
+ }
}
#define scanner (context->GetScanner())
/* Line 343 of yacc.c */
-#line 258 "config_parser.cc"
+#line 264 "config_parser.cc"
#ifdef short
# undef short
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 110, 110, 111, 114, 114, 114, 114, 117, 121,
- 126, 131, 132, 139, 138, 160, 163, 170, 169, 181,
- 182, 184, 185, 186, 189, 194, 202, 203, 209, 210,
- 211, 212, 213, 220, 225, 220, 244, 245, 248, 252,
- 258, 259, 262, 269, 270, 274, 273, 285, 286, 288,
- 289, 290, 293, 301, 315, 324, 325, 326, 327, 328,
- 334, 339, 343, 349, 350
+ 0, 116, 116, 117, 120, 120, 120, 120, 123, 127,
+ 132, 137, 138, 145, 144, 166, 169, 176, 175, 187,
+ 188, 190, 191, 192, 195, 200, 208, 209, 215, 216,
+ 217, 218, 219, 226, 231, 226, 250, 251, 254, 258,
+ 264, 265, 268, 275, 276, 280, 279, 291, 292, 294,
+ 295, 296, 299, 307, 321, 330, 331, 332, 333, 334,
+ 340, 345, 349, 355, 356
};
#endif
case 8:
/* Line 1806 of yacc.c */
-#line 118 "config_parser.yy"
+#line 124 "config_parser.yy"
{
context->HandleInclude((yyvsp[(2) - (2)].text), false, yylloc);
}
case 9:
/* Line 1806 of yacc.c */
-#line 122 "config_parser.yy"
+#line 128 "config_parser.yy"
{
context->HandleInclude((yyvsp[(2) - (2)].text), true, yylloc);
}
case 10:
/* Line 1806 of yacc.c */
-#line 127 "config_parser.yy"
+#line 133 "config_parser.yy"
{
context->HandleLibrary((yyvsp[(2) - (2)].text));
}
case 12:
/* Line 1806 of yacc.c */
-#line 133 "config_parser.yy"
+#line 139 "config_parser.yy"
{
(yyval.text) = (yyvsp[(1) - (1)].text);
}
case 13:
/* Line 1806 of yacc.c */
-#line 139 "config_parser.yy"
+#line 145 "config_parser.yy"
{
String name = String((yyvsp[(3) - (3)].text));
- m_Type = context->GetTypeByName(name);
+ m_Type = ConfigCompilerContext::GetContext()->GetType(name);
if (!m_Type) {
if ((yyvsp[(1) - (3)].num))
throw_exception(invalid_argument("partial type definition for unknown type '" + name + "'"));
m_Type = boost::make_shared<ConfigType>(name, yylloc);
- context->AddType(m_Type);
+ ConfigCompilerContext::GetContext()->AddType(m_Type);
}
}
break;
case 14:
/* Line 1806 of yacc.c */
-#line 152 "config_parser.yy"
+#line 158 "config_parser.yy"
{
TypeRuleList::Ptr ruleList = *(yyvsp[(6) - (6)].variant);
m_Type->GetRuleList()->AddRules(ruleList);
case 15:
/* Line 1806 of yacc.c */
-#line 160 "config_parser.yy"
+#line 166 "config_parser.yy"
{
(yyval.num) = 0;
}
case 16:
/* Line 1806 of yacc.c */
-#line 164 "config_parser.yy"
+#line 170 "config_parser.yy"
{
(yyval.num) = 1;
}
case 17:
/* Line 1806 of yacc.c */
-#line 170 "config_parser.yy"
+#line 176 "config_parser.yy"
{
m_RuleLists.push(boost::make_shared<TypeRuleList>());
}
case 18:
/* Line 1806 of yacc.c */
-#line 175 "config_parser.yy"
+#line 181 "config_parser.yy"
{
(yyval.variant) = new Value(m_RuleLists.top());
m_RuleLists.pop();
case 24:
/* Line 1806 of yacc.c */
-#line 190 "config_parser.yy"
+#line 196 "config_parser.yy"
{
TypeRule rule((yyvsp[(1) - (2)].type), (yyvsp[(2) - (2)].text), TypeRuleList::Ptr(), yylloc);
m_RuleLists.top()->AddRule(rule);
case 25:
/* Line 1806 of yacc.c */
-#line 195 "config_parser.yy"
+#line 201 "config_parser.yy"
{
TypeRule rule((yyvsp[(1) - (3)].type), (yyvsp[(2) - (3)].text), *(yyvsp[(3) - (3)].variant), yylloc);
delete (yyvsp[(3) - (3)].variant);
case 27:
/* Line 1806 of yacc.c */
-#line 204 "config_parser.yy"
+#line 210 "config_parser.yy"
{
m_Type->SetParent((yyvsp[(2) - (2)].text));
}
case 32:
/* Line 1806 of yacc.c */
-#line 214 "config_parser.yy"
+#line 220 "config_parser.yy"
{
(yyval.type) = (yyvsp[(1) - (1)].type);
}
case 33:
/* Line 1806 of yacc.c */
-#line 220 "config_parser.yy"
+#line 226 "config_parser.yy"
{
m_Abstract = false;
m_Local = false;
case 34:
/* Line 1806 of yacc.c */
-#line 225 "config_parser.yy"
+#line 231 "config_parser.yy"
{
m_Item = boost::make_shared<ConfigItemBuilder>(yylloc);
m_Item->SetType((yyvsp[(4) - (5)].text));
case 35:
/* Line 1806 of yacc.c */
-#line 231 "config_parser.yy"
+#line 237 "config_parser.yy"
{
ExpressionList::Ptr exprl = *(yyvsp[(8) - (8)].variant);
delete (yyvsp[(8) - (8)].variant);
m_Item->SetLocal(m_Local);
m_Item->SetAbstract(m_Abstract);
- context->AddObject(m_Item->Compile());
+ ConfigCompilerContext::GetContext()->AddItem(m_Item->Compile());
m_Item.reset();
}
break;
case 38:
/* Line 1806 of yacc.c */
-#line 249 "config_parser.yy"
+#line 255 "config_parser.yy"
{
m_Abstract = true;
}
case 39:
/* Line 1806 of yacc.c */
-#line 253 "config_parser.yy"
+#line 259 "config_parser.yy"
{
m_Local = true;
}
case 42:
/* Line 1806 of yacc.c */
-#line 263 "config_parser.yy"
+#line 269 "config_parser.yy"
{
m_Item->AddParent((yyvsp[(1) - (1)].text));
free((yyvsp[(1) - (1)].text));
case 45:
/* Line 1806 of yacc.c */
-#line 274 "config_parser.yy"
+#line 280 "config_parser.yy"
{
m_ExpressionLists.push(boost::make_shared<ExpressionList>());
}
case 46:
/* Line 1806 of yacc.c */
-#line 279 "config_parser.yy"
+#line 285 "config_parser.yy"
{
(yyval.variant) = new Value(m_ExpressionLists.top());
m_ExpressionLists.pop();
case 52:
/* Line 1806 of yacc.c */
-#line 294 "config_parser.yy"
+#line 300 "config_parser.yy"
{
Expression expr((yyvsp[(1) - (3)].text), (yyvsp[(2) - (3)].op), *(yyvsp[(3) - (3)].variant), yylloc);
free((yyvsp[(1) - (3)].text));
case 53:
/* Line 1806 of yacc.c */
-#line 302 "config_parser.yy"
+#line 308 "config_parser.yy"
{
Expression subexpr((yyvsp[(3) - (6)].text), (yyvsp[(5) - (6)].op), *(yyvsp[(6) - (6)].variant), yylloc);
free((yyvsp[(3) - (6)].text));
case 54:
/* Line 1806 of yacc.c */
-#line 316 "config_parser.yy"
+#line 322 "config_parser.yy"
{
Expression expr((yyvsp[(1) - (1)].text), OperatorSet, (yyvsp[(1) - (1)].text), yylloc);
free((yyvsp[(1) - (1)].text));
case 59:
/* Line 1806 of yacc.c */
-#line 329 "config_parser.yy"
+#line 335 "config_parser.yy"
{
(yyval.op) = (yyvsp[(1) - (1)].op);
}
case 60:
/* Line 1806 of yacc.c */
-#line 335 "config_parser.yy"
+#line 341 "config_parser.yy"
{
(yyval.variant) = new Value((yyvsp[(1) - (1)].text));
free((yyvsp[(1) - (1)].text));
case 61:
/* Line 1806 of yacc.c */
-#line 340 "config_parser.yy"
+#line 346 "config_parser.yy"
{
(yyval.variant) = new Value((yyvsp[(1) - (1)].num));
}
case 62:
/* Line 1806 of yacc.c */
-#line 344 "config_parser.yy"
+#line 350 "config_parser.yy"
{
(yyval.variant) = new Value();
}
case 64:
/* Line 1806 of yacc.c */
-#line 351 "config_parser.yy"
+#line 357 "config_parser.yy"
{
(yyval.variant) = (yyvsp[(1) - (1)].variant);
}
/* Line 1806 of yacc.c */
-#line 1936 "config_parser.cc"
+#line 1942 "config_parser.cc"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
/* Line 2067 of yacc.c */
-#line 355 "config_parser.yy"
+#line 361 "config_parser.yy"
void ConfigCompiler::Compile(void)
{
- yyparse(this);
+ assert(ConfigCompilerContext::GetContext() != NULL);
+
+ try {
+ yyparse(this);
+ } catch (const exception& ex) {
+ ConfigCompilerContext::GetContext()->AddError(false, ex.what());
+ }
}
#define scanner (context->GetScanner())
type: partial_specifier T_TYPE identifier
{
String name = String($3);
- m_Type = context->GetTypeByName(name);
+ m_Type = ConfigCompilerContext::GetContext()->GetType(name);
if (!m_Type) {
if ($1)
throw_exception(invalid_argument("partial type definition for unknown type '" + name + "'"));
m_Type = boost::make_shared<ConfigType>(name, yylloc);
- context->AddType(m_Type);
+ ConfigCompilerContext::GetContext()->AddType(m_Type);
}
}
type_inherits_specifier typerulelist
m_Item->SetLocal(m_Local);
m_Item->SetAbstract(m_Abstract);
- context->AddObject(m_Item->Compile());
+ ConfigCompilerContext::GetContext()->AddItem(m_Item->Compile());
m_Item.reset();
}
;
return m_Scanner;
}
-/**
- * Retrieves the result from the compiler.
- *
- * @returns A list of configuration items.
- */
-vector<ConfigItem::Ptr> ConfigCompiler::GetResultObjects(void) const
-{
- return m_ResultObjects;
-}
-
-/**
- * Retrieves the resulting type objects from the compiler.
- *
- * @returns A list of type objects.
- */
-vector<ConfigType::Ptr> ConfigCompiler::GetResultTypes(void) const
-{
- vector<ConfigType::Ptr> types;
-
- ConfigType::Ptr type;
- BOOST_FOREACH(tie(tuples::ignore, type), m_ResultTypes) {
- types.push_back(type);
- }
-
- return types;
-}
-
/**
* Retrieves the path for the input file.
*
else
path = Utility::DirName(GetPath()) + "/" + include;
- vector<ConfigType::Ptr> types;
- m_HandleInclude(path, search, &m_ResultObjects, &types, debuginfo);
-
- BOOST_FOREACH(const ConfigType::Ptr& type, types) {
- AddType(type);
- }
+ m_HandleInclude(path, search, debuginfo);
}
/**
* @param stream The input stream.
* @returns Configuration items.
*/
-void ConfigCompiler::CompileStream(const String& path,
- istream *stream, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes)
+void ConfigCompiler::CompileStream(const String& path, istream *stream)
{
stream->exceptions(istream::badbit);
ConfigCompiler ctx(path, stream);
ctx.Compile();
-
- if (resultItems) {
- vector<ConfigItem::Ptr> items = ctx.GetResultObjects();
- std::copy(items.begin(), items.end(), std::back_inserter(*resultItems));
- }
-
- if (resultTypes) {
- vector<ConfigType::Ptr> types = ctx.GetResultTypes();
- std::copy(types.begin(), types.end(), std::back_inserter(*resultTypes));
- }
}
/**
* @param path The path.
* @returns Configuration items.
*/
-void ConfigCompiler::CompileFile(const String& path,
- vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes)
+void ConfigCompiler::CompileFile(const String& path)
{
ifstream stream;
stream.open(path.CStr(), ifstream::in);
Logger::Write(LogInformation, "config", "Compiling config file: " + path);
- return CompileStream(path, &stream, resultItems, resultTypes);
+ return CompileStream(path, &stream);
}
/**
* @param text The text.
* @returns Configuration items.
*/
-void ConfigCompiler::CompileText(const String& path, const String& text,
- vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes)
+void ConfigCompiler::CompileText(const String& path, const String& text)
{
stringstream stream(text);
- return CompileStream(path, &stream, resultItems, resultTypes);
+ return CompileStream(path, &stream);
}
/**
*
* @param include The path from the include directive.
* @param search Whether to search include dirs.
- * @param resultItems The resulting items.
- * @param resultTypes The resulting types.
* @param debuginfo Debug information.
*/
void ConfigCompiler::HandleFileInclude(const String& include, bool search,
- vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes, const DebugInfo& debuginfo)
+ const DebugInfo& debuginfo)
{
String includePath = include;
vector<ConfigItem::Ptr> items;
- if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CompileFile, _1, resultItems, resultTypes))) {
+ if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CompileFile, _1))) {
stringstream msgbuf;
msgbuf << "Include file '" + include + "' does not exist (or no files found for pattern): " << debuginfo;
throw_exception(invalid_argument(msgbuf.str()));
}
}
-/**
- * Adds an object to the result.
- *
- * @param object The configuration item.
- */
-void ConfigCompiler::AddObject(const ConfigItem::Ptr& object)
-{
- m_ResultObjects.push_back(object);
-}
-
/**
* Adds a directory to the list of include search dirs.
*
m_IncludeSearchDirs.push_back(dir);
}
-void ConfigCompiler::AddType(const ConfigType::Ptr& type)
-{
- m_ResultTypes[type->GetName()] = type;
-}
-
-ConfigType::Ptr ConfigCompiler::GetTypeByName(const String& name) const
-{
- map<String, ConfigType::Ptr>::const_iterator it;
-
- it = m_ResultTypes.find(name);
-
- if (it == m_ResultTypes.end())
- return ConfigType::Ptr();
-
- return it->second;
-}
class I2_CONFIG_API ConfigCompiler
{
public:
- typedef function<void (const String&, bool, vector<ConfigItem::Ptr> *,
- vector<ConfigType::Ptr> *, const DebugInfo&)> HandleIncludeFunc;
+ typedef function<void (const String&, bool, const DebugInfo&)> HandleIncludeFunc;
ConfigCompiler(const String& path, istream *input = &cin,
HandleIncludeFunc includeHandler = &ConfigCompiler::HandleFileInclude);
void Compile(void);
- static void CompileStream(const String& path,
- istream *stream, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes);
- static void CompileFile(const String& path, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes);
- static void CompileText(const String& path,
- const String& text, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes);
+ static void CompileStream(const String& path, istream *stream);
+ static void CompileFile(const String& path);
+ static void CompileText(const String& path, const String& text);
static void AddIncludeSearchDir(const String& dir);
- vector<ConfigItem::Ptr> GetResultObjects(void) const;
- vector<ConfigType::Ptr> GetResultTypes(void) const;
-
String GetPath(void) const;
static void HandleFileInclude(const String& include, bool search,
- vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes,
const DebugInfo& debuginfo);
/* internally used methods */
void HandleInclude(const String& include, bool search, const DebugInfo& debuginfo);
void HandleLibrary(const String& library);
- void AddObject(const ConfigItem::Ptr& object);
- void AddType(const ConfigType::Ptr& type);
-
- ConfigType::Ptr GetTypeByName(const String& name) const;
-
size_t ReadInput(char *buffer, size_t max_bytes);
void *GetScanner(void) const;
HandleIncludeFunc m_HandleInclude;
void *m_Scanner;
- vector<ConfigItem::Ptr> m_ResultObjects;
- map<String, ConfigType::Ptr> m_ResultTypes;
static vector<String> m_IncludeSearchDirs;
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012 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 "i2-config.h"
+
+using std::ifstream;
+
+using namespace icinga;
+
+ConfigCompilerContext *ConfigCompilerContext::m_Context = NULL;
+
+ConfigCompilerContext::ConfigCompilerContext(void)
+ : m_Flags(0)
+{ }
+
+void ConfigCompilerContext::AddItem(const ConfigItem::Ptr& item)
+{
+ m_Items.push_back(item);
+ m_ItemsMap[make_pair(item->GetType(), item->GetName())] = item;
+}
+
+ConfigItem::Ptr ConfigCompilerContext::GetItem(const String& type, const String& name) const
+{
+ map<pair<String, String>, ConfigItem::Ptr>::const_iterator it;
+
+ it = m_ItemsMap.find(make_pair(type, name));
+
+ if (it == m_ItemsMap.end())
+ return ConfigItem::Ptr();
+
+ return it->second;
+}
+
+vector<ConfigItem::Ptr> ConfigCompilerContext::GetItems(void) const
+{
+ return m_Items;
+}
+
+void ConfigCompilerContext::AddType(const ConfigType::Ptr& type)
+{
+ m_Types[type->GetName()] = type;
+}
+
+ConfigType::Ptr ConfigCompilerContext::GetType(const String& name) const
+{
+ map<String, ConfigType::Ptr>::const_iterator it;
+
+ it = m_Types.find(name);
+
+ if (it == m_Types.end())
+ return ConfigType::Ptr();
+
+ return it->second;
+}
+
+void ConfigCompilerContext::AddError(bool warning, const String& message)
+{
+ m_Errors.push_back(ConfigCompilerError(warning, message));
+}
+
+vector<ConfigCompilerError> ConfigCompilerContext::GetErrors(void) const
+{
+ return m_Errors;
+}
+
+void ConfigCompilerContext::SetFlags(int flags)
+{
+ m_Flags = flags;
+}
+
+int ConfigCompilerContext::GetFlags(void) const
+{
+ return m_Flags;
+}
+
+void ConfigCompilerContext::SetContext(ConfigCompilerContext *context)
+{
+ assert(m_Context == NULL || context == NULL);
+
+ m_Context = context;
+}
+
+ConfigCompilerContext *ConfigCompilerContext::GetContext(void)
+{
+ return m_Context;
+}
+
+void ConfigCompilerContext::Validate(void)
+{
+ SetContext(this);
+
+ BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
+ ConfigType::Ptr ctype = GetType(item->GetType());
+
+ if (!ctype)
+ continue;
+
+ ctype->ValidateItem(item);
+ }
+
+ SetContext(NULL);
+}
+
+void ConfigCompilerContext::ActivateItems(void)
+{
+ assert(m_Context == NULL);
+
+ Logger::Write(LogInformation, "config", "Executing config items...");
+ BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
+ item->Commit();
+ }
+}
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012 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 CONFIGCOMPILERCONTEXT_H
+#define CONFIGCOMPILERCONTEXT_H
+
+namespace icinga
+{
+
+/**
+ * @ingroup config
+ */
+enum ConfigCompilerFlag
+{
+ CompilerStrict = 1, /**< Treat warnings as errors. */
+ CompilerLinkExisting = 2 /**< Link objects to existing config items. */
+};
+
+struct ConfigCompilerError
+{
+ bool Warning;
+ String Message;
+
+ ConfigCompilerError(bool warning, const String& message)
+ : Warning(warning), Message(message)
+ { }
+};
+
+/*
+ * @ingroup config
+ */
+class ConfigCompilerContext
+{
+public:
+ ConfigCompilerContext(void);
+
+ void AddItem(const ConfigItem::Ptr& item);
+ ConfigItem::Ptr GetItem(const String& type, const String& name) const;
+ vector<ConfigItem::Ptr> GetItems(void) const;
+
+ void AddType(const ConfigType::Ptr& type);
+ ConfigType::Ptr GetType(const String& name) const;
+
+ void AddError(bool warning, const String& message);
+ vector<ConfigCompilerError> GetErrors(void) const;
+
+ void SetFlags(int flags);
+ int GetFlags(void) const;
+
+ void Validate(void);
+ void ActivateItems(void);
+
+ static void SetContext(ConfigCompilerContext *context);
+ static ConfigCompilerContext *GetContext(void);
+
+private:
+ int m_Flags;
+
+ vector<shared_ptr<ConfigItem> > m_Items;
+ map<pair<String, String>, shared_ptr<ConfigItem> > m_ItemsMap;
+
+ map<String, shared_ptr<ConfigType> > m_Types;
+
+ vector<ConfigCompilerError> m_Errors;
+
+ static ConfigCompilerContext *m_Context;
+};
+
+}
+
+#endif /* CONFIGCOMPILERCONTEXT_H */
return m_Parents;
}
+Dictionary::Ptr ConfigItem::Link(void) const
+{
+ Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
+ InternalLink(attrs);
+ return attrs;
+}
+
/**
* Calculates the object's properties based on parent objects and the object's
* expression list.
* @param dictionary The dictionary that should be used to store the
* properties.
*/
-void ConfigItem::CalculateProperties(const Dictionary::Ptr& dictionary) const
+void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
{
BOOST_FOREACH(const String& name, m_Parents) {
ConfigItem::Ptr parent = ConfigItem::GetObject(GetType(), name);
throw_exception(domain_error(message.str()));
}
- parent->CalculateProperties(dictionary);
+ parent->InternalLink(dictionary);
}
m_ExpressionList->Execute(dictionary);
DynamicObject::Ptr dobj = m_DynamicObject.lock();
- Dictionary::Ptr properties = boost::make_shared<Dictionary>();
- CalculateProperties(properties);
+ Dictionary::Ptr properties = Link();
/* Create a fake update in the format that
* DynamicObject::ApplyUpdate expects. */
ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
{
ConfigItem::ItemMap::iterator it;
+
+ ConfigCompilerContext *context = ConfigCompilerContext::GetContext();
+
+ if (context) {
+ ConfigItem::Ptr item = context->GetItem(type, name);
+
+ if (item)
+ return item;
+
+ /* ignore already active objects while we're in the compiler
+ * context and linking to existing items is disabled. */
+ if ((context->GetFlags() & CompilerLinkExisting) == 0)
+ return ConfigItem::Ptr();
+ }
+
it = m_Items.find(make_pair(type, name));
- if (it == m_Items.end())
- return ConfigItem::Ptr();
+ if (it != m_Items.end())
+ return it->second;
- return it->second;
+ return ConfigItem::Ptr();
}
void ConfigItem::Dump(ostream& fp) const
DebugInfo GetDebugInfo(void) const;
+ Dictionary::Ptr Link(void) const;
+
static ConfigItem::Ptr GetObject(const String& type,
const String& name);
static boost::signal<void (const ConfigItem::Ptr&)> OnRemoved;
private:
- void CalculateProperties(const Dictionary::Ptr& dictionary) const;
+ void InternalLink(const Dictionary::Ptr& dictionary) const;
void RegisterChild(const ConfigItem::Ptr& child);
void UnregisterChild(const ConfigItem::Ptr& child);
\r
using namespace icinga;\r
\r
-ConfigType::TypeMap ConfigType::m_Types;\r
-\r
ConfigType::ConfigType(const String& name, const DebugInfo& debuginfo)\r
: m_Name(name), m_RuleList(boost::make_shared<TypeRuleList>()), m_DebugInfo(debuginfo)\r
{ }\r
return m_DebugInfo;\r
}\r
\r
-void ConfigType::ValidateObject(const DynamicObject::Ptr& object) const\r
+void ConfigType::ValidateItem(const ConfigItem::Ptr& object) const\r
{\r
- DynamicObject::AttributeConstIterator it;\r
- const DynamicObject::AttributeMap& attributes = object->GetAttributes();\r
- \r
- for (it = attributes.begin(); it != attributes.end(); it++) {\r
- if ((it->second.Type & Attribute_Config) == 0)\r
- continue;\r
-\r
- if (!ValidateAttribute(it->first, it->second.Data))\r
- Logger::Write(LogWarning, "config", "Configuration attribute '" + it->first +\r
- "' on object '" + object->GetName() + "' of type '" + object->GetType()->GetName() + "' is unknown or contains an invalid type.");\r
- }\r
-}\r
+ Dictionary::Ptr attrs = object->Link();\r
\r
-void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary, const TypeRuleList::Ptr& ruleList)\r
-{\r
- String key;\r
- Value value;\r
- BOOST_FOREACH(tie(key, value), dictionary) {\r
- // TODO: implement (#3619)\r
- }\r
-}\r
+ vector<String> locations;\r
+ locations.push_back("Object '" + object->GetName() + "' (Type: '" + object->GetType() + "')");\r
\r
-bool ConfigType::ValidateAttribute(const String& name, const Value& value) const\r
-{\r
ConfigType::Ptr parent;\r
- \r
if (m_Parent.IsEmpty()) {\r
if (GetName() != "DynamicObject")\r
- parent = ConfigType::GetByName("DynamicObject");\r
+ parent = ConfigCompilerContext::GetContext()->GetType("DynamicObject");\r
} else {\r
- parent = ConfigType::GetByName(m_Parent);\r
+ parent = ConfigCompilerContext::GetContext()->GetType(m_Parent);\r
}\r
- \r
- if (parent && parent->ValidateAttribute(name, value))\r
- return true;\r
- \r
- TypeRuleList::Ptr subRules;\r
-\r
- if (!m_RuleList->FindMatch(name, value, &subRules))\r
- return false;\r
- \r
- if (subRules && value.IsObjectType<Dictionary>())\r
- ValidateDictionary(value, subRules);\r
-\r
- return true;\r
-}\r
\r
-void ConfigType::Commit(void)\r
-{\r
- m_Types[GetName()] = GetSelf();\r
+ vector<TypeRuleList::Ptr> ruleLists;\r
+ if (parent)\r
+ ruleLists.push_back(parent->m_RuleList);\r
+\r
+ ruleLists.push_back(m_RuleList);\r
+\r
+ ValidateDictionary(attrs, ruleLists, locations);\r
}\r
\r
-ConfigType::Ptr ConfigType::GetByName(const String& name)\r
+void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,\r
+ const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& locations)\r
{\r
- ConfigType::TypeMap::iterator it;\r
- \r
- it = m_Types.find(name);\r
- \r
- if (it == m_Types.end())\r
- return ConfigType::Ptr();\r
-\r
- return it->second;\r
+ String key;\r
+ Value value;\r
+ BOOST_FOREACH(tie(key, value), dictionary) {\r
+ TypeValidationResult overallResult = ValidationUnknownField;\r
+ vector<TypeRuleList::Ptr> subRuleLists;\r
+\r
+ locations.push_back("Attribute '" + key + "'");\r
+\r
+ BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {\r
+ TypeRuleList::Ptr subRuleList;\r
+ TypeValidationResult result = ruleList->Validate(key, value, &subRuleList);\r
+\r
+ if (subRuleList)\r
+ subRuleLists.push_back(subRuleList);\r
+\r
+ if (result == ValidationOK) {\r
+ overallResult = result;\r
+ break;\r
+ }\r
+\r
+ if (result == ValidationInvalidType)\r
+ overallResult = result;\r
+ }\r
+\r
+ bool first = true;\r
+ String stack;\r
+ BOOST_FOREACH(const String& location, locations) {\r
+ if (!first)\r
+ stack += " -> ";\r
+ else\r
+ first = false;\r
+\r
+ stack += location;\r
+ }\r
+\r
+ if (overallResult == ValidationUnknownField)\r
+ ConfigCompilerContext::GetContext()->AddError(true, "Unknown attribute: " + stack);\r
+ else if (overallResult == ValidationInvalidType)\r
+ ConfigCompilerContext::GetContext()->AddError(false, "Invalid type for attribute: " + stack);\r
+\r
+ if (subRuleLists.size() > 0 && value.IsObjectType<Dictionary>())\r
+ ValidateDictionary(value, subRuleLists, locations);\r
+\r
+ locations.pop_back();\r
+ }\r
}\r
+\r
namespace icinga\r
{\r
\r
+struct ConfigCompilerContext;\r
+\r
/**\r
* A configuration type. Used to validate config objects.\r
*\r
String GetParent(void) const;\r
void SetParent(const String& parent);\r
\r
- void Commit(void);\r
- \r
TypeRuleList::Ptr GetRuleList(void) const;\r
\r
DebugInfo GetDebugInfo(void) const;\r
\r
- void ValidateObject(const DynamicObject::Ptr& object) const;\r
+ void ValidateItem(const ConfigItem::Ptr& object) const;\r
\r
- static ConfigType::Ptr GetByName(const String& name);\r
- \r
private:\r
String m_Name; /**< The type name. */\r
String m_Parent; /**< The parent type. */\r
TypeRuleList::Ptr m_RuleList;\r
DebugInfo m_DebugInfo; /**< Debug information. */\r
\r
- typedef map<String, ConfigType::Ptr> TypeMap;\r
- static TypeMap m_Types; /**< All registered configuration types. */\r
-\r
- bool ValidateAttribute(const String& name, const Value& value) const;\r
- static void ValidateDictionary(const Dictionary::Ptr& dictionary, const TypeRuleList::Ptr& ruleList);\r
+ static void ValidateDictionary(const Dictionary::Ptr& dictionary,\r
+ const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& locations);\r
\r
};\r
\r
#include "debuginfo.h"
#include "typerulelist.h"
#include "typerule.h"
-#include "configtype.h"
#include "expression.h"
#include "expressionlist.h"
#include "configitem.h"
+#include "configtype.h"
#include "configitembuilder.h"
#include "configcompiler.h"
+#include "configcompilercontext.h"
#endif /* I2CONFIG_H */
return m_SubRules;
}
-bool TypeRule::Matches(const String& name, const Value& value) const
+bool TypeRule::MatchName(const String& name) const
{
- if (!Utility::Match(m_NamePattern, name))
- return false;
+ return (Utility::Match(m_NamePattern, name));
+}
+bool TypeRule::MatchValue(const Value& value) const
+{
if (value.IsEmpty())
return true;
assert(!"Type rule has invalid type specifier.");
}
}
+
\r
TypeRuleList::Ptr GetSubRules(void) const;\r
\r
- bool Matches(const String& name, const Value& value) const;\r
+ bool MatchName(const String& name) const;\r
+ bool MatchValue(const Value& value) const;\r
\r
private:\r
TypeSpecifier m_Type;\r
}\r
\r
/**\r
- * Finds a matching rule.\r
+ * Validates a field.\r
*\r
* @param name The name of the attribute.\r
* @param value The value of the attribute.\r
- * *@param[out] subRules The list of sub-rules for the matching rule.\r
+ * @param[out] subRules The list of sub-rules for the matching rule.\r
+ * @returns The validation result.\r
*/\r
-bool TypeRuleList::FindMatch(const String& name, const Value& value, TypeRuleList::Ptr *subRules)\r
+TypeValidationResult TypeRuleList::Validate(const String& name, const Value& value, TypeRuleList::Ptr *subRules) const\r
{\r
+ bool foundField = false;\r
BOOST_FOREACH(const TypeRule& rule, m_Rules) {\r
- if (rule.Matches(name, value)) {\r
+ if (!rule.MatchName(name))\r
+ continue;\r
+\r
+ foundField = true;\r
+\r
+ if (rule.MatchValue(value)) {\r
*subRules = rule.GetSubRules();\r
- return true;\r
+ return ValidationOK;\r
}\r
}\r
- \r
- return false;\r
+\r
+ if (foundField)\r
+ return ValidationInvalidType;\r
+ else\r
+ return ValidationUnknownField;\r
}\r
+\r
\r
struct TypeRule;\r
\r
+/**\r
+ * @ingroup config\r
+ */\r
+enum TypeValidationResult\r
+{\r
+ ValidationOK,\r
+ ValidationInvalidType,\r
+ ValidationUnknownField\r
+};\r
+\r
/**\r
* A list of configuration type rules.\r
*\r
void AddRule(const TypeRule& rule);\r
void AddRules(const TypeRuleList::Ptr& ruleList);\r
\r
- bool FindMatch(const String& name, const Value& value, TypeRuleList::Ptr *subRules);\r
+ TypeValidationResult Validate(const String& name, const Value& value, TypeRuleList::Ptr *subRules) const;\r
\r
size_t GetLength(void) const;\r
\r