App-Netdisco

 view release on metacpan or  search on metacpan

lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm  view on Meta::CPAN

       and scalar @{ $i_subs->{$pidx} }
       and exists $deviceports{$parent};

      $deviceports{$parent}->{has_subinterfaces} = 'true';
      foreach my $sidx (@{ $i_subs->{$pidx} }) {
          my $sub = $interfaces->{$sidx} or next;
          next unless exists $deviceports{$sub};
          $deviceports{$sub}->{slave_of} = $parent;
      }
  }

  # update num_ports
  $device->num_ports( scalar values %deviceports );

  # support for updated_device Hook - detect meaningful PORT-LEVEL changes
  unless (vars->{'device_changed'}) {
    my $ignore = (setting('updated_device_hook_ignored_fields') || {})->{'device_port'} || [];
    my %ignore_field = map {($_ => 1)} @$ignore;

    # boolean columns: ->hri bypasses DBIC's column handling, so an
    # existing row's true/false comes back as the driver's raw "1"/"0"
    # while our freshly built %deviceports uses the literal 'true'/'false'
    # strings - normalize both before comparing so this isn't a false positive
    my $normalize_bool = sub {
      my $val = shift;
      return (defined $val and grep {$val eq $_} qw/1 t true/) ? 1 : 0;
    };

    if (join("\0", sort {$a cmp $b} keys %{ vars->{'device_ports'} }) ne join("\0", sort keys %deviceports)) {
        vars->{'device_changed'} = 1;
        debug sprintf ' [%s] hooks - port set changed: had [%s], now [%s]',
          $device->ip, (join ', ', sort {$a cmp $b} keys %{ vars->{'device_ports'} }),
                       (join ', ', sort {$a cmp $b} keys %deviceports);
    }
    else {
        my $ports_rsrc = schema('netdisco')->resultset('DevicePort')->result_source;
        PORTDIFF: foreach my $port (sort {$a cmp $b} keys %deviceports) {
            my $old = vars->{'device_ports'}->{$port};
            my $new = $deviceports{$port};
            foreach my $field (sort {$a cmp $b} keys %$new) {
                next if $ignore_field{$field};
                my $oldval = (defined $old->$field   ? $old->$field   : '');
                my $newval = (defined $new->{$field} ? $new->{$field} : '');
                if ($ports_rsrc->column_info($field)->{'data_type'} =~ m/bool/i) {
                    $oldval = $normalize_bool->($oldval);
                    $newval = $normalize_bool->($newval);
                }
                next if $oldval eq $newval;
                vars->{'device_changed'} = 1;
                debug sprintf ' [%s] hooks - port %s field %s changed: "%s" -> "%s"',
                  $device->ip, $port, $field, $oldval, $newval;
                last PORTDIFF;
            }
        }
    }
  }

  # support for Hooks
  vars->{'hook_data'}->{'ports'} = [values %deviceports];

  schema('netdisco')->resultset('DevicePort')->txn_do_locked(ACCESS_EXCLUSIVE, sub {
    my $coder = JSON::PP->new->utf8(0)->allow_nonref(1)->allow_unknown(1);

    # backup the custom_fields
    my %fields = map  {($_->port => $coder->decode(Encode::encode('UTF-8',$_->custom_fields || '{}')))}
                 grep {exists $deviceports{$_->port}}
                      values %{ vars->{'device_ports'} };

    my %ok_fields = map {$_ => 1}
                    grep {defined}
                    map {$_->{name}}
                    @{ setting('custom_fields')->{device_port} || [] };

    # filter custom_fields for current valid fields
    foreach my $port (keys %fields) {
        my %new_fields = ();

        foreach my $field (keys %ok_fields) {
            $new_fields{$field} = exists $fields{$port}->{$field}
              ? Encode::decode('UTF-8', $fields{$port}->{$field}) : undef;
        }

        # set new custom_fields
        $deviceports{$port}->{custom_fields} = $coder->encode(\%new_fields);
    }

    my $gone = $device->ports->delete({keep_nodes => 1});
    debug sprintf ' [%s] interfaces - removed %d interfaces',
      $device->ip, $gone;

    # uptime and num_ports changed
    $device->update();

    $device->ports->populate([values %deviceports]);

    return Status->info(sprintf ' [%s] interfaces - added %d new interfaces',
      $device->ip, scalar values %deviceports);
  });
});

# return a list of VRF which are OK to connect
sub _get_vrf_list {
    my ($device, $snmp) = @_;

    return () if ! $snmp->cisco_comm_indexing;

    my @ok_vrfs = ();
    my $vrf_name = $snmp->vrf_name || {};

    while (my ($idx, $vrf) = each(%$vrf_name)) {
        if ($vrf =~ /^\S+$/) {
            my $ctx_name = pack("C*",split(/\./,$idx));
            $ctx_name =~ s/.*[^[:print:]]+//;
            debug sprintf(' [%s] Discover VRF %s with SNMP Context %s', $device->ip, $vrf, $ctx_name);
            push (@ok_vrfs, $ctx_name);
        }
    }

    return @ok_vrfs;
}



( run in 1.042 second using v1.01-cache-2.11-cpan-800906f7e73 )