diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 728414401..14eeb5bb5 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -24,6 +24,7 @@ #include "base/exception.hpp" #include "base/socket.hpp" #include "base/utility.hpp" +#include "base/json.hpp" #include #include #include @@ -1088,3 +1089,39 @@ bool Utility::PathExists(const String& path) return (_stat(path.CStr(), &statbuf) >= 0); #endif /* _WIN32 */ } + +Value Utility::LoadJsonFile(const String& path) +{ + std::ifstream fp; + fp.open(path.CStr()); + + String json((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); + + fp.close(); + + if (fp.fail()) + BOOST_THROW_EXCEPTION(std::runtime_error("Could not read JSON file '" + path + "'.")); + + return JsonDecode(json); +} + +void Utility::SaveJsonFile(const String& path, const Value& value) +{ + String tempPath = path + ".tmp"; + + std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc); + fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); + fp << JsonEncode(value); + fp.close(); + +#ifdef _WIN32 + _unlink(path.CStr()); +#endif /* _WIN32 */ + + if (rename(tempPath.CStr(), path.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("rename") + << boost::errinfo_errno(errno) + << boost::errinfo_file_name(tempPath)); + } +} diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index eab224aeb..de4e332b7 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -139,6 +139,9 @@ public: static bool CopyFile(const String& source, const String& target); + static Value LoadJsonFile(const String& path); + static void SaveJsonFile(const String& path, const Value& value); + private: Utility(void); diff --git a/lib/cli/agentaddcommand.cpp b/lib/cli/agentaddcommand.cpp index 3226dd864..034e425b4 100644 --- a/lib/cli/agentaddcommand.cpp +++ b/lib/cli/agentaddcommand.cpp @@ -55,11 +55,7 @@ int AgentAddCommand::GetMinArguments(void) const */ int AgentAddCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { - if (!AgentUtility::AddAgent(ap[0])) { - Log(LogCritical, "cli") - << "Cannot add agent '" << ap[0] << "'."; - return 1; - } + AgentUtility::AddAgent(ap[0]); return 0; } diff --git a/lib/cli/agentremovecommand.cpp b/lib/cli/agentremovecommand.cpp index 28187c836..d8f9394d9 100644 --- a/lib/cli/agentremovecommand.cpp +++ b/lib/cli/agentremovecommand.cpp @@ -65,17 +65,9 @@ int AgentRemoveCommand::GetMaxArguments(void) const */ int AgentRemoveCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { - bool failed = false; - BOOST_FOREACH(const String& agent, ap) { - if (!AgentUtility::RemoveAgent(agent)) { - Log(LogCritical, "cli", "Cannot remove agent '" + ap[0] + "'."); - failed = true; - } + AgentUtility::RemoveAgent(agent); } - if (failed) - return 1; - else - return 0; + return 0; } diff --git a/lib/cli/agentsetcommand.cpp b/lib/cli/agentsetcommand.cpp index 6238f832a..60ad59256 100644 --- a/lib/cli/agentsetcommand.cpp +++ b/lib/cli/agentsetcommand.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "cli/agentsetcommand.hpp" +#include "cli/agentutility.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include @@ -45,7 +46,10 @@ String AgentSetCommand::GetShortDescription(void) const void AgentSetCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { - + visibleDesc.add_options() + ("host", po::value(), "Icinga 2 host") + ("port", po::value(), "Icinga 2 port") + ("log_duration", po::value(), "Log duration (in seconds)"); } int AgentSetCommand::GetMinArguments(void) const @@ -60,7 +64,27 @@ int AgentSetCommand::GetMinArguments(void) const */ int AgentSetCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { - Log(LogWarning, "cli", "TODO: Not implemented yet."); + String repoFile = AgentUtility::GetAgentRepositoryFile(ap[0]); + + if (!Utility::PathExists(repoFile)) { + Log(LogCritical, "cli") + << "Agent '" << ap[0] << "' does not exist."; + return 1; + } + + String host, port = "5665"; + double log_duration = 24 * 60 * 60; + + if (vm.count("host")) + host = vm["host"].as(); + + if (vm.count("port")) + port = vm["port"].as(); + + if (vm.count("log_duration")) + log_duration = vm["log_duration"].as(); + + AgentUtility::AddAgentSettings(ap[0], host, port, log_duration); return 0; } diff --git a/lib/cli/agentutility.cpp b/lib/cli/agentutility.cpp index 94ac0d17d..a378309ef 100644 --- a/lib/cli/agentutility.cpp +++ b/lib/cli/agentutility.cpp @@ -23,6 +23,7 @@ #include "base/application.hpp" #include "base/tlsutility.hpp" #include "base/convert.hpp" +#include "base/utility.hpp" #include "base/json.hpp" #include "base/netstring.hpp" #include "base/stdiostream.hpp" @@ -80,7 +81,22 @@ void AgentUtility::PrintAgents(std::ostream& fp) fp << "Agent '" << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << agent->Get("endpoint") << ConsoleColorTag(Console_Normal) - << "' (last seen: " << Utility::FormatDateTime("%c", agent->Get("seen")) << ")\n"; + << "' ("; + + Dictionary::Ptr settings = agent->Get("settings"); + + if (settings) { + String host = settings->Get("host"); + String port = settings->Get("port"); + double log_duration = settings->Get("log_duration"); + + if (!host.IsEmpty() && !port.IsEmpty()) + fp << "host: " << host << ", port: " << port << ", "; + + fp << "log duration: " << Utility::FormatDuration(log_duration) << ", "; + } + + fp << "last seen: " << Utility::FormatDateTime("%c", agent->Get("seen")) << ")\n"; PrintAgentRepository(fp, agent->Get("repository")); } @@ -115,14 +131,13 @@ void AgentUtility::PrintAgentsJson(std::ostream& fp) fp << JsonEncode(result); } -bool AgentUtility::AddAgent(const String& name) +void AgentUtility::AddAgent(const String& name) { String path = GetAgentRepositoryFile(name); if (Utility::PathExists(path) ) { - Log(LogCritical, "cli") - << "Cannot add agent repo. '" << path << "' already exists.\n"; - return false; + Log(LogInformation, "cli") + << "Agent '" << name << "' exists already."; } Dictionary::Ptr agent = make_shared(); @@ -132,110 +147,51 @@ bool AgentUtility::AddAgent(const String& name) agent->Set("zone", name); agent->Set("repository", Empty); - return WriteAgentToRepository(path, agent); + Utility::SaveJsonFile(path, agent); } -bool AgentUtility::AddAgentSettings(const String& name, const String& host, const String& port) +void AgentUtility::AddAgentSettings(const String& name, const String& host, + const String& port, double log_duration) { - String path = GetAgentSettingsFile(name); + Dictionary::Ptr settings = make_shared(); - Dictionary::Ptr peer = make_shared(); + settings->Set("host", host); + settings->Set("port", port); + settings->Set("log_duration", log_duration); - peer->Set("agent_host", host); - peer->Set("agent_port", port); - - return WriteAgentToRepository(path, peer); + Utility::SaveJsonFile(GetAgentSettingsFile(name), settings); } -bool AgentUtility::RemoveAgent(const String& name) +void AgentUtility::RemoveAgent(const String& name) { - if (!RemoveAgentFile(GetAgentRepositoryFile(name))) { + String repoPath = GetAgentRepositoryFile(name); + + if (!Utility::PathExists(repoPath)) + return; + + if (unlink(repoPath.CStr()) < 0) { Log(LogCritical, "cli") - << "Cannot remove agent repo. '" << GetAgentRepositoryFile(name) << "' does not exist.\n"; - return false; - } + << "Cannot remove file '" << repoPath + << "'. Failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) + "\"."; + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("unlink") + << boost::errinfo_errno(errno) + << boost::errinfo_file_name(repoPath)); + } - if (Utility::PathExists(GetAgentSettingsFile(name))) { - if (!RemoveAgentFile(GetAgentSettingsFile(name))) { - Log(LogWarning, "cli") - << "Cannot remove agent settings. '" << GetAgentSettingsFile(name) << "' does not exist.\n"; - return false; + String settingsPath = GetAgentSettingsFile(name); + + if (Utility::PathExists(settingsPath)) { + if (unlink(settingsPath.CStr()) < 0) { + Log(LogCritical, "cli") + << "Cannot remove file '" << settingsPath + << "'. Failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) + "\"."; + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("unlink") + << boost::errinfo_errno(errno) + << boost::errinfo_file_name(settingsPath)); } } - - return true; -} - -bool AgentUtility::RemoveAgentFile(const String& path) -{ - if (!Utility::PathExists(path)) { - Log(LogCritical, "cli") - << "Cannot remove '" << path << "'. Does not exist."; - return false; - } - - if (unlink(path.CStr()) < 0) { - Log(LogCritical, "cli") - << "Cannot remove file '" << path - << "'. Failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) + "\"."; - return false; - } - - return true; -} - -bool AgentUtility::SetAgentAttribute(const String& name, const String& attr, const Value& val) -{ - String repo_path = GetAgentRepositoryFile(name); - Dictionary::Ptr repo = GetAgentFromRepository(repo_path); - - if (repo) { - repo->Set(attr, val); - WriteAgentToRepository(repo_path, repo); - return true; - } - - return false; -} - -bool AgentUtility::WriteAgentToRepository(const String& filename, const Dictionary::Ptr& item) -{ - Log(LogInformation, "cli") - << "Dumping agent to file '" << filename << "'"; - - String tempFilename = filename + ".tmp"; - - std::ofstream fp(tempFilename.CStr(), std::ofstream::out | std::ostream::trunc); - fp << JsonEncode(item); - 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)); - } - - return true; -} - -Dictionary::Ptr AgentUtility::GetAgentFromRepository(const String& filename) -{ - std::fstream fp; - fp.open(filename.CStr(), std::ifstream::in); - - if (!fp) - return Dictionary::Ptr(); - - String content((std::istreambuf_iterator(fp)), std::istreambuf_iterator()); - - fp.close(); - - return JsonDecode(content); } std::vector AgentUtility::GetAgents(void) @@ -248,9 +204,26 @@ std::vector AgentUtility::GetAgents(void) return agents; } +Dictionary::Ptr AgentUtility::LoadAgentFile(const String& agent_file) +{ + Dictionary::Ptr agent = Utility::LoadJsonFile(agent_file); + + if (!agent) + return Dictionary::Ptr(); + + String settingsFile = GetAgentSettingsFile(agent->Get("endpoint")); + + if (Utility::PathExists(settingsFile)) + agent->Set("settings", Utility::LoadJsonFile(settingsFile)); + else + agent->Remove("settings"); + + return agent; +} + void AgentUtility::CollectAgents(const String& agent_file, std::vector& agents) { - Dictionary::Ptr agent = GetAgentFromRepository(agent_file); + Dictionary::Ptr agent = LoadAgentFile(agent_file); if (!agent) return; diff --git a/lib/cli/agentutility.hpp b/lib/cli/agentutility.hpp index dae441d9a..b1e37a04a 100644 --- a/lib/cli/agentutility.hpp +++ b/lib/cli/agentutility.hpp @@ -44,13 +44,9 @@ public: static void PrintAgents(std::ostream& fp); static void PrintAgentsJson(std::ostream& fp); static void PrintAgentRepository(std::ostream& fp, const Dictionary::Ptr& repository); - static bool AddAgent(const String& name); - static bool AddAgentSettings(const String& name, const String& host, const String& port); - static bool RemoveAgent(const String& name); - static bool SetAgentAttribute(const String& name, const String& attr, const Value& val); - - static bool WriteAgentToRepository(const String& filename, const Dictionary::Ptr& item); - static Dictionary::Ptr GetAgentFromRepository(const String& filename); + static void AddAgent(const String& name); + static void AddAgentSettings(const String& name, const String& host, const String& port, double log_duration); + static void RemoveAgent(const String& name); static std::vector GetAgents(void); @@ -67,6 +63,7 @@ public: private: AgentUtility(void); static bool RemoveAgentFile(const String& path); + static Dictionary::Ptr LoadAgentFile(const String& agent_file); static void CollectAgents(const String& agent_file, std::vector& agents); static void SerializeObject(std::ostream& fp, const String& name, const String& type, const Dictionary::Ptr& object);