Script for adding or removing hosts in a hostgroup

This support forum board is for support questions relating to Nagios XI, our flagship commercial network monitoring solution.
mp4783
Posts: 116
Joined: Wed May 14, 2014 11:11 am

Re: Script for adding or removing hosts in a hostgroup

Post by mp4783 »

It seems like we're all trying to solve this. I too have written (or am writing) a utility to allow you to programmatically execute almost everything you can do in the GUI.

The thing we need to watch out for is "collisions" between a user in the GUI making changes which are not yet applied, while the external utility is making its changes. In other words, if I make an external change and reconfigure, then the user in the GUI will be working in an "unsynchronized" environment.

I'm going to ask this question in separate thread.
cmerchant
Posts: 546
Joined: Wed Sep 24, 2014 11:19 am

Re: Script for adding or removing hosts in a hostgroup

Post by cmerchant »

Going to post a link to your new thread: Nagios XI Reconfiguration Collisions and Conflicts
http://support.nagios.com/forum/viewtop ... 40#p126992
mp4783
Posts: 116
Joined: Wed May 14, 2014 11:11 am

Re: Script for adding or removing hosts in a hostgroup

Post by mp4783 »

Modification of a single attribute is really just a matter of determining the characteristics and dependencies of that attribute. For example, if I modify the service_description of a service check (perhaps it was misspelled), Nagios would assume it to be a new service upon import. But if I wanted that service check and its associated history and performance data to stay together, how would I achieve that?

The utility I'm working on is going to do this. I already have host cloning working consistently. Modifying all hosts within a host group should just be a matter of identifying the hosts and iteratively performing modifications on the appropriate configuration file(s).

You would need to understand the relationship between that service description and all objects associated with it. These relationships are not well-defined in the documentation. So, in this specific example, to modify all members of a hostgroup, assuming you are not changing the service_description directive value, you should consider doing the following:

1) Identify the object (dependency, host, service, etc.) you want to modify or add
2) Identify the directive(s) you are modifying
3) Trace any dependencies that directive may have through the configuration files (reference: http://nagios.sourceforge.net/docs/nagi ... tions.html)
4) Determine a method for modifying the directive's value
5) Iteratively parse and modify copies of the configuration files
6) Place these modified copies into the /usr/local/nagios/etc/import directive
7) Execute the /usr/local/nagios/nagiosxi/scripts/reconfigure_nagios.sh script
8) Verify that the changes were made

The preceding is probably obvious to many in this forum, but as I've progressed through my own development, there are aspects of how Nagios works that may not be immediately apparent.

A more deterministic, although dangerous, method of making these changes would be to perform direct updates on the MySQL and PostgreSQL databases and then flush the changes to the configuration files. This would be a non-trivial effort and is not something I'm going to try at this point.
cmerchant
Posts: 546
Joined: Wed Sep 24, 2014 11:19 am

Re: Script for adding or removing hosts in a hostgroup

Post by cmerchant »

There exists already that function in Nagios XI Enterprise the Bulk Renaming Tool that:
Bulk Renaming Tool
The Renaming Tool allows for host and service names to be updated in bulk, while retaining all historical status information and performance data. The renaming tool updates configurations based on what is defined in the Core Config Manager.
mp4783
Posts: 116
Joined: Wed May 14, 2014 11:11 am

Re: Script for adding or removing hosts in a hostgroup

Post by mp4783 »

I'm not sure how that would be applicable here.
User avatar
lmiltchev
Bugs find me
Posts: 13589
Joined: Mon May 23, 2011 12:15 pm

Re: Script for adding or removing hosts in a hostgroup

Post by lmiltchev »

@mp4783
I too have written (or am writing) a utility to allow you to programmatically execute almost everything you can do in the GUI.
I would be very interested in testing this in house. It could benefit many XI users with large environments, who want to manage hosts/services from the CLI.
Be sure to check out our Knowledgebase for helpful articles and solutions!
User avatar
WillemDH
Posts: 2320
Joined: Wed Mar 20, 2013 5:49 am
Location: Ghent
Contact:

Re: Script for adding or removing hosts in a hostgroup

Post by WillemDH »

I would be very interested in testing this in house. It could benefit many XI users with large environments, who want to manage hosts/services from the CLI.
I'll +1 this. It it has been done well and is reliable, this would indeed be very beneficial. C'mon mp, convince your boss. Explain him Nagios is build on the work of many. :) Check out all the plugins I wrote and released on the Nagios Exchange: http://exchange.nagios.org/directory/Owner/willemdh/1

It could also help you to discover issues faster if more people use it..

Grtz

Willem
Nagios XI 5.8.1
https://outsideit.net
jwelch
Posts: 225
Joined: Wed Sep 05, 2012 12:49 pm

Re: Script for adding or removing hosts in a hostgroup

Post by jwelch »

Sorry for the delay...I ended up almost completely re-writing my perl script. Now it runs every hour via cron as the nagios user and only does a nagios restart if the new hostgroups.cfg is different from the existing hostgroups.cfg (*not* using direct file comparison since timestamps, sort order, etc make comparing the files problematic). Following are code snippets from the actual script so may be missing libraries, subs, variable declarations, etc...

Notes: I only use/modify hostgroups.cfg. You can still make hostgroup assignments in the individual host config files and they will not be affected
by this script. My script does read the host configs and check a few things like notification periods which are compared to an external database, but
I just add those to the info array so I get email and manually make those changes. I might automate those changes later but so far it hasn't been
necessary.

First I import the existing hostgroups.cfg into a hash:

Code: Select all

#!/usr/bin/perl
 
#####################################################
# nagios-import
#####################################################
use Data::Dumper;
use Clone qw(clone);
use Array::Utils qw(:all);
use strict;

my $hg_current;
my $hg_external;
my $hg_import;
my @info;  #array to store info  msgs for email notification
my @error; #array to store error msgs for email notification
my $restart_required=0;

get_hostgroups_hash(\$hg_current,"$WorkFile");

#iterate through hash example
#foreach my $key (sort keys %{$hg_current}) {
# print "check key $key\n";
# foreach my $subkey (sort keys %{$hg_current->{$key}}) {
#  print "check subkey $subkey\n";
#  my $type=ref($hg_current->{$key}{$subkey});
#  if ($type eq '') {
#   print "VALUE: ".$hg_current->{$key}{$subkey}."\n";
#  } elsif ($type eq 'HASH') {
#   foreach my $subsubkey (sort keys %{$hg_current->{$key}{$subkey}}) {
#    print "subsubkey: $subsubkey\n";
#    print "value: ".$hg_current->{$key}{$subkey}{$subsubkey}."\n";
#   }
#  } else {
#   print "REF: $type\n";
#  }
# }
#}
Then clone the hash

Code: Select all

$hg_import = clone($hg_current);
and build a new hash ($hg_external) based on the external data (source specific so not shown here)

Then merge the two into a third hash for export.

Code: Select all

 #check for changes and if found, merge hg_external hosts into hg_import;
 foreach my $hostgroup (sort keys %{$hg_external->{'hostgroup'}}) {
   my $hosts_import = $hg_import->{'hostgroup'}{$hostgroup}{'hosts'};
   my $hosts_external = $hg_external->{'hostgroup'}{$hostgroup}{'hosts'};
   my $mask = $hosts_import ^ $hosts_external;
   my @s1=split(",",$hosts_import);
   my @s2=split(",",$hosts_external);
   my $diff=array_diff(@s1,@s2);
   #print "$hostgroup: diff=$diff\n";
   if ("$diff" == 0) {
    #print "$hostgroup : match\n";
   } else {
     my @removed=array_minus(@s1,@s2);
     my @added=array_minus(@s2,@s1);
     $restart_required=1; #trigger import file write and nagios restart
     if ($diff > 1) {
       push(@info,"HOSTGROUP: *$hostgroup* : $diff changes");
     } else {
       push(@info,"HOSTGROUP: *$hostgroup* : $diff change");
     }
     my $removed_detail;
     foreach my $host (@removed) {
       if ($removed_detail eq '') {
         $removed_detail.="$host";
       } else {
        $removed_detail.=",$host";
       }
     }
     my $added_detail;
     foreach my $host (@added) {
       if ($added_detail eq '') {
         $added_detail.="$host";
       } else {
         $added_detail.=",$host";
       }
     }
     push(@info,"Removed: $removed_detail") if ($removed_detail);
     #print "Removed: $removed_detail\n" if ($removed_detail);
     push(@info,"Added  : $removed_detail") if ($added_detail);
     #print "Added  : $removed_detail\n" if ($added_detail);
     push(@info,"---") if ($diff);
   }
   #print "merge $hostgroup\n";
   #print " using: *".$hg_external->{'hostgroup'}{$hostgroup}{'hosts'}."*\n";
   $hg_import->{'hostgroup'}{$hostgroup}{'hosts'} = $hg_external->{'hostgroup'}{$hostgroup}{'hosts'};
   $restart_required=1;
 }
If changes made, then create the new hostgroups.cfg file in the import directory

Code: Select all

