App-Netdisco

 view release on metacpan or  search on metacpan

xt/208-vrf-default-leak-exclusion.t  view on Meta::CPAN

#!/usr/bin/env perl

use strict; use warnings;

BEGIN { $ENV{DANCER_ENVDIR} = '/dev/null'; }

use Test::More 0.88;
use Test::File::ShareDir::Dist { 'App-Netdisco' => 'share/' };

use App::Netdisco;
use App::Netdisco::DB;
use App::Netdisco::Util::VRF 'each_vrf_instance';
use Dancer qw/:script !pass/;

# On Juniper the default instance's SNMP read also returns every virtual
# router's rows, so with store_vrfs on it was never whole and the default
# table never updated or retired. SNMP::Info 3.985001 names the instances
# mixed in (vrf_read_leaked) and drops their ports from the default readers
# once told them (vrf_exclude_ports), so each_vrf_instance reads the default
# instance a second time with those ports excluded.

config->{'enable_incomplete_walk_protection'} = 1;

package FakeSession;
sub new { my ($class, $snmp) = @_; return bless { snmp => $snmp }, $class }
sub get {
  my ($self) = @_;
  my $snmp = $self->{snmp};
  if (($snmp->{answers}{ $snmp->{context} } || '') eq 'timeout') {
    @$self{qw/ErrorStr ErrorNum/} = ('Timeout', -24);
    return undef;
  }
  @$self{qw/ErrorStr ErrorNum/} = ('', 0);
  return 12345;
}

# Context switching, walk records and error() as in xt/205. Has neither
# vrf_read_leaked nor vrf_exclude_ports, as SNMP::Info before 3.985001.
package FakeSNMP;
sub new {
  my ($class, %vals) = @_;
  my $self = bless { context => '', walk_failures => [], updates => 0, excluded => {},
                     exclusions => [], complete => {}, %vals }, $class;
  $self->{session} = FakeSession->new($self);
  return $self;
}
sub snmp_ver { 2 }
sub snmp_comm { 'public' }
sub class { 'SNMP::Info::Layer3::Fake' }
sub session { $_[0]{session} }
sub walk_failures { $_[0]{walk_failures} }
sub error { my $self = shift; my $error = $self->{error}; $self->{error} = undef; return $error }
sub update {
  my ($self, %args) = @_;
  my $target = ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
  # SNMP::Info::update() keeps the old session and returns false on failure
  return if $self->{fail_update_to}{$target};
  $self->{context} = $target;
  $self->{updates}++;
  # update() calls clear_cache(), which forgets recorded exclusions
  $self->{excluded} = {};
  return $self->{session};
}
sub vrf_read_complete {
  my ($self, $name) = @_;
  return ($self->{complete}{$name} // 1) unless $name eq 'default';
  return 1 unless $self->{leaks};
  return (grep { not $self->{excluded}{$_} } @{ $self->{leaks} }) ? 0 : 1;
}
sub i_vrf {
  my $self = shift;
  my $context = $self->{context};
  push @{ $self->{walk_failures} }, { method => 'i_vrf', complete => 0, reason => 'timeout' }
    if $self->{short_i_vrf}{$context};
  return $self->{i_vrf}{$context} || {};
}

package FakeLeakSNMP;
our @ISA = ('FakeSNMP');
sub vrf_read_leaked {
  my ($self, $name) = @_;
  return undef unless $name eq 'default' and $self->{leaks} and $self->{context} eq '';
  return [ sort grep { not $self->{excluded}{$_} } @{ $self->{leaks} } ];
}
sub vrf_exclude_ports {
  my ($self, $name, $ports) = @_;
  push @{ $self->{exclusions} },
    { name => $name, ports => [@$ports], context => $self->{context}, updates => $self->{updates} };
  if ($self->{refuse_exclusion}) { $self->{error} = 'refused'; return undef }
  $self->{excluded}{$name} = 1;
  return 1;
}

package main;

my $device = App::Netdisco::DB->resultset('Device')->new_result({ ip => '192.0.2.1' });

sub switched { my $name = shift;
  return { name => $name, contexts => [{ kind => 'vrf', id => $name, v2c => "%s\@$name", v3 => $name }] } }
my %instances = (
  default => { name => 'default', contexts => [{ kind => 'none' }] },
  blue    => switched('blue'),
  red     => switched('red'),
);

sub run_each {
  my ($snmp, $instances) = @_;
  my @read;
  my $reads = each_vrf_instance($device, $snmp, ($instances || \%instances),
    sub { my ($name) = @_; push @read, [$name, $snmp->{context}]; return "data of $name" });
  return ($reads, \@read);
}



( run in 0.631 second using v1.01-cache-2.11-cpan-145b269f2f3 )