Config Storage/Generation

Brian Wilson wilson at unity.ncsu.edu
Wed Dec 11 19:38:10 CET 2002


Russell, I think this request is somewhat impossible because I haven't met
anyone who wants to do the exact same thing with nagios as I.  Thus, their
configs are going to be different, and most likely their database will be
different.  How will one populate their database? Where will notifications
go?  How do you make changes to the db?

Just to make my point, I'll attach the script that runs to pull data out
of my mysql db and generate my nagios configs.  It will probably be of
little use to anyone.

1) all notifications are handled by an event handler accept those that
have a notify_email in the db.  the event handler writes back to the db
and populates fields such as down_count_* last_down_count_* last_down_*.
2) the db is populated by another script that dumps data from ciscoworks.
this script is somewhat intelligent as it will take care of ip/hostname
changes, password changes, etc.
3) Nagios is only used for checks, all managing/unmanaging of devices,
downtime, etc is handled through a web-based db frontend and commands are
pushed to nagios rw.
4) The event handler checks to see if I device is supposed to be down
(schedled downtime), then sends proper commands to the nagios rw file.
5) cronjob is run every 15 minutes to look at the db and find all devices
that a) are down b) have been down and recovered - but if the device has
gone down and comes back up before the cronjob is run, no notification
will be sent c) devices that have been acknowledged and d) devices that
have downtime or been unmanaged.   This way, if 100 devices go down, you
don't get 100 different emails, instead, you get 1 email with info about
100 devices:
myswtich.blah.com	DOWN             (12/10/2002 10:10:03)
myrouter.blah.com	POWERSUPPLY FAIL (12/10/2002 10:10:03)
..

So, what good is it if you have the config generation piece with none of
the other pieces?  Prolly not much good at all.  I'd share everything, but
there's not enough time in the day to fully document and make everything
so that it would be portable to other locations.. not to mention
supporting what is published.. My advice to you is to spend a day (or
week) designing exactly what you want out of nagios, build a db (you'll
have to rebuild it and add more things later, trust me), then start
coding.

mysql> describe host_table;
+----------------------+---------------------+------+-----+------------+----------------+
| Field                | Type                | Null | Key | Default    |
Extra          |
+----------------------+---------------------+------+-----+------------+----------------+
| oid                  | int(11)             |      | PRI | NULL       |
auto_increment |
| a                    | tinyint(4) unsigned |      |     | 0          |
|
| b                    | tinyint(4) unsigned |      |     | 0          |
|
| c                    | tinyint(6) unsigned |      |     | 0          |
|
| d                    | tinyint(4) unsigned |      |     | 0          |
|
| hostname             | varchar(40)         |      | MUL |            |
|
| alias                | varchar(35)         | YES  | MUL | NULL       |
|
| vlan                 | varchar(60)         | YES  |     | NULL       |
|
| readonly             | varchar(12)         | YES  |     | public     |
|
| readwrite            | varchar(12)         | YES  |     | private    |
|
| pw1                  | varchar(20)         | YES  |     | NULL       |
|
| pw2                  | varchar(20)         | YES  |     | NULL       |
|
| pw_type              | varchar(20)         |      |     | telnet     |
|
| device_type          | text                | YES  |     | NULL       |
|
| device_version       | text                | YES  |     | NULL       |
|
| to_monitor           | tinyint(4)          |      |     | 1          |
|
| notification_sent    | tinyint(4)          | YES  |     | 0          |
|
| downtime_start       | datetime            | YES  |     | NULL       |
|
| downtime_stop        | datetime            | YES  |     | NULL       |
|
| down_count_sys1      | smallint(6)         | YES  |     | 0          |
|
| down_count_sys2      | tinyint(6)          | YES  |     | 0          |
|
| last_down_count_sys1 | tinyint(6)          | YES  |     | 0          |
|
| last_down_count_sys2 | tinyint(4)          | YES  |     | 0          |
|
| last_down_sys1       | datetime            | YES  |     | NULL       |
|
| last_down_sys2       | datetime            | YES  |     | NULL       |
|
| check_type           | text                |      |     |            |
|
| check_time           | smallint(6)         |      |     | 8          |
|
| check_num            | smallint(5)         |      |     | 3          |
|
| retry_interval       | smallint(11)        |      |     | 1          |
|
| email_notify         | text                | YES  |     | NULL       |
|
| creation_date        | datetime            | YES  |     | NULL       |
|
| last_modified        | timestamp(14)       | YES  |     | NULL       |
|
| status_comment       | text                | YES  |     | NULL       |
|
| comment              | text                | YES  |     | NULL       |
|
+----------------------+---------------------+------+-----+------------+----------------+
34 rows in set (0.00 sec)

