App-Netdisco

 view release on metacpan or  search on metacpan

lib/App/Netdisco/Worker/Plugin/Macsuck/Nodes.pm  view on Meta::CPAN

package App::Netdisco::Worker::Plugin::Macsuck::Nodes;

use Dancer ':syntax';
use App::Netdisco::Worker::Plugin;
use aliased 'App::Netdisco::Worker::Status';

use App::Netdisco::Transport::SSH ();
use App::Netdisco::Transport::SNMP ();
use App::Netdisco::Util::Permission 'acl_matches';
use App::Netdisco::Util::PortMAC 'get_port_macs';
use App::Netdisco::Util::Device 'match_to_setting';
use App::Netdisco::Util::Node 'check_mac';
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
use App::Netdisco::Util::Web 'sort_port';

use Dancer::Plugin::DBIC 'schema';
use Time::HiRes 'gettimeofday';
use Scope::Guard 'guard';
use Regexp::Common 'net';
use NetAddr::MAC ();
use List::MoreUtils ();

register_worker({ phase => 'early',
  title => 'prepare common data' }, sub {

  my ($job, $workerconf) = @_;
  my $device = $job->device;

  # would be possible just to use LOCALTIMESTAMP on updated records, but by using this
  # same value for them all, we can if we want add a job at the end to
  # select and do something with the updated set (see set archive, below)
  vars->{'timestamp'} = ($job->is_offline and $job->entered)
    ? (schema('netdisco')->storage->dbh->quote($job->entered) .'::timestamp')
    : 'to_timestamp('. (join '.', gettimeofday) .')::timestamp';

  # initialise the cache
  vars->{'fwtable'} = {};

  # cache the device ports to save hitting the database for many single rows
  vars->{'device_ports'} = {map {($_->port => $_)}
                          $device->ports(undef, {prefetch => ['properties',
                                                              {neighbor_alias => 'device'}]})->all};
});

register_worker({ phase => 'main', driver => 'direct',
  title => 'gather macs from file' }, sub {

  my ($job, $workerconf) = @_;
  my $device = $job->device;

  return Status->info('skip: fwtable data supplied by other source')
    unless $job->is_offline;

  # load cache from file or copy from job param
  my $data = $job->extra;
  my @fwtable = (length $data ? @{ from_json($data) } : ());

  return $job->cancel('data provided but 0 fwd entries found')
    unless scalar @fwtable;

  debug sprintf ' [%s] macsuck - %s forwarding table entries provided',
    $device->ip, scalar @fwtable;

  # rebuild fwtable in format for filtering more easily
  foreach my $node (@fwtable) {
      my $mac = NetAddr::MAC->new(mac => ($node->{'mac'} || ''));
      next unless $node->{'port'} and $mac;
      next if (($mac->as_ieee eq '00:00:00:00:00:00') or ($mac->as_ieee !~ m{^$RE{net}{MAC}$}i));

      vars->{'fwtable'}->{ $node->{'vlan'} || 0 }
                       ->{ $node->{'port'} }
                       ->{ $mac->as_ieee } += 1;
  }

  return Status->done("Received MAC addresses for $device");
});

register_worker({ phase => 'main', driver => 'cli',
  title => 'gather macs from CLI'}, sub {

  my ($job, $workerconf) = @_;
  my $device = $job->device;

  my $cli = App::Netdisco::Transport::SSH->session_for($device)
    or return Status->defer("macsuck failed: could not SSH connect to $device");

  # Retrieve data through SSH connection
  my $macs = $cli->macsuck;

  my $nodecount = 0;
  foreach my $vlan (keys %{ $macs }) {



( run in 1.229 second using v1.01-cache-2.11-cpan-39bf76dae61 )