Refactor the config validator so that it doesn't require serialized objects

refs #7701
This commit is contained in:
Gunnar Beutner 2014-11-20 13:28:21 +01:00
parent 5321bc4643
commit 2d53e000c8
16 changed files with 102 additions and 116 deletions

View File

@ -563,11 +563,11 @@ void CompatLogger::RotationTimerHandler(void)
ScheduleNextRotation();
}
void CompatLogger::ValidateRotationMethod(const String& location, const Dictionary::Ptr& attrs)
void CompatLogger::ValidateRotationMethod(const String& location, const CompatLogger::Ptr& object)
{
Value rotation_method = attrs->Get("rotation_method");
String rotation_method = object->GetRotationMethod();
if (!rotation_method.IsEmpty() && rotation_method != "HOURLY" && rotation_method != "DAILY" &&
if (rotation_method != "HOURLY" && rotation_method != "DAILY" &&
rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Rotation method '" + rotation_method + "' is invalid.");

View File

@ -41,7 +41,7 @@ public:
static Value StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
static void ValidateRotationMethod(const String& location, const Dictionary::Ptr& attrs);
static void ValidateRotationMethod(const String& location, const CompatLogger::Ptr& object);
protected:
virtual void Start(void);

View File

@ -21,6 +21,8 @@
%require "__name",
%attribute %string "__name",
%attribute %string "name",
%require "type",
%attribute %string "type",

View File

@ -209,8 +209,7 @@ DynamicObject::Ptr ConfigItem::Commit(bool discard)
TypeRuleUtilities utils;
try {
attrs->Remove("name");
ctype->ValidateItem(GetName(), attrs, GetDebugInfo(), &utils);
ctype->ValidateItem(GetName(), dobj, GetDebugInfo(), &utils);
} catch (const ConfigError& ex) {
const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());

View File

@ -19,6 +19,7 @@
#include "config/configtype.hpp"
#include "config/configcompilercontext.hpp"
#include "config/expression.hpp"
#include "base/objectlock.hpp"
#include "base/convert.hpp"
#include "base/singleton.hpp"
@ -72,7 +73,7 @@ void ConfigType::AddParentRules(std::vector<TypeRuleList::Ptr>& ruleLists, const
}
}
void ConfigType::ValidateItem(const String& name, const Dictionary::Ptr& attrs, const DebugInfo& debugInfo, const TypeRuleUtilities *utils)
void ConfigType::ValidateItem(const String& name, const Object::Ptr& object, const DebugInfo& debugInfo, const TypeRuleUtilities *utils)
{
String location = "Object '" + name + "' (Type: '" + GetName() + "')";
@ -86,7 +87,7 @@ void ConfigType::ValidateItem(const String& name, const Dictionary::Ptr& attrs,
AddParentRules(ruleLists, this);
ruleLists.push_back(m_RuleList);
ValidateDictionary(attrs, ruleLists, locations, utils);
ValidateObject(object, ruleLists, locations, utils);
}
String ConfigType::LocationToString(const std::vector<String>& locations)
@ -105,7 +106,55 @@ String ConfigType::LocationToString(const std::vector<String>& locations)
return stack;
}
void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
void ConfigType::ValidateAttribute(const String& key, const Value& value,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils)
{
TypeValidationResult overallResult = ValidationUnknownField;
std::vector<TypeRuleList::Ptr> subRuleLists;
String hint;
locations.push_back("Key " + key);
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
TypeRuleList::Ptr subRuleList;
TypeValidationResult result = ruleList->ValidateAttribute(key, value, &subRuleList, &hint, utils);
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::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations));
else if (overallResult == ValidationInvalidType) {
String message = "Invalid value: " + LocationToString(locations);
if (!hint.IsEmpty())
message += ": " + hint;
ConfigCompilerContext::GetInstance()->AddMessage(true, message);
}
if (!subRuleLists.empty() && value.IsObject() && !value.IsObjectType<Array>())
ValidateObject(value, subRuleLists, locations, utils);
else if (!subRuleLists.empty() && value.IsObjectType<Array>())
ValidateArray(value, subRuleLists, locations, utils);
locations.pop_back();
}
void ConfigType::ValidateObject(const Object::Ptr& object,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils)
{
@ -113,7 +162,7 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
BOOST_FOREACH(const String& require, ruleList->GetRequires()) {
locations.push_back("Attribute '" + require + "'");
Value value = dictionary->Get(require);
Value value = Expression::GetField(object, require);
if (value.IsEmpty() || (value.IsString() && static_cast<String>(value).IsEmpty())) {
ConfigCompilerContext::GetInstance()->AddMessage(true,
@ -133,57 +182,34 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
std::vector<Value> arguments;
arguments.push_back(LocationToString(locations));
arguments.push_back(dictionary);
arguments.push_back(object);
func->Invoke(arguments);
}
}
ObjectLock olock(dictionary);
Dictionary::Ptr dictionary = dynamic_pointer_cast<Dictionary>(object);
BOOST_FOREACH(const Dictionary::Pair& kv, dictionary) {
TypeValidationResult overallResult = ValidationUnknownField;
std::vector<TypeRuleList::Ptr> subRuleLists;
String hint;
if (dictionary) {
ObjectLock olock(dictionary);
locations.push_back("Attribute '" + kv.first + "'");
BOOST_FOREACH(const Dictionary::Pair& kv, dictionary) {
ValidateAttribute(kv.first, kv.second, ruleLists, locations, utils);
}
} else {
Type::Ptr type = object->GetReflectionType();
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
TypeRuleList::Ptr subRuleList;
TypeValidationResult result = ruleList->ValidateAttribute(kv.first, kv.second, &subRuleList, &hint, utils);
if (!type)
return;
if (subRuleList)
subRuleLists.push_back(subRuleList);
for (int i = 0; i < type->GetFieldCount(); i++) {
Field field = type->GetFieldInfo(i);
if (overallResult == ValidationOK)
if (!(field.Attributes & FAConfig))
continue;
if (result == ValidationOK) {
overallResult = result;
continue;
}
if (result == ValidationInvalidType)
overallResult = result;
ValidateAttribute(field.Name, object->GetField(i), ruleLists, locations, utils);
}
if (overallResult == ValidationUnknownField)
ConfigCompilerContext::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations));
else if (overallResult == ValidationInvalidType) {
String message = "Invalid value for attribute: " + LocationToString(locations);
if (!hint.IsEmpty())
message += ": " + hint;
ConfigCompilerContext::GetInstance()->AddMessage(true, message);
}
if (!subRuleLists.empty() && kv.second.IsObjectType<Dictionary>())
ValidateDictionary(kv.second, subRuleLists, locations, utils);
else if (!subRuleLists.empty() && kv.second.IsObjectType<Array>())
ValidateArray(kv.second, subRuleLists, locations, utils);
locations.pop_back();
}
}
@ -229,48 +255,7 @@ void ConfigType::ValidateArray(const Array::Ptr& array,
key = Convert::ToString(index);
index++;
TypeValidationResult overallResult = ValidationUnknownField;
std::vector<TypeRuleList::Ptr> subRuleLists;
String hint;
locations.push_back("Index " + key);
BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
TypeRuleList::Ptr subRuleList;
TypeValidationResult result = ruleList->ValidateAttribute(key, value, &subRuleList, &hint, utils);
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::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations));
else if (overallResult == ValidationInvalidType) {
String message = "Invalid value for array index: " + LocationToString(locations);
if (!hint.IsEmpty())
message += ": " + hint;
ConfigCompilerContext::GetInstance()->AddMessage(true, message);
}
if (!subRuleLists.empty() && value.IsObjectType<Dictionary>())
ValidateDictionary(value, subRuleLists, locations, utils);
else if (!subRuleLists.empty() && value.IsObjectType<Array>())
ValidateArray(value, subRuleLists, locations, utils);
locations.pop_back();
ValidateAttribute(key, value, ruleLists, locations, utils);
}
}

