implementation of refresh, discover, and store_device

This commit is contained in:
Oliver Gorwits
2013-04-04 14:47:28 +01:00
parent 4c2e3cf82d
commit a8f0894986
6 changed files with 178 additions and 3 deletions

View File

@@ -33,7 +33,7 @@ sub capacity_for {
debug "checking local capacity for action $action"; debug "checking local capacity for action $action";
my $action_map = { my $action_map = {
Poller => [qw//], Poller => [qw/refresh discover/],
Interactive => [qw/location contact portcontrol portname vlan power/], Interactive => [qw/location contact portcontrol portname vlan power/],
}; };

View File

@@ -14,7 +14,7 @@ my $fqdn = hostfqdn || 'localhost';
my $role_map = { my $role_map = {
(map {$_ => 'Poller'} (map {$_ => 'Poller'}
qw//), qw/refresh discover/),
(map {$_ => 'Interactive'} (map {$_ => 'Interactive'}
qw/location contact portcontrol portname vlan power/) qw/location contact portcontrol portname vlan power/)
}; };

View File

@@ -26,6 +26,7 @@ sub worker_body {
my $job = schema('daemon')->resultset('Admin') my $job = schema('daemon')->resultset('Admin')
->new_result($candidate); ->new_result($candidate);
my $jid = $job->job; my $jid = $job->job;
my $target = $job->action;
next unless $self->can($target); next unless $self->can($target);
debug "poll ($wid): can ${target}() for job $jid"; debug "poll ($wid): can ${target}() for job $jid";

View File

@@ -3,9 +3,13 @@ package App::Netdisco::Daemon::Worker::Poller::Discover;
use Dancer qw/:moose :syntax :script/; use Dancer qw/:moose :syntax :script/;
use Dancer::Plugin::DBIC 'schema'; use Dancer::Plugin::DBIC 'schema';
use App::Netdisco::Util::SNMP ':all'; use App::Netdisco::Util::SNMP 'snmp_connect';
use App::Netdisco::Util::Device 'get_device';
use App::Netdisco::Util::DiscoverAndStore ':all';
use App::Netdisco::Daemon::Worker::Interactive::Util ':all'; use App::Netdisco::Daemon::Worker::Interactive::Util ':all';
use NetAddr::IP::Lite ':lower';
use Role::Tiny; use Role::Tiny;
use namespace::clean; use namespace::clean;
@@ -29,6 +33,21 @@ sub refresh {
sub discover { sub discover {
my ($self, $job) = @_; my ($self, $job) = @_;
my $host = NetAddr::IP::Lite->new($job->device);
my $device = get_device($host->addr);
my $snmp = snmp_connect($device);
if (!defined $snmp) {
return error("Discover failed: could not SNMP connect to $host");
}
store_device($device, $snmp);
#store_interfaces($ip, $snmp);
#store_vlans($ip, $snmp);
#store_power($ip, $snmp);
#store_modules($ip, $snmp);
return done("Ended Discover for $host");
} }
1; 1;

View File

@@ -0,0 +1,53 @@
package App::Netdisco::Util::DNS;
use strict;
use warnings FATAL => 'all';
use Net::DNS;
use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/
hostname_from_ip
/;
our %EXPORT_TAGS = (all => \@EXPORT_OK);
=head1 NAME
App::Netdisco::Util::DNS
=head1 DESCRIPTION
A set of helper subroutines to support parts of the Netdisco application.
There are no default exports, however the C<:all> tag will export all
subroutines.
=head1 EXPORT_OK
=head2 hostname_from_ip( $ip )
Given an IP address (either IPv4 or IPv6), return the canonical hostname.
Returns C<undef> if no PTR record exists for the IP.
=cut
sub hostname_from_ip {
my $ip = shift;
my $res = Net::DNS::Resolver->new;
my $query = $res->search($ip);
if ($query) {
foreach my $rr ($query->answer) {
next unless $rr->type eq "PTR";
return $rr->ptrdname;
}
}
return undef;
}
1;

View File

@@ -0,0 +1,102 @@
package App::Netdisco::Util::DiscoverAndStore;
use Dancer qw/:syntax :script/;
use App::Netdisco::Util::DNS 'hostname_from_ip';
use NetAddr::IP::Lite ':lower';
use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/
store_device
/;
our %EXPORT_TAGS = (all => \@EXPORT_OK);
=head1 NAME
App::Netdisco::Util::DiscoverAndStore
=head1 DESCRIPTION
A set of helper subroutines to support parts of the Netdisco application.
There are no default exports, however the C<:all> tag will export all
subroutines.
=head1 EXPORT_OK
=head2 store_device( $device, $snmp )
Given a Device database object, and a working SNMP connection, discover and
store basic device information.
The Device database object can be a fresh L<DBIx::Class::Row> object which is
not yet stored to the database.
=cut
sub store_device {
my ($device, $snmp) = @_;
my $ip_index = $snmp->ip_index;
my $interfaces = $snmp->interfaces;
my $ip_netmask = $snmp->ip_netmask;
# build device interfaces suitable for DBIC
my @interfaces;
foreach my $entry (keys %$ip_index) {
my $ip = NetAddr::IP::Lite->new($entry);
my $addr = $ip->addr;
next if $addr eq '0.0.0.0';
next if $ip->within(NetAddr::IP::Lite->new('127.0.0.0/8'));
next if setting('ignore_private_nets') and $ip->is_rfc1918;
my $iid = $ip_index->{$addr};
my $port = $interfaces->{$iid};
my $subnet = $ip_netmask->{$addr}
? NetAddr::IP::Lite->new($addr, $ip_netmask->{$addr})->network->cidr
: undef;
push @interfaces, {
alias => $addr,
port => $port,
subnet => $subnet,
dns => hostname_from_ip($addr),
};
}
# VTP Management Domain -- assume only one.
my $vtpdomains = $snmp->vtp_d_name;
my $vtpdomain;
if (defined $vtpdomains and scalar values %$vtpdomains) {
$device->vtp_domain( (values %$vtpdomains)[-1] );
}
my $hostname = hostname_from_ip($device->ip);
$device->dns($hostname) if length $hostname;
my @properties = qw/
snmp_ver snmp_comm
description uptime contact name location
layers ports mac serial model
ps1_type ps2_type ps1_status ps2_status
fan slots
vendor os os_ver
/;
foreach my $property (@properties) {
$device->$property( $snmp->$property );
}
$device->snmp_class( $snmp->class );
$device->last_discover(scalar localtime);
schema('netdisco')->txn_do(sub {
$device->device_ips->delete;
$device->update_or_insert;
$device->device_ips->populate(\@interfaces);
});
}
1;