Validate config objects before trying to activate them.

Fixes #3619
This commit is contained in:
Gunnar Beutner 2013-02-05 13:06:42 +01:00
parent 312756a886
commit 7a150d2c29
19 changed files with 475 additions and 277 deletions

View File

@ -38,28 +38,35 @@ static bool g_ReloadConfig = false;
static Timer::Ptr g_ReloadConfigTimer; static Timer::Ptr g_ReloadConfigTimer;
#endif /* _WIN32 */ #endif /* _WIN32 */
static bool LoadConfigFiles(void) static bool LoadConfigFiles(bool validateOnly)
{ {
set<ConfigItem::Ptr> allItems; ConfigCompilerContext context;
ConfigCompilerContext::SetContext(&context);
try {
BOOST_FOREACH(const String& configPath, g_AppParams["config"].as<vector<String> >()) { BOOST_FOREACH(const String& configPath, g_AppParams["config"].as<vector<String> >()) {
vector<ConfigItem::Ptr> items; ConfigCompiler::CompileFile(configPath);
vector<ConfigType::Ptr> types;
ConfigCompiler::CompileFile(configPath, &items, &types);
Logger::Write(LogInformation, "icinga-app", "Registering config types...");
BOOST_FOREACH(const ConfigType::Ptr& type, types) {
type->Commit();
} }
Logger::Write(LogInformation, "icinga-app", "Executing config items..."); ConfigCompilerContext::SetContext(NULL);
BOOST_FOREACH(const ConfigItem::Ptr& item, items) {
item->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", "Validating config items..."); if (hasError)
return false;
/* Logger::Write(LogInformation, "icinga-app", "Validating config items...");
DynamicType::Ptr type; DynamicType::Ptr type;
BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) { BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) {
ConfigType::Ptr ctype = ConfigType::GetByName(type->GetName()); ConfigType::Ptr ctype = ConfigType::GetByName(type->GetName());
@ -74,10 +81,9 @@ static bool LoadConfigFiles(void)
BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) { BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) {
ctype->ValidateObject(object); ctype->ValidateObject(object);
} }
} }*/
std::copy(items.begin(), items.end(), std::inserter(allItems, allItems.begin())); context.ActivateItems();
}
BOOST_FOREACH(const ConfigItem::WeakPtr& witem, g_ConfigItems) { BOOST_FOREACH(const ConfigItem::WeakPtr& witem, g_ConfigItems) {
ConfigItem::Ptr item = witem.lock(); ConfigItem::Ptr item = witem.lock();
@ -86,20 +92,15 @@ static bool LoadConfigFiles(void)
if (!item || ConfigItem::GetObject(item->GetType(), item->GetName()) != item) if (!item || ConfigItem::GetObject(item->GetType(), item->GetName()) != item)
continue; 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(); g_ConfigItems.clear();
std::copy(allItems.begin(), allItems.end(), std::back_inserter(g_ConfigItems));
vector<ConfigItem::Ptr> items = context.GetItems();
std::copy(items.begin(), items.end(), std::back_inserter(g_ConfigItems));
return true; return true;
} catch (const exception& ex) {
Logger::Write(LogCritical, "icinga-app", "Configuration error: " + String(ex.what()));
return false;
}
} }
#ifndef _WIN32 #ifndef _WIN32
@ -107,7 +108,7 @@ static void ReloadConfigTimerHandler(void)
{ {
if (g_ReloadConfig) { if (g_ReloadConfig) {
Logger::Write(LogInformation, "icinga-app", "Received SIGHUP. Reloading config files."); Logger::Write(LogInformation, "icinga-app", "Received SIGHUP. Reloading config files.");
LoadConfigFiles(); LoadConfigFiles(false);
g_ReloadConfig = false; g_ReloadConfig = false;
} }
} }
@ -241,21 +242,23 @@ int main(int argc, char **argv)
DynamicObject::BeginTx(); DynamicObject::BeginTx();
if (!LoadConfigFiles()) bool validateOnly = g_AppParams.count("validate");
if (!LoadConfigFiles(validateOnly))
return EXIT_FAILURE; return EXIT_FAILURE;
DynamicObject::FinishTx(); DynamicObject::FinishTx();
if (validateOnly) {
Logger::Write(LogInformation, "icinga-app", "Terminating as requested by --validate.");
return EXIT_SUCCESS;
}
Application::Ptr app = Application::GetInstance(); Application::Ptr app = Application::GetInstance();
if (!app) if (!app)
throw_exception(runtime_error("Configuration must create an Application object.")); 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")) { if (g_AppParams.count("daemonize")) {
Logger::Write(LogInformation, "icinga", "Daemonizing."); Logger::Write(LogInformation, "icinga", "Daemonizing.");
Utility::Daemonize(); Utility::Daemonize();

View File

@ -88,7 +88,7 @@ String Value::Serialize(void) const
char *jsonString; char *jsonString;
if (Application::GetInstance()->IsDebugging()) if (Application::IsDebugging())
jsonString = cJSON_Print(json); jsonString = cJSON_Print(json);
else else
jsonString = cJSON_PrintUnformatted(json); jsonString = cJSON_PrintUnformatted(json);

View File

@ -11,6 +11,8 @@ AM_YFLAGS = -d
libconfig_la_SOURCES = \ libconfig_la_SOURCES = \
configcompiler.cpp \ configcompiler.cpp \
configcompiler.h \ configcompiler.h \
configcompilercontext.cpp \
configcompilercontext.h \
config_lexer.ll \ config_lexer.ll \
config_parser.yy \ config_parser.yy \
i2-config.h \ i2-config.h \

View File

@ -20,6 +20,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="configcompiler.h" /> <ClInclude Include="configcompiler.h" />
<ClInclude Include="configcompilercontext.h" />
<ClInclude Include="configitem.h" /> <ClInclude Include="configitem.h" />
<ClInclude Include="configitembuilder.h" /> <ClInclude Include="configitembuilder.h" />
<ClInclude Include="configtype.h" /> <ClInclude Include="configtype.h" />
@ -33,6 +34,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="configcompiler.cpp" /> <ClCompile Include="configcompiler.cpp" />
<ClCompile Include="configcompilercontext.cpp" />
<ClCompile Include="configitem.cpp" /> <ClCompile Include="configitem.cpp" />
<ClCompile Include="configitembuilder.cpp" /> <ClCompile Include="configitembuilder.cpp" />
<ClCompile Include="configtype.cpp" /> <ClCompile Include="configtype.cpp" />

View File

@ -246,7 +246,13 @@ static ConfigType::Ptr m_Type;
void ConfigCompiler::Compile(void) void ConfigCompiler::Compile(void)
{ {
assert(ConfigCompilerContext::GetContext() != NULL);
try {
yyparse(this); yyparse(this);
} catch (const exception& ex) {
ConfigCompilerContext::GetContext()->AddError(false, ex.what());
}
} }
#define scanner (context->GetScanner()) #define scanner (context->GetScanner())
@ -254,7 +260,7 @@ void ConfigCompiler::Compile(void)
/* Line 343 of yacc.c */ /* Line 343 of yacc.c */
#line 258 "config_parser.cc" #line 264 "config_parser.cc"
#ifdef short #ifdef short
# undef short # undef short
@ -565,13 +571,13 @@ static const yytype_int8 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] = static const yytype_uint16 yyrline[] =
{ {
0, 110, 110, 111, 114, 114, 114, 114, 117, 121, 0, 116, 116, 117, 120, 120, 120, 120, 123, 127,
126, 131, 132, 139, 138, 160, 163, 170, 169, 181, 132, 137, 138, 145, 144, 166, 169, 176, 175, 187,
182, 184, 185, 186, 189, 194, 202, 203, 209, 210, 188, 190, 191, 192, 195, 200, 208, 209, 215, 216,
211, 212, 213, 220, 225, 220, 244, 245, 248, 252, 217, 218, 219, 226, 231, 226, 250, 251, 254, 258,
258, 259, 262, 269, 270, 274, 273, 285, 286, 288, 264, 265, 268, 275, 276, 280, 279, 291, 292, 294,
289, 290, 293, 301, 315, 324, 325, 326, 327, 328, 295, 296, 299, 307, 321, 330, 331, 332, 333, 334,
334, 339, 343, 349, 350 340, 345, 349, 355, 356
}; };
#endif #endif
@ -1616,7 +1622,7 @@ yyreduce:
case 8: case 8:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 118 "config_parser.yy" #line 124 "config_parser.yy"
{ {
context->HandleInclude((yyvsp[(2) - (2)].text), false, yylloc); context->HandleInclude((yyvsp[(2) - (2)].text), false, yylloc);
} }
@ -1625,7 +1631,7 @@ yyreduce:
case 9: case 9:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 122 "config_parser.yy" #line 128 "config_parser.yy"
{ {
context->HandleInclude((yyvsp[(2) - (2)].text), true, yylloc); context->HandleInclude((yyvsp[(2) - (2)].text), true, yylloc);
} }
@ -1634,7 +1640,7 @@ yyreduce:
case 10: case 10:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 127 "config_parser.yy" #line 133 "config_parser.yy"
{ {
context->HandleLibrary((yyvsp[(2) - (2)].text)); context->HandleLibrary((yyvsp[(2) - (2)].text));
} }
@ -1643,7 +1649,7 @@ yyreduce:
case 12: case 12:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 133 "config_parser.yy" #line 139 "config_parser.yy"
{ {
(yyval.text) = (yyvsp[(1) - (1)].text); (yyval.text) = (yyvsp[(1) - (1)].text);
} }
@ -1652,17 +1658,17 @@ yyreduce:
case 13: case 13:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 139 "config_parser.yy" #line 145 "config_parser.yy"
{ {
String name = String((yyvsp[(3) - (3)].text)); String name = String((yyvsp[(3) - (3)].text));
m_Type = context->GetTypeByName(name); m_Type = ConfigCompilerContext::GetContext()->GetType(name);
if (!m_Type) { if (!m_Type) {
if ((yyvsp[(1) - (3)].num)) if ((yyvsp[(1) - (3)].num))
throw_exception(invalid_argument("partial type definition for unknown type '" + name + "'")); throw_exception(invalid_argument("partial type definition for unknown type '" + name + "'"));
m_Type = boost::make_shared<ConfigType>(name, yylloc); m_Type = boost::make_shared<ConfigType>(name, yylloc);
context->AddType(m_Type); ConfigCompilerContext::GetContext()->AddType(m_Type);
} }
} }
break; break;
@ -1670,7 +1676,7 @@ yyreduce:
case 14: case 14:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 152 "config_parser.yy" #line 158 "config_parser.yy"
{ {
TypeRuleList::Ptr ruleList = *(yyvsp[(6) - (6)].variant); TypeRuleList::Ptr ruleList = *(yyvsp[(6) - (6)].variant);
m_Type->GetRuleList()->AddRules(ruleList); m_Type->GetRuleList()->AddRules(ruleList);
@ -1681,7 +1687,7 @@ yyreduce:
case 15: case 15:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 160 "config_parser.yy" #line 166 "config_parser.yy"
{ {
(yyval.num) = 0; (yyval.num) = 0;
} }
@ -1690,7 +1696,7 @@ yyreduce:
case 16: case 16:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 164 "config_parser.yy" #line 170 "config_parser.yy"
{ {
(yyval.num) = 1; (yyval.num) = 1;
} }
@ -1699,7 +1705,7 @@ yyreduce:
case 17: case 17:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 170 "config_parser.yy" #line 176 "config_parser.yy"
{ {
m_RuleLists.push(boost::make_shared<TypeRuleList>()); m_RuleLists.push(boost::make_shared<TypeRuleList>());
} }
@ -1708,7 +1714,7 @@ yyreduce:
case 18: case 18:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 175 "config_parser.yy" #line 181 "config_parser.yy"
{ {
(yyval.variant) = new Value(m_RuleLists.top()); (yyval.variant) = new Value(m_RuleLists.top());
m_RuleLists.pop(); m_RuleLists.pop();
@ -1718,7 +1724,7 @@ yyreduce:
case 24: case 24:
/* Line 1806 of yacc.c */ /* 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); TypeRule rule((yyvsp[(1) - (2)].type), (yyvsp[(2) - (2)].text), TypeRuleList::Ptr(), yylloc);
m_RuleLists.top()->AddRule(rule); m_RuleLists.top()->AddRule(rule);
@ -1728,7 +1734,7 @@ yyreduce:
case 25: case 25:
/* Line 1806 of yacc.c */ /* 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); TypeRule rule((yyvsp[(1) - (3)].type), (yyvsp[(2) - (3)].text), *(yyvsp[(3) - (3)].variant), yylloc);
delete (yyvsp[(3) - (3)].variant); delete (yyvsp[(3) - (3)].variant);
@ -1739,7 +1745,7 @@ yyreduce:
case 27: case 27:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 204 "config_parser.yy" #line 210 "config_parser.yy"
{ {
m_Type->SetParent((yyvsp[(2) - (2)].text)); m_Type->SetParent((yyvsp[(2) - (2)].text));
} }
@ -1748,7 +1754,7 @@ yyreduce:
case 32: case 32:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 214 "config_parser.yy" #line 220 "config_parser.yy"
{ {
(yyval.type) = (yyvsp[(1) - (1)].type); (yyval.type) = (yyvsp[(1) - (1)].type);
} }
@ -1757,7 +1763,7 @@ yyreduce:
case 33: case 33:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 220 "config_parser.yy" #line 226 "config_parser.yy"
{ {
m_Abstract = false; m_Abstract = false;
m_Local = false; m_Local = false;
@ -1767,7 +1773,7 @@ yyreduce:
case 34: case 34:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 225 "config_parser.yy" #line 231 "config_parser.yy"
{ {
m_Item = boost::make_shared<ConfigItemBuilder>(yylloc); m_Item = boost::make_shared<ConfigItemBuilder>(yylloc);
m_Item->SetType((yyvsp[(4) - (5)].text)); m_Item->SetType((yyvsp[(4) - (5)].text));
@ -1778,7 +1784,7 @@ yyreduce:
case 35: case 35:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 231 "config_parser.yy" #line 237 "config_parser.yy"
{ {
ExpressionList::Ptr exprl = *(yyvsp[(8) - (8)].variant); ExpressionList::Ptr exprl = *(yyvsp[(8) - (8)].variant);
delete (yyvsp[(8) - (8)].variant); delete (yyvsp[(8) - (8)].variant);
@ -1787,7 +1793,7 @@ yyreduce:
m_Item->SetLocal(m_Local); m_Item->SetLocal(m_Local);
m_Item->SetAbstract(m_Abstract); m_Item->SetAbstract(m_Abstract);
context->AddObject(m_Item->Compile()); ConfigCompilerContext::GetContext()->AddItem(m_Item->Compile());
m_Item.reset(); m_Item.reset();
} }
break; break;
@ -1795,7 +1801,7 @@ yyreduce:
case 38: case 38:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 249 "config_parser.yy" #line 255 "config_parser.yy"
{ {
m_Abstract = true; m_Abstract = true;
} }
@ -1804,7 +1810,7 @@ yyreduce:
case 39: case 39:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 253 "config_parser.yy" #line 259 "config_parser.yy"
{ {
m_Local = true; m_Local = true;
} }
@ -1813,7 +1819,7 @@ yyreduce:
case 42: case 42:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 263 "config_parser.yy" #line 269 "config_parser.yy"
{ {
m_Item->AddParent((yyvsp[(1) - (1)].text)); m_Item->AddParent((yyvsp[(1) - (1)].text));
free((yyvsp[(1) - (1)].text)); free((yyvsp[(1) - (1)].text));
@ -1823,7 +1829,7 @@ yyreduce:
case 45: case 45:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 274 "config_parser.yy" #line 280 "config_parser.yy"
{ {
m_ExpressionLists.push(boost::make_shared<ExpressionList>()); m_ExpressionLists.push(boost::make_shared<ExpressionList>());
} }
@ -1832,7 +1838,7 @@ yyreduce:
case 46: case 46:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 279 "config_parser.yy" #line 285 "config_parser.yy"
{ {
(yyval.variant) = new Value(m_ExpressionLists.top()); (yyval.variant) = new Value(m_ExpressionLists.top());
m_ExpressionLists.pop(); m_ExpressionLists.pop();
@ -1842,7 +1848,7 @@ yyreduce:
case 52: case 52:
/* Line 1806 of yacc.c */ /* 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); Expression expr((yyvsp[(1) - (3)].text), (yyvsp[(2) - (3)].op), *(yyvsp[(3) - (3)].variant), yylloc);
free((yyvsp[(1) - (3)].text)); free((yyvsp[(1) - (3)].text));
@ -1855,7 +1861,7 @@ yyreduce:
case 53: case 53:
/* Line 1806 of yacc.c */ /* 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); Expression subexpr((yyvsp[(3) - (6)].text), (yyvsp[(5) - (6)].op), *(yyvsp[(6) - (6)].variant), yylloc);
free((yyvsp[(3) - (6)].text)); free((yyvsp[(3) - (6)].text));
@ -1874,7 +1880,7 @@ yyreduce:
case 54: case 54:
/* Line 1806 of yacc.c */ /* 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); Expression expr((yyvsp[(1) - (1)].text), OperatorSet, (yyvsp[(1) - (1)].text), yylloc);
free((yyvsp[(1) - (1)].text)); free((yyvsp[(1) - (1)].text));
@ -1886,7 +1892,7 @@ yyreduce:
case 59: case 59:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 329 "config_parser.yy" #line 335 "config_parser.yy"
{ {
(yyval.op) = (yyvsp[(1) - (1)].op); (yyval.op) = (yyvsp[(1) - (1)].op);
} }
@ -1895,7 +1901,7 @@ yyreduce:
case 60: case 60:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 335 "config_parser.yy" #line 341 "config_parser.yy"
{ {
(yyval.variant) = new Value((yyvsp[(1) - (1)].text)); (yyval.variant) = new Value((yyvsp[(1) - (1)].text));
free((yyvsp[(1) - (1)].text)); free((yyvsp[(1) - (1)].text));
@ -1905,7 +1911,7 @@ yyreduce:
case 61: case 61:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 340 "config_parser.yy" #line 346 "config_parser.yy"
{ {
(yyval.variant) = new Value((yyvsp[(1) - (1)].num)); (yyval.variant) = new Value((yyvsp[(1) - (1)].num));
} }
@ -1914,7 +1920,7 @@ yyreduce:
case 62: case 62:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 344 "config_parser.yy" #line 350 "config_parser.yy"
{ {
(yyval.variant) = new Value(); (yyval.variant) = new Value();
} }
@ -1923,7 +1929,7 @@ yyreduce:
case 64: case 64:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 351 "config_parser.yy" #line 357 "config_parser.yy"
{ {
(yyval.variant) = (yyvsp[(1) - (1)].variant); (yyval.variant) = (yyvsp[(1) - (1)].variant);
} }
@ -1932,7 +1938,7 @@ yyreduce:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 1936 "config_parser.cc" #line 1942 "config_parser.cc"
default: break; default: break;
} }
/* User semantic actions sometimes alter yychar, and that requires /* User semantic actions sometimes alter yychar, and that requires
@ -2170,6 +2176,6 @@ yyreturn:
/* Line 2067 of yacc.c */ /* Line 2067 of yacc.c */
#line 355 "config_parser.yy" #line 361 "config_parser.yy"

View File

@ -99,7 +99,13 @@ static ConfigType::Ptr m_Type;
void ConfigCompiler::Compile(void) void ConfigCompiler::Compile(void)
{ {
assert(ConfigCompilerContext::GetContext() != NULL);
try {
yyparse(this); yyparse(this);
} catch (const exception& ex) {
ConfigCompilerContext::GetContext()->AddError(false, ex.what());
}
} }
#define scanner (context->GetScanner()) #define scanner (context->GetScanner())
@ -138,14 +144,14 @@ identifier: T_IDENTIFIER
type: partial_specifier T_TYPE identifier type: partial_specifier T_TYPE identifier
{ {
String name = String($3); String name = String($3);
m_Type = context->GetTypeByName(name); m_Type = ConfigCompilerContext::GetContext()->GetType(name);
if (!m_Type) { if (!m_Type) {
if ($1) if ($1)
throw_exception(invalid_argument("partial type definition for unknown type '" + name + "'")); throw_exception(invalid_argument("partial type definition for unknown type '" + name + "'"));
m_Type = boost::make_shared<ConfigType>(name, yylloc); m_Type = boost::make_shared<ConfigType>(name, yylloc);
context->AddType(m_Type); ConfigCompilerContext::GetContext()->AddType(m_Type);
} }
} }
type_inherits_specifier typerulelist type_inherits_specifier typerulelist
@ -236,7 +242,7 @@ object_inherits_specifier expressionlist
m_Item->SetLocal(m_Local); m_Item->SetLocal(m_Local);
m_Item->SetAbstract(m_Abstract); m_Item->SetAbstract(m_Abstract);
context->AddObject(m_Item->Compile()); ConfigCompilerContext::GetContext()->AddItem(m_Item->Compile());
m_Item.reset(); m_Item.reset();
} }
; ;

View File

@ -71,33 +71,6 @@ void *ConfigCompiler::GetScanner(void) const
return m_Scanner; 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. * Retrieves the path for the input file.
* *
@ -125,12 +98,7 @@ void ConfigCompiler::HandleInclude(const String& include, bool search, const Deb
else else
path = Utility::DirName(GetPath()) + "/" + include; path = Utility::DirName(GetPath()) + "/" + include;
vector<ConfigType::Ptr> types; m_HandleInclude(path, search, debuginfo);
m_HandleInclude(path, search, &m_ResultObjects, &types, debuginfo);
BOOST_FOREACH(const ConfigType::Ptr& type, types) {
AddType(type);
}
} }
/** /**
@ -150,23 +118,12 @@ void ConfigCompiler::HandleLibrary(const String& library)
* @param stream The input stream. * @param stream The input stream.
* @returns Configuration items. * @returns Configuration items.
*/ */
void ConfigCompiler::CompileStream(const String& path, void ConfigCompiler::CompileStream(const String& path, istream *stream)
istream *stream, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes)
{ {
stream->exceptions(istream::badbit); stream->exceptions(istream::badbit);
ConfigCompiler ctx(path, stream); ConfigCompiler ctx(path, stream);
ctx.Compile(); 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));
}
} }
/** /**
@ -175,8 +132,7 @@ void ConfigCompiler::CompileStream(const String& path,
* @param path The path. * @param path The path.
* @returns Configuration items. * @returns Configuration items.
*/ */
void ConfigCompiler::CompileFile(const String& path, void ConfigCompiler::CompileFile(const String& path)
vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes)
{ {
ifstream stream; ifstream stream;
stream.open(path.CStr(), ifstream::in); stream.open(path.CStr(), ifstream::in);
@ -186,7 +142,7 @@ void ConfigCompiler::CompileFile(const String& path,
Logger::Write(LogInformation, "config", "Compiling config file: " + path); Logger::Write(LogInformation, "config", "Compiling config file: " + path);
return CompileStream(path, &stream, resultItems, resultTypes); return CompileStream(path, &stream);
} }
/** /**
@ -196,11 +152,10 @@ void ConfigCompiler::CompileFile(const String& path,
* @param text The text. * @param text The text.
* @returns Configuration items. * @returns Configuration items.
*/ */
void ConfigCompiler::CompileText(const String& path, const String& text, void ConfigCompiler::CompileText(const String& path, const String& text)
vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes)
{ {
stringstream stream(text); stringstream stream(text);
return CompileStream(path, &stream, resultItems, resultTypes); return CompileStream(path, &stream);
} }
/** /**
@ -209,12 +164,10 @@ void ConfigCompiler::CompileText(const String& path, const String& text,
* *
* @param include The path from the include directive. * @param include The path from the include directive.
* @param search Whether to search include dirs. * @param search Whether to search include dirs.
* @param resultItems The resulting items.
* @param resultTypes The resulting types.
* @param debuginfo Debug information. * @param debuginfo Debug information.
*/ */
void ConfigCompiler::HandleFileInclude(const String& include, bool search, 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; String includePath = include;
@ -239,23 +192,13 @@ void ConfigCompiler::HandleFileInclude(const String& include, bool search,
vector<ConfigItem::Ptr> items; 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; stringstream msgbuf;
msgbuf << "Include file '" + include + "' does not exist (or no files found for pattern): " << debuginfo; msgbuf << "Include file '" + include + "' does not exist (or no files found for pattern): " << debuginfo;
throw_exception(invalid_argument(msgbuf.str())); 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. * Adds a directory to the list of include search dirs.
* *
@ -268,19 +211,3 @@ void ConfigCompiler::AddIncludeSearchDir(const String& dir)
m_IncludeSearchDirs.push_back(dir); 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;
}

View File

@ -32,8 +32,7 @@ namespace icinga
class I2_CONFIG_API ConfigCompiler class I2_CONFIG_API ConfigCompiler
{ {
public: public:
typedef function<void (const String&, bool, vector<ConfigItem::Ptr> *, typedef function<void (const String&, bool, const DebugInfo&)> HandleIncludeFunc;
vector<ConfigType::Ptr> *, const DebugInfo&)> HandleIncludeFunc;
ConfigCompiler(const String& path, istream *input = &cin, ConfigCompiler(const String& path, istream *input = &cin,
HandleIncludeFunc includeHandler = &ConfigCompiler::HandleFileInclude); HandleIncludeFunc includeHandler = &ConfigCompiler::HandleFileInclude);
@ -41,32 +40,21 @@ public:
void Compile(void); void Compile(void);
static void CompileStream(const String& path, static void CompileStream(const String& path, istream *stream);
istream *stream, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes); static void CompileFile(const String& path);
static void CompileFile(const String& path, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes); static void CompileText(const String& path, const String& text);
static void CompileText(const String& path,
const String& text, vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes);
static void AddIncludeSearchDir(const String& dir); static void AddIncludeSearchDir(const String& dir);
vector<ConfigItem::Ptr> GetResultObjects(void) const;
vector<ConfigType::Ptr> GetResultTypes(void) const;
String GetPath(void) const; String GetPath(void) const;
static void HandleFileInclude(const String& include, bool search, static void HandleFileInclude(const String& include, bool search,
vector<ConfigItem::Ptr> *resultItems, vector<ConfigType::Ptr> *resultTypes,
const DebugInfo& debuginfo); const DebugInfo& debuginfo);
/* internally used methods */ /* internally used methods */
void HandleInclude(const String& include, bool search, const DebugInfo& debuginfo); void HandleInclude(const String& include, bool search, const DebugInfo& debuginfo);
void HandleLibrary(const String& library); 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); size_t ReadInput(char *buffer, size_t max_bytes);
void *GetScanner(void) const; void *GetScanner(void) const;
@ -77,8 +65,6 @@ private:
HandleIncludeFunc m_HandleInclude; HandleIncludeFunc m_HandleInclude;
void *m_Scanner; void *m_Scanner;
vector<ConfigItem::Ptr> m_ResultObjects;
map<String, ConfigType::Ptr> m_ResultTypes;
static vector<String> m_IncludeSearchDirs; static vector<String> m_IncludeSearchDirs;

View File

@ -0,0 +1,128 @@
/******************************************************************************
* 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();
}
}

View File

@ -0,0 +1,87 @@
/******************************************************************************
* 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 */

View File

@ -92,6 +92,13 @@ vector<String> ConfigItem::GetParents(void) const
return m_Parents; 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 * Calculates the object's properties based on parent objects and the object's
* expression list. * expression list.
@ -99,7 +106,7 @@ vector<String> ConfigItem::GetParents(void) const
* @param dictionary The dictionary that should be used to store the * @param dictionary The dictionary that should be used to store the
* properties. * properties.
*/ */
void ConfigItem::CalculateProperties(const Dictionary::Ptr& dictionary) const void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
{ {
BOOST_FOREACH(const String& name, m_Parents) { BOOST_FOREACH(const String& name, m_Parents) {
ConfigItem::Ptr parent = ConfigItem::GetObject(GetType(), name); ConfigItem::Ptr parent = ConfigItem::GetObject(GetType(), name);
@ -111,7 +118,7 @@ void ConfigItem::CalculateProperties(const Dictionary::Ptr& dictionary) const
throw_exception(domain_error(message.str())); throw_exception(domain_error(message.str()));
} }
parent->CalculateProperties(dictionary); parent->InternalLink(dictionary);
} }
m_ExpressionList->Execute(dictionary); m_ExpressionList->Execute(dictionary);
@ -129,8 +136,7 @@ DynamicObject::Ptr ConfigItem::Commit(void)
DynamicObject::Ptr dobj = m_DynamicObject.lock(); DynamicObject::Ptr dobj = m_DynamicObject.lock();
Dictionary::Ptr properties = boost::make_shared<Dictionary>(); Dictionary::Ptr properties = Link();
CalculateProperties(properties);
/* Create a fake update in the format that /* Create a fake update in the format that
* DynamicObject::ApplyUpdate expects. */ * DynamicObject::ApplyUpdate expects. */
@ -279,12 +285,27 @@ DynamicObject::Ptr ConfigItem::GetDynamicObject(void) const
ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name) ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
{ {
ConfigItem::ItemMap::iterator it; 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)); it = m_Items.find(make_pair(type, name));
if (it == m_Items.end()) if (it != m_Items.end())
return ConfigItem::Ptr();
return it->second; return it->second;
return ConfigItem::Ptr();
} }
void ConfigItem::Dump(ostream& fp) const void ConfigItem::Dump(ostream& fp) const