network_table where name=vlan name router=router vlan hangs off of
hub=hub that router is associated with sX are starting ip address
eX are ending ip address.
mysql> describe network_table;
+--------+------------------+------+-----+---------+----------------+
| Field  | Type             | Null | Key | Default | Extra          |
+--------+------------------+------+-----+---------+----------------+
| oid    | bigint(20)       |      | PRI | NULL    | auto_increment |
| name   | text             |      |     |         |                |
| router | text             |      |     |         |                |
| hub    | text             |      |     |         |                |
| s1     | int(10) unsigned |      | MUL | 0       |                |
| s2     | int(10) unsigned |      |     | 0       |                |
| s3     | int(10) unsigned |      |     | 0       |                |
| s4     | int(10) unsigned |      |     | 0       |                |
| e1     | int(10) unsigned |      |     | 0       |                |
| e2     | int(10) unsigned |      |     | 0       |                |
| e3     | int(10) unsigned |      |     | 0       |                |
| e4     | int(10) unsigned |      |     | 0       |                |
+--------+------------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)



On Wed, 11 Dec 2002, Russell Scibetti wrote:

> I received a question regarding this, so maybe I should try to be more
> clear.
>
> I am trying to work on a way of storing, generating, and managing all
> our Nagios configs, most likely using a database (MySQL?).  I know I've
> seen some messages on these lists about people already doing this.  What
> I was hoping, is that if anyone has done work like this (create a config
> DB, written cfg generation scripts, etc), that they could share it to
> the list.  It might save me and others a lot of time and grief if there
> has already been some work done in this area.  If enough people have
> these types of components, we might be able to put together a good
> Nagios config management tool even (as a loftier goal to look at).
>
> Thanks.
>
> -Russell Scibetti
>
> Russell Scibetti wrote:
>
> > I know I have read emails about users storing config data in DB's,
> > using scripts for generating/storing configs, etc.  I was hoping that
> > anyone who has created these type of extra components for Nagios could
> > share them.  It would definitely help me out, as I am in charge of
> > Nagios config creations and management.  Thanks.
> >
> > -Russell Scibetti
> >
>
>

--
Brian Wilson  <wilson at ncsu.edu>      Network Analyst
Communication Technologies, ATD      W: 919.513.3472
North Carolina State University      www.ncstate.net
-------------- next part --------------
#!/usr/bin/perl

use Getopt::Long;
use DBI;
use Net::hostent;
use Socket;
use Data::Dumper;

$database = "nagios";
$hostname = "localhost";
$username = "nagios";
$password = "nagios";
$user="nagios";
$conf_dir="/etc/nagios";
$hostg_file="$conf_dir/hostgroups.cfg";
$hosts_file="$conf_dir/hosts.cfg";
$services_file="$conf_dir/services.cfg";
$contacts_file="$conf_dir/contacts.cfg";
$contactg_file="$conf_dir/contactgroups.cfg";
$backup_dir="$conf_dir/backup";

####################### Do Not Edit Below Here ############

$data_source = "DBI:mysql:$database:$hostname:$hostname";
$dbh = DBI->connect($data_source, $username, $password) ||
  die "Can't connect to $data_source: $dbh->errstr\n";
my %Options;
GetOptions(\%Options,"noreload","noupdate");

&backup_files;
&get_objects;
&do_hosts($hosts_file);
&do_hostgroups($hostg_file);
&do_services($services_file);
&reload_nagios;
&chown_files($user);

