diff --git a/Netdisco/Changes b/Netdisco/Changes index 56f48163..ffe1a76e 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -3,6 +3,7 @@ [NEW FEATURES] * macsuck_unsupported setting to allow node gathering on delinquent switches + * netdisco-do -d accepts IP prefixes (subnet in CIDR format) [ENHANCEMENTS] diff --git a/Netdisco/bin/netdisco-do b/Netdisco/bin/netdisco-do index a29e2b37..7d8aff15 100755 --- a/Netdisco/bin/netdisco-do +++ b/Netdisco/bin/netdisco-do @@ -40,8 +40,12 @@ use Dancer qw/:moose :script/; info "App::Netdisco version $App::Netdisco::VERSION loaded."; +use NetAddr::IP ':rfc3021'; +use App::Netdisco::Util::Device 'get_device'; + use Try::Tiny; use Pod::Usage; +use Scalar::Util 'blessed'; use Getopt::Long; Getopt::Long::Configure ("bundling"); @@ -121,12 +125,9 @@ unless ($action) { } sub show { - my $ip = NetAddr::IP::Lite->new($device) - or return ('error', "Bad host or IP: $device"); - my $dev = get_device($ip->addr); - unless (blessed $dev and $dev->in_storage) { - return ('error', "Don't know device: $device"); - } + my ($self, $job) = @_; + my ($device, $port, $extra) = map {$job->$_} qw/device port extra/; + return ('error', 'Missing device (-d).') if !defined $device; $extra ||= 'interfaces'; my $class = undef; ($class, $extra) = split(/::([^:]+)$/, $extra); @@ -137,59 +138,56 @@ unless ($action) { $extra = $class; undef $class; } - my $i = App::Netdisco::Util::SNMP::snmp_connect($dev, $class); + my $i = App::Netdisco::Util::SNMP::snmp_connect($device, $class); Data::Printer::p($i->$extra); - return ('done', "Showed $extra response from $device."); + return ('done', sprintf "Showed %s response from %s.", $extra, $device->ip); } sub delete { - my $ip = NetAddr::IP::Lite->new($device) - or return ('error', "Bad host or IP: $device"); - my $dev = get_device($ip->addr); - unless (blessed $dev and $dev->in_storage) { - return ('error', "Don't know device: $device"); - } + my ($self, $job) = @_; + my ($device, $port, $extra) = map {$job->$_} qw/device port extra/; + return ('error', 'Missing device (-d).') if !defined $device; $port = ($port ? 1 : 0); - delete_device($dev->ip, $port, $extra); - return ('done', "Deleted device $device."); + delete_device($device, $port, $extra); + return ('done', sprintf "Deleted device %s.", $device->ip); } sub renumber { - my $ip = NetAddr::IP::Lite->new($device) - or return ('error', "Bad host or IP: $device"); - my $dev = get_device($ip->addr); - unless (blessed $dev and $dev->in_storage) { - return ('error', "Don't know device: $device"); - } - my $old_ip = $dev->ip; + my ($self, $job) = @_; + my ($device, $port, $extra) = map {$job->$_} qw/device port extra/; + return ('error', 'Missing device (-d).') if !defined $device; + my $old_ip = $device->ip; my $new_ip = NetAddr::IP::Lite->new($extra) or return ('error', "Bad host or IP: $extra"); my $new_dev = get_device($new_ip->addr); unless ($new_dev and not $new_dev->in_storage) { - return ('error', "Already know new device: $device"); + return ('error', sprintf "Already know new device: %s.", $device->ip); } - renumber_device($dev->ip, $new_dev->ip); + renumber_device($device, $new_dev->ip); return ('done', sprintf 'Renumbered device %s from %s to %s.', - $device, $old_ip, $new_dev->ip); + $device->ip, $old_ip, $new_dev->ip); } sub psql { + my ($self, $job) = @_; + my ($device, $port, $extra) = map {$job->$_} qw/device port extra/; + my $name = (setting('database')->{name} || 'netdisco'); my $host = setting('database')->{host}; my $user = setting('database')->{user}; my $pass = setting('database')->{pass}; - my $port = undef; + my $portnum = undef; if ($host =~ m/([^;]+);port=(\d+)/) { $host = $1; - $port = $2; + $portnum = $2; } $ENV{PGHOST} = $host if $host; - $ENV{PGPORT} = $port if defined $port; + $ENV{PGPORT} = $portnum if defined $portnum; $ENV{PGDATABASE} = $name; $ENV{PGUSER} = $user; $ENV{PGPASSWORD} = $pass; @@ -215,30 +213,48 @@ if (not $worker->can( $action )) { ); } -# what job are we asked to do? -my $job = App::Netdisco::Daemon::Job->new({ - job => 0, - action => $action, - device => $device, - port => $port, - subaction => $extra, -}); - -# do job -my ($status, $log); -try { - info sprintf '%s: started at %s', $action, scalar localtime; - ($status, $log) = $worker->$action($job); +my $net = NetAddr::IP->new($device); +if ($device and (!$net or $net->num == 0)) { + info sprintf '%s: error - Bad host, IP or prefix: %s', $action, $device; + exit 1; } -catch { - $status = 'error'; - $log = "error running job: $_"; -}; -info sprintf '%s: finished at %s', $action, scalar localtime; -info sprintf '%s: status %s: %s', $action, $status, $log; +my @hostlist = defined $device ? ($net->hostenum) : (undef); +my $exitstatus = 0; -exit ($status eq 'done' ? 0 : 1); +foreach my $host (@hostlist) { + my $dev = $host ? get_device($host->addr) : undef; + if ($dev and not (blessed $dev and $dev->in_storage) and $action ne 'discover') { + info sprintf "%s: error - Don't know device: %s", $action, $host->addr; + next; + } + + # what job are we asked to do? + my $job = App::Netdisco::Daemon::Job->new({ + job => 0, + action => $action, + device => $dev, + port => $port, + subaction => $extra, + }); + + # do job + my ($status, $log); + try { + info sprintf '%s: started at %s', $action, scalar localtime; + ($status, $log) = $worker->$action($job); + } + catch { + $status = 'error'; + $log = "error running job: $_"; + }; + + info sprintf '%s: finished at %s', $action, scalar localtime; + info sprintf '%s: status %s: %s', $action, $status, $log; + $exitstatus = 1 if !defined $status or $status eq 'error'; +} + +exit $exitstatus; =head1 NAME @@ -252,6 +268,10 @@ netdisco-do - Run any Netdisco job from the command-line. This program allows you to run any Netdisco poller job from the command-line. +The C<-d> option will accept a hostname (that can be resolved to an IP with +DNS), an IP address, or IP prefix (subnets in CIDR format). It can be any +interface on the device known to Netdisco. + Note that some jobs (C, C, C, C) simply add entries to the Netdisco job queue for other jobs, so won't seem to do much when you trigger them. diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Common.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Common.pm index 70ce0630..bc41c13f 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Common.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Common.pm @@ -46,8 +46,9 @@ sub _single_body { my $layer_method = $job_type .'_layer'; my $job_layer = $self->$layer_method; - my $host = NetAddr::IP::Lite->new($job->device); - my $device = get_device($host->addr); + my $device = get_device($job->device) + or job_error("$job_type failed: unable to interpret device parameter"); + my $host = $device->ip; if ($device->in_storage and $device->vendor and $device->vendor eq 'netdisco') { @@ -72,7 +73,7 @@ sub _single_body { $job_action->($device, $snmp); - return job_done("Ended $job_type for ". $host->addr); + return job_done("Ended $job_type for $host"); } sub _single_node_body { diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Device.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Device.pm index d3950b22..2df3d38c 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Device.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Device.pm @@ -39,8 +39,9 @@ sub discoverall { sub discover { my ($self, $job) = @_; - my $host = NetAddr::IP::Lite->new($job->device); - my $device = get_device($host->addr); + my $device = get_device($job->device) + or job_error("discover failed: unable to interpret device parameter"); + my $host = $device->ip; if ($device->ip eq '0.0.0.0') { return job_error("discover failed: no device param (need -d ?)"); @@ -90,7 +91,7 @@ sub discover { } } - return job_done("Ended discover for ". $host->addr); + return job_done("Ended discover for $host"); } 1; diff --git a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Nbtstat.pm b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Nbtstat.pm index 97c6e882..52acc991 100644 --- a/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Nbtstat.pm +++ b/Netdisco/lib/App/Netdisco/Daemon/Worker/Poller/Nbtstat.pm @@ -25,8 +25,9 @@ sub nbtwalk { (shift)->_walk_body('nbtstat', @_) } sub nbtstat { my ($self, $job) = @_; - my $host = NetAddr::IP::Lite->new($job->device); - my $device = get_device($host->addr); + my $device = get_device($job->device) + or job_error("nbtstat failed: unable to interpret device parameter"); + my $host = $device->ip; unless (is_discoverable($device->ip)) { return job_defer("nbtstat deferred: $host is not discoverable"); @@ -66,7 +67,7 @@ sub nbtstat { } } - return job_done("Ended nbtstat for ". $host->addr); + return job_done("Ended nbtstat for $host"); } 1;