View File

@ -54,6 +54,8 @@ public:
DebugInfo GetDebugInfo(void) const; DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr Link(void) const;
static ConfigItem::Ptr GetObject(const String& type, static ConfigItem::Ptr GetObject(const String& type,
const String& name); const String& name);
@ -61,7 +63,7 @@ public:
static boost::signal<void (const ConfigItem::Ptr&)> OnRemoved; static boost::signal<void (const ConfigItem::Ptr&)> OnRemoved;
private: private:
void CalculateProperties(const Dictionary::Ptr& dictionary) const; void InternalLink(const Dictionary::Ptr& dictionary) const;
void RegisterChild(const ConfigItem::Ptr& child); void RegisterChild(const ConfigItem::Ptr& child);
void UnregisterChild(const ConfigItem::Ptr& child); void UnregisterChild(const ConfigItem::Ptr& child);

View File

@ -21,8 +21,6 @@
using namespace icinga; using namespace icinga;
ConfigType::TypeMap ConfigType::m_Types;
ConfigType::ConfigType(const String& name, const DebugInfo& debuginfo) ConfigType::ConfigType(const String& name, const DebugInfo& debuginfo)
: m_Name(name), m_RuleList(boost::make_shared<TypeRuleList>()), m_DebugInfo(debuginfo) : m_Name(name), m_RuleList(boost::make_shared<TypeRuleList>()), m_DebugInfo(debuginfo)
{ } { }
@ -52,68 +50,77 @@ DebugInfo ConfigType::GetDebugInfo(void) const
return m_DebugInfo; return m_DebugInfo;
} }
void ConfigType::ValidateObject(const DynamicObject::Ptr& object) const void ConfigType::ValidateItem(const ConfigItem::Ptr& object) const
{ {
DynamicObject::AttributeConstIterator it; Dictionary::Ptr attrs = object->Link();
const DynamicObject::AttributeMap& attributes = object->GetAttributes();
for (it = attributes.begin(); it != attributes.end(); it++) { vector<String> locations;
if ((it->second.Type & Attribute_Config) == 0) locations.push_back("Object '" + object->GetName() + "' (Type: '" + object->GetType() + "')");
continue;
if (!ValidateAttribute(it->first, it->second.Data)) ConfigType::Ptr parent;
Logger::Write(LogWarning, "config", "Configuration attribute '" + it->first + if (m_Parent.IsEmpty()) {
"' on object '" + object->GetName() + "' of type '" + object->GetType()->GetName() + "' is unknown or contains an invalid type."); if (GetName() != "DynamicObject")
} parent = ConfigCompilerContext::GetContext()->GetType("DynamicObject");
} else {
parent = ConfigCompilerContext::GetContext()->GetType(m_Parent);
} }
void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary, const TypeRuleList::Ptr& ruleList) vector<TypeRuleList::Ptr> ruleLists;
if (parent)
ruleLists.push_back(parent->m_RuleList);
ruleLists.push_back(m_RuleList);
ValidateDictionary(attrs, ruleLists, locations);
}
void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& locations)
{ {
String key; String key;
Value value; Value value;
BOOST_FOREACH(tie(key, value), dictionary) { BOOST_FOREACH(tie(key, value), dictionary) {
// TODO: implement (#3619) TypeValidationResult overallResult = ValidationUnknownField;
vector<TypeRuleList::Ptr> subRuleLists;
locations.push_back("Attribute '" + key + "'");
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
TypeRuleList::Ptr subRuleList;
TypeValidationResult result = ruleList->Validate(key, value, &subRuleList);
if (subRuleList)
subRuleLists.push_back(subRuleList);
if (result == ValidationOK) {
overallResult = result;
break;
}
if (result == ValidationInvalidType)
overallResult = result;
}
bool first = true;
String stack;
BOOST_FOREACH(const String& location, locations) {
if (!first)
stack += " -> ";
else
first = false;
stack += location;
}
if (overallResult == ValidationUnknownField)
ConfigCompilerContext::GetContext()->AddError(true, "Unknown attribute: " + stack);
else if (overallResult == ValidationInvalidType)
ConfigCompilerContext::GetContext()->AddError(false, "Invalid type for attribute: " + stack);
if (subRuleLists.size() > 0 && value.IsObjectType<Dictionary>())
ValidateDictionary(value, subRuleLists, locations);
locations.pop_back();
} }
} }
bool ConfigType::ValidateAttribute(const String& name, const Value& value) const
{
ConfigType::Ptr parent;
if (m_Parent.IsEmpty()) {
if (GetName() != "DynamicObject")
parent = ConfigType::GetByName("DynamicObject");
} else {
parent = ConfigType::GetByName(m_Parent);
}
if (parent && parent->ValidateAttribute(name, value))
return true;
TypeRuleList::Ptr subRules;
if (!m_RuleList->FindMatch(name, value, &subRules))
return false;
if (subRules && value.IsObjectType<Dictionary>())
ValidateDictionary(value, subRules);
return true;
}
void ConfigType::Commit(void)
{
m_Types[GetName()] = GetSelf();
}
ConfigType::Ptr ConfigType::GetByName(const String& name)
{
ConfigType::TypeMap::iterator it;
it = m_Types.find(name);
if (it == m_Types.end())
return ConfigType::Ptr();
return it->second;
}

