Implement the include_zones directive

refs #9083
This commit is contained in:
Gunnar Beutner 2015-07-21 09:32:17 +02:00
parent 4bc42281be
commit ccd63b9d15
9 changed files with 124 additions and 11 deletions

View 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

View 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.

View 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"

View 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);

View 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; }

View 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, @$);

View 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;
}

View 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;

View 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);