]> granicus.if.org Git - icinga2/commitdiff
Implement the include_zones directive
authorGunnar Beutner <gunnar@beutner.name>
Tue, 21 Jul 2015 07:32:17 +0000 (09:32 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Tue, 21 Jul 2015 07:32:17 +0000 (09:32 +0200)
refs #9083

doc/19-language-reference.md
doc/4-configuring-icinga-2.md
etc/icinga2/icinga2.conf
lib/cli/daemonutility.cpp
lib/config/config_lexer.ll
lib/config/config_parser.yy
lib/config/configcompiler.cpp
lib/config/configcompiler.hpp
lib/remote/apilistener-sync.cpp

index 746704f22e4d9ea177ac3cdcd873abdf84f25730..a63b16e65f21f769393d8dc1ce1bdf2bf596cfcf 100644 (file)
@@ -517,6 +517,29 @@ recursively included.
 The file names need to match the pattern given in the second parameter.
 When no pattern is specified the default pattern "*.conf" is used.
 
+## <a id="zone-includes"></a> Zone Includes
+
+The `include_zones` recursively includes all subdirectories for the
+given path.
+
+In addition to that it sets the `zone` attribute for all objects created
+in these subdirectories to the name of the subdirectory.
+
+Example:
+
+    include_zones "etc", "zones.d", "*.conf"
+    include_zones "puppet", "puppet-zones"
+
+The first parameter specifies a tag name for this directive. Each `include_zones`
+invocation should use a unique tag name. When copying the zones' configuration
+files Icinga uses the tag name as the name for the destination directory in
+`/var/lib/icinga2/api/config`.
+
+The second parameter specifies the directory which contains the subdirectories.
+
+The file names need to match the pattern given in the third parameter.
+When no pattern is specified the default pattern "*.conf" is used.
+
 ## <a id="library"></a> Library directive
 
 The `library` directive can be used to manually load additional
index f5686365e3b5608fc7b3f25ae404269663f72488..a85d83e136d70f4ea26e08f9ebce7291042d02ae 100644 (file)
@@ -136,6 +136,16 @@ and their generated configuration described in
 You can put your own configuration files in the [conf.d](4-configuring-icinga-2.md#conf-d) directory. This
 directive makes sure that all of your own configuration files are included.
 
+    /**
+     * The zones.d directory contains configuration files for satellite
+     * instances.
+     */
+    include_zones "etc", "zones.d"
+
+Configuration files for satellite instances are managed in 'zones'. This directive ensures
+that all configuration files in the `zones.d` directory are included and that the `zones`
+attribute for objects defined in this directory is set appropriately.
+
 ### <a id="constants-conf"></a> constants.conf
 
 The `constants.conf` configuration file can be used to define global constants.
index 1d733546565eb30bd48502cb680d9a48b33c7b99..825ffe19b56496b95bc20a2a1bb313751f7a1d22 100644 (file)
@@ -49,3 +49,8 @@ include_recursive "repository.d"
  */
 include_recursive "conf.d"
 
+/**
+ * The zones.d directory contains configuration files for satellite
+ * instances.
+ */
+include_zones "etc", "zones.d"
index deffb3caa5639af8f57479600785714d3c1972b8..c09de03464ef578b165df4bc87aa761572d87f6b 100644 (file)
@@ -85,13 +85,6 @@ bool DaemonUtility::ValidateConfigFiles(const std::vector<std::string>& configs,
        * unfortunately moving it there is somewhat non-trivial. */
        success = true;
 
-       String zonesEtcDir = Application::GetZonesDir();
-       if (!zonesEtcDir.IsEmpty() && Utility::PathExists(zonesEtcDir))
-               Utility::Glob(zonesEtcDir + "/*", boost::bind(&IncludeZoneDirRecursive, _1, boost::ref(success)), GlobDirectory);
-
-       if (!success)
-               return false;
-
        String zonesVarDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
        if (Utility::PathExists(zonesVarDir))
                Utility::Glob(zonesVarDir + "/*", boost::bind(&IncludeNonLocalZone, _1, boost::ref(success)), GlobDirectory);
index dc0a7eed5c688d76e7e5f7e17fd64d93138c6846..9455eb1b41642c57e1aca0625335930caf32375e 100644 (file)
@@ -171,6 +171,7 @@ object                              return T_OBJECT;
 template                       return T_TEMPLATE;
 include                                return T_INCLUDE;
 include_recursive              return T_INCLUDE_RECURSIVE;
+include_zones          return T_INCLUDE_ZONES;
 library                                return T_LIBRARY;
 null                           return T_NULL;
 true                           { yylval->boolean = 1; return T_BOOLEAN; }
index 1abcb16a4fda6a9831276f60ade5693d803969a2..2e63f6f569bef8b08f9aefec2ff4d3c4b6564df0 100644 (file)
@@ -149,6 +149,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
 %token T_TEMPLATE "template (T_TEMPLATE)"
 %token T_INCLUDE "include (T_INCLUDE)"
 %token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)"
+%token T_INCLUDE_ZONES "include_zones (T_INCLUDE_ZONES)"
 %token T_LIBRARY "library (T_LIBRARY)"
 %token T_INHERITS "inherits (T_INHERITS)"
 %token T_APPLY "apply (T_APPLY)"
@@ -197,7 +198,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
 %type <num> object_declaration
 
 %right T_FOLLOWS
-%right T_INCLUDE T_INCLUDE_RECURSIVE T_OBJECT T_TEMPLATE T_APPLY T_IMPORT T_ASSIGN T_IGNORE T_WHERE
+%right T_INCLUDE T_INCLUDE_RECURSIVE T_INCLUDE_ZONES T_OBJECT T_TEMPLATE T_APPLY T_IMPORT T_ASSIGN T_IGNORE T_WHERE
 %right T_FUNCTION T_FOR
 %left T_SET T_SET_ADD T_SET_SUBTRACT T_SET_MULTIPLY T_SET_DIVIDE T_SET_MODULO T_SET_XOR T_SET_BINARY_AND T_SET_BINARY_OR
 %left T_LOGICAL_OR
@@ -464,6 +465,14 @@ lterm: library
                free($2);
                free($4);
        }
+       | T_INCLUDE_ZONES T_STRING ',' T_STRING
+       {
+               $$ = context->HandleIncludeZones($2, $4, "*.conf", @$);
+       }
+       | T_INCLUDE_ZONES T_STRING ',' T_STRING ',' T_STRING
+       {
+               $$ = context->HandleIncludeZones($2, $4, $6, @$);
+       }
        | T_IMPORT rterm
        {
                $$ = new ImportExpression($2, @$);
index 8fc48c64fc2e43bcf333cd94929eeb10f1d31bd1..80c8850d9935de3848b38666c92454db59a8873d 100644 (file)
@@ -30,6 +30,7 @@
 using namespace icinga;
 
 std::vector<String> ConfigCompiler::m_IncludeSearchDirs;
+std::map<String, std::vector<ZoneFragment> > ConfigCompiler::m_ZoneDirs;
 
 /**
  * Constructor for the ConfigCompiler class.
@@ -165,6 +166,47 @@ Expression *ConfigCompiler::HandleIncludeRecursive(const String& path, const Str
        return new DictExpression(expressions);
 }
 
+void ConfigCompiler::HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector<Expression *>& expressions)
+{
+       String zoneName = Utility::BaseName(path);
+
+       String ppath;
+
+       if (path.GetLength() > 0 && path[0] == '/')
+               ppath = path;
+       else
+               ppath = Utility::DirName(GetPath()) + "/" + path;
+
+       ZoneFragment zf;
+       zf.Tag = tag;
+       zf.Path = ppath;
+       m_ZoneDirs[zoneName].push_back(zf);
+
+       Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName), GlobFile);
+}
+
+/**
+ * Handles zone includes.
+ *
+ * @param tag The tag name.
+ * @param path The directory path.
+ * @param pattern The file pattern.
+ * @param debuginfo Debug information.
+ */
+Expression *ConfigCompiler::HandleIncludeZones(const String& tag, const String& path, const String& pattern, const DebugInfo&)
+{
+       String ppath;
+
+       if (path.GetLength() > 0 && path[0] == '/')
+               ppath = path;
+       else
+               ppath = Utility::DirName(GetPath()) + "/" + path;
+
+       std::vector<Expression *> expressions;
+       Utility::Glob(ppath + "/*", boost::bind(&ConfigCompiler::HandleIncludeZone, this, tag, _1, pattern, boost::ref(expressions)), GlobDirectory);
+       return new DictExpression(expressions);
+}
+
 /**
  * Handles the library directive.
  *
@@ -272,3 +314,12 @@ void ConfigCompiler::AddIncludeSearchDir(const String& dir)
        m_IncludeSearchDirs.push_back(dir);
 }
 
+std::vector<ZoneFragment> ConfigCompiler::GetZoneDirs(const String& zone)
+{
+       std::map<String, std::vector<ZoneFragment> >::const_iterator it;
+       it = m_ZoneDirs.find(zone);
+       if (it == m_ZoneDirs.end())
+               return std::vector<ZoneFragment>();
+       else
+               return it->second; 
+}
index f0a429b29f07a435c44f3caa6bdc0525cc2db34e..e4626758b1edd5791099a67941d47be7eab8fd90 100644 (file)
@@ -64,6 +64,12 @@ struct EItemInfo
        CompilerDebugInfo DebugInfo;
 };
 
+struct ZoneFragment
+{
+       String Tag;
+       String Path;
+};
+
 /**
  * The configuration compiler can be used to compile a configuration file
  * into a number of configuration items.
@@ -94,11 +100,14 @@ public:
        /* internally used methods */
        Expression *HandleInclude(const String& include, bool search, const DebugInfo& debuginfo = DebugInfo());
        Expression *HandleIncludeRecursive(const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo());
+       Expression *HandleIncludeZones(const String& tag, const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo());
        void HandleLibrary(const String& library);
 
        size_t ReadInput(char *buffer, size_t max_bytes);
        void *GetScanner(void) const;
 
+       static std::vector<ZoneFragment> GetZoneDirs(const String& zone);
+
 private:
        boost::promise<boost::shared_ptr<Expression> > m_Promise;
 
@@ -109,12 +118,15 @@ private:
        void *m_Scanner;
 
        static std::vector<String> m_IncludeSearchDirs;
+       static std::map<String, std::vector<ZoneFragment> > m_ZoneDirs;
 
        void InitializeScanner(void);
        void DestroyScanner(void);
 
        void CompileHelper(void);
 
+       void HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector<Expression *>& expressions);
+
 public:
        bool m_Eof;
        int m_OpenBraces;
index 21002109a347cc8a859dfaefd0e4f25dd874d037..7bca5731cbd8b5926d4288d63f55144a1bd5f4da 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "remote/apilistener.hpp"
 #include "remote/apifunction.hpp"
+#include "config/configcompiler.hpp"
 #include "base/dynamictype.hpp"
 #include "base/logger.hpp"
 #include "base/convert.hpp"
@@ -121,11 +122,20 @@ bool ApiListener::UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictio
 
 void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
 {
-       String newDir = Application::GetZonesDir() + "/" + zone->GetName();
+       Dictionary::Ptr newConfig = new Dictionary();
+       BOOST_FOREACH(const ZoneFragment& zf, ConfigCompiler::GetZoneDirs(zone->GetName())) {
+               Dictionary::Ptr newConfigPart = LoadConfigDir(zf.Path);
+
+               ObjectLock olock(newConfigPart);
+               BOOST_FOREACH(const Dictionary::Pair& kv, newConfigPart) {
+                       newConfig->Set(zf.Tag + "/" + kv.first, kv.second);
+               }
+       }
+
        String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
 
        Log(LogInformation, "ApiListener")
-           << "Copying zone configuration files from '" << newDir << "' to  '" << oldDir << "'.";
+           << "Copying zone configuration files for zone '" << zone->GetName() << "' to  '" << oldDir << "'.";
 
        if (!Utility::MkDir(oldDir, 0700)) {
                Log(LogCritical, "ApiListener")
@@ -137,7 +147,6 @@ void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
                        << boost::errinfo_file_name(oldDir));
        }
 
-       Dictionary::Ptr newConfig = LoadConfigDir(newDir);
        Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
 
        UpdateConfigDir(oldConfig, newConfig, oldDir, true);