View File

@ -50,7 +50,7 @@ public:
DebugInfo GetDebugInfo(void) const;
void ValidateItem(const String& name, const Dictionary::Ptr& attrs,
void ValidateItem(const String& name, const Object::Ptr& object,
const DebugInfo& debugInfo, const TypeRuleUtilities *utils);
void Register(void);
@ -65,7 +65,10 @@ private:
TypeRuleList::Ptr m_RuleList;
DebugInfo m_DebugInfo; /**< Debug information. */
static void ValidateDictionary(const Dictionary::Ptr& dictionary,
static void ValidateAttribute(const String& key, const Value& value,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils);
static void ValidateObject(const Object::Ptr& object,
const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils);
static void ValidateArray(const Array::Ptr& array,

View File

@ -421,12 +421,9 @@ void DbConnection::PrepareDatabase(void)
}
}
void DbConnection::ValidateFailoverTimeout(const String& location, const Dictionary::Ptr& attrs)
void DbConnection::ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object)
{
if (!attrs->Contains("failover_timeout"))
return;
if (attrs->Get("failover_timeout") < 60) {
if (object->GetFailoverTimeout() < 60) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Failover timeout minimum is 60s.");
}

View File

@ -63,7 +63,7 @@ public:
void SetStatusUpdate(const DbObject::Ptr& dbobj, bool hasupdate);
bool GetStatusUpdate(const DbObject::Ptr& dbobj) const;
static void ValidateFailoverTimeout(const String& location, const Dictionary::Ptr& attrs);
static void ValidateFailoverTimeout(const String& location, const DbConnection::Ptr& object);
protected:
virtual void OnConfigLoaded(void);

View File

@ -44,9 +44,9 @@ void Command::SetModifiedAttributes(int flags, const MessageOrigin& origin)
}
}
void Command::ValidateAttributes(const String& location, const Dictionary::Ptr& attrs)
void Command::ValidateAttributes(const String& location, const Command::Ptr& object)
{
if (attrs->Get("arguments") != Empty && !attrs->Get("command").IsObjectType<Array>()) {
if (object->GetArguments() != Empty && !object->GetCommandLine().IsObjectType<Array>()) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Attribute 'command' must be an array if the 'arguments' attribute is set.");
}

View File

@ -39,7 +39,7 @@ public:
//virtual Dictionary::Ptr Execute(const Object::Ptr& context) = 0;
static void ValidateAttributes(const String& location, const Dictionary::Ptr& attrs);
static void ValidateAttributes(const String& location, const Command::Ptr& object);
int GetModifiedAttributes(void) const;
void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin());

