]> granicus.if.org Git - icinga2/commitdiff
Implement validation for "repository add"
authorGunnar Beutner <gunnar.beutner@netways.de>
Tue, 28 Oct 2014 10:54:56 +0000 (11:54 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 28 Oct 2014 10:55:25 +0000 (11:55 +0100)
fixes #7458

lib/cli/repositoryobjectcommand.cpp
lib/cli/repositoryutility.cpp
lib/config/configitem.cpp
lib/config/configtype.cpp
lib/config/configtype.hpp
lib/config/typerule.cpp
lib/config/typerule.hpp
lib/config/typerulelist.cpp
lib/config/typerulelist.hpp

index c2a67521c757b529f2e7c846a3c073fd91175a7b..6924dccdfd8d5fa5905939bd1fa7e500d14ee286 100644 (file)
@@ -175,13 +175,6 @@ int RepositoryObjectCommand::Run(const boost::program_options::variables_map& vm
 
        String name = attrs->Get("name");
 
-       if (m_Type == "Service") {
-               if (!attrs->Contains("host_name")) {
-                       Log(LogCritical, "cli", "Service objects require the 'host_name' attribute.");
-                       return 1;
-               }
-       }
-
        if (vm.count("import")) {
                Array::Ptr imports = make_shared<Array>();
 
@@ -196,13 +189,12 @@ int RepositoryObjectCommand::Run(const boost::program_options::variables_map& vm
 
 
        if (m_Command == RepositoryCommandAdd) {
+               Utility::LoadExtensionLibrary("icinga");
                RepositoryUtility::AddObject(name, m_Type, attrs);
-       }
-       else if (m_Command == RepositoryCommandRemove) {
+       } else if (m_Command == RepositoryCommandRemove) {
                /* pass attrs for service->host_name requirement */
                RepositoryUtility::RemoveObject(name, m_Type, attrs);
-       }
-       else if (m_Command == RepositoryCommandSet) {
+       } else if (m_Command == RepositoryCommandSet) {
                Log(LogWarning, "cli")
                    << "Not supported yet. Please check the roadmap at https://dev.icinga.org\n";
                return 1;
index a77d0533657ddea5da05b12e84def3df1c720349..ffef6dc5ece06bf86883957fb6b92700f4d5e886 100644 (file)
@@ -19,6 +19,9 @@
 
 #include "cli/repositoryutility.hpp"
 #include "cli/clicommand.hpp"
+#include "config/configtype.hpp"
+#include "config/configcompilercontext.hpp"
+#include "config/configcompiler.hpp"
 #include "base/logger.hpp"
 #include "base/application.hpp"
 #include "base/convert.hpp"
@@ -177,6 +180,15 @@ void RepositoryUtility::PrintChangeLog(std::ostream& fp)
        }
 }
 
+class RepositoryTypeRuleUtilities : public TypeRuleUtilities
+{
+public:
+       virtual bool ValidateName(const String& type, const String& name, String *hint) const
+       {
+               return true;
+       }
+};
+
 /* modify objects and write changelog */
 bool RepositoryUtility::AddObject(const String& name, const String& type, const Dictionary::Ptr& attrs)
 {
@@ -191,6 +203,45 @@ bool RepositoryUtility::AddObject(const String& name, const String& type, const
        change->Set("command", "add");
        change->Set("attrs", attrs);
 
+       ConfigCompilerContext::GetInstance()->Reset();
+
+       String fname, fragment;
+       BOOST_FOREACH(boost::tie(fname, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) {
+               ConfigCompiler::CompileText(fname, fragment);
+       }
+
+       ConfigType::Ptr ctype = ConfigType::GetByName(type);
+
+       if (!ctype)
+               Log(LogCritical, "cli")
+                   << "No validation type available for '" << type << "'.";
+       else {
+               Dictionary::Ptr vattrs = attrs->ShallowClone();
+               vattrs->Set("__name", vattrs->Get("name"));
+               vattrs->Remove("name");
+               vattrs->Set("type", type);
+
+               RepositoryTypeRuleUtilities utils;
+               ctype->ValidateItem(name, vattrs, DebugInfo(), &utils);
+
+               int warnings = 0, errors = 0;
+
+               BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
+                       String logmsg = String("Config ") + (message.Error ? "error" : "warning") + ": " + message.Text;
+
+                       if (message.Error) {
+                               Log(LogCritical, "config", logmsg);
+                               errors++;
+                       } else {
+                               Log(LogWarning, "config", logmsg);
+                               warnings++;
+                       }
+               }
+
+               if (errors > 0)
+                       return false;
+       }
+
        return WriteObjectToRepositoryChangeLog(path, change);
 }
 
index 67b288ba87256fe7de29065194dec0c9b3815f15..06bf024a5fb36d9fa915b6daf54f9b19f3d2b561 100644 (file)
@@ -270,8 +270,10 @@ void ConfigItem::ValidateItem(void)
                return;
        }
 
+       TypeRuleUtilities utils;
+       
        try {
-               ctype->ValidateItem(GetSelf());
+               ctype->ValidateItem(GetName(), GetProperties(), 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());
index 3c15d09decd4cfcf92871fe6db328e38ebdab62a..fb28c654e4e6f12d4d410d59845024db7a9eb6be 100644 (file)
@@ -74,33 +74,21 @@ void ConfigType::AddParentRules(std::vector<TypeRuleList::Ptr>& ruleLists, const
        }
 }
 
-void ConfigType::ValidateItem(const ConfigItem::Ptr& item)
+void ConfigType::ValidateItem(const String& name, const Dictionary::Ptr& attrs, const DebugInfo& debugInfo, const TypeRuleUtilities *utils)
 {
-       /* Don't validate abstract items. */
-       if (item->IsAbstract())
-               return;
-
-       Dictionary::Ptr attrs;
-       DebugInfo debugInfo;
-       String type, name;
-
-       {
-               ObjectLock olock(item);
-
-               attrs = item->GetProperties();
-               debugInfo = item->GetDebugInfo();
-               type = item->GetType();
-               name = item->GetName();
-       }
+       String location = "Object '" + name + "' (Type: '" + GetName() + "')";
 
+       if (!debugInfo.Path.IsEmpty())
+               location += " at " + debugInfo.Path + ":" + Convert::ToString(debugInfo.FirstLine);
+       
        std::vector<String> locations;
-       locations.push_back("Object '" + name + "' (Type: '" + type + "') at " + debugInfo.Path + ":" + Convert::ToString(debugInfo.FirstLine));
+       locations.push_back(location);
 
        std::vector<TypeRuleList::Ptr> ruleLists;
        AddParentRules(ruleLists, GetSelf());
        ruleLists.push_back(m_RuleList);
 
-       ValidateDictionary(attrs, ruleLists, locations);
+       ValidateDictionary(attrs, ruleLists, locations, utils);
 }
 
 String ConfigType::LocationToString(const std::vector<String>& locations)
@@ -120,7 +108,8 @@ String ConfigType::LocationToString(const std::vector<String>& locations)
 }
 
 void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
-    const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations)
+    const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
+    const TypeRuleUtilities *utils)
 {
        BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
                BOOST_FOREACH(const String& require, ruleList->GetRequires()) {
@@ -163,7 +152,7 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
 
                BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
                        TypeRuleList::Ptr subRuleList;
-                       TypeValidationResult result = ruleList->ValidateAttribute(kv.first, kv.second, &subRuleList, &hint);
+                       TypeValidationResult result = ruleList->ValidateAttribute(kv.first, kv.second, &subRuleList, &hint, utils);
 
                        if (subRuleList)
                                subRuleLists.push_back(subRuleList);
@@ -192,16 +181,17 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
                }
 
                if (!subRuleLists.empty() && kv.second.IsObjectType<Dictionary>())
-                       ValidateDictionary(kv.second, subRuleLists, locations);
+                       ValidateDictionary(kv.second, subRuleLists, locations, utils);
                else if (!subRuleLists.empty() && kv.second.IsObjectType<Array>())
-                       ValidateArray(kv.second, subRuleLists, locations);
+                       ValidateArray(kv.second, subRuleLists, locations, utils);
 
                locations.pop_back();
        }
 }
 
 void ConfigType::ValidateArray(const Array::Ptr& array,
-    const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations)
+    const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,
+    const TypeRuleUtilities *utils)
 {
        BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
                BOOST_FOREACH(const String& require, ruleList->GetRequires()) {
@@ -249,7 +239,7 @@ void ConfigType::ValidateArray(const Array::Ptr& array,
 
                BOOST_FOREACH(const TypeRuleList::Ptr& ruleList, ruleLists) {
                        TypeRuleList::Ptr subRuleList;
-                       TypeValidationResult result = ruleList->ValidateAttribute(key, value, &subRuleList, &hint);
+                       TypeValidationResult result = ruleList->ValidateAttribute(key, value, &subRuleList, &hint, utils);
 
                        if (subRuleList)
                                subRuleLists.push_back(subRuleList);
@@ -267,7 +257,7 @@ void ConfigType::ValidateArray(const Array::Ptr& array,
                }
 
                if (overallResult == ValidationUnknownField)
-                       ConfigCompilerContext::GetInstance()->AddMessage(false, "Unknown attribute: " + LocationToString(locations));
+                       ConfigCompilerContext::GetInstance()->AddMessage(true, "Unknown attribute: " + LocationToString(locations));
                else if (overallResult == ValidationInvalidType) {
                        String message = "Invalid value for array index: " + LocationToString(locations);
 
@@ -278,9 +268,9 @@ void ConfigType::ValidateArray(const Array::Ptr& array,
                }
 
                if (!subRuleLists.empty() && value.IsObjectType<Dictionary>())
-                       ValidateDictionary(value, subRuleLists, locations);
+                       ValidateDictionary(value, subRuleLists, locations, utils);
                else if (!subRuleLists.empty() && value.IsObjectType<Array>())
-                       ValidateArray(value, subRuleLists, locations);
+                       ValidateArray(value, subRuleLists, locations, utils);
 
                locations.pop_back();
        }
@@ -310,4 +300,3 @@ ConfigTypeRegistry *ConfigTypeRegistry::GetInstance(void)
 {
        return Singleton<ConfigTypeRegistry>::GetInstance();
 }
-
index 3b62d96dba0e94c4a2ea59183c52142304124d89..aa8b770adf4dc8ef438bfabf0f7b041072f2b36b 100644 (file)
@@ -50,7 +50,8 @@ public:
 \r
        DebugInfo GetDebugInfo(void) const;\r
 \r
-       void ValidateItem(const ConfigItem::Ptr& object);\r
+       void ValidateItem(const String& name, const Dictionary::Ptr& attrs,\r
+           const DebugInfo& debugInfo, const TypeRuleUtilities *utils);\r
 \r
        void Register(void);\r
        static ConfigType::Ptr GetByName(const String& name);\r
@@ -65,9 +66,11 @@ private:
        DebugInfo m_DebugInfo; /**< Debug information. */\r
 \r
        static void ValidateDictionary(const Dictionary::Ptr& dictionary,\r
-           const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations);\r
+           const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,\r
+           const TypeRuleUtilities *utils);\r
        static void ValidateArray(const Array::Ptr& array,\r
-           const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations);\r
+           const std::vector<TypeRuleList::Ptr>& ruleLists, std::vector<String>& locations,\r
+           const TypeRuleUtilities *utils);\r
 \r
        static String LocationToString(const std::vector<String>& locations);\r
 \r
index fd33429a6f00d4ae89965553e905e6f4d9802bf8..4a0c3940fe8900f86c9dd436c0617b3124c89375 100644 (file)
@@ -42,7 +42,7 @@ bool TypeRule::MatchName(const String& name) const
        return (Utility::Match(m_NamePattern, name));
 }
 
-bool TypeRule::MatchValue(const Value& value, String *hint) const
+bool TypeRule::MatchValue(const Value& value, String *hint, const TypeRuleUtilities *utils) const
 {
        ConfigItem::Ptr item;
 
@@ -77,21 +77,26 @@ bool TypeRule::MatchValue(const Value& value, String *hint) const
                        if (!value.IsScalar())
                                return false;
 
-                       item = ConfigItem::GetObject(m_NameType, value);
+                       return utils->ValidateName(m_NameType, value, hint);
 
-                       if (!item) {
-                               *hint = "Object '" + value + "' of type '" + m_NameType + "' does not exist.";
-                               return false;
-                       }
+               default:
+                       return false;
+       }
+}
 
