Updated script for Zabbix v3 support

This commit is contained in:
Ryan Armstrong 2016-08-08 17:55:05 +08:00
parent 7d293da3fc
commit 2ac32ded1a
2 changed files with 144 additions and 268 deletions

View file

@ -1,27 +1,23 @@
# mib2zabbix # mib2zabbix
This Perl script will generate a Zabbix Template in XML format from an OID tree This Perl script will generate a Zabbix v3 Template in XML format from an OID
in a SNMP MIB file. tree in a SNMP MIB file.
### Usage ### Usage
mib2zabbix.pl [ -l | -t ] -o <OID> [OPTIONS]... mib2zabbix.pl -o <OID> [OPTIONS]...
Export loaded SNMP MIB OIDs to Zabbix Template XML Export loaded SNMP MIB OIDs to Zabbix Template XML
--export-maps export value maps directly to Zabbix database
-t, --template generate a Zabbix template
-f, --filename=PATH output filename (default: stdout) -f, --filename=PATH output filename (default: stdout)
-N, --name=STRING template name (default: OID label) -N, --name=STRING template name (default: OID label)
-G, --group=STRING template group (default: 'Templates') -G, --group=STRING template group (default: 'Templates')
-e, --enable-items enable template items (default: disabled) -e, --enable-items enable all template items (default: disabled)
* enable with caution *
-o, --oid=STRING OID tree root to export -o, --oid=STRING OID tree root to export (must start with '.')
-v, --snmpver=1|2|3 SNMP version (default: 1) -v, --snmpver=1|2|3 SNMP version (default: 2)
-p, --port=PORT SNMP UDP port number (default: 161) -p, --port=PORT SNMP UDP port number (default: 161)
SNMP Version 1 or 2c specific SNMP Version 1 or 2c specific
@ -38,16 +34,19 @@ in a SNMP MIB file.
-x, --privacy=PROTOCOL privacy protocol (DES|AES) -x, --privacy=PROTOCOL privacy protocol (DES|AES)
-X, --privpass=PASSPHRASE privacy passphrase -X, --privpass=PASSPHRASE privacy passphrase
--check-delay=SECONDS check interval in seconds (default: 300) Zabbix item configuration
--disc-delay=SECONDS discovery interval in seconds (default: 86400)
--history=DAYS history retention in days (default: 365) --check-delay=SECONDS check interval in seconds (default: 60)
--trends=DAYS trends retention in days (default: 3650) --disc-delay=SECONDS discovery interval in seconds (default: 3600)
--history=DAYS history retention in days (default: 7)
--trends=DAYS trends retention in days (default: 365)
-h, --help print this message -h, --help print this message
### Requirements ### Requirements
* Perl v5+ * Zabbix v3+
* Perl v5
* Pod::Usage * Pod::Usage
* XML::Simple * XML::Simple
* Net-SNMP * Net-SNMP
@ -55,11 +54,14 @@ in a SNMP MIB file.
### Translations ### Translations
This table describes how MIB elements are translated into Zabbix template
elements:
* Scalar OID -> Zabbix SNMP Item * Scalar OID -> Zabbix SNMP Item
* Table OID -> Zabbix SNMP Discovery Rule * Table OID -> Zabbix SNMP Discovery Rule
* Table Column OID -> Zabbix Discovery Prototype * Table Column OID -> Zabbix Discovery Prototype
* Trap/Notification OID -> Zabbix SNMP Trap Item * Trap/Notification OID -> Zabbix SNMP Trap Item
* OID Enums -> Zabbix Value Map * OID Enums -> Zabbix Value Maps
### License ### License

View file