View File

@ -203,16 +203,16 @@ TimePeriod::Ptr Dependency::GetPeriod(void) const
return TimePeriod::GetByName(GetPeriodRaw());
}
void Dependency::ValidateFilters(const String& location, const Dictionary::Ptr& attrs)
void Dependency::ValidateFilters(const String& location, const Dependency::Ptr& object)
{
int sfilter = FilterArrayToInt(attrs->Get("states"), 0);
int sfilter = FilterArrayToInt(object->GetStates(), 0);
if (attrs->Get("parent_service_name") == Empty && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
if (object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid for host dependency.");
}
if (attrs->Get("parent_service_name") != Empty && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
if (!object->GetParentServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid for service dependency.");
}

View File

@ -49,7 +49,7 @@ public:
static void RegisterApplyRuleHandler(void);
static void ValidateFilters(const String& location, const Dictionary::Ptr& attrs);
static void ValidateFilters(const String& location, const Dependency::Ptr& object);
protected:
virtual void OnConfigLoaded(void);

View File

@ -493,21 +493,21 @@ int icinga::FilterArrayToInt(const Array::Ptr& typeFilters, int defaultValue)
return resultTypeFilter;
}
void Notification::ValidateFilters(const String& location, const Dictionary::Ptr& attrs)
void Notification::ValidateFilters(const String& location, const Notification::Ptr& object)
{
int sfilter = FilterArrayToInt(attrs->Get("states"), 0);
int sfilter = FilterArrayToInt(object->GetStates(), 0);
if (attrs->Get("service_name") == Empty && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
if (object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid.");
}
if (attrs->Get("service_name") != Empty && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
if (!object->GetServiceName().IsEmpty() && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid.");
}
int tfilter = FilterArrayToInt(attrs->Get("types"), 0);
int tfilter = FilterArrayToInt(object->GetTypes(), 0);
if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery |

View File

@ -106,7 +106,7 @@ public:
static void RegisterApplyRuleHandler(void);
static void ValidateFilters(const String& location, const Dictionary::Ptr& attrs);
static void ValidateFilters(const String& location, const Notification::Ptr& object);
protected:
virtual void OnConfigLoaded(void);

View File

@ -183,11 +183,11 @@ void LivestatusListener::ClientHandler(const Socket::Ptr& client)
}
void LivestatusListener::ValidateSocketType(const String& location, const Dictionary::Ptr& attrs)
void LivestatusListener::ValidateSocketType(const String& location, const LivestatusListener::Ptr& object)
{
Value socket_type = attrs->Get("socket_type");
String socket_type = object->GetSocketType();
if (!socket_type.IsEmpty() && socket_type != "unix" && socket_type != "tcp") {
if (socket_type != "unix" && socket_type != "tcp") {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Socket type '" + socket_type + "' is invalid.");
}

View File

@ -44,7 +44,7 @@ public:
static int GetClientsConnected(void);
static int GetConnections(void);
static void ValidateSocketType(const String& location, const Dictionary::Ptr& attrs);
static void ValidateSocketType(const String& location, const LivestatusListener::Ptr& object);
protected:
virtual void Start(void);