#!/usr/bin/perl

# Generate a text file with a simple list of Devices
# with their types, ip addresses and parents (uplink devices),
# grouped by the building their located in and their subnet
#
# 
use lib "/usr/local/www/netdot/lib";
use Netdot::Export;
use Netdot::Model;
use strict;
use Getopt::Long;

use vars qw( %self $USAGE %types %hosts %entities %ip2name %name2ip );

my $dns    = Netdot::Util::DNS->new();
my $export = Netdot::Export->new();

&set_defaults();

my $USAGE = <<EOF;
usage: $0 --dir <DIR> --out <FILE>
    --monitor         <hostname> Monitoring system name
    --dir             <path> Path to configuration file
    --out             <name> Configuration file name (default: $self{out})
    --strip_domain    <domain_name> Strip off domain name from device name
    --debug           Print debugging output
    --help            Display this message

EOF

&setup();
&gather_data();
&build_configs();


##################################################
sub set_defaults {
    %self = ( 
	      dir             => '',
	      out             => 'master.cnf',
	      help            => 0,
	      debug           => 0, 
	      );

}

##################################################
sub setup{
    
    my $result = GetOptions( "monitor=s"        => \$self{monitor},
			     "dir=s"            => \$self{dir},
			     "out=s"            => \$self{out},
			     "strip_domain=s"   => \$self{strip_domain},
			     "debug"            => \$self{debug},
			     "h"                => \$self{help},
			     "help"             => \$self{help},
			     );
    
    if( ! $result || $self{help} ) {
	print $USAGE;
	exit 0;
    }

    unless ( $self{dir} && $self{out} ) {
	print "ERROR: Missing required arguments\n";
	die $USAGE;
    }
}

##################################################
sub gather_data{

    my $monitor = Device->search(name=>$self{monitor})->first 
	|| die "Cannot find monitor device"; 

    my $device_ips = $export->get_device_ips();
    foreach my $row ( @$device_ips ){
	my ($deviceid, $ipid, $int_monitored, $dev_monitored) = @$row;
	my $ip = Ipblock->retrieve($ipid);
	my $address = $ip->address;
	my ($type, $site, $entity);
	if ( my $device = Netdot::Model::Device->retrieve($deviceid) ){
	    if ( $device->product && $device->product->type ){
		$type = $device->product->type->name;
		$type =~ s/\s+/_/g;
	    }else{
		$type = 'Unknown';
		warn "Can't figure out type for Device with ip $address" if $self{debug};
	    }
	    if ( $device->site ){
		$site = $device->site->name;
		$site = join '_', split /\s+/, $site;
	    }else{
		$site = 'unknown';
		warn "Can't determine site for Device with ip $address" if $self{debug};
	    }
	    if ( my $e = $device->used_by ){
		$entity = $e->name;
		$entity = join '_', split /\s+/, $entity;
		$entities{$entity}{id} = $e->id;
	    }else{
		$entity = 'unknown';
		$entities{$entity}{id} = 0;
		warn "Can't determine entity for Device with ip $address" if $self{debug};
	    }
	}else{
	    warn "Can't determine Device from ip ", $address if $self{debug};
	    next;
	}
	
	my $name;
	if ( my @arecords = $ip->arecords ){
	    $name = $arecords[0]->rr->get_label;
	}else{ 
	    $name = $dns->resolve_ip($address) || $address;
	}
	$name =~ s/$self{strip_domain}// if $self{strip_domain};

	$name2ip{$name} = $ip->id;
	$ip2name{$ipid} = $name;
	$hosts{$address}{type} = $type;
	$hosts{$address}{name} = $name;
	push @{ $entities{$entity}{site}{$site}{hosts} }, $address;
    }

    my $dependencies = $export->get_dependencies($monitor->id);
    foreach my $ipid ( keys %ip2name ){
	next unless defined $dependencies->{$ipid};
	my $ipobj = Ipblock->retrieve($ipid);
	my @parentlist = @{$dependencies->{$ipid}};
	if ( scalar @parentlist ){
	    my @names;
	    foreach my $parent ( @parentlist ){
		if ( !exists $ip2name{$parent} ){
		    warn "Can't determine name for Ipblock id $parent\n";
		}
		push @names, $ip2name{$parent};
	    }
	    if ( scalar @names ){
		$hosts{$ipobj->address}{parents} = join ',', @names;
	    }else{
		$hosts{$ipobj->address}{parents} = 'NULL';
	    }
	}else{
	    $hosts{$ipobj->address}{parents} = 'NULL';
	}
    }

}

##################################################
sub build_configs {

    my $filename = "$self{dir}/$self{out}";
    open (FILE, ">$filename") or die "Couldn't open $filename for writing: $!\n";
    select (FILE);

    print "#            ****        THIS FILE WAS GENERATED FROM A DATABASE         ****\n";
    print "#            ****           ANY CHANGES YOU MAKE WILL BE LOST            ****\n";
    print "#  Generated by $0 on ", scalar(localtime), "\n\n\n";

    foreach my $entity ( sort keys %entities ){
	
	print "############################################################################################################################\n";
	print "network               $entity                      NULL\n";
	print "############################################################################################################################\n";
	
	print "\n";
	
	if ( my $entobj = Entity->retrieve($entities{$entity}{id}) ){
	    foreach my $subnet ($entobj->used_blocks){
		print "prefix                 ", $subnet->address, "/", $subnet->prefix, "\n";
	    }
	}
	
	print "\n";
	
	foreach my $site ( sort keys %{$entities{$entity}{site}} ){
	    my $oldhandle = select FILE;
	    $~ = "HOSTLIST";
	    select ($oldhandle);
	    
	    print "building               $site\n";
	    foreach my $ipadd (sort @{$entities{$entity}{site}{$site}{hosts}} ){
		
		# Define a format for the host list
		
		format HOSTLIST = 
@<<<<<<<<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$hosts{$ipadd}{type}, $hosts{$ipadd}{name}, $ipadd, $hosts{$ipadd}{parents}
.
    write ;
}

           $oldhandle = select FILE;
           $~ = "FILE";
           select ($oldhandle);
           print "\n";
       }
    }
}