###################
# reload nagios?
###################
sub reload_nagios {
   if (!$Options{"noreload"}) {
	open(RELOAD, "/etc/init.d/nagios reload 2>&1|");
	while(<RELOAD>) {
	   if (/Error/) {
	      print "Error in regeneration of nagios configs. ";
	      open(NAGVER, "/usr/sbin/nagios -v -c $conf_dir/nagios.cfg 2>&1|");
	      my @output = <NAGVER>;
	      close(NAGVER);
	      print "Please fix the following errors:\n\n";
	      print @output;
	      print "\n\nRestoring old config files from backup.\n";
	      &restore_files;
	      system("/etc/init.d/nagios reload");
	      last;
	   }
	}
	close(RELOAD);
   }
}
	
######################
# restore config files
######################
sub restore_files {
	my @files = ($contacts_file,$contactg_file,
	             $services_file,$hosts_file,$hostg_file);
	foreach my $file (@files) {
		my $filename=$file;
		$filename =~ s/$conf_dir\///;
		system("cp -f $backup_dir/$filename $file");
	}
}
#####################
# backup config files
#####################
sub backup_files {
	my @files = ($contacts_file,$contactg_file,
	             $services_file,$hosts_file,$hostg_file);
	foreach my $file (@files) {
		my $filename=$file;
		$filename =~ s/$conf_dir\///;
		system("cp -f $file $backup_dir/$filename");
	}
}
############################
# change perms on cfg files
############################
sub chown_files {
	my ($user) = @_;
	my @files = ($contacts_file,$contactg_file,
	             $services_file,$hosts_file,$hostg_file);
	($l,$p,$uid,$gid) = getpwnam($user);
	chown $uid, 33, @files;
	chmod 0775, @files;
}

sub do_services {
  my ($file) = @_;
  open(SERVICES, ">$file") or die "Cannot open $file\n";
  print SERVICES "# Generic service definition template\n";
  print SERVICES "define service{\n\tname\tgeneric-service;\n\t";
  print SERVICES "active_checks_enabled\t1;\n\t";
  print SERVICES "passive_checks_enabled\t1;\n\t";
  print SERVICES "parallelize_check\t1;\n\t";
  print SERVICES "obsess_over_service\t1;\n\t";
  print SERVICES "check_freshness\t\t1;\n\t";
  print SERVICES "notifications_enabled\t1;\n\t";
  print SERVICES "event_handler_enabled\t1;\n\t";
  print SERVICES "flap_detection_enabled\t0;\n\t";
  print SERVICES "process_perf_data\t0;\n\t";
  print SERVICES "retain_status_information\t1;\n\t";
  print SERVICES "retain_nonstatus_information\t1;\n\t";
  print SERVICES "register\t0;\n\t}\n\n";
	
  foreach $object (keys %objects) {
  	my $notify="dummy-group";
	my $contact_group="";
  	if ($objects{$object}{"email"} && !$user_created{$objects{$object}{"email"}}) {
		my $email = $objects{$object}{"email"};
		#my ($username) = split(/\@/,$email);
		my @addys = split(/\,/,$email);
		foreach my $addy (@addys) {
			$addy =~ s/\s+//g;
			$username=$addy;
			$username =~ s/[\@.]/_/g;
			$contact_group=$username . "-group" . "," . $contact_group;
			$notify = $contact_group;
			if (&create_contactgroup($username)) {
				&create_contact($username,$addy);
				#$created_contact{$username}++;
				$user_created{$addy}++;
			}
		}
		chop($notify);
	}

	my $svc = $objects{$object}{"type"};
	my @svcs=split(/[,]/,$svc);

	foreach $svc (@svcs) {
		my $svc_desc = $svc;
		$svc =~ s/\s+//g;
		if ($svc =~ /check_(.*)/) {
			$svc_desc = $1;
		}

   	print SERVICES "# Service definition for " . $objects{$object}{"alias"};
   	print SERVICES "\ndefine service{\n\t";
   	print SERVICES "use\t\t\tgeneric-service;\n\t";
   	print SERVICES "host_name\t\t" . $objects{$object}{"alias"};
   	print SERVICES ";\n\tis_volatile\t\t0;\n\t";
   	print SERVICES "check_period\t\t24x7;\n\t";
   	print SERVICES "contact_groups\t\t$notify;\n\t";
   	print SERVICES "notification_period\t24x7;\n\t";
   	print SERVICES "notification_interval\t180;\n\t";
   	print SERVICES "notification_options\tc,r;\n\t";
		print SERVICES "service_description\t$svc_desc;\n\t";
   	print SERVICES "max_check_attempts\t" . $objects{$object}{"check_num"};
   	print SERVICES ";\n\tnormal_check_interval\t".$objects{$object}{"check_time"};
   	print SERVICES ";\n\tretry_check_interval\t".$objects{$object}{"retry_int"};
   	print SERVICES ";\n\tcheck_command\t\t".$svc;
		print SERVICES ";\n\t";
		if (!$contact_group) {
   		print SERVICES "event_handler\t\tdevice-down-event-handler;\n\t";
		}
		print SERVICES "}\n\n";
	}
  }
  close(SERVICES);
}

