1package App::Netdisco::Worker::Plugin::Discover::Entities; 2 3use Dancer ':syntax'; 4use App::Netdisco::Worker::Plugin; 5use aliased 'App::Netdisco::Worker::Status'; 6 7use App::Netdisco::Transport::SNMP (); 8use Dancer::Plugin::DBIC 'schema'; 9use Encode; 10 11my $clean = sub { 12 my $device = shift; 13 14 my $gone = $device->modules->delete; 15 debug sprintf ' [%s] modules - removed %d chassis modules', 16 $device->ip, $gone; 17 18 $device->modules->update_or_create({ 19 ip => $device->ip, 20 index => 1, 21 parent => 0, 22 name => 'chassis', 23 class => 'chassis', 24 pos => -1, 25 # too verbose and link doesn't work anyway 26 # description => $device->description, 27 sw_ver => $device->os_ver, 28 serial => $device->serial, 29 model => $device->model, 30 fru => \'false', 31 last_discover => \'now()', 32 }); 33}; 34 35register_worker({ phase => 'main', driver => 'snmp' }, sub { 36 my ($job, $workerconf) = @_; 37 38 my $device = $job->device; 39 return unless $device->in_storage; 40 41 if (not setting('store_modules')) { 42 schema('netdisco')->txn_do($clean, $device); 43 return Status->info( 44 sprintf ' [%s] modules - store_modules is disabled (added one pseudo for chassis)', 45 $device->ip); 46 } 47 48 my $snmp = App::Netdisco::Transport::SNMP->reader_for($device) 49 or return Status->defer("discover failed: could not SNMP connect to $device"); 50 my $e_index = $snmp->e_index; 51 52 if (!defined $e_index) { 53 schema('netdisco')->txn_do($clean, $device); 54 return Status->info( 55 sprintf ' [%s] modules - 0 chassis components (added one pseudo for chassis)', 56 $device->ip); 57 } 58 59 my $e_descr = $snmp->e_descr; 60 my $e_type = $snmp->e_type; 61 my $e_parent = $snmp->e_parent; 62 my $e_name = $snmp->e_name; 63 my $e_class = $snmp->e_class; 64 my $e_pos = $snmp->e_pos; 65 my $e_hwver = $snmp->e_hwver; 66 my $e_fwver = $snmp->e_fwver; 67 my $e_swver = $snmp->e_swver; 68 my $e_model = $snmp->e_model; 69 my $e_serial = $snmp->e_serial; 70 my $e_fru = $snmp->e_fru; 71 72 # build device modules list for DBIC 73 my (@modules, %seen_idx); 74 foreach my $entry (keys %$e_index) { 75 next unless defined $e_index->{$entry}; 76 next if $seen_idx{ $e_index->{$entry} }++; 77 78 if ($e_index->{$entry} !~ m/^[0-9]+$/) { 79 debug sprintf ' [%s] modules - index %s is not an integer', 80 $device->ip, $e_index->{$entry}; 81 next; 82 } 83 84 push @modules, { 85 index => $e_index->{$entry}, 86 type => $e_type->{$entry}, 87 parent => $e_parent->{$entry}, 88 name => Encode::decode('UTF-8', $e_name->{$entry}), 89 class => $e_class->{$entry}, 90 pos => $e_pos->{$entry}, 91 hw_ver => Encode::decode('UTF-8', $e_hwver->{$entry}), 92 fw_ver => Encode::decode('UTF-8', $e_fwver->{$entry}), 93 sw_ver => Encode::decode('UTF-8', $e_swver->{$entry}), 94 model => Encode::decode('UTF-8', $e_model->{$entry}), 95 serial => Encode::decode('UTF-8', $e_serial->{$entry}), 96 fru => $e_fru->{$entry}, 97 description => Encode::decode('UTF-8', $e_descr->{$entry}), 98 last_discover => \'now()', 99 }; 100 } 101 102 foreach my $m (@modules){ 103 unless ($seen_idx{$m->{parent}} || !$m->{parent}){ 104 # Some combined devices like Nexus with FEX or ASR with Satellites can return invalid 105 # EntityMIB trees. This workaround relocates entitites with invalid parents to the root 106 # of the tree, so they are at least visible in the Modules tab (see #710) 107 108 info sprintf ' [%s] Entity %s (%s) has invalid parent %s - attaching as root entity instead', 109 $device->ip, $m->{index}, $m->{name}, $m->{parent}; 110 $m->{parent} = undef; 111 } 112 } 113 114 schema('netdisco')->txn_do(sub { 115 my $gone = $device->modules->delete; 116 debug sprintf ' [%s] modules - removed %d chassis modules', 117 $device->ip, $gone; 118 $device->modules->populate(\@modules); 119 120 return Status->info(sprintf ' [%s] modules - added %d new chassis modules', 121 $device->ip, scalar @modules); 122 }); 123}); 124 125true; 126