Skip to content

Instantly share code, notes, and snippets.

@ctalkington
Last active March 21, 2020 09:27
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctalkington/5130513 to your computer and use it in GitHub Desktop.
Save ctalkington/5130513 to your computer and use it in GitHub Desktop.
Observium BIND Unix Agent

Observium BIND 9.6 Unix Agent

This collection of scripts is designed for BIND 9.6+ and the SVN version of Observium. Only tested on one machine at this point in time so YMMV.

Files

  • agent-local -> scripts/agent-local/bind
  • app-bind.inc.php -> html/pages/device/apps/bind.inc.php
  • graph-bind_queries.inc.php -> html/includes/graphs/application/bind_queries.inc.php
  • graph-bind_queries_by_type.inc.php -> html/includes/graphs/application/bind_queries_by_type.inc.php
  • poller-bind.inc.php -> includes/polling/applications/bind.inc.php
#!/usr/bin/env perl
# BIND 9.6+ Unix Agent for Observium
# Inspired by script found at http://www.packetmischief.ca/monitoring-bind9/
my $DEBUG = 0; # Value greater than 0 sets debug mode. Useful for testing (not for production).
my $stats_file = "/var/named/data/named_stats.txt";
my $stats_tmp_file = "/tmp/named_stats.txt";
my $stats_cmd = "rndc stats";
# --- DO NOT EDIT BENEATH THIS LINE --- #
use strict;
use File::Copy;
my $prefix;
my $view;
my $item;
my $cnt;
my $go = 0;
sub debug($) {
my $errMsg = shift;
if ($DEBUG > 0) {
print "$errMsg\n";
}
exit(0);
}
unlink($stats_tmp_file);
if (-e $stats_file) {
move($stats_file, $stats_tmp_file) or debug("Error moving $stats_file: ". $!);
}
system($stats_cmd);
if ($? == -1) {
print "Error running $stats_cmd: $!";
}
open(SF, $stats_file) or debug("Error opening $stats_file: ". $!);
print "<<<app-bind>>>\n";
while (<SF>) {
chomp;
# +++ Statistics Dump +++ (1293358206)
if (m/^\+\+\+ Statistics Dump \+\+\+ \((\d+)\)/) {
$go++;
}
next unless $go;
# ++ Incoming Requests ++
# ++ Socket I/O Statistics ++
if (m/^\+\+ ([^+]+) \+\+$/) {
($prefix = lc $1) =~ s/\s/_/g;
$view = $item = $cnt = "";
}
# [View: custom_view_name]
# we ignore the view name "default" so that the word "default" is not
# inserted into the output.
if (m/^\[View: (\w+)(| .*)\]/) {
next if $1 eq "default";
$view = $1;
}
# 407104 QUERY
# 3379 EDNS(0) query failures
# 134 queries with RTT < 10ms
if (m/^\s+(\d+) ([^\n]+)/) {
($cnt = lc $1) =~ s/\s/_/g;
($item = lc $2) =~ s/\s/_/g;
if ($view) {
print "$prefix\+$view:$item=$cnt\n";
} else {
print "$prefix:$item=$cnt\n";
}
}
}
close(SF);
if (-e $stats_tmp_file) {
move($stats_tmp_file, $stats_file) or debug("Error moving $stats_tmp_file: ". $!);
}
<?php
global $config;
$graphs = array(
'bind_queries' => 'Total UDP/TCP Queries and Answers',
'bind_queries_by_type' => 'Total UDP/TCP Queries by Record Type',
);
foreach ($graphs as $key => $text) {
$graph_type = $key;
$graph_array['to'] = $config['time']['now'];
$graph_array['id'] = $app['app_id'];
$graph_array['type'] = "application_$key";
printf('<h3>%s</h3><tr bgcolor="%s"><td colspan=5>', $text, $row_colour);
include('includes/print-graphrow.inc.php');
echo '</td></tr>';
}
<?php
include('includes/graphs/common.inc.php');
$rrd_filename = $config['rrd_dir'] . '/' . $device['hostname'] . '/app-bind-' . $app['app_id'] . '.rrd';
$scale_min = 0;
$colours = 'mixed';
$nototal = ($width < 224);
$unit_text = ' ';
$array = array(
'qry_requests' => array(
'descr' => 'IPv4 Queries'
),
'qry_requests6' => array(
'descr' => 'IPv6 Queries'
),
'qry_responses' => array(
'descr' => 'Answers'
)
);
$i = 0;
if (is_file($rrd_filename)) {
foreach ($array as $ds => $vars) {
$rrd_list[$i] = $vars;
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['ds'] = $ds;
$i++;
}
$rrd_options .= " DEF:qry_requests=$rrd_filename:qry_requests:AVERAGE";
$rrd_options .= " DEF:qry_requests4=$rrd_filename:qry_requests4:AVERAGE";
$rrd_options .= " DEF:qry_requests6=$rrd_filename:qry_requests6:AVERAGE";
$rrd_options .= " DEF:qry_responses=$rrd_filename:qry_responses:AVERAGE";
$rrd_options .= " CDEF:qry_responses_n=qry_responses,-1,*";
$rrd_options .= " COMMENT:' Current Average Maximum\\n'";
$rrd_options .= " AREA:qry_requests4#AF63AF:'Queries v4'";
$rrd_options .= " GPRINT:qry_requests4:LAST:%6.2lf";
$rrd_options .= " GPRINT:qry_requests4:AVERAGE:%6.2lf";
$rrd_options .= " GPRINT:qry_requests4:MAX:%6.2lf\\\\n";
$rrd_options .= " AREA:qry_requests6#CDEB8B:'Queries v6':STACK";
$rrd_options .= " GPRINT:qry_requests6:LAST:%6.2lf";
$rrd_options .= " GPRINT:qry_requests6:AVERAGE:%6.2lf";
$rrd_options .= " GPRINT:qry_requests6:MAX:%6.2lf\\\\n";
$rrd_options .= " AREA:qry_responses_n#C3D9FF:'Answers '";
$rrd_options .= " GPRINT:qry_responses:LAST:%6.2lf";
$rrd_options .= " GPRINT:qry_responses:AVERAGE:%6.2lf";
$rrd_options .= " GPRINT:qry_responses:MAX:%6.2lf\\\\n";
$rrd_options .= " LINE1.25:qry_requests#9DaB6B:";
$rrd_options .= " LINE1.25:qry_responses_n#93a6eF:";
} else {
echo "file missing: $file";
}
//include("includes/graphs/generic_multi_line.inc.php");
//include("includes/graphs/generic_multi_simplex_seperated.inc.php");
<?php
include('includes/graphs/common.inc.php');
$rrd_filename = $config['rrd_dir'] . '/' . $device['hostname'] . '/app-bind-' . $app['app_id'] . '.rrd';
$bind_data_points = array();
$bind_rr_types = array(
'A',
'A6',
'ANY',
'AAAA',
'CNAME',
'DNSKEY',
'DS',
'KEY',
'MX',
'NS',
'NSEC',
'PTR',
'RRSIG',
'SOA',
'SPF',
'SRV',
'TXT'
);
$scale_min = 0;
$colours = 'mixed';
$nototal = ($width < 224);
$unit_text = 'Type';
foreach ($bind_rr_types as $type) {
$key = strtolower("qry_type_{$type}");
$bind_data_points[$key] = array(
'descr' => $type
);
}
$i = 0;
if (is_file($rrd_filename)) {
foreach ($bind_data_points as $ds => $vars) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $vars['descr'];
$rrd_list[$i]['ds'] = $ds;
$i++;
}
} else {
echo "file missing: $file";
}
include("includes/graphs/generic_multi_simplex_seperated.inc.php");
<?php
if (!empty($agent_data['app']['bind'])) {
$rrd_filename = $config['rrd_dir'] . '/' . $device['hostname'] . '/app-bind-' . $app['app_id'] . '.rrd';
$bind_data = array();
$bind_data_values = array();
$bind_rr_types = array(
'A',
'A6',
'ANY',
'AAAA',
'CNAME',
'DNSKEY',
'DS',
'KEY',
'MX',
'NS',
'NSEC',
'PTR',
'RRSIG',
'SOA',
'SPF',
'SRV',
'TXT'
);
$bind_data_keys = array(
'incoming_requests:query' => 'qry_requests',
'name_server_statistics:ipv4_requests_received' => 'qry_requests4',
'name_server_statistics:ipv6_requests_received' => 'qry_requests6',
'name_server_statistics:responses_sent' => 'qry_responses',
'name_server_statistics:queries_dropped' => 'qry_dropped', // unsure on key
'name_server_statistics:queries_duplicate' => 'qry_duped', // unsure on key
'name_server_statistics:auth_queries_rejected' => 'qry_rej_auth',
'name_server_statistics:recursive_queries_rejected' => 'qry_rej_recursive',
'name_server_statistics:queries_caused_recursion' => 'qry_res_recursive',
'name_server_statistics:queries_resulted_in_successful_answer' => 'qry_res_success',
'name_server_statistics:queries_resulted_in_authoritative_answer' => 'qry_res_authr',
'name_server_statistics:queries_resulted_in_non_authoritative_answer' => 'qry_res_nonauthr',
'name_server_statistics:queries_resulted_in_referral_answer' => 'qry_res_referral', // unsure on key
'name_server_statistics:queries_resulted_in_nxrrset' => 'qry_res_nxrrset',
'name_server_statistics:queries_resulted_in_srvfail' => 'qry_res_srvfail', // unsure on key
'name_server_statistics:queries_resulted_in_formerr' => 'qry_res_formerr', // unsure on key
'name_server_statistics:queries_resulted_in_nxdomain' => 'qry_res_nxdomain'
);
foreach (explode("\n", $agent_data['app']['bind']) as $line) {
list($key, $value) = explode('=', $line, 2);
$bind_data[$key] = $value;
}
foreach ($bind_data_keys as $key => $dummy) {
$bind_data_values[] = (is_numeric($bind_data[$key]) ? $bind_data[$key] : 'U');
}
foreach ($bind_rr_types as $type) {
$in_key = strtolower("incoming_queries:$type");
$bind_data_values[] = (is_numeric($bind_data[$in_key]) ? $bind_data[$in_key] : 'U');
}
if (!is_file($rrd_filename)) {
$structure = array(
'DS:qry_requests:DERIVE:600:0:125000000000',
'DS:qry_requests4:DERIVE:600:0:125000000000',
'DS:qry_requests6:DERIVE:600:0:125000000000',
'DS:qry_responses:DERIVE:600:0:125000000000',
'DS:qry_dropped:DERIVE:600:0:125000000000',
'DS:qry_duped:DERIVE:600:0:125000000000',
'DS:qry_rej_auth:DERIVE:600:0:125000000000',
'DS:qry_rej_recursive:DERIVE:600:0:125000000000',
'DS:qry_res_recursive:DERIVE:600:0:125000000000',
'DS:qry_res_success:DERIVE:600:0:125000000000',
'DS:qry_res_authr:DERIVE:600:0:125000000000',
'DS:qry_res_nonauthr:DERIVE:600:0:125000000000',
'DS:qry_res_referral:DERIVE:600:0:125000000000',
'DS:qry_res_nxrrset:DERIVE:600:0:125000000000',
'DS:qry_res_srvfail:DERIVE:600:0:125000000000',
'DS:qry_res_formerr:DERIVE:600:0:125000000000',
'DS:qry_res_nxdomain:DERIVE:600:0:125000000000'
);
foreach ($bind_rr_types as $type) {
$type = strtolower($type);
$structure[] = 'DS:qry_type_' . $type . ':DERIVE:600:0:125000000000';
}
rrdtool_create($rrd_filename, '--step 300 ' . implode(' ', $structure) . ' ' . $config['rrd_rra']);
}
rrdtool_update($rrd_filename, 'N:' . implode(':', $bind_data_values));
}
@ColoEnzo
Copy link

trying it out now on a Observium with 4 servers

@ColoEnzo
Copy link

it works! Thanks.
I had to do a lot of configuration for Bind, I use a Virtualmin setup.
But it all works now, thanks!!!!!!!!!!!!!!!!!!!!

@jungletiger
Copy link

I have this working out of the box (other than closing each file with '?>' as needed) on CentOS 6.X X86_64 and I686, running ISPConfig BIND setup. I have 6 total boxes running and working well. Forgot to mention I added the needed line in unix-agent.inc.php

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment