Implement array validation

Fixes #3701
This commit is contained in:
Gunnar Beutner 2013-03-14 13:24:07 +01:00
parent df4a31556a
commit 5b0a413f32
4 changed files with 182 additions and 27 deletions

View File

@ -27,8 +27,7 @@ type DynamicObject {
%require "__type",
%attribute string "__type",
%attribute dictionary "methods" {
},
%attribute dictionary "methods",
%attribute any "custom::*"
}

View File

@ -173,6 +173,92 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
if (!subRuleLists.empty() && value.IsObjectType<Dictionary>())
ValidateDictionary(value, subRuleLists, locations);
else if (!subRuleLists.empty() && value.IsObjectType<Array>())
ValidateArray(value, subRuleLists, locations);
locations.pop_back();
}
}
/**
* @threadsafety Always.
*/
void ConfigType::ValidateArray(const Array::Ptr& array,
const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& 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<Value> arguments;
arguments.push_back(LocationToString(locations));
arguments.push_back(array);
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(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<TypeRuleList::Ptr> 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<Dictionary>())
ValidateDictionary(value, subRuleLists, locations);
else if (!subRuleLists.empty() && value.IsObjectType<Array>())
ValidateArray(value, subRuleLists, locations);
locations.pop_back();
}

View File

@ -55,6 +55,8 @@ private:
static void ValidateDictionary(const Dictionary::Ptr& dictionary,
const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& locations);
static void ValidateArray(const Array::Ptr& array,
const vector<TypeRuleList::Ptr>& ruleLists, vector<String>& locations);
static String LocationToString(const vector<String>& locations);
};

View File

@ -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 {