]> granicus.if.org Git - icinga2/commitdiff
Cli: Don't overwrite existing objects; delete old agent objects on 'agent update...
authorMichael Friedrich <michael.friedrich@netways.de>
Tue, 28 Oct 2014 18:17:37 +0000 (19:17 +0100)
committerMichael Friedrich <michael.friedrich@netways.de>
Tue, 28 Oct 2014 18:28:38 +0000 (19:28 +0100)
refs #7248

lib/cli/agentupdateconfigcommand.cpp

index ff5963b463231ab383c69ba9b5f7fa7c8a03550d..018c7997ca738cb1601c53e80214fadeab2c8b74 100644 (file)
@@ -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>
@@ -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);
 
@@ -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);
@@ -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");
 
@@ -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"));
 
@@ -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;