1package App::Netdisco::Worker::Plugin::Discover::CanonicalIP; 2 3use Dancer ':syntax'; 4use App::Netdisco::Worker::Plugin; 5use aliased 'App::Netdisco::Worker::Status'; 6 7use App::Netdisco::Transport::SNMP (); 8use App::Netdisco::Util::Permission 'check_acl_only'; 9use App::Netdisco::Util::DNS 'ipv4_from_hostname'; 10use App::Netdisco::Util::Device 'is_discoverable'; 11use Dancer::Plugin::DBIC 'schema'; 12 13register_worker({ phase => 'main', driver => 'snmp' }, sub { 14 my ($job, $workerconf) = @_; 15 16 my $device = $job->device; 17 return unless $device->in_storage; 18 my $snmp = App::Netdisco::Transport::SNMP->reader_for($device) 19 or return Status->defer("discover failed: could not SNMP connect to $device"); 20 21 my $old_ip = $device->ip; 22 my $new_ip = $old_ip; 23 my $revofname = ipv4_from_hostname($snmp->name); 24 25 if (setting('reverse_sysname') and $revofname) { 26 if (App::Netdisco::Transport::SNMP->test_connection( $new_ip )) { 27 $new_ip = $revofname; 28 } 29 else { 30 debug sprintf ' [%s] device - cannot renumber to %s - SNMP connect failed', 31 $old_ip, $revofname; 32 } 33 } 34 35 if (scalar @{ setting('device_identity') }) { 36 my @idmaps = @{ setting('device_identity') }; 37 my $devips = $device->device_ips->order_by('alias'); 38 39 ALIAS: while (my $alias = $devips->next) { 40 next if $alias->alias eq $old_ip; 41 42 foreach my $map (@idmaps) { 43 next unless ref {} eq ref $map; 44 45 foreach my $key (sort keys %$map) { 46 # lhs matches device, rhs matches device_ip 47 if (check_acl_only($device, $key) 48 and check_acl_only($alias, $map->{$key})) { 49 50 if (not is_discoverable( $alias->alias )) { 51 debug sprintf ' [%s] device - cannot renumber to %s - not discoverable', 52 $old_ip, $alias->alias; 53 next; 54 } 55 56 if (App::Netdisco::Transport::SNMP->test_connection( $alias->alias )) { 57 $new_ip = $alias->alias; 58 last ALIAS; 59 } 60 else { 61 debug sprintf ' [%s] device - cannot renumber to %s - SNMP connect failed', 62 $old_ip, $alias->alias; 63 } 64 } 65 } 66 } 67 } # ALIAS 68 } 69 70 return if $new_ip eq $old_ip; 71 72 schema('netdisco')->txn_do(sub { 73 my $existing = schema('netdisco')->resultset('Device')->search({ 74 ip => $new_ip, vendor => $device->vendor, serial => $device->serial, 75 }); 76 77 if (($job->subaction eq 'with-nodes') and $existing->count) { 78 $device->delete; 79 return $job->cancel( 80 " [$old_ip] device - cancelling fresh discover: already known as $new_ip"); 81 } 82 83 # discover existing device but change IP, need to remove existing device 84 $existing->delete; 85 86 # if target device exists then this will die 87 $device->renumber($new_ip) 88 or die "cannot renumber to: $new_ip"; # rollback 89 90 # is not done in renumber, but required, otherwise confusing at job end! 91 schema('netdisco')->resultset('Admin') 92 ->find({job => $job->id})->update({device => $new_ip}) if $job->id; 93 94 return Status->info(sprintf ' [%s] device - changed IP to %s (%s)', 95 $old_ip, $device->ip, ($device->dns || '')); 96 }); 97}); 98 99true; 100