Implement agent settings for "agent set" and "agent list"

refs #7248
This commit is contained in:
Gunnar Beutner 2014-10-27 15:12:19 +01:00
parent c0103268e1
commit 3f032692ce
7 changed files with 144 additions and 122 deletions

View File

@ -24,6 +24,7 @@
#include "base/exception.hpp" #include "base/exception.hpp"
#include "base/socket.hpp" #include "base/socket.hpp"
#include "base/utility.hpp" #include "base/utility.hpp"
#include "base/json.hpp"
#include <mmatch.h> #include <mmatch.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -1088,3 +1089,39 @@ bool Utility::PathExists(const String& path)
return (_stat(path.CStr(), &statbuf) >= 0); return (_stat(path.CStr(), &statbuf) >= 0);
#endif /* _WIN32 */ #endif /* _WIN32 */
} }
Value Utility::LoadJsonFile(const String& path)
{
std::ifstream fp;
fp.open(path.CStr());
String json((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
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));
}
}

View File

@ -139,6 +139,9 @@ public:
static bool CopyFile(const String& source, const String& target); 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: private:
Utility(void); Utility(void);

View File

@ -55,11 +55,7 @@ int AgentAddCommand::GetMinArguments(void) const
*/ */
int AgentAddCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const int AgentAddCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
{ {
if (!AgentUtility::AddAgent(ap[0])) { AgentUtility::AddAgent(ap[0]);
Log(LogCritical, "cli")
<< "Cannot add agent '" << ap[0] << "'.";
return 1;
}
return 0; return 0;
} }

View File

@ -65,17 +65,9 @@ int AgentRemoveCommand::GetMaxArguments(void) const
*/ */
int AgentRemoveCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const int AgentRemoveCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
{ {
bool failed = false;
BOOST_FOREACH(const String& agent, ap) { BOOST_FOREACH(const String& agent, ap) {
if (!AgentUtility::RemoveAgent(agent)) { AgentUtility::RemoveAgent(agent);
Log(LogCritical, "cli", "Cannot remove agent '" + ap[0] + "'.");
failed = true;
}
} }
if (failed) return 0;
return 1;
else
return 0;
} }

View File

@ -18,6 +18,7 @@
******************************************************************************/ ******************************************************************************/
#include "cli/agentsetcommand.hpp" #include "cli/agentsetcommand.hpp"
#include "cli/agentutility.hpp"
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/application.hpp" #include "base/application.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -45,7 +46,10 @@ String AgentSetCommand::GetShortDescription(void) const
void AgentSetCommand::InitParameters(boost::program_options::options_description& visibleDesc, void AgentSetCommand::InitParameters(boost::program_options::options_description& visibleDesc,
boost::program_options::options_description& hiddenDesc) const boost::program_options::options_description& hiddenDesc) const
{ {
visibleDesc.add_options()
("host", po::value<std::string>(), "Icinga 2 host")
("port", po::value<std::string>(), "Icinga 2 port")
("log_duration", po::value<double>(), "Log duration (in seconds)");
} }
int AgentSetCommand::GetMinArguments(void) const 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<std::string>& ap) const int AgentSetCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& 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<std::string>();
if (vm.count("port"))
port = vm["port"].as<std::string>();
if (vm.count("log_duration"))
log_duration = vm["log_duration"].as<double>();
AgentUtility::AddAgentSettings(ap[0], host, port, log_duration);
return 0; return 0;
} }

View File