View File

@ -23,6 +23,8 @@
namespace icinga namespace icinga
{ {
struct ConfigCompilerContext;
/** /**
* A configuration type. Used to validate config objects. * A configuration type. Used to validate config objects.
* *
@ -40,15 +42,11 @@ public:
String GetParent(void) const; String GetParent(void) const;
void SetParent(const String& parent); void SetParent(const String& parent);
void Commit(void);
TypeRuleList::Ptr GetRuleList(void) const; TypeRuleList::Ptr GetRuleList(void) const;
DebugInfo GetDebugInfo(void) const; DebugInfo GetDebugInfo(void) const;
void ValidateObject(const DynamicObject::Ptr& object) const; void ValidateItem(const ConfigItem::Ptr& object) const;
static ConfigType::Ptr GetByName(const String& name);
private: private:
String m_Name; /**< The type name. */ String m_Name; /**< The type name. */
@ -57,11 +55,8 @@ private:
TypeRuleList::Ptr m_RuleList; TypeRuleList::Ptr m_RuleList;
DebugInfo m_DebugInfo; /**< Debug information. */ DebugInfo m_DebugInfo; /**< Debug information. */
typedef map<String, ConfigType::Ptr> TypeMap; static void ValidateDictionary(const Dictionary::Ptr& dictionary,
static TypeMap m_Types; /**< All registered configuration types. */ const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& locations);
bool ValidateAttribute(const String& name, const Value& value) const;
static void ValidateDictionary(const Dictionary::Ptr& dictionary, const TypeRuleList::Ptr& ruleList);
}; };

