Skip to content

Commit

Permalink
Cli: Don't overwrite existing objects; delete old agent objects on 'a…
Browse files Browse the repository at this point in the history
…gent update-config'

refs #7248
  • Loading branch information
Michael Friedrich committed Oct 28, 2014
1 parent d92dc85 commit 16069a7
Showing 1 changed file with 144 additions and 0 deletions.
144 changes: 144 additions & 0 deletions lib/cli/agentupdateconfigcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/objectlock.hpp"
#include "base/json.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
Expand Down Expand Up @@ -66,22 +67,57 @@ int AgentUpdateConfigCommand::Run(const boost::program_options::variables_map& v
return 1;
}

String inventory_path = AgentUtility::GetRepositoryPath() + "/inventory.index";

Dictionary::Ptr old_inventory = make_shared<Dictionary>();
if (Utility::PathExists(inventory_path)) {
old_inventory = Utility::LoadJsonFile(inventory_path);
}

Dictionary::Ptr inventory = make_shared<Dictionary>();

Log(LogInformation, "cli")
<< "Updating agent configuration for ";

AgentUtility::PrintAgents(std::cout);

Utility::LoadExtensionLibrary("icinga");

std::vector<String> object_paths = RepositoryUtility::GetObjects();

BOOST_FOREACH(const Dictionary::Ptr& agent, AgentUtility::GetAgents()) {

/* store existing structure in index */
inventory->Set(agent->Get("endpoint"), agent);

Dictionary::Ptr repository = agent->Get("repository");
String zone = agent->Get("zone");
String endpoint = agent->Get("endpoint");

Dictionary::Ptr host_services = make_shared<Dictionary>();

ObjectLock olock(repository);
BOOST_FOREACH(const Dictionary::Pair& kv, repository) {
String host = kv.first;
String host_pattern = host + ".conf";
bool skip = false;

BOOST_FOREACH(const String& object_path, object_paths) {
if (object_path.Contains(host_pattern)) {
Log(LogWarning, "cli")
<< "Host '" << host << "' already existing. Skipping its creation.";
skip = true;
break;
}
}

if (skip)
continue;

/* add a new host to the config repository */
Dictionary::Ptr host_attrs = make_shared<Dictionary>();
host_attrs->Set("__name", host);
host_attrs->Set("name", host);
host_attrs->Set("check_command", "dummy"); //TODO: add a repository-host template
host_attrs->Set("zone", zone);

Expand All @@ -92,11 +128,36 @@ int AgentUpdateConfigCommand::Run(const boost::program_options::variables_map& v
}

Array::Ptr services = kv.second;

if (services->GetLength() == 0) {
Log(LogNotice, "cli")
<< "Host '" << host << "' without services.";
continue;
}

ObjectLock xlock(services);
BOOST_FOREACH(const String& service, services) {

String service_pattern = host + "/" + service + ".conf";
bool skip = false;

BOOST_FOREACH(const String& object_path, object_paths) {
if (object_path.Contains(service_pattern)) {
Log(LogWarning, "cli")
<< "Service '" << service << "' on Host '" << host << "' already existing. Skipping its creation.";
skip = true;
break;
}
}

if (skip)
continue;

/* add a new service for this host to the config repository */
Dictionary::Ptr service_attrs = make_shared<Dictionary>();
String long_name = host + "!" + service; //use NameComposer?
service_attrs->Set("__name", long_name);
service_attrs->Set("name", service);
service_attrs->Set("host_name", host); //Required for host-service relation
service_attrs->Set("check_command", "dummy"); //TODO: add a repository-service template
service_attrs->Set("zone", zone);
Expand All @@ -111,6 +172,8 @@ int AgentUpdateConfigCommand::Run(const boost::program_options::variables_map& v

/* write a new zone and endpoint for the agent */
Dictionary::Ptr endpoint_attrs = make_shared<Dictionary>();
endpoint_attrs->Set("__name", endpoint);
endpoint_attrs->Set("name", endpoint);

Dictionary::Ptr settings = agent->Get("settings");

Expand All @@ -130,6 +193,8 @@ int AgentUpdateConfigCommand::Run(const boost::program_options::variables_map& v
Array::Ptr zone_members = make_shared<Array>();

zone_members->Add(endpoint);
zone_attrs->Set("__name", zone);
zone_attrs->Set("name", zone);
zone_attrs->Set("endpoints", zone_members);
zone_attrs->Set("parent", agent->Get("parent_zone"));

Expand All @@ -139,12 +204,91 @@ int AgentUpdateConfigCommand::Run(const boost::program_options::variables_map& v
}
}

/* check if there are objects inside the old_inventory which do not exist anymore */
BOOST_FOREACH(const Dictionary::Pair& old_agent_objs, old_inventory) {

String old_agent_name = old_agent_objs.first;

/* check if the agent was dropped */
if (!inventory->Contains(old_agent_name)) {
Log(LogInformation, "cli")
<< "Agent update found old agent '" << old_agent_name << "'. Removing it and all of its hosts/services.";

//TODO Remove an agent and all of his hosts
Dictionary::Ptr old_agent = old_inventory->Get(old_agent_name);
Dictionary::Ptr old_agent_repository = old_agent->Get("repository");

ObjectLock olock(old_agent_repository);
BOOST_FOREACH(const Dictionary::Pair& kv, old_agent_repository) {
String host = kv.first;

Dictionary::Ptr host_attrs = make_shared<Dictionary>();
host_attrs->Set("name", host);
RepositoryUtility::RemoveObject(host, "Host", host_attrs); //this removes all services for this host as well
}

//TODO: Remove zone/endpoint information as well
String zone = old_agent->Get("zone");
String endpoint = old_agent->Get("endpoint");

Dictionary::Ptr zone_attrs = make_shared<Dictionary>();
zone_attrs->Set("name", zone);
RepositoryUtility::RemoveObject(zone, "Zone", zone_attrs);

Dictionary::Ptr endpoint_attrs = make_shared<Dictionary>();
endpoint_attrs->Set("name", endpoint);
RepositoryUtility::RemoveObject(endpoint, "Endpoint", endpoint_attrs);
} else {
/* get the current agent */
Dictionary::Ptr new_agent = inventory->Get(old_agent_name);
Dictionary::Ptr new_agent_repository = new_agent->Get("repository");

Dictionary::Ptr old_agent = old_inventory->Get(old_agent_name);
Dictionary::Ptr old_agent_repository = old_agent->Get("repository");

ObjectLock xlock(old_agent_repository);
BOOST_FOREACH(const Dictionary::Pair& kv, old_agent_repository) {
String old_host = kv.first;

if (!new_agent_repository->Contains(old_host)) {
Log(LogInformation, "cli")
<< "Agent update found old host '" << old_host << "' on agent '" << old_agent_name << "'. Removing it.";

Dictionary::Ptr host_attrs = make_shared<Dictionary>();
host_attrs->Set("name", old_host);
RepositoryUtility::RemoveObject(old_host, "Host", host_attrs); //this will remove all services for this host too
} else {
/* host exists, now check all services for this host */
Array::Ptr old_services = kv.second;
Array::Ptr new_services = new_agent_repository->Get(old_host);

ObjectLock ylock(old_services);
BOOST_FOREACH(const String& old_service, old_services) {
if (!new_services->Contains(old_service)) {
Log(LogInformation, "cli")
<< "Agent update found old service '" << old_service << "' on host '" << old_host
<< "' on agent '" << old_agent_name << "'. Removing it.";

Dictionary::Ptr service_attrs = make_shared<Dictionary>();
service_attrs->Set("name", old_service);
service_attrs->Set("host_name", old_host);
RepositoryUtility::RemoveObject(old_service, "Service", service_attrs);
}
}
}
}
}
}

Log(LogInformation, "cli", "Committing agent configuration.");

RepositoryUtility::PrintChangeLog(std::cout);
std::cout << "\n";
RepositoryUtility::CommitChangeLog();

/* store the new inventory for next run */
Utility::SaveJsonFile(inventory_path, inventory);

std::cout << "Make sure to reload Icinga 2 for these changes to take effect." << std::endl;

return 0;
Expand Down

0 comments on commit 16069a7

Please sign in to comment.