Merge branch 'master' into og-api-tokens-simple

This commit is contained in:
Oliver Gorwits
2019-03-11 17:55:31 +00:00
committed by GitHub
65 changed files with 794 additions and 334 deletions

View File

@@ -45,7 +45,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
# only enqueue if device is not already discovered,
# discover_* config permits the discovery
foreach my $neighbor (@to_discover) {
my ($ip, $remote_type, $remote_id) = @$neighbor;
my ($ip, $remote_id) = @$neighbor;
if ($seen_ip{ $ip }++) {
debug sprintf
' queue - skip: IP %s is already queued from %s',
@@ -63,13 +63,6 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
my $newdev = get_device($ip);
next if $newdev->in_storage;
if (not is_discoverable($newdev, $remote_type)) {
debug sprintf
' queue - skip: %s of type [%s] excluded by discover_* config',
$ip, ($remote_type || '');
next;
}
# risk of things going wrong...?
# https://quickview.cloudapps.cisco.com/quickview/bug/CSCur12254
@@ -114,6 +107,7 @@ sub store_neighbors {
or return (); # already checked!
# first allow any manually configured topology to be set
# and do this before we cache the rows in vars->{'device_ports'}
set_manual_topology($device);
if (!defined $snmp->has_topo) {
@@ -126,6 +120,12 @@ sub store_neighbors {
my $c_port = $snmp->c_port;
my $c_id = $snmp->c_id;
my $c_platform = $snmp->c_platform;
my $c_cap = $snmp->c_cap;
# cache the device ports to save hitting the database for many single rows
vars->{'device_ports'} =
{ map {($_->port => $_)} $device->ports->reset->all };
my $device_ports = vars->{'device_ports'};
# v4 and v6 neighbor tables
my $c_ip = ($snmp->c_ip || {});
@@ -144,12 +144,12 @@ sub store_neighbors {
next;
}
my $port = $interfaces->{ $c_if->{$entry} };
my $portrow = schema('netdisco')->resultset('DevicePort')
->single({ip => $device->ip, port => $port});
# WRT #475 this is SAFE because we check against known ports below
my $port = $interfaces->{ $c_if->{$entry} } or next;
my $portrow = $device_ports->{$port};
if (!defined $portrow) {
info sprintf ' [%s] neigh - local port %s not in database!',
debug sprintf ' [%s] neigh - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
@@ -161,7 +161,7 @@ sub store_neighbors {
}
if ($portrow->manual_topo) {
info sprintf ' [%s] neigh - %s has manually defined topology',
debug sprintf ' [%s] neigh - %s has manually defined topology',
$device->ip, $port;
next;
}
@@ -170,12 +170,13 @@ sub store_neighbors {
my $remote_port = undef;
my $remote_type = Encode::decode('UTF-8', $c_platform->{$entry} || '');
my $remote_id = Encode::decode('UTF-8', $c_id->{$entry});
my $remote_cap = $c_cap->{$entry} || [];
next unless $remote_ip;
my $r_netaddr = NetAddr::IP::Lite->new($remote_ip);
if ($r_netaddr and ($r_netaddr->addr ne $remote_ip)) {
info sprintf ' [%s] neigh - IP on %s: using %s as canonical form of %s',
debug sprintf ' [%s] neigh - IP on %s: using %s as canonical form of %s',
$device->ip, $port, $r_netaddr->addr, $remote_ip;
$remote_ip = $r_netaddr->addr;
}
@@ -189,7 +190,7 @@ sub store_neighbors {
if ($remote_id) {
my $devices = schema('netdisco')->resultset('Device');
my $neigh = $devices->single({name => $remote_id});
info sprintf
debug sprintf
' [%s] neigh - bad address %s on port %s, searching for %s instead',
$device->ip, $remote_ip, $port, $remote_id;
@@ -207,7 +208,7 @@ sub store_neighbors {
(my $tmpid = $remote_id) =~ s/.*\(([0-9a-f]{6})-([0-9a-f]{6})\).*/$1$2/;
my $mac = NetAddr::MAC->new(mac => $tmpid);
if ($mac and not $mac->errstr) {
info sprintf
debug sprintf
' [%s] neigh - trying to find neighbor %s by MAC %s',
$device->ip, $remote_id, $mac->as_ieee;
$neigh = $devices->single({mac => $mac->as_ieee});
@@ -221,17 +222,17 @@ sub store_neighbors {
if ($neigh) {
$remote_ip = $neigh->ip;
info sprintf ' [%s] neigh - found %s with IP %s',
debug sprintf ' [%s] neigh - found %s with IP %s',
$device->ip, $remote_id, $remote_ip;
}
else {
info sprintf ' [%s] neigh - could not find %s, skipping',
debug sprintf ' [%s] neigh - could not find %s, skipping',
$device->ip, $remote_id;
next;
}
}
else {
info sprintf ' [%s] neigh - skipping unuseable address %s on port %s',
debug sprintf ' [%s] neigh - skipping unuseable address %s on port %s',
$device->ip, $remote_ip, $port;
next;
}
@@ -240,7 +241,15 @@ sub store_neighbors {
# what we came here to do.... discover the neighbor
debug sprintf ' [%s] neigh - %s with ID [%s] on %s',
$device->ip, $remote_ip, ($remote_id || ''), $port;
push @to_discover, [$remote_ip, $remote_type, $remote_id];
if (is_discoverable($remote_ip, $remote_type, $remote_cap)) {
push @to_discover, [$remote_ip, $remote_id];
}
else {
debug sprintf
' [%s] neigh - skip: %s of type [%s] excluded by discover_* config',
$device->ip, $remote_ip, ($remote_type || '');
}
$remote_port = $c_port->{$entry};
if (defined $remote_port) {
@@ -248,18 +257,18 @@ sub store_neighbors {
$remote_port =~ s/[^\d\s\/\.,()\w:-]+//gi;
}
else {
info sprintf ' [%s] neigh - no remote port found for port %s at %s',
debug sprintf ' [%s] neigh - no remote port found for port %s at %s',
$device->ip, $port, $remote_ip;
}
$portrow->update({
$portrow = $portrow->update({
remote_ip => $remote_ip,
remote_port => $remote_port,
remote_type => $remote_type,
remote_id => $remote_id,
is_uplink => \"true",
manual_topo => \"false",
});
})->discard_changes();
# update master of our aggregate to be a neighbor of
# the master on our peer device (a lot of iffs to get there...).

View File

@@ -22,8 +22,8 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
my $eigrp_peers = $snmp->eigrp_peers || {};
return Status->info(" [$device] neigh - no BGP, OSPF, or EIGRP peers")
unless ((scalar values %$ospf_peers) or (scalar values %$bgp_peers)
or (scalar values %$eigrp_peers));
unless ((scalar values %$ospf_peers) or (scalar values %$ospf_routers)
or (scalar values %$bgp_peers) or (scalar values %$eigrp_peers));
my $count = 0;
foreach my $ip ((values %$ospf_peers), (values %$ospf_routers),

View File

@@ -32,6 +32,10 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
};
}
# cache the device ports to save hitting the database for many single rows
my $device_ports = vars->{'device_ports'}
|| { map {($_->port => $_)} $device->ports->all };
my $interfaces = $snmp->interfaces;
my $p_ifindex = $snmp->peth_port_ifindex;
my $p_admin = $snmp->peth_port_admin;
@@ -42,11 +46,16 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
# build device port power info suitable for DBIC
my @portpower;
foreach my $entry (keys %$p_ifindex) {
my $port = $interfaces->{ $p_ifindex->{$entry} };
next unless $port;
# WRT #475 this is SAFE because we check against known ports below
my $port = $interfaces->{ $p_ifindex->{$entry} } or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] power - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
my ($module) = split m/\./, $entry;
push @portpower, {
port => $port,
module => $module,

View File

@@ -8,7 +8,7 @@ use App::Netdisco::Transport::SNMP ();
use Dancer::Plugin::DBIC 'schema';
use Encode;
use App::Netdisco::Util::Device 'match_devicetype';
use App::Netdisco::Util::Device 'match_to_setting';
register_worker({ phase => 'main', driver => 'snmp' }, sub {
my ($job, $workerconf) = @_;
@@ -21,10 +21,20 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
my $interfaces = $snmp->interfaces || {};
my %properties = ();
# cache the device ports to save hitting the database for many single rows
my $device_ports = vars->{'device_ports'}
|| { map {($_->port => $_)} $device->ports->all };
my $raw_speed = $snmp->i_speed_raw || {};
foreach my $idx (keys %$raw_speed) {
my $port = $interfaces->{$idx} or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] properties/speed - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
$properties{ $port }->{raw_speed} = $raw_speed->{$idx};
}
@@ -32,6 +42,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
foreach my $idx (keys %$err_cause) {
my $port = $interfaces->{$idx} or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] properties/errdis - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
$properties{ $port }->{error_disable_cause} = $err_cause->{$idx};
}
@@ -39,6 +55,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
foreach my $idx (keys %$faststart) {
my $port = $interfaces->{$idx} or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] properties/faststart - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
$properties{ $port }->{faststart} = $faststart->{$idx};
}
@@ -54,17 +76,22 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
foreach my $idx (keys %$c_if) {
my $port = $interfaces->{ $c_if->{$idx} } or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] properties/lldpcap - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
my $remote_cap = $c_cap->{$idx} || [];
my $remote_type = Encode::decode('UTF-8', $c_platform->{$idx} || '');
$properties{ $port }->{remote_is_wap} = 'true'
if scalar grep {match_devicetype($_, 'wap_capabilities')} @$remote_cap
or match_devicetype($remote_type, 'wap_platforms');
if scalar grep {match_to_setting($_, 'wap_capabilities')} @$remote_cap
or match_to_setting($remote_type, 'wap_platforms');
$properties{ $port }->{remote_is_phone} = 'true'
if scalar grep {match_devicetype($_, 'phone_capabilities')} @$remote_cap
or match_devicetype($remote_type, 'phone_platforms');
if scalar grep {match_to_setting($_, 'phone_capabilities')} @$remote_cap
or match_to_setting($remote_type, 'phone_platforms');
next unless scalar grep {defined && m/^inventory$/} @{ $rem_media_cap->{$idx} };
@@ -74,17 +101,28 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
$properties{ $port }->{remote_serial} = $rem_serial->{ $idx };
}
foreach my $idx (keys %$interfaces) {
my $port = $interfaces->{$idx} or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] properties/ifindex - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
$properties{ $port }->{ifindex} = $idx;
}
return Status->info(" [$device] no port properties to record")
unless scalar keys %properties;
schema('netdisco')->txn_do(sub {
my $gone = $device->properties_ports->delete;
debug sprintf ' [%s] props - removed %d ports with properties',
debug sprintf ' [%s] properties - removed %d ports with properties',
$device->ip, $gone;
$device->properties_ports->populate(
[map {{ port => $_, %{ $properties{$_} } }} keys %properties] );
return Status->info(sprintf ' [%s] props - added %d new port properties',
return Status->info(sprintf ' [%s] properties - added %d new port properties',
$device->ip, scalar keys %properties);
});
});

View File

@@ -151,7 +151,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
if (defined $snmp->snmpEngineTime) {
$dev_uptime_wrapped = int( $snmp->snmpEngineTime * 100 / 2**32 );
if ($dev_uptime_wrapped > 0) {
info sprintf ' [%s] interface - device uptime wrapped %d times - correcting',
debug sprintf ' [%s] interfaces - device uptime wrapped %d times - correcting',
$device->ip, $dev_uptime_wrapped;
$device->uptime( $dev_uptime + $dev_uptime_wrapped * 2**32 );
}
@@ -190,7 +190,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
my $lc = $i_lastchange->{$entry} || 0;
if (not $dev_uptime_wrapped and $lc > $dev_uptime) {
info sprintf ' [%s] interfaces - device uptime wrapped (%s) - correcting',
debug sprintf ' [%s] interfaces - device uptime wrapped (%s) - correcting',
$device->ip, $port;
$device->uptime( $dev_uptime + 2**32 );
$dev_uptime_wrapped = 1;
@@ -238,6 +238,7 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
# must do this after building %interfaces so that we can set is_master
foreach my $sidx (keys %$agg_ports) {
my $slave = $interfaces->{$sidx} or next;
next unless defined $agg_ports->{$sidx}; # slave without a master?!
my $master = $interfaces->{ $agg_ports->{$sidx} } or next;
next unless exists $interfaces{$slave} and exists $interfaces{$master};

View File

@@ -33,6 +33,10 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
};
}
# cache the device ports to save hitting the database for many single rows
my $device_ports = vars->{'device_ports'}
|| { map {($_->port => $_)} $device->ports->all };
my $i_vlan = $snmp->i_vlan;
my $i_vlan_membership = $snmp->i_vlan_membership;
my $i_vlan_type = $snmp->i_vlan_type;
@@ -42,8 +46,13 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
my @portvlans = ();
foreach my $entry (keys %$i_vlan_membership) {
my %port_vseen = ();
my $port = $interfaces->{$entry};
next unless defined $port;
my $port = $interfaces->{$entry} or next;
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] vlans - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
my $type = $i_vlan_type->{$entry};

View File

@@ -18,6 +18,10 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
my $ssidlist = $snmp->i_ssidlist;
return unless scalar keys %$ssidlist;
# cache the device ports to save hitting the database for many single rows
my $device_ports = vars->{'device_ports'}
|| { map {($_->port => $_)} $device->ports->all };
my $interfaces = $snmp->interfaces;
my $ssidbcast = $snmp->i_ssidbcast;
my $ssidmac = $snmp->i_ssidmac;
@@ -36,6 +40,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
next;
}
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] wireless - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
push @ssids, {
port => $port,
ssid => $ssidlist->{$entry},
@@ -64,6 +74,12 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
next;
}
if (!defined $device_ports->{$port}) {
debug sprintf ' [%s] wireless - local port %s already skipped, ignoring',
$device->ip, $port;
next;
}
push @channels, {
port => $port,
channel => $channel->{$entry},

View File

@@ -7,7 +7,7 @@ use aliased 'App::Netdisco::Worker::Status';
use App::Netdisco::Transport::SNMP ();
use App::Netdisco::Util::Permission 'check_acl_no';
use App::Netdisco::Util::PortMAC 'get_port_macs';
use App::Netdisco::Util::Device 'match_devicetype';
use App::Netdisco::Util::Device 'match_to_setting';
use App::Netdisco::Util::Node 'check_mac';
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
use Dancer::Plugin::DBIC 'schema';
@@ -248,7 +248,6 @@ sub get_vlan_list {
# check in use by a port on this device
if (!$vlans{$vlan} && !setting('macsuck_all_vlans')) {
debug sprintf
' [%s] macsuck VLAN %s/%s - not in use by any port - skipping.',
$device->ip, $vlan, $name;
@@ -299,6 +298,8 @@ sub walk_fwtable {
next;
}
# WRT #475 this is SAFE because we check against known ports below
# but we do need the SNMP interface IDs to get the job done
my $port = $interfaces->{$iid};
unless (defined $port) {
@@ -318,6 +319,7 @@ sub walk_fwtable {
# this uses the cached $ports resultset to limit hits on the db
my $device_port = $device_ports->{$port};
# WRT #475 ... see? :-)
unless (defined $device_port) {
debug sprintf
' [%s] macsuck %s - port %s is not in database - skipping.',
@@ -340,7 +342,7 @@ sub walk_fwtable {
# neighbors otherwise it would kill the DB with device lookups.
my $neigh_cannot_macsuck = eval { # can fail
check_acl_no(($device_port->neighbor || "0 but true"), 'macsuck_unsupported') ||
match_devicetype($device_port->remote_type, 'macsuck_unsupported_type') };
match_to_setting($device_port->remote_type, 'macsuck_unsupported_type') };
if ($device_port->is_uplink) {
if ($neigh_cannot_macsuck) {

View File

@@ -41,11 +41,11 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
next unless defined $mac; # avoid null entries
# there can be more rows in txrate than other tables
my $txrate = defined $txrates->[$#$txrates]
my $txrate = (ref $txrates and defined $txrates->[$#$txrates])
? int($txrates->[$#$txrates])
: undef;
my $maxrate = defined $rates->[$#$rates]
my $maxrate = (ref $rates and defined $rates->[$#$rates])
? int($rates->[$#$rates])
: undef;

View File

@@ -1,5 +1,8 @@
package App::Netdisco::Worker::Plugin::MakeRancidConf;
use strict;
use warnings;
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
@@ -8,7 +11,7 @@ use aliased 'App::Netdisco::Worker::Status';
use Path::Class;
use List::Util qw/pairkeys pairfirst/;
use File::Slurper 'write_text';
use File::Slurper qw/read_lines write_text/;
use App::Netdisco::Util::Permission 'check_acl_no';
register_worker({ phase => 'main' }, sub {
@@ -16,14 +19,31 @@ register_worker({ phase => 'main' }, sub {
my $config = setting('rancid') || {};
my $domain_suffix = setting('domain_suffix') || '';
my $delimiter = $config->{delimiter} || ':';
my $delimiter = $config->{delimiter} || ';';
my $down_age = $config->{down_age} || '1 day';
my $default_group = $config->{default_group} || 'default';
my $rancidhome = $config->{rancid_home}
my $rancidconf = $config->{rancid_conf} || '/etc/rancid';
my $rancidcvsroot = $config->{rancid_cvsroot}
|| dir($ENV{NETDISCO_HOME}, 'rancid')->stringify;
mkdir $rancidhome if ! -d $rancidhome;
return Status->error("cannot create or see rancid home: $rancidhome")
if ! -d $rancidhome;
mkdir $rancidcvsroot if ! -d $rancidcvsroot;
return Status->error("cannot create or access rancid cvsroot: $rancidcvsroot")
if ! -d $rancidcvsroot;
my $allowed_types = {};
foreach my $type (qw/base conf/) {
my $type_file = file($rancidconf, "rancid.types.$type")->stringify;
debug sprintf("trying rancid configuration file %s\n", $type_file);
next unless -f $type_file;
my @lines = read_lines($type_file);
foreach my $line (@lines) {
next if $line =~ m/^(?:\#|\$)/;
$allowed_types->{$1} += 1 if $line =~ m/^([a-z0-9_\-]+);login;.*$/;
}
}
return Status->error("You didn't have any device types configured in your rancid installation.")
if ! scalar keys %$allowed_types;
my $devices = schema('netdisco')->resultset('Device')->search(undef, {
'+columns' => { old =>
@@ -32,24 +52,37 @@ register_worker({ phase => 'main' }, sub {
$config->{groups} ||= { default => 'any' };
$config->{vendormap} ||= {};
$config->{excluded} ||= {};
$config->{by_ip} ||= {};
$config->{by_hostname} ||= {};
my $routerdb = {};
while (my $d = $devices->next) {
my $name =
check_acl_no($d, $config->{by_ip}) ? $d->ip : ($d->dns || $d->name);
$name =~ s/$domain_suffix$//
if check_acl_no($d, $config->{by_hostname});
if (check_acl_no($d, $config->{excluded})) {
debug " skipping $d: device excluded of export";
next
}
my $name = check_acl_no($d, $config->{by_ip}) ? $d->ip : ($d->dns || $d->name);
$name =~ s/$domain_suffix$// if check_acl_no($d, $config->{by_hostname});
my ($group) =
pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{groups} };
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{groups} }) || $default_group;
my ($vendor) =
(pairkeys pairfirst { check_acl_no($d, $b) } %{ $config->{vendormap} })
|| $d->vendor;
if ($vendor =~ m/(?:enterprises\.|netdisco)/) {
if (not ($name and $vendor)) {
debug " skipping $d: the name or vendor is not defined";
next
} elsif ($vendor =~ m/(?:enterprises\.|netdisco)/) {
debug " skipping $d with unresolved vendor: $vendor";
next;
} elsif (scalar keys %$allowed_types and !exists($allowed_types->{$vendor})) {
debug " skipping $d: $vendor doesn't exist in rancid's vendor list";
next;
}
push @{$routerdb->{$group}},
@@ -58,12 +91,14 @@ register_worker({ phase => 'main' }, sub {
}
foreach my $group (keys %$routerdb) {
mkdir dir($rancidhome, $group)->stringify;
my $content = join "\n", @{$routerdb->{$group}};
write_text(file($rancidhome, $group, 'router.db')->stringify, "${content}\n");
mkdir dir($rancidcvsroot, $group)->stringify;
my $content = "#\n# Router list file for rancid group $group.\n";
$content .= "# Generate automatically by App::Netdisco::Worker::Plugin::MakeRancidConf\n#\n";
$content .= join "\n", sort @{$routerdb->{$group}};
write_text(file($rancidcvsroot, $group, 'router.db')->stringify, "${content}\n");
}
return Status->done('Wrote RANCID configuration.');
return Status->done('Wrote rancid configuration.');
});
true;
@@ -72,17 +107,20 @@ true;
=head1 NAME
MakeRancidConf - Generate RANCID Configuration
MakeRancidConf - Generate rancid Configuration
=head1 INTRODUCTION
This worker will generate a RANCID configuration for all devices in Netdisco.
This worker will generate a rancid configuration for all devices in Netdisco.
Optionally you can provide configuration to control the output, however the
defaults are sane, and will create one RANCID group called "C<default>" which
contains all devices. Those devices not discovered successfully within the
past day will be marked as "down" for RANCID to skip. Configuration is saved
to the "rancid" subdirectory of Netdisco's home folder.
defaults are sane for rancid versions 3.x and will create one rancid group
called C<default> which contains all devices. Those devices not discovered
successfully within the past day will be marked as C<down> for rancid to skip.
Configuration is saved to the F<~/rancid> subdirectory of Netdisco's home folder.
Note that this only generates the router.db files, you will still need to
configure rancid's F<.cloginrc> and schedule C<rancid-run> to run.
You could run this worker at 09:05 each day using the following configuration:
@@ -90,95 +128,142 @@ You could run this worker at 09:05 each day using the following configuration:
makerancidconf:
when: '5 9 * * *'
Since MakeRancidConf is a worker module it can also be run via C<netdisco-do>:
netdisco-do makerancidconf
=head1 CONFIGURATION
Here is a complete example of the configuration, which must be called
"C<rancid>". All keys are optional:
C<rancid>. All keys are optional:
rancid:
rancid_home: "$ENV{NETDISCO_HOME}/rancid" # default
down_age: '1 day' # default
delimiter: ':' # default
rancid_cvsroot: '$ENV{NETDISCO_HOME}/rancid' # default
rancid_conf: '/etc/rancid' # default
down_age: '1 day' # default
delimiter: ';' # default
default_group: 'default' # default
excluded:
excludegroup1: 'host_group1_acl'
excludegroup2: 'host_group2_acl'
groups:
groupname1: 'host_group1_acl'
groupname2: 'host_group2_acl'
groupname1: 'host_group3_acl'
groupname2: 'host_group4_acl'
vendormap:
vname1: 'host_group3_acl'
vname2: 'host_group4_acl'
by_ip: 'host_group5_acl'
by_hostname: 'host_group6_acl'
vname1: 'host_group5_acl'
vname2: 'host_group6_acl'
by_ip: 'host_group7_acl'
by_hostname: 'host_group8_acl'
Note that the default home for writing files is not "C</var/lib/rancid>" so
you may wish to set this (especially if migrating from the old
Note that the default directory for writing files is not F</var/lib/rancid> so
you may wish to set this in C<rancid_cvsroot>, (especially if migrating from the old
C<netdisco-rancid-export> script).
Any values above that are a Host Group ACL will take either a single item or
list of Network Identifiers or Device Properties. See the L<ACL
Any values above that are a host group ACL will take either a single item or
a list of network identifiers or device properties. See the L<ACL
documentation|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
wiki page for full details. We advise you to use the "C<host_groups>" setting
wiki page for full details. We advise you to use the C<host_groups> setting
and then refer to named entries in that, for example:
host_groups:
coredevices: '192.0.2.0/24'
edgedevices: '172.16.0.0/16'
grp-nxos: 'os:nx-os'
rancid:
groups:
core_devices: 'group:coredevices'
edge_devices: 'group:edgedevices'
vendormap:
cisco-nx: 'group:grp-nxos'
by_ip: 'any'
=head2 C<rancid_home>
Do not forget that rancid also needs configuring when adding a new group,
such as scheduling the group to run, adding it to F<rancid.conf>, setting up the
email config and creating the repository with C<rancid-cvs>.
The location to write RANCID Group configuration files into. A subdirectory
for each Group will be created.
=head2 C<rancid_conf>
The location where the rancid configuration (F<rancid.types.base> and
F<rancid.types.conf>) is installed. It will be used to check the existance
of device types before exporting the devices to the rancid configuration. if no match
is found the device will not be added to rancid.
=head2 C<rancid_cvsroot>
The location to write rancid group configuration files (F<router.db>) into. A
subdirectory for each group will be created.
=head2 C<down_age>
This should be the same or greater than the interval between regular discover
jobs on your network. Devices which have not been discovered within this time
will be marked as "C<down>" to RANCID.
will be marked as C<down> to rancid.
The format is any time interval known and understood by PostgreSQL, such as at
L<https://www.postgresql.org/docs/8.4/static/functions-datetime.html>.
L<https://www.postgresql.org/docs/10/static/functions-datetime.html>.
=head2 C<delimiter>
Set this to the delimiter character if needed to be different from the
default.
Set this to the delimiter character for your F<router.db> entries if needed to
be different from the default, the default is C<;>.
=head2 C<default_group>
Put devices into this group if they do not match any other groups defined.
=head2 C<excluded>
This dictionary defines a list of devices that you do not wish to export to
rancid configuration.
The value should be a L<Netdisco ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
to select devices in the Netdisco database.
=head2 C<groups>
This dictionary maps RANCID Group names with configuration which will match
This dictionary maps rancid group names with configuration which will match
devices in the Netdisco database.
The left hand side (key) should be the RANCID group name, the right hand side
The left hand side (key) should be the rancid group name, the right hand side
(value) should be a L<Netdisco
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
to select devices in the Netdisco database.
=head2 C<vendormap>
If the device Vendor in Netdisco is not the same as the RANCID vendor script,
configure a mapping here.
If the device vendor in Netdisco is not the same as the rancid vendor script or
device type, configure a mapping here.
The left hand side (key) should be the RANCID vendor, the right hand side
The left hand side (key) should be the rancid device type, the right hand side
(value) should be a L<Netdisco
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
to select devices in the Netdisco database.
Note that vendors might have a large array of operating systems which require
different rancid modules. Mapping operating systems to rancid device types is
a good solution to use the correct device type. Example:
host_groups:
grp-ciscosb: 'os:ros'
rancid:
vendormap:
cisco-sb: 'group:grp-ciscosb'
=head2 C<by_ip>
L<Netdisco
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
to select devices which will be written to the RANCID config as an IP address,
instead of the DNS FQDN or SNMP host name.
to select devices which will be written to the rancid config as an IP address,
instead of the DNS FQDN or SNMP hostname.
=head2 C<by_hostname>
L<Netdisco
ACL|https://github.com/netdisco/netdisco/wiki/Configuration#access-control-lists>
to select devices which will have the unqualified host name written to the
RANCID config. This is done simply by stripping the C<domain_suffix>
to select devices which will have the unqualified hostname written to the
rancid config. This is done simply by stripping the C<domain_suffix>
configuration setting from the device FQDN.
=head1 SEE ALSO

View File

@@ -47,4 +47,3 @@ register_worker({ phase => 'main' }, sub {
});
true;

View File

@@ -17,9 +17,9 @@ register_worker({ phase => 'check' }, sub {
or return Status->error(sprintf "Unknown port name [%s] on device %s",
$job->port, $job->device);
my $vlan_reconfig_check = vlan_reconfig_check(vars->{'port'});
return Status->error("Cannot alter vlan: $vlan_reconfig_check")
if $vlan_reconfig_check;
my $port_reconfig_check = port_reconfig_check(vars->{'port'});
return Status->error("Cannot alter port: $port_reconfig_check")
if $port_reconfig_check;
return Status->done('PortControl is able to run');
});
@@ -56,7 +56,7 @@ sub _action {
my $rv = $snmp->set_i_up_admin($data, $iid);
if (!defined $rv) {
return Status->error(sprintf 'Failed to set [%s] up_admin to [%s] on $device: %s',
return Status->error(sprintf "Failed to set [%s] up_admin to [%s] on $device: %s",
$pn, $data, ($snmp->error || ''));
}

View File

@@ -19,9 +19,9 @@ register_worker({ phase => 'check' }, sub {
or return Status->error(sprintf "Unknown port name [%s] on device %s",
$job->port, $job->device);
my $vlan_reconfig_check = vlan_reconfig_check(vars->{'port'});
return Status->error("Cannot alter vlan: $vlan_reconfig_check")
if $vlan_reconfig_check;
my $port_reconfig_check = port_reconfig_check(vars->{'port'});
return Status->error("Cannot alter port: $port_reconfig_check")
if $port_reconfig_check;
return Status->error("No PoE service on port [$pn] on device $device")
unless vars->{'port'}->power;
@@ -40,7 +40,7 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
# snmp connect using rw community
my $snmp = App::Netdisco::Transport::SNMP->writer_for($device)
or return Status->defer("failed to connect to $device to update vlan");
or return Status->defer("failed to connect to $device to set power");
my $powerid = get_powerid($snmp, vars->{'port'})
or return Status->error("failed to get power ID for [$pn] from $device");

View File

@@ -18,13 +18,14 @@ register_worker({ phase => 'main', driver => 'snmp' }, sub {
my ($device, $port, $extra) = map {$job->$_} qw/device port extra/;
$extra ||= 'interfaces'; my $class = undef;
($class, $extra) = split(/::([^:]+)$/, $extra);
if ($class and $extra) {
$class = 'SNMP::Info::'.$class;
}
else {
$extra = $class;
undef $class;
my @values = split /::/, $extra;
$extra = pop @values;
if (scalar(@values)) {
$class = "SNMP::Info";
foreach my $v (@values) {
last if ($v eq '');
$class = $class.'::'.$v;
}
}
my $i = App::Netdisco::Transport::SNMP->reader_for($device, $class);