View File

@ -48,11 +48,12 @@ using std::endl;
#include "debuginfo.h" #include "debuginfo.h"
#include "typerulelist.h" #include "typerulelist.h"
#include "typerule.h" #include "typerule.h"
#include "configtype.h"
#include "expression.h" #include "expression.h"
#include "expressionlist.h" #include "expressionlist.h"
#include "configitem.h" #include "configitem.h"
#include "configtype.h"
#include "configitembuilder.h" #include "configitembuilder.h"
#include "configcompiler.h" #include "configcompiler.h"
#include "configcompilercontext.h"
#endif /* I2CONFIG_H */ #endif /* I2CONFIG_H */

View File

@ -31,11 +31,13 @@ TypeRuleList::Ptr TypeRule::GetSubRules(void) const
return m_SubRules; 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 (Utility::Match(m_NamePattern, name));
return false; }
bool TypeRule::MatchValue(const Value& value) const
{
if (value.IsEmpty()) if (value.IsEmpty())
return true; return true;
@ -64,3 +66,4 @@ bool TypeRule::Matches(const String& name, const Value& value) const
assert(!"Type rule has invalid type specifier."); assert(!"Type rule has invalid type specifier.");
} }
} }

View File

@ -50,7 +50,8 @@ public:
TypeRuleList::Ptr GetSubRules(void) const; TypeRuleList::Ptr GetSubRules(void) const;
bool Matches(const String& name, const Value& value) const; bool MatchName(const String& name) const;
bool MatchValue(const Value& value) const;
private: private:
TypeSpecifier m_Type; TypeSpecifier m_Type;

