From 6ee94bcb212aef14982e29a26f1fb368d8570a8c Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 12 Aug 2014 13:46:54 +0200 Subject: [PATCH] Implement support for writing the objects.json file refs #6702 --- doc/6-configuring-icinga-2.md | 1 + icinga-app/icinga.cpp | 7 +++-- lib/base/application.cpp | 26 +++++++++++++++-- lib/base/application.hpp | 3 ++ lib/config/configitem.cpp | 53 ++++++++++++++++++++++++++++++++++- lib/config/configitem.hpp | 4 ++- 6 files changed, 87 insertions(+), 7 deletions(-) diff --git a/doc/6-configuring-icinga-2.md b/doc/6-configuring-icinga-2.md index 922de5e5af1..73f48f61e10 100644 --- a/doc/6-configuring-icinga-2.md +++ b/doc/6-configuring-icinga-2.md @@ -13,6 +13,7 @@ LocalStateDir |**Read-only.** Contains the path of the local state directo RunDir |**Read-only.** Contains the path of the run directory. Defaults to LocalStateDir + "/run". PkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to PrefixDir + "/share/icinga2". StatePath |**Read-write.** Contains the path of the Icinga 2 state file. Defaults to LocalStateDir + "/lib/icinga2/icinga2.state". +ObjectsPath |**Read-write.** Contains the path of the Icinga 2 objects file. Defaults to LocalStateDir + "/cache/icinga2/objects.json". PidPath |**Read-write.** Contains the path of the Icinga 2 PID file. Defaults to RunDir + "/icinga2/icinga2.pid". Vars |**Read-write.** Contains a dictionary with global custom attributes. Not set by default. NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default. diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 5cec83f9195..b5ce7963ca9 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -82,7 +82,7 @@ static void IncludeNonLocalZone(const String& zonePath) IncludeZoneDirRecursive(zonePath); } -static bool LoadConfigFiles(const String& appType) +static bool LoadConfigFiles(const String& appType, const String& objectsFile = String()) { ConfigCompilerContext::GetInstance()->Reset(); @@ -113,7 +113,7 @@ static bool LoadConfigFiles(const String& appType) ConfigItem::Ptr item = builder->Compile(); item->Register(); - bool result = ConfigItem::ValidateItems(); + bool result = ConfigItem::ValidateItems(objectsFile); int warnings = 0, errors = 0; @@ -382,6 +382,7 @@ int Main(void) } Application::DeclareStatePath(Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state"); + Application::DeclareObjectsPath(Application::GetLocalStateDir() + "/cache/icinga2/objects.json"); Application::DeclarePidPath(Application::GetRunDir() + "/icinga2/icinga2.pid"); #ifndef _WIN32 @@ -543,7 +544,7 @@ int Main(void) } } - if (!LoadConfigFiles(appType)) + if (!LoadConfigFiles(appType, Application::GetObjectsPath())) return EXIT_FAILURE; if (g_AppParams.count("validate")) { diff --git a/lib/base/application.cpp b/lib/base/application.cpp index e2a00039db6..49d2d39a079 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -478,6 +478,7 @@ void Application::DisplayInfoMessage(bool skipVersion) << " Local state directory: " << GetLocalStateDir() << std::endl << " Package data directory: " << GetPkgDataDir() << std::endl << " State path: " << GetStatePath() << std::endl + << " Objects path: " << GetObjectsPath() << std::endl << " PID path: " << GetPidPath() << std::endl << " Application type: " << GetApplicationType() << std::endl; } @@ -976,6 +977,26 @@ void Application::DeclareStatePath(const String& path) ScriptVariable::Set("StatePath", path, false); } +/** + * Retrieves the path for the objects file. + * + * @returns The path. + */ +String Application::GetObjectsPath(void) +{ + return ScriptVariable::Get("ObjectsPath"); +} + +/** + * Sets the path for the objects file. + * + * @param path The new path. + */ +void Application::DeclareObjectsPath(const String& path) +{ + ScriptVariable::Set("ObjectsPath", path, false); +} + /** * Retrieves the path for the PID file. * @@ -1023,8 +1044,9 @@ void Application::MakeVariablesConstant(void) ScriptVariable::GetByName("LocalStateDir")->SetConstant(true); ScriptVariable::GetByName("RunDir")->SetConstant(true); ScriptVariable::GetByName("PkgDataDir")->SetConstant(true); - ScriptVariable::GetByName("StatePath")->SetConstant(false); - ScriptVariable::GetByName("PidPath")->SetConstant(false); + ScriptVariable::GetByName("StatePath")->SetConstant(true); + ScriptVariable::GetByName("ObjectsPath")->SetConstant(true); + ScriptVariable::GetByName("PidPath")->SetConstant(true); ScriptVariable::GetByName("ApplicationType")->SetConstant(true); } diff --git a/lib/base/application.hpp b/lib/base/application.hpp index 2213fc6698d..b1d043b6b99 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -104,6 +104,9 @@ class I2_BASE_API Application : public ObjectImpl { static String GetStatePath(void); static void DeclareStatePath(const String& path); + static String GetObjectsPath(void); + static void DeclareObjectsPath(const String& path); + static String GetPidPath(void); static void DeclarePidPath(const String& path); diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 80e9d99f944..ece7c9b4c96 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -30,7 +30,10 @@ #include "base/debug.hpp" #include "base/workqueue.hpp" #include "base/exception.hpp" +#include "base/stdiostream.hpp" +#include "base/netstring.hpp" #include +#include #include using namespace icinga; @@ -264,7 +267,52 @@ void ConfigItem::ValidateItem(void) m_Validated = true; } -bool ConfigItem::ValidateItems(void) +void ConfigItem::WriteObjectsFile(const String& filename) +{ + Log(LogInformation, "ConfigItem", "Dumping config items to file '" + filename + "'"); + + String tempFilename = filename + ".tmp"; + + std::fstream fp; + fp.open(tempFilename.CStr(), std::ios_base::out); + + if (!fp) + BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); + + StdioStream::Ptr sfp = make_shared(&fp, false); + + BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { + ConfigItem::Ptr item = kv.second; + + Dictionary::Ptr persistentItem = make_shared(); + + persistentItem->Set("type", item->GetType()); + persistentItem->Set("name", item->GetName()); + persistentItem->Set("abstract", item->IsAbstract()); + persistentItem->Set("properties", item->GetProperties()); + + String json = JsonSerialize(persistentItem); + + NetString::WriteStringToStream(sfp, json); + } + + sfp->Close(); + + fp.close(); + +#ifdef _WIN32 + _unlink(filename.CStr()); +#endif /* _WIN32 */ + + if (rename(tempFilename.CStr(), filename.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("rename") + << boost::errinfo_errno(errno) + << boost::errinfo_file_name(tempFilename)); + } +} + +bool ConfigItem::ValidateItems(const String& objectsFile) { if (ConfigCompilerContext::GetInstance()->HasErrors()) return false; @@ -323,6 +371,9 @@ bool ConfigItem::ValidateItems(void) upq.Join(); + if (!objectsFile.IsEmpty()) + ConfigItem::WriteObjectsFile(objectsFile); + ConfigItem::DiscardItems(); ConfigType::DiscardTypes(); diff --git a/lib/config/configitem.hpp b/lib/config/configitem.hpp index 7c79cbb03e0..4053161875b 100644 --- a/lib/config/configitem.hpp +++ b/lib/config/configitem.hpp @@ -64,10 +64,12 @@ class I2_CONFIG_API ConfigItem : public Object { void ValidateItem(void); - static bool ValidateItems(void); + static bool ValidateItems(const String& objectsFile = String()); static bool ActivateItems(void); static void DiscardItems(void); + static void WriteObjectsFile(const String& filename); + private: String m_Type; /**< The object type. */ String m_Name; /**< The name. */