#now create data array for import file hostgroups.cfg.
push (@data,"###############################################################################");
push (@data,"#");
push (@data,"# Hostgroup configuration file");
push (@data,"#");
push (@data,"# Created by: $0");
push (@data,"# Date:       $timestamp");
push (@data,"# Nagios 4.x config file");
push (@data,"#");
push (@data,"###############################################################################");
foreach my $hostgroup (sort keys %{$hg_import->{'hostgroup'}}) {
  #print "create data for $hostgroup\n";
  my $alias=$hg_import->{'hostgroup'}{$hostgroup}{'alias'};
  my $members=$hg_import->{'hostgroup'}{$hostgroup}{'hosts'};
  my $hostgroup_members=$hg_import->{'hostgroup'}{$hostgroup}{'hostgroup_members'};
  #print "alias = $alias\n";
  #print "members = $members\n";
  #print "hostgroup_members = $hostgroup_members\n";
  push (@data,"");
  push (@data,"define hostgroup {");
  push (@data,"        hostgroup_name                  $hostgroup");
  push (@data,"        alias                           $alias");
  push (@data,"        members                         $members") if ($members ne '');
  push (@data,"        hostgroup_members               $hostgroup_members") if ($hostgroup_members ne '');
  push (@data,"        }");
}
push (@data,"###############################################################################");
push (@data,"#");
push (@data,"# Hostgroups configuration file");
push (@data,"#");
push (@data,"# END OF FILE");
push (@data,"#");
push (@data,"###############################################################################");
Write new hosttroups.cfg and restart nagios (if necessary)

Code: Select all

my $errors=@error;
my $infos = @info;
if (("$errors" == 0) && ($restart_required)) {
  #create and write import file
  open(IMPORTFILE,">$ImportFile");
  foreach my $line (@data) {
    print IMPORTFILE "$line\n";
  }
  close(IMPORTFILE);
  #restart nagios
  print "restart nagios\n";
  my $reconfig=`cd /usr/local/nagiosxi/scripts/;/usr/local/nagiosxi/scripts/reconfigure_nagios.sh`;
  push(@info," ");
  if ($reconfig=~/Starting nagios\: done\./) {
    push(@info,"Nagios restarted with new hostgroups.cfg");
  }
} else {
  #don't import or restart due to info or err msgs
  push(@info,"Import deferred due to error messages");
  print "Import deferred due to error messages";
}
print "errors = $errors\n";
if ($errors) {
  print "sending errors email\n";
  send_error_email();
}
my $infos = @info;
if ($infos) {
  print "sending infos email\n";
  send_info_email();
}
exit 0;
This is the subroutine that imports the hostgroups.cfg file into a hash.

Code: Select all

sub get_hostgroups_hash($$) {
  my $file = $_[1];
  my $hostgroup;
  my $hostgroup_members;
  my $alias;
  my $hosts;
  open(FILE,"<$file");
  while (my $line = <FILE>) {
   #print "line: $line\n";
   if ($line=~/^define hostgroup/) {
    if ($hostgroup ne '') {
     #print "storing hostgroup $hostgroup\n";
     ${($_[0])}->{'hostgroup'}{$hostgroup}{'alias'}=$alias;
     ${($_[0])}->{'hostgroup'}{$hostgroup}{'hosts'}=$hosts;
     ${($_[0])}->{'hostgroup'}{$hostgroup}{'hostgroup_members'}=$hostgroup_members if ($hostgroup_members ne '')        ;
     ${($_[0])}->{'alias'}{$alias}=$hostgroup;
    }
    $hostgroup='';
    $hostgroup_members='';
    $alias='';
    $hosts='';
    #print "hostgroup=*$hostgroup* alias=*$alias* hosts=*$hosts*\n";
   } elsif ($line=~/hostgroup_name\s+(\S+)/) {
    $hostgroup=$1;
    #print "Starting hostgroup $hostgroup\n";
   } elsif ($line=~/^\s+alias\s+(\S+.*)$/) {
    $alias=$1;
    #print "alias for hostgroup $hostgroup is $alias\n";
   } elsif ($line=~/^\s+members\s+(\S+)/) {
    $hosts=$1;
    #print "hosts for hostgroup $hostgroup is $hosts\n";
    my @members=split(",",$hosts);
    $hosts='';
    foreach my $host (sort @members) {
     #print "Inserting $host into $hostgroup\n";
     if ($hosts eq '') {
      $hosts=$host;
     } else {
      $hosts.=",$host";
     }
    }
   } elsif ($line=~/^\s+hostgroup_members\s+(\S+)/) {
    $hostgroup_members=$1;
   }
  }
 }
User avatar
WillemDH
Posts: 2320
Joined: Wed Mar 20, 2013 5:49 am
Location: Ghent
Contact:

Re: Script for adding or removing hosts in a hostgroup

Post by WillemDH »

Thanks for sharing your code Jwelch.

I'll have a look at it asap.

Willem
Nagios XI 5.8.1
https://outsideit.net
User avatar
lmiltchev
Bugs find me
Posts: 13589
Joined: Mon May 23, 2011 12:15 pm

Re: Script for adding or removing hosts in a hostgroup

Post by lmiltchev »

Thanks from me too, jwelch! I will set a reminder for testing this later. It's not going to be today for sure :) Monday is not a good day.
Be sure to check out our Knowledgebase for helpful articles and solutions!
Locked