-                       if (item->IsAbstract()) {
-                               *hint = "Object '" + value + "' of type '" + m_NameType + "' must not be a template.";
-                               return false;
-                       }
+bool TypeRuleUtilities::ValidateName(const String& type, const String& name, String *hint) const
+{
+       ConfigItem::Ptr item = ConfigItem::GetObject(type, name);
 
-                       return true;
+       if (!item) {
+               *hint = "Object '" + name + "' of type '" + type + "' does not exist.";
+               return false;
+       }
 
-               default:
-                       return false;
+       if (item->IsAbstract()) {
+               *hint = "Object '" + name + "' of type '" + type + "' must not be a template.";
+               return false;
        }
+
+       return true;
 }
index 2e6ece95a0abe834b3ac20b6e77d3c0e66e8b33c..355913239180a813f439c36a1efb4cb10db0c182 100644 (file)
 namespace icinga\r
 {\r
 \r
+/**\r
+ * Utilities for type rules.\r
+ *\r
+ * @ingroup config\r
+ */\r
+class TypeRuleUtilities\r
+{\r
+public:\r
+       virtual bool ValidateName(const String& type, const String& name, String *hint) const;\r
+};\r
+\r
 /**\r
  * The allowed type for a type rule.\r
  *\r
@@ -58,7 +69,7 @@ public:
        TypeRuleList::Ptr GetSubRules(void) const;\r
 \r
        bool MatchName(const String& name) const;\r
-       bool MatchValue(const Value& value, String *hint) const;\r
+       bool MatchValue(const Value& value, String *hint, const TypeRuleUtilities *utils) const;\r
 \r
 private:\r
        TypeSpecifier m_Type;\r
index 9f48fbf15935d36b78b09ed576bd1794800b1a25..b9e9ab4be010526a95b0d4f0949e14f81414a396 100644 (file)
@@ -117,7 +117,8 @@ size_t TypeRuleList::GetLength(void) const
  * @returns The validation result.\r
  */\r
 TypeValidationResult TypeRuleList::ValidateAttribute(const String& name,\r
-    const Value& value, TypeRuleList::Ptr *subRules, String *hint) const\r
+    const Value& value, TypeRuleList::Ptr *subRules, String *hint,\r
+    const TypeRuleUtilities *utils) const\r
 {\r
        bool foundField = false;\r
        BOOST_FOREACH(const TypeRule& rule, m_Rules) {\r
@@ -126,7 +127,7 @@ TypeValidationResult TypeRuleList::ValidateAttribute(const String& name,
 \r
                foundField = true;\r
 \r
-               if (rule.MatchValue(value, hint)) {\r
+               if (rule.MatchValue(value, hint, utils)) {\r
                        *subRules = rule.GetSubRules();\r
                        return ValidationOK;\r
                }\r
index 0c6a1504e97a3e03189f4022782703d6b86f8255..a131b4960e79e3896b086872ee7d30066cafc46b 100644 (file)
@@ -28,6 +28,7 @@ namespace icinga
 {\r
 \r
 struct TypeRule;\r
+class TypeRuleUtilities;\r
 \r
 /**\r
  * @ingroup config\r
@@ -59,7 +60,8 @@ public:
        void AddRule(const TypeRule& rule);\r
        void AddRules(const TypeRuleList::Ptr& ruleList);\r
 \r
-       TypeValidationResult ValidateAttribute(const String& name, const Value& value, TypeRuleList::Ptr *subRules, String *hint) const;\r
+       TypeValidationResult ValidateAttribute(const String& name, const Value& value,\r
+           TypeRuleList::Ptr *subRules, String *hint, const TypeRuleUtilities *utils) const;\r
 \r
        size_t GetLength(void) const;\r
 \r