@ -1,4 +1,4 @@
#!/usr/bin/perl -w #!/usr/bin/perl
=pod =pod
=head1 NAME =head1 NAME
@ -7,23 +7,19 @@ mib2zabbix.pl - SNMP MIB to Zabbix Template
=head1 SYNOPSIS =head1 SYNOPSIS
mib2zabbix.pl [ -l | -t ] -o <OID> [OPTIONS]... mib2zabbix.pl -o <OID> [OPTIONS]...
Export loaded SNMP MIB OIDs to Zabbix Template XML Export loaded SNMP MIB OIDs to Zabbix Template XML
--export-maps export value maps directly to Zabbix database
-t, --template generate a Zabbix template
-f, --filename=PATH output filename (default: stdout) -f, --filename=PATH output filename (default: stdout)
-N, --name=STRING template name (default: OID label) -N, --name=STRING template name (default: OID label)
-G, --group=STRING template group (default: 'Templates') -G, --group=STRING template group (default: 'Templates')
-e, --enable-items enable template items (default: disabled) -e, --enable-items enable all template items (default: disabled)
* enable with caution *
-o, --oid=STRING OID tree root to export -o, --oid=STRING OID tree root to export (must start with '.')
-v, --snmpver=1|2|3 SNMP version (default: 1) -v, --snmpver=1|2|3 SNMP version (default: 2)
-p, --port=PORT SNMP UDP port number (default: 161) -p, --port=PORT SNMP UDP port number (default: 161)
SNMP Version 1 or 2c specific SNMP Version 1 or 2c specific
@ -40,10 +36,12 @@ SNMP Version 3 specific
-x, --privacy=PROTOCOL privacy protocol (DES|AES) -x, --privacy=PROTOCOL privacy protocol (DES|AES)
-X, --privpass=PASSPHRASE privacy passphrase -X, --privpass=PASSPHRASE privacy passphrase
--check-delay=SECONDS check interval in seconds (default: 300) Zabbix item configuration
--disc-delay=SECONDS discovery interval in seconds (default: 86400)
--history=DAYS history retention in days (default: 365) --check-delay=SECONDS check interval in seconds (default: 60)
--trends=DAYS trends retention in days (default: 3650) --disc-delay=SECONDS discovery interval in seconds (default: 3600)
--history=DAYS history retention in days (default: 7)
--trends=DAYS trends retention in days (default: 365)
-h, --help print this message -h, --help print this message
@ -52,19 +50,7 @@ SNMP Version 3 specific
B<mib2zabbix.pl> will export a loaded MIB tree into a Zabbix Template starting B<mib2zabbix.pl> will export a loaded MIB tree into a Zabbix Template starting
from the OID root specified. from the OID root specified.
Requires: Perl v5+, Pod::Usage, XML::Simple, Net-SNMP Requires: Zabbix v3, Perl v5, Pod::Usage, XML::Simple, Net-SNMP
=head1 NOTES
Value mappings query:
SELECT * FROM valuemaps JOIN mappings ON mappings.valuemapid = valuemaps.valuemapid
Delete Value Maps and linked mappings:
DELETE FROM valuemaps USING mappings WHERE mappings.valuemapid = valuemaps.valuemapid AND valuemaps.name LIKE 'SEARCH%';
=head1 BUGS
- Table indexes not found in iso.org.dod.internet.mgmt.mib-2.host (.1.3.6.1.2.1.25)
=head1 AUTHOR =head1 AUTHOR
@ -75,7 +61,8 @@ Ryan Armstrong <ryan@cavaliercoder.com>
Guidelines for Authors and Reviewers of MIB Documents Guidelines for Authors and Reviewers of MIB Documents
https://www.ietf.org/rfc/rfc4181.txt https://www.ietf.org/rfc/rfc4181.txt
Next Generation Structure of Management Information (SMIng) Mappings to the Simple Network Management Protocol (SNMP) Next Generation Structure of Management Information (SMIng) Mappings to the
Simple Network Management Protocol (SNMP)
https://tools.ietf.org/html/rfc3781 https://tools.ietf.org/html/rfc3781
SNMP Table Basics SNMP Table Basics
@ -91,7 +78,6 @@ use warnings;
use Cwd 'abs_path'; use Cwd 'abs_path';
use Data::Dumper; use Data::Dumper;
use Date::Format; use Date::Format;
use DBI;
use Encode qw(decode encode); use Encode qw(decode encode);
use File::Basename; use File::Basename;
use Pod::Usage; use Pod::Usage;
@ -104,10 +90,10 @@ use constant SCRIPT_NAME => basename($0);
use constant BASE_PATH => dirname(abs_path($0)); use constant BASE_PATH => dirname(abs_path($0));
use constant ZBX_SERVER_CONF => '/etc/zabbix/zabbix_server.conf'; use constant ZBX_SERVER_CONF => '/etc/zabbix/zabbix_server.conf';
use constant ZBX_WEB_CONF => '/usr/share/zabbix/conf/zabbix.conf.php'; use constant ZBX_WEB_CONF => '/etc/zabbix/web/zabbix.conf.php';
# For Zabbix type constants see: # For Zabbix type constants see:
# https://www.zabbix.com/documentation/2.2/manual/api/reference/item/object # https://www.zabbix.com/documentation/3.0/manual/api/reference/item/object
# Zabbix Item status # Zabbix Item status
use constant ZBX_ITEM_ENABLED => 0; use constant ZBX_ITEM_ENABLED => 0;
use constant ZBX_ITEM_DISABLED => 1; use constant ZBX_ITEM_DISABLED => 1;
@ -141,23 +127,23 @@ use constant ZBX_V3_SEC_AUTHPRIV => 2;
# SNMP Type -> Zabbix type mapping # SNMP Type -> Zabbix type mapping
my $type_map = { my $type_map = {
BITS => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type 'BITS' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type
COUNTER => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'COUNTER' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
COUNTER32 => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'COUNTER32' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
COUNTER64 => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'COUNTER64' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
GAUGE => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'GAUGE' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
GAUGE32 => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'GAUGE32' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
INTEGER => ZBX_VAL_TYPE_FLOAT, # Zabbix 'Numeric Float' value type for an signed integer 'INTEGER' => ZBX_VAL_TYPE_FLOAT, # Zabbix 'Numeric Float' value type for an signed integer
INTEGER32 => ZBX_VAL_TYPE_FLOAT, # Zabbix 'Numeric Float' value type for an signed 32 bit integer 'INTEGER32' => ZBX_VAL_TYPE_FLOAT, # Zabbix 'Numeric Float' value type for an signed 32 bit integer
IPADDR => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for an IP address 'IPADDR' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for an IP address
NETADDDR => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for a network address 'NETADDDR' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for a network address
NOTIF => ZBX_ITEM_TYPE_SNMPTRAP, # Zabbix 'SNMP Trap' item type 'NOTIF' => ZBX_ITEM_TYPE_SNMPTRAP, # Zabbix 'SNMP Trap' item type
'TRAP' => ZBX_ITEM_TYPE_SNMPTRAP, # Zabbix 'SNMP Trap' item type 'TRAP' => ZBX_ITEM_TYPE_SNMPTRAP, # Zabbix 'SNMP Trap' item type
OBJECTID => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for an OID 'OBJECTID' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for an OID
OCTETSTR => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type 'OCTETSTR' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type
OPAQUE => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type 'OPAQUE' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type
TICKS => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' for a Module 232 timestamp 'TICKS' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' for a Module 232 timestamp
UNSIGNED32 => ZBX_VAL_TYPE_UINT # Zabbix 'Numeric Unsigned' value type for an unsigned 32bit integer 'UNSIGNED32' => ZBX_VAL_TYPE_UINT # Zabbix 'Numeric Unsigned' value type for an unsigned 32bit integer
}; };
# SNMP Version -> Zabbix item type mapping # SNMP Version -> Zabbix item type mapping
@ -186,19 +172,19 @@ my $snmpv3_sec_protocol_map = {
# Default command line options # Default command line options
my $opts = { my $opts = {
delay => 300, # 5 minute check interval delay => 60, # 1 minute check interval
disc_delay => 3600, # Hourly discovery disc_delay => 3600, # Hourly discovery
enableitems => 0, # Disable items enableitems => 0, # Disable items
group => 'Templates', group => 'Templates',
history => 365, history => 7,
trends => 3650, trends => 365,
list => 0, list => 0,
maxdepth => -1, maxdepth => -1,
oid => '.1', oid => '.1',
use_macros => 0, use_macros => 0,
snmpcomm => 'public', snmpcomm => 'public',
snmpport => 161, snmpport => 161,
snmpver => 1, snmpver => 2,
v3auth_level => 'noAuthNoPriv', v3auth_level => 'noAuthNoPriv',
v3context => '', v3context => '',
v3user => '', v3user => '',
@ -208,12 +194,12 @@ my $opts = {
v3sec_pass => '' v3sec_pass => ''
}; };
# Capture calling args
my $cmd = basename($0) . " @ARGV";
# Get command line options # Get command line options
Getopt::Long::Configure ("posix_default", "bundling"); Getopt::Long::Configure ("posix_default", "bundling");
GetOptions( GetOptions(
'export-maps' => \$opts->{ export_maps }, # Export value maps to database
't|template' => \$opts->{ template }, # Output an XML Template
'f|filename=s' => \$opts->{ filename }, # Filename to output 'f|filename=s' => \$opts->{ filename }, # Filename to output
'N|name=s' => \$opts->{ name }, # Template name 'N|name=s' => \$opts->{ name }, # Template name
@ -296,15 +282,20 @@ my %item_template = (
multiplier => '0', # Enable multiplier multiplier => '0', # Enable multiplier
trends => $opts->{ trends }, # Trends retention in days trends => $opts->{ trends }, # Trends retention in days
units => '', units => '',
valuemap => '' valuemap => '',
logtimefmt => '',
); );
%item_template = (%item_base_template, %item_template); %item_template = (%item_base_template, %item_template);
# Discovery rule template # Discovery rule template
my %disc_rule_template = ( my %disc_rule_template = (
delay => $opts->{ disc_delay }, delay => $opts->{ disc_delay },
filter => ':',
lifetime => '30', lifetime => '30',
filter => {
evaltype => 0,
formula => undef,
conditions => undef
},
# The following items must be created as unique refs for each item # The following items must be created as unique refs for each item
host_prototypes => [], host_prototypes => [],
@ -354,7 +345,9 @@ my %trap_template = (
); );
# Item prototype template # Item prototype template
my %item_proto_template = (); my %item_proto_template = (
application_prototypes => undef,
);
%item_proto_template = (%item_template, %item_proto_template); %item_proto_template = (%item_template, %item_proto_template);
# Global value maps array # Global value maps array
@ -477,21 +470,24 @@ sub node_to_item {
# Process value maps # Process value maps
if (scalar keys % {$node->{ enums } }) { if (scalar keys % {$node->{ enums } }) {
# Add valuemap to global list
my $map_name = "$node->{ moduleID }::$node->{ label }"; my $map_name = "$node->{ moduleID }::$node->{ label }";
# If the map_name is longer than 64 characters... # If the map_name is longer than 64 characters truncate to 64 characters
if ( length($map_name) > 64 ) { # to match maximum database field length.
if (length($map_name) > 64) {
# Truncate to 64 characters to match maximum database field length.
$map_name = substr($map_name,0,61) . "..."; $map_name = substr($map_name,0,61) . "...";
} }
# add template value map
$valuemaps->{ $map_name }->{ 'mappings' } = [];
foreach(keys %{ $node->{ enums } }) {
push(@{ $valuemaps->{ $map_name }->{ 'mappings' } }, {
'value' => $node->{ enums }->{ $_ },
'newvalue' => $_
});
}
$valuemaps->{ $map_name } = $node->{ enums }; # Assign value map to item
# Assign value map to template
$item->{ valuemap } = { name => $map_name }; $item->{ valuemap } = { name => $map_name };
} }
@ -780,123 +776,6 @@ sub build_template {
} }
} }
sub export_valuemaps {
my ($oid_root) = @_;
# Parse MIBs to get a hash of required value maps
my $template = {};
build_template($template, $oid_root, 0);
# Fetch DB connection details from Zabbix server config
my ($dbhost, $dbname, $dbschema, $dbport, $dbuser, $dbpassword);
$dbhost = 'localhost';
$dbport = 5432;
$dbname = 'zabbix';
$dbpassword = '';
if ( -e ZBX_SERVER_CONF ) {
open (FH, "<${\ZBX_SERVER_CONF}") or die ("Failed to open ${\ZBX_SERVER_CONF} for reading.");
while (my $line = <FH>) {
my ($key, $val) = ($line =~ m/^(\w*)=(.*)/);
if ($key ) {
if ($key eq 'DBHost') {
$dbhost = $val;
} elsif ($key eq 'DBName') {
$dbname = $val;
} elsif ($key eq 'DBSchema') {
$dbschema = $val;
} elsif ($key eq 'DBPort') {
$dbport = $val;
} elsif ($key eq 'DBUser') {
$dbuser = $val;
} elsif ($key eq 'DBPassword') {
$dbpassword = "$val";
}
}
}
close(FH);
} elsif( -e ZBX_WEB_CONF ) {
} else {
die("No database connection details could be obtained.");
}
# Create a connection string and connect
my $dsn = "DBI:Pg:host=$dbhost;dbname=$dbname;port=$dbport;";
my $dbh = DBI->connect($dsn, $dbuser, $dbpassword);
$dbh || die($DBI::errstr);
my $results;
# Get highest valuemap id
$results = query($dbh, 'SELECT MAX(valuemapid) AS valuemapid FROM valuemaps');
my $valuemapid = @{ $results }[0]->{ valuemapid };
# Get highest map id
$results = query($dbh, 'SELECT MAX(mappingid) AS mappingid FROM mappings');
my $mappingid = @{ $results }[0]->{ mappingid };
# Get existings valuemaps
$results = query($dbh, 'SELECT * FROM valuemaps');
my $existing_maps = {};
foreach my $valuemap(@{ $results }) {
$existing_maps->{ $valuemap->{ name } } = $valuemap->{ valuemapid };
}
# Process each map
foreach my $map_name (keys %{ $valuemaps }) {
if (defined($existing_maps->{ $map_name })) {
print STDERR "Value map '$map_name' already exists\n";
next;
}
# Insert new map
$valuemapid++;
insert($dbh, "INSERT INTO valuemaps (valuemapid, name) VALUES ($valuemapid, '$map_name')");
print ("Added Value Map '$map_name' with ID $valuemapid\n");
# Add mappings
foreach my $key (keys %{ $valuemaps->{ $map_name } }) {
my $val = $valuemaps->{ $map_name }->{ $key };
$mappingid++;
insert($dbh, "INSERT INTO mappings (mappingid, valuemapid, value, newvalue) VALUES ($mappingid, $valuemapid, $val, '$key');");
print (" - Added mapping '$key' => '$val' with ID $mappingid\n");
}
}
# Increment ids for nextid.
$valuemapid++;
$mappingid++;
# Now update the tables max ids in the ids table.
insert($dbh, "UPDATE ids SET nextid = $valuemapid WHERE table_name = 'valuemaps' AND field_name = 'valuemapid';");
insert($dbh, "UPDATE ids SET nextid = $mappingid WHERE table_name = 'mappings' AND field_name = 'mappingid';");
# Clean up
$dbh->disconnect;
}
sub query {
my ($dbh, $sql) = @_;
my @results;
my $sth = $dbh->prepare($sql);
$sth->execute();
while(my $row = $sth->fetchrow_hashref()) {
push @results, $row;
}
return \@results;
}
sub insert {
my ($dbh, $sql) = @_;
my $sth = $dbh->prepare($sql);
$sth->execute();
}
# Initialize net-snmp # Initialize net-snmp
$SNMP::save_descriptions = 1; $SNMP::save_descriptions = 1;
SNMP::initMib(); SNMP::initMib();
@ -906,20 +785,15 @@ my $oid_root = $SNMP::MIB{ $opts->{ oid } };
if (!$oid_root || $oid_root->{ objectID } ne $opts->{ oid }) { if (!$oid_root || $oid_root->{ objectID } ne $opts->{ oid }) {
print STDERR "OID $opts->{ oid } not found in MIB tree.\n"; print STDERR "OID $opts->{ oid } not found in MIB tree.\n";
exit 1; exit 1;
}
# Export value maps directly to Zabbix database
if($opts->{ export_maps }) {
export_valuemaps($oid_root);
}
# Build a Zabbix template # Build a Zabbix template
elsif ($opts->{ template }) { } else {
my $suffix = $opts->{ snmpver } > 2 ? " v$opts->{ snmpver }" : ''; my $suffix = $opts->{ snmpver } > 2 ? " v$opts->{ snmpver }" : '';
my $template_name = $opts->{ name } || "Template $oid_root->{ moduleID } - $oid_root->{ label }$suffix"; my $template_name = $opts->{ name } || "Template $oid_root->{ moduleID } - $oid_root->{ label }$suffix";
my $template = { my $template = {
name => $template_name, name => $template_name,
template => $template_name, template => $template_name,
description => "Generated by mib2zabbix",
apptags => {}, apptags => {},
applications => [], applications => [],
discovery_rules => [], discovery_rules => [],
@ -928,6 +802,7 @@ elsif ($opts->{ template }) {
}], }],
items => [], items => [],
macros => [ macros => [
{ macro => '{$MIB2ZABBIX_CMD}', value => $cmd },
{ macro => '{$OID}', value => "$oid_root->{ objectID }" }, { macro => '{$OID}', value => "$oid_root->{ objectID }" },
{ macro => '{$OID_PATH}', value => oid_path($oid_root) }, { macro => '{$OID_PATH}', value => oid_path($oid_root) },
{ macro => '{$OID_MOD}', value => $oid_root->{ moduleID } }, { macro => '{$OID_MOD}', value => $oid_root->{ moduleID } },
@ -953,12 +828,13 @@ elsif ($opts->{ template }) {
# Build XML document # Build XML document
my $time = time(); my $time = time();
my $output = { my $output = {
version => '2.0', version => '3.0',
date => time2str("%Y-%m-%dT%H:%M:%SZ", $time), date => time2str("%Y-%m-%dT%H:%M:%SZ", $time),
groups => $template->{ groups }, groups => $template->{ groups },
templates => [$template], templates => [$template],
triggers => [], triggers => [],
graphs => [] graphs => [],
value_maps => [$valuemaps]
}; };
# Output stream # Output stream
@ -984,7 +860,9 @@ elsif ($opts->{ template }) {
'item_prototypes' => 'item_prototype', 'item_prototypes' => 'item_prototype',
'trigger_prototypes' => 'trigger_prototype', 'trigger_prototypes' => 'trigger_prototype',
'graph_prototypes' => 'graph_prototype', 'graph_prototypes' => 'graph_prototype',
'host_prototypes' => 'host_prototype' 'host_prototypes' => 'host_prototype',
'value_maps' => 'value_map',
'mappings' => 'mapping'
} }
); );
@ -992,7 +870,3 @@ elsif ($opts->{ template }) {
close $fh; close $fh;
} }
} }
else {
pod2usage();
}