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(); 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") { rotation_method != "WEEKLY" && rotation_method != "MONTHLY" && rotation_method != "NONE") {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Rotation method '" + rotation_method + "' is invalid."); 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 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: protected:
virtual void Start(void); virtual void Start(void);

View File

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

View File

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

View File

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

View File

@ -50,7 +50,7 @@ public:
DebugInfo GetDebugInfo(void) const; 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); const DebugInfo& debugInfo, const TypeRuleUtilities *utils);
void Register(void); void Register(void);
@ -65,7 +65,10 @@ private:
TypeRuleList::Ptr m_RuleList; TypeRuleList::Ptr m_RuleList;
DebugInfo m_DebugInfo; /**< Debug information. */ 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 std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
const TypeRuleUtilities *utils); const TypeRuleUtilities *utils);
static void ValidateArray(const Array::Ptr& array, 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")) if (object->GetFailoverTimeout() < 60) {
return;
if (attrs->Get("failover_timeout") < 60) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Failover timeout minimum is 60s."); location + ": Failover timeout minimum is 60s.");
} }

View File

@ -63,7 +63,7 @@ public:
void SetStatusUpdate(const DbObject::Ptr& dbobj, bool hasupdate); void SetStatusUpdate(const DbObject::Ptr& dbobj, bool hasupdate);
bool GetStatusUpdate(const DbObject::Ptr& dbobj) const; 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: protected:
virtual void OnConfigLoaded(void); 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 " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Attribute 'command' must be an array if the 'arguments' attribute is set."); 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; //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; int GetModifiedAttributes(void) const;
void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin()); void SetModifiedAttributes(int flags, const MessageOrigin& origin = MessageOrigin());

View File

@ -203,16 +203,16 @@ TimePeriod::Ptr Dependency::GetPeriod(void) const
return TimePeriod::GetByName(GetPeriodRaw()); 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 " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid for host dependency."); 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 " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid for service dependency."); location + ": State filter is invalid for service dependency.");
} }

View File

@ -49,7 +49,7 @@ public:
static void RegisterApplyRuleHandler(void); 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: protected:
virtual void OnConfigLoaded(void); virtual void OnConfigLoaded(void);

View File

@ -493,21 +493,21 @@ int icinga::FilterArrayToInt(const Array::Ptr& typeFilters, int defaultValue)
return resultTypeFilter; 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 " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid."); 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 " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": State filter is invalid."); 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 | if ((tfilter & ~(1 << NotificationDowntimeStart | 1 << NotificationDowntimeEnd | 1 << NotificationDowntimeRemoved |
1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery | 1 << NotificationCustom | 1 << NotificationAcknowledgement | 1 << NotificationProblem | 1 << NotificationRecovery |

View File

@ -106,7 +106,7 @@ public:
static void RegisterApplyRuleHandler(void); 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: protected:
virtual void OnConfigLoaded(void); 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 " + ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Socket type '" + socket_type + "' is invalid."); location + ": Socket type '" + socket_type + "' is invalid.");
} }

View File

@ -44,7 +44,7 @@ public:
static int GetClientsConnected(void); static int GetClientsConnected(void);
static int GetConnections(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: protected:
virtual void Start(void); virtual void Start(void);