diff --git a/Changes b/Changes index d0b33097..81d682c7 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,9 @@ +2.040000 - 2018-05 + + [ENHANCEMENTS] + + * #408 improvements to MakeRancidConf (earendilfr) + 2.039028 - 2018-05-05 [BUG FIXES] diff --git a/lib/App/Netdisco/Worker/Plugin/MakeRancidConf.pm b/lib/App/Netdisco/Worker/Plugin/MakeRancidConf.pm index af1a2805..12bb33b9 100644 --- a/lib/App/Netdisco/Worker/Plugin/MakeRancidConf.pm +++ b/lib/App/Netdisco/Worker/Plugin/MakeRancidConf.pm @@ -8,7 +8,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,15 +16,29 @@ 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 $rancidconf = $config->{rancid_conf} || '/etc/rancid'; my $rancidhome = $config->{rancid_home} || dir($ENV{NETDISCO_HOME}, 'rancid')->stringify; mkdir $rancidhome if ! -d $rancidhome; return Status->error("cannot create or see rancid home: $rancidhome") if ! -d $rancidhome; + my $allowed_types = {}; + foreach my $type (qw/base conf/) { + my $type_file = file($rancidconf, "rancid.types.$type")->stringify; + 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;.*$/; + } + } + my $devices = schema('netdisco')->resultset('Device')->search(undef, { '+columns' => { old => \['age(now(), last_discover) > ?::interval', $down_age] }, @@ -32,23 +46,39 @@ register_worker({ phase => 'main' }, sub { $config->{groups} ||= { default => 'any' }; $config->{vendormap} ||= {}; + $config->{excluded} ||= {}; my $routerdb = {}; while (my $d = $devices->next) { + + if (check_acl_no($d, $config->{excluded})) { + debug " skipping $d: device excluded from 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)/) { - debug " skipping $d with unresolved vendor: $vendor"; + if (not ($name and $vendor)) { + debug " skipping $d: the name or vendor is not defined"; + next; + + } elsif ($vendor =~ m/(?:enterprises\.|netdisco)/) { + debug " skipping $d: unresolved vendor $vendor"; + next; + + } elsif (scalar keys %$allowed_types and !exists $allowed_types->{$vendor}) { + debug " skipping $d: $vendor does not exist in RANCiD's vendor list"; next; } @@ -59,7 +89,9 @@ register_worker({ phase => 'main' }, sub { foreach my $group (keys %$routerdb) { mkdir dir($rancidhome, $group)->stringify; - my $content = join "\n", @{$routerdb->{$group}}; + my $content = "#\n# Router list file for RANCID group $group.\n"; + $content .= "# Generated automatically by App::Netdisco::Worker::Plugin::MakeRancidConf\n#\n"; + $content .= join "\n", @{$routerdb->{$group}}; write_text(file($rancidhome, $group, 'router.db')->stringify, "${content}\n"); } @@ -94,20 +126,25 @@ Here is a complete example of the configuration, which must be called "C". All keys are optional: rancid: - rancid_home: "$ENV{NETDISCO_HOME}/rancid" # default - down_age: '1 day' # default - delimiter: ':' # default + rancid_home: "$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" so -you may wish to set this (especially if migrating from the old +you may wish to set this in C, (especially if migrating from the old C script). Any values above that are a Host Group ACL will take either a single item or @@ -130,6 +167,11 @@ and then refer to named entries in that, for example: The location to write RANCID Group configuration files into. A subdirectory for each Group will be created. +=head2 C + +The location (optional) of your RANCID configuration. It will be used to check +the device's vendor parameter before the export to RANCID configuration. + =head2 C This should be the same or greater than the interval between regular discover @@ -144,6 +186,19 @@ L. Set this to the delimiter character if needed to be different from the default. +=head2 C + +Put devices into this group if they do not match other groups defined. + +=head2 C + +This dictionary defines a list of devices that you do not wish to export to +RANCID configuration. + +The value should be a L +to select devices in the Netdisco database. + =head2 C This dictionary maps RANCID Group names with configuration which will match