View File

@ -54,20 +54,31 @@ size_t TypeRuleList::GetLength(void) const
} }
/** /**
* Finds a matching rule. * Validates a field.
* *
* @param name The name of the attribute. * @param name The name of the attribute.
* @param value The value of the attribute. * @param value The value of the attribute.
* *@param[out] subRules The list of sub-rules for the matching rule. * @param[out] subRules The list of sub-rules for the matching rule.
* @returns The validation result.
*/ */
bool TypeRuleList::FindMatch(const String& name, const Value& value, TypeRuleList::Ptr *subRules) TypeValidationResult TypeRuleList::Validate(const String& name, const Value& value, TypeRuleList::Ptr *subRules) const
{ {
bool foundField = false;
BOOST_FOREACH(const TypeRule& rule, m_Rules) { BOOST_FOREACH(const TypeRule& rule, m_Rules) {
if (rule.Matches(name, value)) { if (!rule.MatchName(name))
continue;
foundField = true;
if (rule.MatchValue(value)) {
*subRules = rule.GetSubRules(); *subRules = rule.GetSubRules();
return true; return ValidationOK;
} }
} }
return false; if (foundField)
return ValidationInvalidType;
else
return ValidationUnknownField;
} }

View File

@ -25,6 +25,16 @@ namespace icinga
struct TypeRule; struct TypeRule;
/**
* @ingroup config
*/
enum TypeValidationResult
{
ValidationOK,
ValidationInvalidType,
ValidationUnknownField
};
/** /**
* A list of configuration type rules. * A list of configuration type rules.
* *
@ -39,7 +49,7 @@ public:
void AddRule(const TypeRule& rule); void AddRule(const TypeRule& rule);
void AddRules(const TypeRuleList::Ptr& ruleList); void AddRules(const TypeRuleList::Ptr& ruleList);
bool FindMatch(const String& name, const Value& value, TypeRuleList::Ptr *subRules); TypeValidationResult Validate(const String& name, const Value& value, TypeRuleList::Ptr *subRules) const;
size_t GetLength(void) const; size_t GetLength(void) const;