######################################
# create a contact entry for an email
######################################
sub create_contact {
	my ($username,$email) = @_;
	my $groupname = $username . "-group";
	my $found = 0;
	my @c;
	open(C, "<$contacts_file") or die "Cannot open $contacts_file\n";
	@c=<C>;
	close(C);
	foreach my $line (@c) {
		if ($line =~ /contact_name\s+$username$/) {
			$found++;
		}
		# caused too many headaches
		#if ($line =~ /email\s+$email/) {
		#	$found++;
		#}
	}
	if (!$found) {
		open(C,">>$contacts_file") or die "Cannot open $contacts_file\n";
		print C "\n#contact entry for $username ($email)\n";		
		print C "define contact{\n\tcontact_name\t\t\t$username\n\t";
		print C "alias\t\t\t\t$username\n\t";
		print C "service_notification_period\t24x7\n\t";
		print C "host_notification_period\t24x7\n\t";
		print C "service_notification_options\tw,u,c,r\n\t";
		print C "host_notification_options\td,u,r\n\t";
		print C "service_notification_commands\tnotify-by-email\n\t";
		print C "host_notification_commands\thost-notify-by-email\n\t";
		print C "email\t\t\t\t$email\n\t}\n\n";
		close(C);
		return 1;
	} else {
		return $found;
	}
}

######################################
# create a contact group for an email
######################################
sub create_contactgroup {
	my ($username) = @_;
	my $groupname = $username . "-group";
	my $found = 0;
	my @cg;
	open(CG, "<$contactg_file") or die "Cannot open $contactg_file\n";
	@cg=<CG>;
	close(CG);
	foreach my $line (@cg) {
		if ($line =~ /contactgroup_name\s+$groupname/) {
			$found=1;
			#print "Group ($groupname) already exists\n";
			return 0;
		}
	}
	if (!$found) {
		open(CG, ">>$contactg_file") or die "Cannot open $contactg_file\n";
		print CG "\n# Contact group definition for $groupname (really just for $username)\n";
		print CG "define contactgroup{\n\t";
		print CG "contactgroup_name\t$groupname\n\t";
		print CG "alias\t\t\tGroup for $username\n\t";
		print CG "members\t\t\t$username\n\t}\n";
		close(CG);
		return 1;
	}
}

	
######################
# do hosts.cfg entries
######################
sub do_hosts {
  my ($file) = @_;
  open(HOST, ">$file") or die "Cannot open $file\n";
  print HOST "define host{\n\tname\tgeneric-host\n\t";
  print HOST "notifications_enabled\t1;\n\t";
  print HOST "event_handler_enabled\t1;\n\t";
  print HOST "flap_detection_enabled\t0;\n\t";
  print HOST "process_perf_data\t0;\n\t";
  print HOST "retain_status_information\t1;\n\t";
  print HOST "retain_nonstatus_information\t1;\n\t";
  print HOST "notification_period\t24x7;\n\t";
  print HOST "notification_interval\t180;\n\t";
  print HOST "notification_options\td,r;\n\t";
  print HOST "register\t0;\n\t}\n\n";

  foreach $object (keys %objects) {
   if (!($host_added{$object})) {
   	print HOST "# $object host definition\n";
   	print HOST "define host{\n\t";
   	print HOST "use\t\t\tgeneric-host;\n\t";
   	print HOST "host_name\t\t". $objects{$object}{"alias"};
   	print HOST ";\n\talias\t\t\t$object;\n\t";
   	print HOST "address\t\t\t". $objects{$object}{"ip"};
   	print HOST ";\n\tmax_check_attempts\t1;\n\t";
   	print HOST "check_command\t\tcheck_dummy;\n\t";
   	print HOST "}\n\n";
	
		my $vlan=$objects{$object}{"vlan"};
		$vlans_added{"$vlan"}=$vlans_added{$vlan}.$objects{$object}{"alias"}.",";
		$host_added{$object}++;
		#print "$object -> $vlan\n";
		
	} else {
		#print "Note: $object already exists. creating additional serivce entry\n";
	}
  }
}

#########################
# do all the work.. generate new config files;
#########################
sub do_hostgroups { 
	my ($file) = @_;
	open(HOSTGRP, ">$file") or die "Cannot open $file\n";
	foreach $vlan (keys %vlans_added) {
		my $cur_vlan = $vlans_added{"$vlan"};
		chop($cur_vlan);
		print HOSTGRP "# $vlan hostgroup definition\n";
		print HOSTGRP "define hostgroup {\n";
		print HOSTGRP "\thostgroup_name\t$vlan\n";
		print HOSTGRP "\talias\t\t$vlan\n";
		print HOSTGRP "\tcontact_groups\tdummy-group\n";
		print HOSTGRP "\t" . $cur_vlan . "\n\t}\n\n";
	}
}
	
	
########################
## get host data from db
########################
sub get_objects {
	%vlans_added=();
   $sta=$dbh->prepare("select distinct h.hostname,h.a,h.b,h.c,h.d,h.alias,
             h.check_type,h.check_time,h.check_num,h.retry_interval,
		       h.email_notify, n.name from host_table h, network_table
             n where n.s1=h.a and n.s2=h.b and h.c>=n.s3 and
		       h.c<=n.e3 and h.d>=n.s4 and h.d<=n.e4 and h.to_monitor=1
		       order by h.hostname");
   $sta->execute or print $DBI::errstr;
	while ($row=$sta->fetchrow_arrayref) {
		my $host        = $row->[0];
		my $ip          = "$row->[1].$row->[2].$row->[3].$row->[4]";
		my $alias       = $row->[5];
		my $check_type  = $row->[6];
		my $check_time  = $row->[7];
		my $check_num   = $row->[8];
		my $retry_int	 = $row->[9];
		my $email       = $row->[10];
		my $vlan			 = $row->[11];
		
		$objects{$host}{"alias"}=$alias;
		$objects{$host}{"ip"}=$ip;
		$objects{$host}{"type"}=$check_type;
		$objects{$host}{"email"}=$email;
		$objects{$host}{"vlan"}=$vlan;
		$objects{$host}{"check_time"}=$check_time;
		$objects{$host}{"check_num"}=$check_num;
		$objects{$host}{"retry_int"}=$retry_int;

		if (!$vlans_added{"$vlan"}) {
			$vlans_added{"$vlan"}="members\t";
		}
	}
   $sta=$dbh->prepare("select hostname,a,b,c,d,alias,check_type,check_time,
                       check_num,retry_interval,email_notify from host_table
						     where to_monitor=1");
   $sta->execute or print $DBI::errstr;
	while ($row=$sta->fetchrow_arrayref) {
		# take care of any uncategorized objects that got missed on the initial query
		if (!$objects{$row->[0]}) {
			my $host        = $row->[0];
			my $ip          = "$row->[1].$row->[2].$row->[3].$row->[4]";
			my $alias       = $row->[5];
			my $check_type  = $row->[6];
			my $check_time  = $row->[7];
			my $check_num   = $row->[8];
			my $retry_int	 = $row->[9];
			my $email       = $row->[10];
			my $vlan			 = "Uncategorized";
		
			$objects{$host}{"ip"}=$ip;
			$objects{$host}{"alias"}=$alias;
			$objects{$host}{"type"}=$check_type;
			$objects{$host}{"email"}=$email;
			$objects{$host}{"vlan"}=$vlan;
			$objects{$host}{"check_time"}=$check_time;
			$objects{$host}{"check_num"}=$check_num;
			$objects{$host}{"retry_int"}=$retry_int;

			if (!$vlans_added{"$vlan"}) {
				$vlans_added{"$vlan"}="members\t";
			}
		}
	}
	if ($Options{"noupdate"}) {
		print Dumper %objects;
		exit;
	}
}


More information about the Users mailing list