view release on metacpan or search on metacpan
lib/App/Netdisco/Util/PortAccessEntity.pm view on Meta::CPAN
App::Netdisco::Util::PortAccessEntity
=head1 DESCRIPTION
Helper subroutines to update PAE details in device_port_properties
These are updated both during discover and macsuck.
=cut
sub update_pae_attributes {
my ($device) = @_;
no warnings "uninitialized";
my $snmp = App::Netdisco::Transport::SNMP->reader_for($device)
or return Status->defer("pae failed: could not SNMP connect to $device");
debug sprintf ' [%s] pae - updating PortAccessEntity details', $device->ip;
# device property
my $pae_control = $snmp->pae_control();
lib/App/Netdisco/Util/Statistics.pm view on Meta::CPAN
=head1 EXPORT_OK
=head2 update_stats()
Update the Netdisco statistics, either new for today or updating today's
figures.
=cut
sub update_stats {
my $schema = schema(vars->{'tenant'});
eval { require SNMP::Info };
my $snmpinfo_ver = ($@ ? 'n/a' : $SNMP::Info::VERSION);
my $postgres_ver = postgres_version($schema->storage->dbh->{pg_server_version});
# roll everything back if we're testing
my $txn_guard = $ENV{ND2_DB_ROLLBACK}
? $schema->storage->txn_scope_guard : undef;
# TODO: (when we have the capabilities table?)
xt/120-hint-over-stored-tag.t view on Meta::CPAN
use Test::More 0.88;
use App::Netdisco;
use App::Netdisco::Util::SNMP 'get_communities';
use Dancer qw/:script !pass/;
package FakeCommunity;
sub new { my ($class, %v) = @_; return bless {%v}, $class }
sub snmp_auth_tag_read { return $_[0]->{snmp_auth_tag_read} }
sub snmp_comm_rw { return $_[0]->{snmp_comm_rw} }
sub update { my ($self, $v) = @_; @$self{keys %$v} = values %$v; return $self }
package FakeDevice;
sub new { my ($class, %v) = @_; return bless {%v}, $class }
sub ip { return '192.0.2.1' }
sub dns { return 'switch1.example.com' }
sub in_storage { return 1 }
sub snmp_comm { return $_[0]->{snmp_comm} }
sub community { return $_[0]->{community} }
package main;
xt/136-vrf-context-discovery.t view on Meta::CPAN
package FakeSNMP;
sub new { my ($class, %vals) = @_; return bless {context => '', %vals}, $class }
sub snmp_ver { $_[0]{snmp_ver} || 2 }
sub snmp_comm { 'labro' }
sub vtp_version { undef }
sub class { 'SNMP::Info::Layer3::Nexus' }
sub cache { }
sub cisco_comm_indexing { 1 }
sub vrf_name { { '3.114.101.100' => 'red', '4.98.108.117.101' => 'blue' } }
sub update {
my ($self, %args) = @_;
$self->{context} = exists $args{Context} ? $args{Context}
: ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
push @{ $self->{contexts_asked} }, $self->{context};
}
sub _answer { my ($self, $table) = @_; return $self->{answers}{ $self->{context} }{$table} }
sub ip_index { $_[0]->_answer('ip_index') }
sub ip_table { $_[0]->_answer('ip_table') }
sub ip_netmask { $_[0]->_answer('ip_netmask') }
sub interfaces { $_[0]->_answer('interfaces') }
xt/145-topology-del-only-matched.t view on Meta::CPAN
sub new { return bless {}, $_[0] }
sub txn_do { return $_[1]->() }
sub resultset { return $_[0] }
sub search { return $_[0] }
sub delete { return $deleted }
package FakePorts;
sub new { return bless { ip => $_[1] }, $_[0] }
sub search { my ($s, $q) = @_; return bless { %$s, port => $q->{port} }, ref $s }
sub single { return $_[0] }
sub update { my ($s, $v) = @_; push @updated, [ $s->{ip}, $s->{port}, $v ]; return $s }
package FakeDevice;
sub new { return bless { ip => $_[1] }, $_[0] }
sub in_storage { 1 }
sub ports { return FakePorts->new($_[0]->{ip}) }
package main;
no warnings 'redefine';
*Dancer::Plugin::Auth::Extensible::logged_in_user = sub { return { username => 'someone' } };
xt/159-macsuck-redundant-writes.t view on Meta::CPAN
set logger => 'null';
my $NODES = 'App::Netdisco::Worker::Plugin::Macsuck::Nodes';
my (@searched, @port_updates, $port_macs);
package FakeNodes;
sub new { return bless {}, $_[0] }
sub resultset { return $_[0] }
sub search { push @searched, $_[1]; return $_[0] }
sub update { return 3 }
package FakePort;
sub new { my ($class, %col) = @_; return bless {%col}, $class }
sub port { $_[0]{port} }
sub update {
my ($self, $set) = @_;
push @port_updates, [$self->{port}, $set];
$self->{$_} = $set->{$_} for keys %$set;
return $self;
}
for my $col (qw/is_uplink neighbor remote_ip remote_id remote_type slave_of is_master/) {
no strict 'refs';
*{"FakePort::$col"} = sub { $_[0]{$col} };
}
xt/165-incomplete-walks-for.t view on Meta::CPAN
}
config->{'device_auth'} = [{driver => 'snmp'}];
config->{'enable_field_protection'} = 0;
config->{'enable_incomplete_walk_protection'} = 1;
config->{'ignore_deviceports'} = [];
config->{'dns'}->{'no'} = ['0.0.0.0/0'];
package RecordingSNMP; # keeps walk_failures and walk_status
# the port tags worker runs inside discover::properties; its clear writes nothing here
{ package NoopTagsSchema; sub resultset { return $_[0] } sub search { return $_[0] } sub update { return 0 } }
sub new { my ($class, %vals) = @_; return bless { walk_failures => [], walk_status => {}, %vals }, $class; }
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { $_[0]{walk_status}{$_[1]} }
package PlainSNMP; # an SNMP::Info with no walk record
sub new { return bless {}, shift }
package FakeSNMP;
our $AUTOLOAD;
xt/167-discover-device-ip-upsert.t view on Meta::CPAN
config->{'device_auth'} = [{driver => 'snmp'}];
config->{'enable_field_protection'} = 0;
config->{'enable_incomplete_walk_protection'} = 1;
config->{'ignore_deviceports'} = [];
config->{'ignore_private_nets'} = 0;
config->{'dns'}->{'no'} = ['0.0.0.0/0'];
package FakeSNMP;
our $AUTOLOAD;
# the port tags worker runs inside discover::properties; its clear writes nothing here
{ package NoopTagsSchema; sub resultset { return $_[0] } sub search { return $_[0] } sub update { return 0 } }
sub new { my ($class, %vals) = @_; return bless { walk_failures => [], %vals }, $class; }
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { $_[0]{walk_status}{$_[1]} }
sub AUTOLOAD {
my $self = shift;
(my $method = $AUTOLOAD) =~ s/.*:://;
return if $method eq 'DESTROY';
$self->{reads}{$method}++;
# a failing walk records itself on its first read only, as a cached table does
xt/172-discover-device-port-upsert.t view on Meta::CPAN
config->{'device_auth'} = [{driver => 'snmp'}];
config->{'enable_field_protection'} = 0;
config->{'enable_incomplete_walk_protection'} = 1;
config->{'ignore_deviceports'} = [];
config->{'dns'}->{'no'} = ['0.0.0.0/0'];
package FakeSNMP;
our $AUTOLOAD;
# the port tags worker runs inside discover::properties; its clear writes nothing here
{ package NoopTagsSchema; sub resultset { return $_[0] } sub search { return $_[0] } sub update { return 0 } }
sub new { my ($class, %vals) = @_; return bless { walk_failures => [], %vals }, $class; }
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { $_[0]{walk_status}{$_[1]} }
sub AUTOLOAD {
my $self = shift;
(my $method = $AUTOLOAD) =~ s/.*:://;
return if $method eq 'DESTROY';
# a failing walk records itself on its first read only, as a cached table does
if (my $failure = delete $self->{fail_on_read}{$method}) {
xt/175-discover-neighbor-columns.t view on Meta::CPAN
sub new { my ($class, %cols) = @_; return bless { manual_topo => 0, %cols }, $class; }
sub port { $_[0]{port} }
sub manual_topo { $_[0]{manual_topo} }
sub slave_of { $_[0]{slave_of} }
sub is_master { $_[0]{is_master} }
sub remote_port { $_[0]{remote_port} }
sub remote_ip { $_[0]{remote_ip} }
sub is_uplink { $_[0]{is_uplink} }
sub discard_changes { $_[0] }
sub store_column { my ($self, $col, $value) = @_; $self->{$col} = $value }
sub update {
my ($self, $values) = @_;
push @main::row_updates,
[ $self->{owner}, $self->{port}, $values, $self, { map {($_ => $self->{$_})} keys %$values } ];
push @main::update_depths, [ $self->{port}, $main::txn_depth ]
if ref $values->{manual_topo} and ${ $values->{manual_topo} } eq 'true';
foreach my $col (keys %$values) {
my $value = $values->{$col};
$self->{$col} = ref $value ? (${$value} eq 'true' ? 1 : 0) : $value;
}
return $self;
xt/175-discover-neighbor-columns.t view on Meta::CPAN
sub single { my ($self, $cond) = @_; return (grep { $_->port eq $cond->{port} } $self->all)[0] }
sub get_column { $_[0] }
sub as_query { \['(SELECT port FROM device_port WHERE ip = ?)'] }
package FakeDevicePortRS;
sub search { my ($self, $where) = @_; return bless { where => $where }, ref $self }
sub single {
my ($self, $cond) = @_;
return (grep { $_->{owner} eq $cond->{ip} and $_->port eq $cond->{port} } @main::port_rows)[0];
}
sub update {
my ($self, $set) = @_;
my ($sql, @bind) = DBIx::Class::SQLMaker->new->update('device_port', $set, $self->{where});
push @main::port_updates, { sql => $sql, bind => [@bind], set => $set, depth => $main::txn_depth };
return 0;
}
package FakeTopologyRS;
sub search { $_[0] }
sub delete { push @main::topology_delete_depths, $main::txn_depth; 0 }
sub next { shift @{ $_[0]{links} } }
xt/176-discover-port-tags-clear.t view on Meta::CPAN
my $CONFIG = config();
$CONFIG->{logger} = 'console';
$CONFIG->{log} = ($ENV{'DANCER_DEBUG'} ? 'debug' : 'error');
Dancer::Logger->init('console', $CONFIG);
config->{'device_auth'} = [{driver => 'snmp'}];
package RecordingRows;
our (@writes, @clears);
sub new { my ($class, $real, $is_clear) = @_; return bless { real => $real, clear => $is_clear }, $class }
sub update {
my ($self, $set) = @_;
my ($sql, @bind) = @{ ${ $self->{real}->as_query } };
push @{ $self->{clear} ? \@clears : \@writes }, { set => $set, sql => $sql, bind => \@bind };
return $self->{clear} ? 3 : 1;
}
package RecordingSchema;
# an offline PostgreSQL schema, so as_query builds the real SQL without a connection
our $offline = do {
local $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /unversioned/ };
xt/191-vrf-snmp-context.t view on Meta::CPAN
sub new {
my ($class, %vals) = @_;
return bless {session => {Community => 'labro', Context => ''}, updates => [], %vals}, $class;
}
sub snmp_ver { $_[0]{snmp_ver} || 2 }
sub snmp_comm { 'labro' }
sub vtp_version { undef }
sub class { 'SNMP::Info::Layer3::Fake' }
sub cache { }
sub session { $_[0]{session} }
sub update {
my ($self, %args) = @_;
push @{ $self->{updates} }, {%args};
# SNMP::Info::update() keeps the old session and returns false on failure
return if $self->{fail_update};
$self->{session}{$_} = $args{$_} for keys %args;
return $self->{session};
}
package main;
xt/192-discover-vrf-collection.t view on Meta::CPAN
config->{'enable_field_protection'} = 0;
config->{'enable_incomplete_walk_protection'} = 1;
config->{'ignore_deviceports'} = [];
config->{'ignore_private_nets'} = 0;
config->{'dns'}->{'no'} = ['0.0.0.0/0'];
our @events;
package FakeSNMP;
our $AUTOLOAD;
{ package NoopTagsSchema; sub resultset { return $_[0] } sub search { return $_[0] } sub update { return 0 } }
sub new {
my ($class, %vals) = @_;
return bless { walk_failures => [], context => '', contexts_asked => [], %vals }, $class;
}
sub walk_failures { $_[0]{walk_failures} }
# the latest outcome of a method, by the context it was walked in
sub walk_status { my ($self, $method) = @_; return $self->{walk_status_in}{ $self->{context} }{$method} }
sub snmp_ver { $_[0]{snmp_ver} || 2 }
sub snmp_comm { 'public' }
sub update {
my ($self, %args) = @_;
$self->{context} = exists $args{Context} ? $args{Context}
: ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
push @{ $self->{contexts_asked} }, $self->{context};
# a reconnect that fails after the session already moved
die "update failed\n" if $self->{die_on_update_to}
and $self->{context} eq $self->{die_on_update_to};
return 1;
}
xt/193-arpnip-vrf-collection.t view on Meta::CPAN
our $AUTOLOAD;
sub new {
my ($class, %vals) = @_;
return bless { walk_failures => [], context => '', contexts_asked => [], %vals }, $class;
}
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { undef }
sub snmp_ver { $_[0]{snmp_ver} || 2 }
sub snmp_comm { 'public' }
sub update {
my ($self, %args) = @_;
$self->{context} = exists $args{Context} ? $args{Context}
: ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
push @{ $self->{contexts_asked} }, $self->{context};
return 1;
}
sub _context_of {
my ($self, $name) = @_;
my $ctx = $self->{instances}{$name}{contexts}[0];
xt/194-arpnip-subnets-vrf.t view on Meta::CPAN
our $AUTOLOAD;
sub new {
my ($class, %vals) = @_;
return bless { walk_failures => [], context => '', contexts_asked => [], %vals }, $class;
}
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { undef }
sub snmp_ver { $_[0]{snmp_ver} || 2 }
sub snmp_comm { 'public' }
sub update {
my ($self, %args) = @_;
$self->{context} = exists $args{Context} ? $args{Context}
: ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
push @{ $self->{contexts_asked} }, $self->{context};
return 1;
}
sub _context_of {
my ($self, $name) = @_;
my $ctx = $self->{instances}{$name}{contexts}[0];
xt/195-arpnip-retire-unvouched.t view on Meta::CPAN
}
# stored: the VRFs this router's active rows sit in
sub run_retire {
my ($stored, @args) = @_;
@ran = (); $txns = 0; @stored_vrfs = @$stored;
my $count = retire_unvouched_arps(device(), @args);
return ($count, @ran);
}
sub updates_of { return grep { $_->[0] =~ m/^\s*UPDATE node_ip/ } @_ }
sub update_of { return (updates_of(@_))[0] }
# the named VRFs' UPDATE binds its list; the default table's names it in the SQL
sub retired_vrfs {
my @updates = updates_of(@_) or return undef;
my @vrfs = map { ($_->[0] =~ m/ANY/ ? @{ $_->[-1] } : ($_->[0] =~ m/vrf = ''\s*$/ ? '' : ())) } @updates;
return [ sort @vrfs ];
}
subtest 'retire__switch_on__complete_vrfs_and_uncovered_vrfs_retired' => sub {
my ($count, @stmts) = run_retire(['', 'gone', 'red'], $now, { '' => 1, red => 1 }, 1);
xt/204-arpnip-cli-subnets-vrf.t view on Meta::CPAN
}
# the SNMP side, as xt/194 fakes it: each context answers only for its VRF
package FakeSNMP;
our $AUTOLOAD;
sub new { my ($class, %vals) = @_; return bless { walk_failures => [], context => '', %vals }, $class }
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { undef }
sub snmp_ver { 2 }
sub snmp_comm { 'public' }
sub update {
my ($self, %args) = @_;
$self->{context} = exists $args{Context} ? $args{Context}
: ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
return 1;
}
sub _context_of {
my ($self, $name) = @_;
my $ctx = $self->{instances}{$name}{contexts}[0];
return '' if not $ctx or ($ctx->{kind} || '') eq 'none';
return $ctx->{id};
xt/205-each-vrf-instance-context-probe.t view on Meta::CPAN
$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 vrf_read_complete { 1 }
sub update {
my ($self, %args) = @_;
my $target = ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
# SNMP::Info::update() keeps the old session and returns false on failure
if ($self->{fail_update_to}{$target}) {
$self->{error} = $self->{update_error} if exists $self->{update_error};
return;
}
$self->{context} = $target;
return $self->{session} || 1;
}
xt/206-vrf-helper-branches.t view on Meta::CPAN
my $got = with_settings(sub { vrf_instances_for($device, $snmp) }, store_vrfs => 1);
is_deeply $got, {}, 'no instances, not undef';
};
{
package ContextSNMP;
sub new { bless { updates => [] }, shift }
sub snmp_ver { 2 }
sub snmp_comm { 'public' }
sub class { 'SNMP::Info::Layer3' }
sub update { my ($self, %args) = @_; push @{ $self->{updates} }, \%args; return 1 }
}
subtest 'snmp_vrf_context__context_without_kind_or_name__switched_or_refused' => sub {
my $snmp = ContextSNMP->new;
is snmp_vrf_context($snmp, $device, { contexts => [{ v2c => '%s@red' }] }), 1,
'a context with no kind and no instance name is switched to';
is_deeply $snmp->{updates}, [{ Community => 'public@red' }], 'with its template';
is snmp_vrf_context($snmp, $device, { name => 'blue', contexts => [{ kind => 'vrf' }] }), undef,
'no template for the version, no switch, undef as for a refused suffix';
is scalar @{ $snmp->{updates} }, 1, 'nothing more sent';
xt/208-vrf-default-leak-exclusion.t view on Meta::CPAN
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};
}
xt/51-updated-device-hook.t view on Meta::CPAN
config->{'device_auth'} = [{driver => 'snmp'}];
config->{'enable_field_protection'} = 0; # unrelated feature, keep it out of the way
config->{'enable_incomplete_walk_protection'} = 1;
config->{'ignore_deviceports'} = []; # ditto - avoid its device_ips() DB lookup
config->{'dns'}->{'no'} = ['0.0.0.0/0']; # skip real DNS resolution of the alias worker
package FakeSNMP;
our $AUTOLOAD;
# the port tags worker runs inside discover::properties; its clear writes nothing here
{ package NoopTagsSchema; sub resultset { return $_[0] } sub search { return $_[0] } sub update { return 0 } }
sub new { my ($class, %vals) = @_; return bless { walk_failures => [], %vals }, $class; }
sub walk_failures { $_[0]{walk_failures} }
sub walk_status { $_[0]{walk_status}{$_[1]} }
sub AUTOLOAD {
my $self = shift;
(my $method = $AUTOLOAD) =~ s/.*:://;
return if $method eq 'DESTROY';
return $self->{$method};
}
xt/92-password-rehash-on-login.t view on Meta::CPAN
use Dancer::Plugin::Passphrase;
use App::Netdisco::Web::Auth::Provider::DBIC;
{ package Test::FakeRealm;
sub new { bless {}, shift }
sub realm_settings { return {} }
}
{ package Test::FakeUser;
sub new { my ($c, %a) = @_; return bless { %a, updates => [] }, $c }
sub password { $_[0]->{password} }
sub update {
my ($self, $data) = @_;
push @{ $self->{updates} }, $data;
$self->{password} = $data->{password};
return $self;
}
}
my $match = \&App::Netdisco::Web::Auth::Provider::DBIC::match_with_local_pass;
my $is_stale = \&App::Netdisco::Web::Auth::Provider::DBIC::password_hash_is_stale;
my $PASSWORD = 'correct horse battery staple';