From: Gunnar Beutner Date: Thu, 14 Mar 2013 12:24:07 +0000 (+0100) Subject: Implement array validation X-Git-Tag: v0.0.2~251 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5b0a413f3293ce74232d09cda2c3d2a3a7992faf;p=icinga2 Implement array validation Fixes #3701 --- diff --git a/lib/config/base-type.conf b/lib/config/base-type.conf index b1615f2dd..60b719d2f 100644 --- a/lib/config/base-type.conf +++ b/lib/config/base-type.conf @@ -27,8 +27,7 @@ type DynamicObject { %require "__type", %attribute string "__type", - %attribute dictionary "methods" { - }, + %attribute dictionary "methods", %attribute any "custom::*" } diff --git a/lib/config/configtype.cpp b/lib/config/configtype.cpp index 9d8620fcd..6926419d2 100644 --- a/lib/config/configtype.cpp +++ b/lib/config/configtype.cpp @@ -173,6 +173,92 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary, if (!subRuleLists.empty() && value.IsObjectType()) ValidateDictionary(value, subRuleLists, locations); + else if (!subRuleLists.empty() && value.IsObjectType()) + ValidateArray(value, subRuleLists, locations); + + locations.pop_back(); + } +} + +/** + * @threadsafety Always. + */ +void ConfigType::ValidateArray(const Array::Ptr& array, + const vector& ruleLists, vector& locations) +{ + BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) { + BOOST_FOREACH(const String& require, ruleList->GetRequires()) { + long index = Convert::ToLong(require); + + locations.push_back("Attribute '" + require + "'"); + + if (array->GetLength() < index) { + ConfigCompilerContext::GetContext()->AddError(false, + "Required array index is missing: " + LocationToString(locations)); + } + + locations.pop_back(); + } + + String validator = ruleList->GetValidator(); + + if (!validator.IsEmpty()) { + ScriptFunction::Ptr func = ScriptFunction::GetByName(validator); + + if (!func) + BOOST_THROW_EXCEPTION(invalid_argument("Validator function '" + validator + "' does not exist.")); + + vector arguments; + arguments.push_back(LocationToString(locations)); + arguments.push_back(array); + + ScriptTask::Ptr task = boost::make_shared(func, arguments); + task->Start(); + task->GetResult(); + } + } + + ObjectLock olock(array); + + int index = 0; + String key; + BOOST_FOREACH(const Value& value, array) { + key = Convert::ToString(index); + index++; + + TypeValidationResult overallResult = ValidationUnknownField; + vector subRuleLists; + + locations.push_back("Attribute '" + key + "'"); + + BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) { + TypeRuleList::Ptr subRuleList; + TypeValidationResult result = ruleList->ValidateAttribute(key, value, &subRuleList); + + if (subRuleList) + subRuleLists.push_back(subRuleList); + + if (overallResult == ValidationOK) + continue; + + if (result == ValidationOK) { + overallResult = result; + continue; + } + + if (result == ValidationInvalidType) + overallResult = result; + } + + if (overallResult == ValidationUnknownField) + ConfigCompilerContext::GetContext()->AddError(true, "Unknown attribute: " + LocationToString(locations)); + else if (overallResult == ValidationInvalidType) + ConfigCompilerContext::GetContext()->AddError(false, "Invalid type for array index: " + LocationToString(locations)); + + if (!subRuleLists.empty() && value.IsObjectType()) + ValidateDictionary(value, subRuleLists, locations); + else if (!subRuleLists.empty() && value.IsObjectType()) + ValidateArray(value, subRuleLists, locations); locations.pop_back(); } diff --git a/lib/config/configtype.h b/lib/config/configtype.h index 4251a5f3d..f0e8b89b8 100644 --- a/lib/config/configtype.h +++ b/lib/config/configtype.h @@ -55,6 +55,8 @@ private: static void ValidateDictionary(const Dictionary::Ptr& dictionary, const vector& ruleLists, vector& locations); + static void ValidateArray(const Array::Ptr& array, + const vector& ruleLists, vector& locations); static String LocationToString(const vector& locations); }; diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index b71009d67..d2f48291a 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -20,14 +20,28 @@ type Host { %attribute string "display_name", %attribute string "hostcheck", - %attribute array "hostgroups", - %attribute array "hostdependencies", - %attribute array "servicedependencies", + %attribute array "hostgroups" { + %attribute string "*" + }, + %attribute array "hostdependencies" { + %attribute string "*" + }, + %attribute array "servicedependencies" { + %attribute dictionary "*" { + %require "host", + %attribute string "host", + + %require "service", + %attribute string "service" + } + }, %attribute dictionary "services" { %validator "ValidateServiceDictionary", %attribute dictionary "*" { - %attribute array "templates", + %attribute array "templates" { + %attribute string "*" + }, %attribute string "short_name", @@ -39,23 +53,43 @@ type Host { %attribute number "check_interval", %attribute number "retry_interval", - %attribute array "servicegroups", - %attribute array "checkers", - %attribute array "hostdependencies", - %attribute array "servicedependencies" + %attribute array "servicegroups" { + %attribute string "*" + }, + %attribute array "checkers" { + %attribute string "*" + }, + %attribute array "hostdependencies" { + %attribute string "*" + }, + %attribute array "servicedependencies" { + %attribute dictionary "*" { + %require "host", + %attribute string "host", + + %require "service", + %attribute string "service" + } + } } }, %attribute dictionary "notifications" { %attribute dictionary "*" { - %attribute array "templates", + %attribute array "templates" { + %attribute string "*" + }, %attribute dictionary "macros" { %attribute string "*" }, - %attribute array "users", - %attribute array "groups" + %attribute array "users" { + %attribute string "*" + }, + %attribute array "groups" { + %attribute string "*" + } } }, @@ -68,8 +102,12 @@ type Host { %attribute dictionary "macros" { %attribute string "*" }, - %attribute array "servicegroups", - %attribute array "checkers" + %attribute array "servicegroups" { + %attribute string "*" + }, + %attribute array "checkers" { + %attribute string "*" + } } type HostGroup { @@ -98,16 +136,32 @@ type Service { %attribute dictionary "macros" { %attribute string "*" }, - %attribute array "check_command", + %attribute array "check_command" { + %attribute string "*" + }, %attribute string "check_command", %attribute number "max_check_attempts", %attribute string "check_period", %attribute number "check_interval", %attribute number "retry_interval", - %attribute array "hostdependencies", - %attribute array "servicedependencies", - %attribute array "servicegroups", - %attribute array "checkers", + %attribute array "hostdependencies" { + %attribute string "*" + }, + %attribute array "servicedependencies" { + %attribute dictionary "*" { + %require "host", + %attribute string "host", + + %require "service", + %attribute string "service" + } + }, + %attribute array "servicegroups" { + %attribute string "*" + }, + %attribute array "checkers" { + %attribute string "*" + }, %require "methods", %attribute dictionary "methods" { @@ -117,14 +171,20 @@ type Service { %attribute dictionary "notifications" { %attribute dictionary "*" { - %attribute array "templates", + %attribute array "templates" { + %attribute string "*" + }, %attribute dictionary "macros" { %attribute string "*" }, - %attribute array "users", - %attribute array "groups" + %attribute array "users" { + %attribute string "*" + }, + %attribute array "groups" { + %attribute string "*" + } } }, @@ -152,10 +212,16 @@ type Notification { %attribute string "*" }, - %attribute array "users", - %attribute array "groups", + %attribute array "users" { + %attribute string "*" + }, + %attribute array "groups" { + %attribute string "*" + }, - %attribute array "notification_command", + %attribute array "notification_command" { + %attribute string "*" + }, %attribute string "notification_command" } @@ -166,7 +232,9 @@ type User { %attribute string "*" }, - %attribute array "groups" + %attribute array "groups" { + %attribute string "*" + } } type UserGroup {