]> granicus.if.org Git - icinga2/blob - lib/cli/daemonutility.cpp
add some object locking to the Dump method (which could theoreticylly suffer from...
[icinga2] / lib / cli / daemonutility.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "cli/daemonutility.hpp"
4 #include "base/utility.hpp"
5 #include "base/logger.hpp"
6 #include "base/application.hpp"
7 #include "base/scriptglobal.hpp"
8 #include "config/configcompiler.hpp"
9 #include "config/configcompilercontext.hpp"
10 #include "config/configitembuilder.hpp"
11
12 using namespace icinga;
13
14 static bool ExecuteExpression(Expression *expression)
15 {
16         if (!expression)
17                 return false;
18
19         try {
20                 ScriptFrame frame(true);
21                 expression->Evaluate(frame);
22         } catch (const std::exception& ex) {
23                 Log(LogCritical, "config", DiagnosticInformation(ex));
24                 return false;
25         }
26
27         return true;
28 }
29
30 static void IncludeZoneDirRecursive(const String& path, const String& package, bool& success)
31 {
32         String zoneName = Utility::BaseName(path);
33
34         /* We don't have an activated zone object yet. We may forcefully guess from configitems
35          * to not include this specific synced zones directory.
36          */
37         if(!ConfigItem::GetByTypeAndName(Type::GetByName("Zone"), zoneName)) {
38                 Log(LogWarning, "config")
39                         << "Ignoring directory '" << path << "' for unknown zone '" << zoneName << "'.";
40                 return;
41         }
42
43         /* register this zone path for cluster config sync */
44         ConfigCompiler::RegisterZoneDir("_etc", path, zoneName);
45
46         std::vector<std::unique_ptr<Expression> > expressions;
47         Utility::GlobRecursive(path, "*.conf", std::bind(&ConfigCompiler::CollectIncludes, std::ref(expressions), _1, zoneName, package), GlobFile);
48         DictExpression expr(std::move(expressions));
49         if (!ExecuteExpression(&expr))
50                 success = false;
51 }
52
53 static void IncludeNonLocalZone(const String& zonePath, const String& package, bool& success)
54 {
55         /* Note: This include function must not call RegisterZoneDir().
56          * We do not need to copy it for cluster config sync. */
57
58         String zoneName = Utility::BaseName(zonePath);
59
60         /* We don't have an activated zone object yet. We may forcefully guess from configitems
61          * to not include this specific synced zones directory.
62          */
63         if(!ConfigItem::GetByTypeAndName(Type::GetByName("Zone"), zoneName)) {
64                 Log(LogWarning, "config")
65                         << "Ignoring directory '" << zonePath << "' for unknown zone '" << zoneName << "'.";
66                 return;
67         }
68
69         /* Check whether this node already has an authoritative config version
70          * from zones.d in etc or api package directory, or a local marker file)
71          */
72         if (ConfigCompiler::HasZoneConfigAuthority(zoneName) || Utility::PathExists(zonePath + "/.authoritative")) {
73                 Log(LogNotice, "config")
74                         << "Ignoring non local config include for zone '" << zoneName << "': We already have an authoritative copy included.";
75                 return;
76         }
77
78         std::vector<std::unique_ptr<Expression> > expressions;
79         Utility::GlobRecursive(zonePath, "*.conf", std::bind(&ConfigCompiler::CollectIncludes, std::ref(expressions), _1, zoneName, package), GlobFile);
80         DictExpression expr(std::move(expressions));
81         if (!ExecuteExpression(&expr))
82                 success = false;
83 }
84
85 static void IncludePackage(const String& packagePath, bool& success)
86 {
87         /* Note: Package includes will register their zones
88          * for config sync inside their generated config. */
89         String packageName = Utility::BaseName(packagePath);
90
91         if (Utility::PathExists(packagePath + "/include.conf")) {
92                 std::unique_ptr<Expression> expr = ConfigCompiler::CompileFile(packagePath + "/include.conf",
93                         String(), packageName);
94
95                 if (!ExecuteExpression(&*expr))
96                         success = false;
97         }
98 }
99
100 bool DaemonUtility::ValidateConfigFiles(const std::vector<std::string>& configs, const String& objectsFile)
101 {
102         bool success;
103         if (!objectsFile.IsEmpty())
104                 ConfigCompilerContext::GetInstance()->OpenObjectsFile(objectsFile);
105
106         if (!configs.empty()) {
107                 for (const String& configPath : configs) {
108                         try {
109                                 std::unique_ptr<Expression> expression = ConfigCompiler::CompileFile(configPath, String(), "_etc");
110                                 success = ExecuteExpression(&*expression);
111                                 if (!success)
112                                         return false;
113                         } catch (const std::exception& ex) {
114                                 Log(LogCritical, "cli", "Could not compile config files: " + DiagnosticInformation(ex, false));
115                                 Application::Exit(1);
116                         }
117                 }
118         }
119
120         /* Load cluster config files from /etc/icinga2/zones.d.
121          * This should probably be in libremote but
122          * unfortunately moving it there is somewhat non-trivial. */
123         success = true;
124
125         String zonesEtcDir = Configuration::ZonesDir;
126         if (!zonesEtcDir.IsEmpty() && Utility::PathExists(zonesEtcDir))
127                 Utility::Glob(zonesEtcDir + "/*", std::bind(&IncludeZoneDirRecursive, _1, "_etc", std::ref(success)), GlobDirectory);
128
129         if (!success)
130                 return false;
131
132         /* Load package config files - they may contain additional zones which
133          * are authoritative on this node and are checked in HasZoneConfigAuthority(). */
134         String packagesVarDir = Configuration::DataDir + "/api/packages";
135         if (Utility::PathExists(packagesVarDir))
136                 Utility::Glob(packagesVarDir + "/*", std::bind(&IncludePackage, _1, std::ref(success)), GlobDirectory);
137
138         if (!success)
139                 return false;
140
141         /* Load cluster synchronized configuration files */
142         String zonesVarDir = Configuration::DataDir + "/api/zones";
143         if (Utility::PathExists(zonesVarDir))
144                 Utility::Glob(zonesVarDir + "/*", std::bind(&IncludeNonLocalZone, _1, "_cluster", std::ref(success)), GlobDirectory);
145
146         if (!success)
147                 return false;
148
149         Namespace::Ptr systemNS = ScriptGlobal::Get("System");
150         VERIFY(systemNS);
151
152         /* This is initialized inside the IcingaApplication class. */
153         Value vAppType;
154         VERIFY(systemNS->Get("ApplicationType", &vAppType));
155
156         Type::Ptr appType = Type::GetByName(vAppType);
157
158         if (ConfigItem::GetItems(appType).empty()) {
159                 ConfigItemBuilder builder;
160                 builder.SetType(appType);
161                 builder.SetName("app");
162                 builder.AddExpression(new ImportDefaultTemplatesExpression());
163                 ConfigItem::Ptr item = builder.Compile();
164                 item->Register();
165         }
166
167         return true;
168 }
169
170 bool DaemonUtility::LoadConfigFiles(const std::vector<std::string>& configs,
171         std::vector<ConfigItem::Ptr>& newItems,
172         const String& objectsFile, const String& varsfile)
173 {
174         ActivationScope ascope;
175
176         if (!DaemonUtility::ValidateConfigFiles(configs, objectsFile)) {
177                 ConfigCompilerContext::GetInstance()->CancelObjectsFile();
178                 return false;
179         }
180
181         WorkQueue upq(25000, Configuration::Concurrency);
182         upq.SetName("DaemonUtility::LoadConfigFiles");
183         bool result = ConfigItem::CommitItems(ascope.GetContext(), upq, newItems);
184
185         if (!result) {
186                 ConfigCompilerContext::GetInstance()->CancelObjectsFile();
187                 return false;
188         }
189
190         ConfigCompilerContext::GetInstance()->FinishObjectsFile();
191
192         try {
193                 ScriptGlobal::WriteToFile(varsfile);
194         } catch (const std::exception& ex) {
195                 Log(LogCritical, "cli", "Could not write vars file: " + DiagnosticInformation(ex, false));
196                 Application::Exit(1);
197         }
198
199         return true;
200 }