@ -23,6 +23,7 @@
#include "base/application.hpp" #include "base/application.hpp"
#include "base/tlsutility.hpp" #include "base/tlsutility.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/utility.hpp"
#include "base/json.hpp" #include "base/json.hpp"
#include "base/netstring.hpp" #include "base/netstring.hpp"
#include "base/stdiostream.hpp" #include "base/stdiostream.hpp"
@ -80,7 +81,22 @@ void AgentUtility::PrintAgents(std::ostream& fp)
fp << "Agent '" fp << "Agent '"
<< ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << agent->Get("endpoint") << ConsoleColorTag(Console_Normal) << 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")); PrintAgentRepository(fp, agent->Get("repository"));
} }
@ -115,14 +131,13 @@ void AgentUtility::PrintAgentsJson(std::ostream& fp)
fp << JsonEncode(result); fp << JsonEncode(result);
} }
bool AgentUtility::AddAgent(const String& name) void AgentUtility::AddAgent(const String& name)
{ {
String path = GetAgentRepositoryFile(name); String path = GetAgentRepositoryFile(name);
if (Utility::PathExists(path) ) { if (Utility::PathExists(path) ) {
Log(LogCritical, "cli") Log(LogInformation, "cli")
<< "Cannot add agent repo. '" << path << "' already exists.\n"; << "Agent '" << name << "' exists already.";
return false;
} }
Dictionary::Ptr agent = make_shared<Dictionary>(); Dictionary::Ptr agent = make_shared<Dictionary>();
@ -132,110 +147,51 @@ bool AgentUtility::AddAgent(const String& name)
agent->Set("zone", name); agent->Set("zone", name);
agent->Set("repository", Empty); 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>();
Dictionary::Ptr peer = make_shared<Dictionary>(); settings->Set("host", host);
settings->Set("port", port);
settings->Set("log_duration", log_duration);
peer->Set("agent_host", host); Utility::SaveJsonFile(GetAgentSettingsFile(name), settings);
peer->Set("agent_port", port);
return WriteAgentToRepository(path, peer);
} }
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") Log(LogCritical, "cli")
<< "Cannot remove agent repo. '" << GetAgentRepositoryFile(name) << "' does not exist.\n"; << "Cannot remove file '" << repoPath
return false; << "'. 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))) { String settingsPath = GetAgentSettingsFile(name);
if (!RemoveAgentFile(GetAgentSettingsFile(name))) {
Log(LogWarning, "cli") if (Utility::PathExists(settingsPath)) {
<< "Cannot remove agent settings. '" << GetAgentSettingsFile(name) << "' does not exist.\n"; if (unlink(settingsPath.CStr()) < 0) {
return false; 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<char>(fp)), std::istreambuf_iterator<char>());
fp.close();
return JsonDecode(content);
} }
std::vector<Dictionary::Ptr> AgentUtility::GetAgents(void) std::vector<Dictionary::Ptr> AgentUtility::GetAgents(void)
@ -248,9 +204,26 @@ std::vector<Dictionary::Ptr> AgentUtility::GetAgents(void)
return agents; 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<Dictionary::Ptr>& agents) void AgentUtility::CollectAgents(const String& agent_file, std::vector<Dictionary::Ptr>& agents)
{ {
Dictionary::Ptr agent = GetAgentFromRepository(agent_file); Dictionary::Ptr agent = LoadAgentFile(agent_file);
if (!agent) if (!agent)
return; return;

View File

@ -44,13 +44,9 @@ public:
static void PrintAgents(std::ostream& fp); static void PrintAgents(std::ostream& fp);
static void PrintAgentsJson(std::ostream& fp); static void PrintAgentsJson(std::ostream& fp);
static void PrintAgentRepository(std::ostream& fp, const Dictionary::Ptr& repository); static void PrintAgentRepository(std::ostream& fp, const Dictionary::Ptr& repository);
static bool AddAgent(const String& name); static void AddAgent(const String& name);
static bool AddAgentSettings(const String& name, const String& host, const String& port); static void AddAgentSettings(const String& name, const String& host, const String& port, double log_duration);
static bool RemoveAgent(const String& name); static void 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 std::vector<Dictionary::Ptr> GetAgents(void); static std::vector<Dictionary::Ptr> GetAgents(void);
@ -67,6 +63,7 @@ public:
private: private:
AgentUtility(void); AgentUtility(void);
static bool RemoveAgentFile(const String& path); static bool RemoveAgentFile(const String& path);
static Dictionary::Ptr LoadAgentFile(const String& agent_file);
static void CollectAgents(const String& agent_file, std::vector<Dictionary::Ptr>& agents); static void CollectAgents(const String& agent_file, std::vector<Dictionary::Ptr>& agents);
static void SerializeObject(std::ostream& fp, const String& name, const String& type, const Dictionary::Ptr& object); static void SerializeObject(std::ostream& fp, const String& name, const String& type, const Dictionary::Ptr& object);