#!/usr/bin/perl --

use NetSNMP::ASN qw(ASN_OCTET_STR);
use NetSNMP::OID (':all');
use NetSNMP::agent(':all');
use NetSNMP::ASN(':all');
use DBI;
use Log::Logger;


$lh = new Log::Logger;

my $dsn  = "DBI:mysql:host=127.0.0.1;port=3306";
my $user = "root";
my $pass = "SK8Yyr9t";

my $LOGFILE = "/var/log/subagentx.log";

# set to 1 to get extra debugging information
my $DEBUGLEVEL = 4;

$subagent  = 0;

$refresh_interval    = 30;

$global_status       = ();
$global_last_refresh = 0;

###
### Called automatically now and then
### Refreshes the $global_status and $global_variables
### caches.
###

$lh->open_append("$LOGFILE");

sub refresh_status {
  my $now = time();

  # Check if we have been called quicker than once every $refresh_interval
  if (($now - $global_last_refresh) < $refresh_interval) {
    # if yes, do not do anything
    # print STDERR "Not refreshing\n" if ($debugging);
    $lh->log_print("Not refreshing\n");
    return;
  }

  # Connect database
  my $dbh = DBI->connect($dsn, $user, $pass);
  my $cmd = "show /*!50002 GLOBAL */ status";

  # Get status info
  my $sth = $dbh->prepare($cmd);
  $sth->execute();

  # 'status_data' becomes mysqlStatusData
  my $oldname = "";
  while (my $ref = $sth->fetchrow_hashref()) {
    my $name = $ref->{'Variable_name'};

    $name =~ s!_(.)!\U\1\E!g;
    $name = "mysql$name";
    $global_status{$name}{'value'}   = $ref->{'Value'};
    $global_status{$oldname}{'next'} = $name if ($oldname ne "");
    $oldname = $name;
  }

  # No next for the last
  $global_status{$name}{'next'} = '';

  # Fixes
  $global_status{'mysqlMIB'}{'value'} = "0";
  $global_status{'mysqlMIB'}{'next'}  = "mysqlMIBOBjects";

  $global_status{'mysqlMIBObjects'}{'value'} = "0";
  $global_status{'mysqlMIBObjects'}{'next'}  = "mysqlStatus";

  $global_status{'mysqlStatus'}{'value'} = "0";
  $global_status{'mysqlStatus'}{'next'}  = "mysqlAbortedClients";

  $dbh->disconnect();
  $global_last_refresh = $now;
  $lh->log_print("Refreshed at $now ", time()-$now, "\n");
  # print STDERR "Refreshed at $now ", time()-$now, "\n" if ($debugging);

  return;
}

my $regOID = new NetSNMP::OID("mysqlMIB");

if (!$agent) {
    $agent = new NetSNMP::agent('Name' => 'mysql_snmp', # reads mysqlsnmp.conf
                                'AgentX' => 1);         # make us a subagent
    $subagent = 1;
    # print STDERR "started us as a subagent ($agent)\n" if ($debugging);
    $lh->log_print("started us as a subagent ($agent)\n");
}

$agent->register("mysql_snmp", $regOID, &mysql_snmp_handler);

if ($subagent) {
    # We need to perform a loop here waiting for snmp requests.  We
    # also check for new STATUS data.
    $SIG{'INT'} = &shut_it_down;
    $SIG{'QUIT'} = &shut_it_down;
    $running = 1;
    while($running) {
        refresh_status();
        $agent->agent_check_and_process(1);  # 1 = block
    }
    $agent->shutdown();
}

sub shut_it_down {
  $running = 0;
  $lh->log_print("shutting down\n");
  #print STDERR "shutting down\n" if ($debugging);
}

sub mysql_snmp_handler {
  my ($handler, $registration_info, $request_info, $requests ) = @_;
  my ($request);

  # print STDERR "refs: ",join(", ", ref($handler), ref($registration_info), ref($request_info), ref($requests)),"\n" if ($debugging);
  $lh->log_print("refs: ",join(", ", ref($handler), ref($registration_info), ref($request_info), ref($requests)),"\n");

  for ($request = $requests; $request; $request = $request->next()) {
    # Process request for $oid (e.g. mysqlUptime)
    my $oid  = $request->getOID();
    my $mode = $request_info->getMode();
    my $value;
    my $next;

    # print STDERR "- asking for oid $oid (mode $mode)\n" if ($debugging);
    $lh->log_print(" - asking for oid $oid (mode $mode)\n");

    if ($mode == MODE_GET) {
      $value = $global_status{$oid}{'value'};
      $request->setValue(ASN_OCTET_STR, "$value");
      # print STDERR " - GET handling ($oid = $value)\n" if ($debugging);
      $lh->log_print(" - GET handling ($oid = $value)\n");
    }

    if ($mode == MODE_GETNEXT) {
      $next  = $global_status{$oid}{'next'};

      if ($next ne "") {
        $value = $global_status{$next}{'value'};

        $request->setOID($next);
        $request->setValue(ASN_OCTET_STR, "$value");
      } else {
        $request->setOID($oid);
      }
      # print STDERR " - GETNEXT handling ($oid: $next = $value)\n" if ($debugging);
      $lh->log_print(" - GETNEXT handling ($oid: $next = $value)\n");
    }
  }
  #print STDERR "- finished processing\n" if ($debugging);
  $lh->log_print(" - finished processing\n");
}

