diff --git a/lib/App/Netdisco/Configuration.pm b/lib/App/Netdisco/Configuration.pm index 1be83434..e3e6817b 100644 --- a/lib/App/Netdisco/Configuration.pm +++ b/lib/App/Netdisco/Configuration.pm @@ -66,6 +66,12 @@ if (exists setting('workers')->{interactives} setting('dns')->{hosts_file} ||= '/etc/hosts'; setting('dns')->{no} ||= ['fe80::/64','169.254.0.0/16']; +# support unordered dictionary as if it were a single item list +if (ref {} eq ref setting('device_identity')) { + config->{'device_identity'} = [ setting('device_identity') ]; +} +else { config->{'device_identity'} ||= [] } + # legacy config item names config->{'devport_vlan_limit'} = diff --git a/lib/App/Netdisco/Core/Discover.pm b/lib/App/Netdisco/Core/Discover.pm index 3fa4e50d..aeed9b5c 100644 --- a/lib/App/Netdisco/Core/Discover.pm +++ b/lib/App/Netdisco/Core/Discover.pm @@ -55,42 +55,46 @@ sub set_canonical_ip { my $revofname = ipv4_from_hostname($snmp->name); if (setting('reverse_sysname') and $revofname) { + if ($snmp->snmp_connect_ip( $new_ip )) { $new_ip = $revofname; + } + else { + debug sprintf ' [%s] device - cannot renumber to %s - SNMP connect failed', + $old_ip, $revofname; + } } - if (ref [] eq ref setting('device_identity') - and scalar @{ setting('device_identity') }) { + if (scalar @{ setting('device_identity') }) { + my @idmaps = @{ setting('device_identity') }; + my $devips = $device->device_ips->order_by('alias'); - my @idmaps = @{ setting('device_identity') }; - my $devips = $device->device_ips->order_by('alias'); + ALIAS: while (my $alias = $devips->next) { + next if $alias->alias eq $old_ip; - ALIAS: while (my $alias = $devips->next) { - next if $alias->alias eq $old_ip; + foreach my $map (@idmaps) { + next unless ref {} eq ref $map; - foreach my $map (@idmaps) { - next unless ref {} eq ref $map; + foreach my $key (sort keys %$map) { + # lhs matches device, rhs matches device_ip + if (check_acl($device, $key) + and check_acl($alias, $map->{$key})) { - foreach my $key (keys %$map) { - # lhs matches device, rhs matches device_ip - if (check_acl($device, $key) - and check_acl($alias, $map->{$key})) { - $new_ip = $alias->alias; - last ALIAS; - } - } + if ($snmp->snmp_connect_ip( $alias->alias )) { + $new_ip = $alias->alias; + last ALIAS; + } + else { + debug sprintf ' [%s] device - cannot renumber to %s - SNMP connect failed', + $old_ip, $alias->alias; + } } + } } + } # ALIAS } return if $new_ip eq $old_ip; - if (not $snmp->snmp_connect_ip( $new_ip )) { - # should be warning or error? - debug sprintf ' [%s] device - cannot change IP to %s - SNMP connect failed', - $old_ip, $device->ip; - return; - } - schema('netdisco')->txn_do(sub { $device->renumber($new_ip) or die "cannot renumber to: $new_ip"; # rollback diff --git a/lib/App/Netdisco/Manual/Configuration.pod b/lib/App/Netdisco/Manual/Configuration.pod index 9befaf99..5786f3cd 100644 --- a/lib/App/Netdisco/Manual/Configuration.pod +++ b/lib/App/Netdisco/Manual/Configuration.pod @@ -607,16 +607,16 @@ for L. =head3 C -Value: List of Access Control List mappings. Default: None. +Value: Dictionary of Access Control List mappings. Default: None. This setting allows you to control the canonical name or identity of devices in Netdisco. For example if Netdisco discovers devices and uses the "wrong" interface to identfy them (thereby confusing users) you can correct that here. -The C setting is a list of dictionaries. For each dictionary, -the key is an Access Control List matching a device and the value is another -Access Control List matching one of the device's interfaces to use as the -device canonical identity. The format of Access Control Lists is described in +The C setting is a dictionary where each key is an Access +Control List matching a device and the corresponding value is another Access +Control List matching one of the device's interfaces to use as the device +canonical identity. The format of Access Control Lists is described in L. In general, because the key of a dictionary must be a simple text string, you @@ -631,10 +631,10 @@ placed in a C entry and referenced by name. For example: - 'model:.*(?i:DCS7508).*' device_identity: - - 'group:backbone_devices': - - !!perl/regexp ^.*\.backbone\.example\.com$ - - '172.16.20.0/24' - - 'vendor:cisco': '192.0.2.0/24' + 'group:backbone_devices': + - !!perl/regexp ^.*\.backbone\.example\.com$ + - '172.16.20.0/24' + 'vendor:cisco': '192.0.2.0/24' During "discover" jobs, Netdisco will find all entries in C where the I matches the device in some way. For those entries, the @@ -649,7 +649,7 @@ all Arista devices to the IP and host name of their Mgmt1 interface (if they have one), you could use: device_identity: - - 'vendor:arista': 'port:(?i)mgmt1' + 'vendor:arista': 'port:(?i)mgmt1' Once a device is renumbered, its new identity is "sticky". That is, you could remove the C configuration and the next "discover" job will @@ -662,7 +662,18 @@ together with the "C" modifier to require that all items in the list match the device (as in the example above). Note also that whatever interface you select as canonical for the device must -be reachable by SNMP. This is tested and the renumber aborted if not possible. +be reachable by SNMP. A failed connection to a matching interfaces does not +abort the whole process - other interfaces are still teted. + +Netdisco will evaluate clauses in C in a random order. If you +need to control this sequence, pass a list of single-key dictionaries instead +of one multi-key dictionary. The above example could then become: + + device_identity: + - 'group:backbone_devices': + - !!perl/regexp ^.*\.backbone\.example\.com$ + - '172.16.20.0/24' + - 'vendor:cisco': '192.0.2.0/24' =head3 C