The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package App::Netdisco::Daemon::Worker::Poller::Common;

use Dancer qw/:moose :syntax :script/;
use Dancer::Plugin::DBIC 'schema';

use App::Netdisco::Util::SNMP 'snmp_connect';
use App::Netdisco::Util::Device 'get_device';
use App::Netdisco::Daemon::Util ':all';

use NetAddr::IP::Lite ':lower';

use Role::Tiny;
use namespace::clean;

# queue a job for all devices known to Netdisco
sub _walk_body {
  my ($self, $job_type, $job) = @_;

  my $devices = schema('netdisco')->resultset('Device')->get_column('ip');
  my $jobqueue = schema('netdisco')->resultset('Admin');

  if ($job->subaction and $job->subaction eq 'after-discoverall') {
      # make sure there are no incomplete discover jobs queued
      my $discover = $jobqueue->search(
        { action => 'discover', status => { -like => 'queued%' } }
      )->count;

      return job_defer("Deferred $job_type due to pending discover jobs")
        if $discover;
  }

  schema('netdisco')->txn_do(sub {
    # clean up user submitted jobs older than 1min,
    # assuming skew between schedulers' clocks is not greater than 1min
    $jobqueue->search({
        action => $job_type,
        status => 'queued',
        entered => { '<' => \"(now() - interval '1 minute')" },
    })->delete;

    # is scuppered by any user job submitted in last 1min (bad), or
    # any similar job from another scheduler (good)
    $jobqueue->populate([
      map {{
          device => $_,
          action => $job_type,
          status => 'queued',
      }} ($devices->all)
    ]);
  });

  return job_done("Queued $job_type job for all devices");
}

sub _single_body {
  my ($self, $job_type, $job) = @_;

  my $action_method = $job_type .'_action';
  my $job_action = $self->$action_method;

  my $layer_method = $job_type .'_layer';
  my $job_layer = $self->$layer_method;

  my $host = NetAddr::IP::Lite->new($job->device);
  my $device = get_device($host->addr);

  if ($device->in_storage
      and $device->vendor and $device->vendor eq 'netdisco') {
      return job_done("Skipped $job_type for pseudo-device $host");
  }

  my $snmp = snmp_connect($device);
  if (!defined $snmp) {
      return job_error("$job_type failed: could not SNMP connect to $host");
  }

  unless ($snmp->has_layer( $job_layer )) {
      return job_done("Skipped $job_type for device $host without OSI layer $job_layer capability");
  }

  $job_action->($device, $snmp);

  return job_done("Ended $job_type for ". $host->addr);
}

1;