From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#!perl
=head1 NAME
netsync - network/database synchronization utility
=head1 DESCRIPTION
This tool can discover a network and synchronize it with a database.
=head1 SYNOPSIS
-h --help Help. Print usage and options.
-V Version. Print build information.
-v Verbose. Print everything.
-q Quiet. Print nothing.
-c .ini Config. Specify a configuration file.
-p # Probe. There are 2 Probe levels:
1: Probe the network for active nodes.
2: Probe the database for those nodes.
-D DNS. Use your the Domain Name System to retrieve relevant nodes.
-m pattern Match. Only process nodes with hostnames matching the pattern.
-d .csv Database. Specify an RFC4180-compliant database file.
-a Automatch. Enable interface auto-matching.
-u Update. Send interface-specific information to network nodes.
nodes Nodes. Nodes. Specify an RFC1035-compliant list of relevant nodes.
=head1 EXAMPLES
$ netsync -Dm "host[0-9]+" -au
Z<>
$ netsync -Dm "host[0-9]+" -p1
> configuring (using /etc/netsync/netsync.ini)... done
> discovering (using DNS)... 778 nodes (47 skipped), 796 devices (12 stacks)
$ netsync -ap2 /var/cache/netsync/active.txt
> configuring (using /etc/netsync/netsync.ini)... done
> discovering (using /var/cache/netsync/active.txt)... 778 nodes, 796 devices (12 stacks)
> identifying (using DBMS)... 664 synchronized (2389 conflicts)
$ netsync -d /var/cache/netsync/synced.csv -a /var/cache/netsync/active.txt
configuring (using /etc/netsync/netsync.ini)... done
discovering (using /var/cache/netsync/active.txt)... 778 nodes, 796 devices (12 stacks)
identifying (using /var/cache/netsync/synced.csv)... 796 synchronized
=cut
use autodie; #XXX Is autodie adequate?
#use diagnostics;
use strict;
use feature 'say';
use App::Netsync::Scribe ('note');
our ($SCRIPT,$VERSION);
our %config;
BEGIN {
($SCRIPT) = ($0);
($VERSION) = (3.00);
$Getopt::Std::STANDARD_HELP_VERSION = 1;
$| = 1;
$config{'Options'} = 'c:p:Dm:d:au';
$config{'Arguments'} = '[nodes]';
}
sub VERSION_MESSAGE {
say 'Perl v'.$];
say $SCRIPT.' v'.$VERSION;
say 'App::Netsync v'.$App::Netsync::VERSION;
say 'App::Netsync::Configurator v'.$App::Netsync::Configurator::VERSION;
say 'App::Netsync::Network v'.$App::Netsync::Network::VERSION;
say 'App::Netsync::Scribe v'.$App::Netsync::Scribe::VERSION;
say 'App::Netsync::SNMP v'.$App::Netsync::SNMP::VERSION;
say '[Core Modules]';
say ' File::Basename v'.$File::Basename::VERSION;
say ' Getopt::Std v'.$Getopt::Std::VERSION;
say ' Pod::Usage v'.$Pod::Usage::VERSION;
say ' POSIX v'.$POSIX::VERSION;
say ' Scalar::Util v'.$Scalar::Util::VERSION;
say '[CPAN Modules]';
say ' Config::Simple v'.$Config::Simple::VERSION;
say ' DBI v'.$DBI::VERSION;
say ' Net::DNS v'.$Net::DNS::VERSION;
say ' SNMP v'.$SNMP::VERSION;
say ' SNMP::Info v'.$SNMP::Info::VERSION;
say ' Text::CSV v'.$Text::CSV::VERSION;
}
sub HELP_MESSAGE {
my $opts = $config{'Options'};
$opts =~ s/://g;
pod2usage({
'-message' => $SCRIPT.' [-'.$opts.'] '.$config{'Arguments'},
'-exitval' => 0,
'-verbose' => 0,
});
}
INIT {
my %opts;
$config{'Options'} = 'hVvq'.$config{'Options'};
HELP_MESSAGE and exit 1 unless getopts ($config{'Options'},\%opts);
HELP_MESSAGE and exit if $opts{'h'};
VERSION_MESSAGE and exit if $opts{'V'};
$config{'Verbose'} = (defined $opts{'q'}) ? 0 : $opts{'v'} // 0;
$config{'Quiet'} = $opts{'q'} // 0;
{ # Read the configuration file.
$config{'File'} = $opts{'c'} // '/etc/'.$SCRIPT.'/'.$SCRIPT.'.ini';
print 'configuring (using '.$config{'File'}.')...' unless $config{'Quiet'};
my %conf = App::Netsync::Configurator::configurate ($config{'File'});
$config{$_} = $conf{$_} foreach keys %conf;
say ' done' unless $config{'Quiet'};
}
$config{'ProbeLevel'} = $opts{'p'} // 0;
unless ($config{'ProbeLevel'} =~ /^[0-2]$/) {
warn 'Invalid ProbeLevel';
HELP_MESSAGE and exit 1;
}
$config{'Probe1Cache'} //= '/var/cache/'.$SCRIPT.'/active.txt';
$config{'Probe2Cache'} //= '/var/cache/'.$SCRIPT.'/synced.csv';
chomp ($config{'NodeFile'} = (defined $opts{'D'}) ? 'DNS' : <>);
$config{'Match'} = $opts{'m'} // '[^.]+';
$config{'DataFile'} = $opts{'d'} // 'DB';
$config{'Automatch'} = $opts{'a'} // 0;
$config{'Update'} = $opts{'u'} // 0;
App::Netsync::configure({
%{App::Netsync::Configurator::config('Netsync')},
'Quiet' => $config{'Quiet'},
'Verbose' => $config{'Verbose'},
},
App::Netsync::Configurator::config('DNS'),
App::Netsync::Configurator::config('SNMP'),
App::Netsync::Configurator::config('DB'),
);
}
{
my $nodes = App::Netsync::discover($config{'NodeFile'},$config{'Match'});
if ($config{'ProbeLevel'} == 1) {
foreach my $ip (sort keys %$nodes) {
note ($config{'Probe1Cache'},$nodes->{$ip}{'RFC1035'},0,'>');
}
exit;
}
App::Netsync::identify($nodes,$config{'DataFile'},$config{'Automatch'});
if ($config{'ProbeLevel'} == 2) {
my $Netsync = App::Netsync::Configurator::config('Netsync');
my $fields = $Netsync->{'DeviceField'}.','.$Netsync->{'InterfaceField'};
$fields .= ','.join (',',sort @{$Netsync->{'InfoFields'}});
note ($config{'Probe2Cache'},$fields,0,'>');
foreach my $ip (sort keys %$nodes) {
my $node = $nodes->{$ip};
foreach my $serial (sort keys %{$node->{'devices'}}) {
my $device = $node->{'devices'}{$serial};
foreach my $ifName (sort keys %{$device->{'interfaces'}}) {
my $interface = $device->{'interfaces'}{$ifName};
my $note = $serial.','.$ifName;
foreach my $field (sort @{$Netsync->{'InfoFields'}}) {
$note .= ','.($interface->{'info'}{$field} // '');
}
note ($config{'Probe2Cache'},$note,0);
}
}
}
exit;
}
App::Netsync::update $nodes if $config{'Update'};
exit;
}
=head1 AUTHOR
David Tucker, C<< <dmtucker at ucsc.edu> >>
=head1 BUGS
Please report any bugs or feature requests to C<bug-netsync at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Netsync>. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
=head1 SUPPORT
You can find documentation for this module with the perldoc command.
perldoc App::Netsync
You can also look for information at:
=over 4
=item * RT: CPAN's request tracker (report bugs here)
=item * AnnoCPAN: Annotated CPAN documentation
=item * CPAN Ratings
=item * Search CPAN
=back
=head1 LICENSE
Copyright 2013 David Tucker.
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.
See L<http://dev.perl.org/licenses/> for more information.
=cut
1;