App-Netsync
view release on metacpan or search on metacpan
lib/App/Netsync.pm view on Meta::CPAN
=back
=cut
sub identify {
warn 'too few arguments' if @_ < 1;
warn 'too many arguments' if @_ > 3;
my ($nodes,$data_source,$auto_match) = @_;
$data_source //= 'DB';
$auto_match //= 0;
unless ($config{'Quiet'}) {
print 'identifying';
print ' (using '.$data_source.')...';
print (($config{'Verbose'}) ? "\n" : (' 'x$config{'DeviceOrder'}).'0');
}
my @data;
{ # Retrieve database.
unless (defined $config{'DeviceField'} and
defined $config{'InterfaceField'} and
defined $config{'InfoFields'}) {
warn 'Database fields have not been configured.';
return undef;
}
# Initialize output table headers.
my $fields = $config{'DeviceField'}.','.$config{'InterfaceField'};
$fields .= ','.join (',',sort @{$config{'InfoFields'}});
my %inputs = (
'DB' => sub {
my %drivers = DBI->installed_drivers;
say $_ foreach values %drivers; exit; #XXX debug
unless (defined $config{'DB'}) {
warn 'A database has not been configured.';
return undef;
}
# Connect to the database.
my $DSN = 'dbi:'.$config{'DBMS'};
$DSN .= ':host='.$config{'Server'};
$DSN .= ';port='.$config{'Port'};
$DSN .= ';database='.$config{'Database'};
my $db = DBI->connect($DSN,$config{'Username'},$config{'Password'},$config{'DB'});
my $query = $db->prepare('SELECT '.$fields.' FROM '.$config{'Table'});
$query->execute;
@data = @{$query->fetchall_arrayref({})};
$db->disconnect;
},
'default' => sub { # Read a CSV file specified with the database option (-d).
open (my $db,'<',$data_source);
my $parser = Text::CSV->new;
chomp (my @fields = split (',',<$db>));
$parser->column_names(@fields);
# Filter out fields that are not needed,
# and verify the presence of necessary fields.
my $removed_field_count = 0;
foreach my $i (keys @fields) {
$i -= $removed_field_count;
unless ($fields =~ /(^|,)$fields[$i](,|$)/) {
++$removed_field_count;
splice (@fields,$i,1);
}
}
die 'incompatible database' unless @fields == scalar split (',',$fields);
foreach my $row (@{$parser->getline_hr_all($db)}) {
my $entry = {};
$entry->{$_} = $row->{$_} foreach @fields;
push (@data,$entry);
}
close $db;
},
);
($inputs{$data_source} || $inputs{'default'})->();
}
my $conflict_count = 0;
{
my %identified; # $identified{$serial} == $node
ROW : foreach my $row (@data) {
my $valid = [
$config{'DeviceField'},
$config{'InterfaceField'},
];
foreach my $field (@$valid) { # Verify necessary fields aren't empty.
next ROW unless defined $row->{$field} and $row->{$field} =~ /\S+/; # Otherwise, skip to the next entry.
}
# Synchronize the entry with gathered info.
$conflict_count += synchronize ($nodes,\%identified,$auto_match,[$row]);
# Show the user how many nodes have been identified if necessary.
unless ($config{'Quiet'} or $config{'Verbose'}) {
print "\b"x$config{'DeviceOrder'};
printf ('%'.$config{'DeviceOrder'}.'d',scalar keys %identified);
}
}
# Show the user what's been found if necessary.
unless ($config{'Quiet'}) {
print scalar keys %identified if $config{'Verbose'};
print ' synchronized';
print ' ('.$conflict_count.' conflicts)' if $conflict_count > 0;
print "\n";
}
}
# Search for network devices and interfaces that were not identified in the database.
foreach my $ip (sort keys %$nodes) {
my $node = $nodes->{$ip};
foreach my $serial (sort keys %{$node->{'devices'}}) {
my $device = $node->{'devices'}{$serial};
unless ($device->{'identified'}) {
( run in 2.057 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )