Update mib2zabbix.pl

Format code to align with the original
This commit is contained in:
Steven Yu 2016-08-24 15:27:44 +10:00 committed by GitHub
parent d1e1ccae28
commit 2f8de1afe9

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl #!/usr/bin/perl
=pod =pod
=head1 NAME =head1 NAME
mib2zabbix.pl - SNMP MIB to Zabbix Template mib2zabbix.pl - SNMP MIB to Zabbix Template
=head1 SYNOPSIS =head1 SYNOPSIS
mib2zabbix.pl -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
-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)
@ -24,11 +18,9 @@ Export loaded SNMP MIB OIDs to Zabbix Template XML
-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
-c, --community=STRING SNMP community string (default: 'public') -c, --community=STRING SNMP community string (default: 'public')
SNMP Version 3 specific SNMP Version 3 specific
-L, --level=LEVEL security level (noAuthNoPriv|authNoPriv|authPriv) -L, --level=LEVEL security level (noAuthNoPriv|authNoPriv|authPriv)
-n, --context=CONTEXT context name -n, --context=CONTEXT context name
-u, --username=USERNAME security name -u, --username=USERNAME security name
@ -38,11 +30,9 @@ SNMP Version 3 specific
-X, --privpass=PASSPHRASE privacy passphrase -X, --privpass=PASSPHRASE privacy passphrase
Zabbix template version Zabbix template version
-z, --zabbix_ver=2|3 Zabbix Template Schema Version (default: 3) -z, --zabbix_ver=2|3 Zabbix Template Schema Version (default: 3)
Zabbix item configuration Zabbix item configuration
--check-delay=SECONDS check interval in seconds (default: 60) --check-delay=SECONDS check interval in seconds (default: 60)
--disc-delay=SECONDS discovery interval in seconds (default: 3600) --disc-delay=SECONDS discovery interval in seconds (default: 3600)
--history=DAYS history retention in days (default: 7) --history=DAYS history retention in days (default: 7)
@ -51,43 +41,28 @@ Zabbix item configuration
Help Help
-h, --help print this message -h, --help print this message
=head1 DESCRIPTION =head1 DESCRIPTION
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: Zabbix v2.4 or 3, Perl v5, Pod::Usage, XML::Simple, Net-SNMP Requires: Zabbix v2.4 or 3, Perl v5, Pod::Usage, XML::Simple, Net-SNMP
=head1 AUTHOR =head1 AUTHOR
Ryan Armstrong <ryan@cavaliercoder.com> Ryan Armstrong <ryan@cavaliercoder.com>
Steven Yu <steven@wordofeternity.org> -- Zabbix v2.4 support Steven Yu <steven@wordofeternity.org> -- Zabbix v2.4 support
=head1 SEE ALSO =head1 SEE ALSO
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 Next Generation Structure of Management Information (SMIng) Mappings to the
Simple Network Management Protocol (SNMP) Simple Network Management Protocol (SNMP)
https://tools.ietf.org/html/rfc3781 https://tools.ietf.org/html/rfc3781
SNMP Table Basics SNMP Table Basics
http://www.webnms.com/snmp/help/snmpapi/snmpv3/table_handling/snmptables_basics.html http://www.webnms.com/snmp/help/snmpapi/snmpv3/table_handling/snmptables_basics.html
Zabbix Template Schema Zabbix Template Schema
v2.4 - https://www.zabbix.com/documentation/2.4/manual/xml_export_import/hosts v2.4 - https://www.zabbix.com/documentation/2.4/manual/xml_export_import/hosts
v3 - https://www.zabbix.com/documentation/3.0/manual/xml_export_import/hosts v3 - https://www.zabbix.com/documentation/3.0/manual/xml_export_import/hosts
=head1 SUBROUTINES =head1 SUBROUTINES
=cut =cut
use strict; use strict;
#use warnings; #use warnings;
use Cwd 'abs_path'; use Cwd 'abs_path';
@ -143,32 +118,22 @@ 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 'COUNTER' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
, # 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 'COUNTER64' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'GAUGE' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
'COUNTER64' => ZBX_VAL_TYPE_UINT 'GAUGE32' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' value type for an unsigned integer
, # Zabbix 'Numeric Unsigned' value type for an unsigned integer 'INTEGER' => ZBX_VAL_TYPE_FLOAT, # Zabbix 'Numeric Float' value type for an signed integer
'GAUGE' => ZBX_VAL_TYPE_UINT 'INTEGER32' => ZBX_VAL_TYPE_FLOAT, # Zabbix 'Numeric Float' value type for an signed 32 bit integer
, # 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
'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' => 'NETADDDR' => ZBX_VAL_TYPE_TEXT, # Zabbix 'Text' value type for a network address
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' => 'TICKS' => ZBX_VAL_TYPE_UINT, # Zabbix 'Numeric Unsigned' for a Module 232 timestamp
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
@ -249,6 +214,7 @@ GetOptions(
'z|zabbix_ver=i' => \$opts->{zabbix_ver}, # Zabbix version 'z|zabbix_ver=i' => \$opts->{zabbix_ver}, # Zabbix version
'check-delay=i' => \$opts->{ delay }, # Update interval in seconds 'check-delay=i' => \$opts->{ delay }, # Update interval in seconds
'disc-delay=i' => \$opts->{ disc_delay }, # Update interval in seconds 'disc-delay=i' => \$opts->{ disc_delay }, # Update interval in seconds
'history=i' => \$opts->{ history }, # History retention in days 'history=i' => \$opts->{ history }, # History retention in days
@ -264,19 +230,14 @@ pod2usage( { -exitval => 0 } ) if ( $opts->{help} );
if ($opts->{ snmpver } == 3) { if ($opts->{ snmpver } == 3) {
$opts->{ snmpcomm } = ''; $opts->{ snmpcomm } = '';
die("Unknown authentication level '$opts->{ v3auth_level }'") die("Unknown authentication level '$opts->{ v3auth_level }'") unless defined($snmpv3_auth_level_map->{ $opts->{ v3auth_level } });
unless defined( $snmpv3_auth_level_map->{ $opts->{v3auth_level} } );
$opts->{ v3auth_level } = $snmpv3_auth_level_map->{ $opts->{ v3auth_level } }; $opts->{ v3auth_level } = $snmpv3_auth_level_map->{ $opts->{ v3auth_level } };
die("Unknown authentical protocol '$opts->{ v3auth_protocol }'") die("Unknown authentical protocol '$opts->{ v3auth_protocol }'") unless defined($snmpv3_auth_protocol_map->{ $opts->{ v3auth_protocol } });
unless defined( $snmpv3_auth_protocol_map->{ $opts->{v3auth_protocol} } ); $opts->{ v3auth_protocol } = $snmpv3_auth_protocol_map->{ $opts->{ v3auth_protocol } };
$opts->{v3auth_protocol} =
$snmpv3_auth_protocol_map->{ $opts->{v3auth_protocol} };
die("Unknown privacy protocol '$opts->{ v3sec_protocol }'") die("Unknown privacy protocol '$opts->{ v3sec_protocol }'") unless defined ($snmpv3_sec_protocol_map->{ $opts->{ v3sec_protocol } });
unless defined( $snmpv3_sec_protocol_map->{ $opts->{v3sec_protocol} } ); $opts->{ v3sec_protocol } = $snmpv3_sec_protocol_map->{ $opts->{ v3sec_protocol } };
$opts->{v3sec_protocol} =
$snmpv3_sec_protocol_map->{ $opts->{v3sec_protocol} };
} }
# Base template for Template Items, Discovery Rules and Item Prototypes # Base template for Template Items, Discovery Rules and Item Prototypes
@ -292,26 +253,15 @@ my %item_base_template = (
port => '{$SNMP_PORT}', # Use macro for SNMP UDP Port port => '{$SNMP_PORT}', # Use macro for SNMP UDP Port
privatekey => '', privatekey => '',
publickey => '', publickey => '',
snmp_community => $opts->{snmpver} < 3 snmp_community => $opts->{ snmpver } < 3 ? '{$SNMP_COMMUNITY}' : '', # Use macro for SNMP Community string
? '{$SNMP_COMMUNITY}' snmpv3_authpassphrase => $opts->{ snmpver } == 3 ? '{$SNMP_AUTHPASS}' : '', # Use macro for SNMPv3 Authentication passphrase
: '', # Use macro for SNMP Community string snmpv3_authprotocol => $opts->{ snmpver } == 3 ? $opts->{ v3auth_protocol } : '0',
snmpv3_authpassphrase => $opts->{snmpver} == 3 snmpv3_contextname => $opts->{ snmpver } == 3 ? '{$SNMP_CONTEXT}' : '', # Use macro for SNMPv3 context name
? '{$SNMP_AUTHPASS}' snmpv3_privpassphrase => $opts->{ snmpver } == 3 ? '{$SNMP_PRIVPASS}' : '', # Use macro for SNMPv3 Privacy passphrase
: '', # Use macro for SNMPv3 Authentication passphrase snmpv3_privprotocol => $opts->{ snmpver } == 3 ? $opts->{ v3sec_protocol } : '0',
snmpv3_authprotocol => $opts->{snmpver} == 3 ? $opts->{v3auth_protocol}
: '0',
snmpv3_contextname => $opts->{snmpver} == 3 ? '{$SNMP_CONTEXT}'
: '', # Use macro for SNMPv3 context name
snmpv3_privpassphrase => $opts->{snmpver} == 3
? '{$SNMP_PRIVPASS}'
: '', # Use macro for SNMPv3 Privacy passphrase
snmpv3_privprotocol => $opts->{snmpver} == 3 ? $opts->{v3sec_protocol}
: '0',
snmpv3_securitylevel => $opts->{ snmpver } == 3 ? $opts->{ v3auth_level } : '0', snmpv3_securitylevel => $opts->{ snmpver } == 3 ? $opts->{ v3auth_level } : '0',
snmpv3_securityname => $opts->{snmpver} == 3 ? '{$SNMP_USER}' snmpv3_securityname => $opts->{ snmpver } == 3 ? '{$SNMP_USER}' : '', # Use macro for SNMPv3 Username
: '', # Use macro for SNMPv3 Username status => ($opts->{ enableitems } ? ZBX_ITEM_ENABLED : ZBX_ITEM_DISABLED), # Enabled (0) | Disabled (1)
status => ( $opts->{enableitems} ? ZBX_ITEM_ENABLED : ZBX_ITEM_DISABLED )
, # Enabled (0) | Disabled (1)
username => '', username => '',
); );
@ -342,7 +292,6 @@ my %item_template_v2 = (
inventory_link => '0', inventory_link => '0',
multiplier => '0', # Enable multiplier multiplier => '0', # Enable multiplier
trends => $opts->{ trends }, # Trends retention in days trends => $opts->{ trends }, # Trends retention in days
valuemap => '',
units => '', units => '',
); );
@ -449,21 +398,19 @@ my %trap_template_v2 = (
); );
# Item prototype template # Item prototype template
my %item_proto_template = ( application_prototypes => undef, ); 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
my $valuemaps = {}; my $valuemaps = {};
=head2 utf8_santize =head2 utf8_santize
Parameters : (string) $malformed_utf8 Parameters : (string) $malformed_utf8
Returns : (string) $wellformed_utf8 Returns : (string) $wellformed_utf8
Description : Returns a sanitized UTF8 string, removing incompatable characters Description : Returns a sanitized UTF8 string, removing incompatable characters
=cut =cut
sub utf8_sanitize { sub utf8_sanitize {
my ($malformed_utf8) = @_; my ($malformed_utf8) = @_;
@ -472,14 +419,11 @@ sub utf8_sanitize {
} }
=head2 oid_path =head2 oid_path
Parameters : SNMP::MIB::Node $oid Parameters : SNMP::MIB::Node $oid
Returns : (String) $oid_path Returns : (String) $oid_path
Description : Returns the fully qualified textual path of a MIB node by Description : Returns the fully qualified textual path of a MIB node by
traversing the node's parents. traversing the node's parents.
=cut =cut
sub oid_path { sub oid_path {
my ($oid) = @_; my ($oid) = @_;
@ -493,14 +437,11 @@ sub oid_path {
} }
=head2 node_to_item =head2 node_to_item
Parameters : SNMP::MIB::Node $node Parameters : SNMP::MIB::Node $node
(Hash) $template (Hash) $template
Returns : (Hash) $item Returns : (Hash) $item
Description : Returns a Zabbix Item hash derived from the specified MIB OID Description : Returns a Zabbix Item hash derived from the specified MIB OID
=cut =cut
sub node_to_item { sub node_to_item {
my ($node, $template) = @_; my ($node, $template) = @_;
$template = $template || \%item_template; $template = $template || \%item_template;
@ -511,53 +452,40 @@ sub node_to_item {
$item->{ name } = $node->{ label }; $item->{ name } = $node->{ label };
$item->{ snmp_oid } = $node->{ objectID }; $item->{ snmp_oid } = $node->{ objectID };
if ($node->{ units }) { if ($node->{ units }) {
# Convert unit to Zabbix postfix # Convert unit to Zabbix postfix
# See 'Units' section of https://www.zabbix.com/documentation/3.0/manual/config/items/item # See 'Units' section of https://www.zabbix.com/documentation/3.0/manual/config/items/item
if ($node->{ units } =~ /^seconds$/) { if ($node->{ units } =~ /^seconds$/) {
$item->{ units } = 's'; $item->{ units } = 's';
} } elsif ($node->{ units } =~ /^(hundreds of seconds)$/i) {
elsif ( $node->{units} =~ /^(hundreds of seconds)$/i ) {
$item->{ units } = 's'; $item->{ units } = 's';
$item->{ multiplier } = '1'; $item->{ multiplier } = '1';
$item->{ formula } = '100'; $item->{ formula } = '100';
} } elsif ($node->{ units } =~ /^(milliseconds|milli-seconds)$/i) {
elsif ( $node->{units} =~ /^(milliseconds|milli-seconds)$/i ) {
$item->{ units } = 's'; $item->{ units } = 's';
$item->{ multiplier } = '1'; $item->{ multiplier } = '1';
$item->{ formula } = '.001'; $item->{ formula } = '.001';
} } elsif ($node->{ units } =~ /^microseconds$/i) {
elsif ( $node->{units} =~ /^microseconds$/i ) {
$item->{ units } = 's'; $item->{ units } = 's';
$item->{ multiplier } = '1'; $item->{ multiplier } = '1';
$item->{ formula } = '.000001'; $item->{ formula } = '.000001';
} } elsif ($node->{ units } =~ /^(octets|bytes)$/i) {
elsif ( $node->{units} =~ /^(octets|bytes)$/i ) {
$item->{ units } = 'B'; $item->{ units } = 'B';
} } elsif ($node->{ units } =~ /^(k-octets|kbytes|kb)$/i) {
elsif ( $node->{units} =~ /^(k-octets|kbytes|kb)$/i ) {
$item->{ units } = 'B'; $item->{ units } = 'B';
$item->{ multiplier } = '1'; $item->{ multiplier } = '1';
$item->{ formula } = '.001'; $item->{ formula } = '.001';
} } elsif ($node->{ units } =~ /^(bits per second)$/i) {
elsif ( $node->{units} =~ /^(bits per second)$/i ) {
$item->{ units } = 'b'; $item->{ units } = 'b';
} } elsif ($node->{ units } =~ /^(kbps|kilobits per second)$/i) {
elsif ( $node->{units} =~ /^(kbps|kilobits per second)$/i ) {
$item->{ units } = 'b'; $item->{ units } = 'b';
$item->{ multiplier } = '1'; $item->{ multiplier } = '1';
$item->{ formula } = '.001'; $item->{ formula } = '.001';
} } elsif ($node->{ units } =~ /^percent$/i) {
elsif ( $node->{units} =~ /^percent$/i ) {
$item->{ units } = '%'; $item->{ units } = '%';
} } elsif ($node->{ units } =~ /\/s$/i) {
elsif ( $node->{units} =~ /\/s$/i ) {
# truncate /s (/sec will be added later) # truncate /s (/sec will be added later)
$item->{ units } = substr($node->{ units }, 0, -2) . "/sec"; $item->{ units } = substr($node->{ units }, 0, -2) . "/sec";
} } else {
else {
# default to original # default to original
$item->{ units } = $node->{ units }; $item->{ units } = $node->{ units };
} }
@ -576,8 +504,7 @@ sub node_to_item {
if ($node->{ type }) { if ($node->{ type }) {
$item->{ value_type } = $type_map->{ $node->{ type } }; $item->{ value_type } = $type_map->{ $node->{ type } };
if (!defined($item->{ value_type })) { if (!defined($item->{ value_type })) {
print STDERR print STDERR "No type mapping found for type $node->{ type } in $node->{ objectID }\n";
"No type mapping found for type $node->{ type } in $node->{ objectID }\n";
} }
} }
@ -587,11 +514,9 @@ sub node_to_item {
if ($item->{ units } =~ /^s$/) { if ($item->{ units } =~ /^s$/) {
$item->{ units } = '/sec'; $item->{ units } = '/sec';
} } elsif ($item->{ units } =~ /^b$/i) {
elsif ( $item->{units} =~ /^b$/i ) {
$item->{ units } .= 'ps'; $item->{ units } .= 'ps';
} } else {
else {
$item->{ units } .= '/sec'; $item->{ units } .= '/sec';
} }
} }
@ -606,8 +531,7 @@ sub node_to_item {
# Parse item desciption # Parse item desciption
$item->{ description } = utf8_sanitize($node->{ description }); $item->{ description } = utf8_sanitize($node->{ description });
if ($item->{ description }) { if ($item->{ description }) {
$item->{description} =~ $item->{ description } =~ s/^\s+|\s+$|\n//g; # Trim left/right whitespace and newlines
s/^\s+|\s+$|\n//g; # Trim left/right whitespace and newlines
$item->{ description } =~ s/\s{2,}/ /g; # Remove padding $item->{ description } =~ s/\s{2,}/ /g; # Remove padding
} }
@ -622,16 +546,13 @@ sub node_to_item {
$map_name = substr($map_name,0,61) . "..."; $map_name = substr($map_name,0,61) . "...";
} }
# add template value map for Zabbix version 3 # add template value map
$valuemaps->{ $map_name }->{ 'mappings' } = []; $valuemaps->{ $map_name }->{ 'mappings' } = [];
foreach(keys %{ $node->{ enums } }) { foreach(keys %{ $node->{ enums } }) {
push( push(@{ $valuemaps->{ $map_name }->{ 'mappings' } }, {
@{ $valuemaps->{$map_name}->{'mappings'} },
{
'value' => $node->{ enums }->{ $_ }, 'value' => $node->{ enums }->{ $_ },
'newvalue' => $_ 'newvalue' => $_
} });
);
} }
# Assign value map to item # Assign value map to item
@ -643,22 +564,18 @@ sub node_to_item {
# Assign value map to item # Assign value map to item
$item->{valuemap} = { name => $map_name }; $item->{valuemap} = { name => $map_name };
} }
} }
return $item; return $item;
} }
=head2 node_to_trapitem =head2 node_to_trapitem
Parameters : SNMP::MIB::Node $node Parameters : SNMP::MIB::Node $node
(Hash) $template (Hash) $template
Returns : (Hash) $item Returns : (Hash) $item
Description : Returns a Zabbix SNMP Trap Item hash derived from the Description : Returns a Zabbix SNMP Trap Item hash derived from the
specified MIB OID specified MIB OID
=cut =cut
sub node_to_trapitem { sub node_to_trapitem {
my ($node, $template) = @_; my ($node, $template) = @_;
@ -714,14 +631,11 @@ sub node_to_trapitem {
if ($varbind->{ description }) { if ($varbind->{ description }) {
my $vbdesc = $varbind->{ description }; my $vbdesc = $varbind->{ description };
$vbdesc =~ $vbdesc =~ s/[ \t]+/ /g; # Replace long whitespace with single space
s/[ \t]+/ /g; # Replace long whitespace with single space $vbdesc =~ s/^ ?/ /mg; # Prepend indent to each description line
$vbdesc =~
s/^ ?/ /mg; # Prepend indent to each description line
$desc .= "$vbdesc\n\n"; $desc .= "$vbdesc\n\n";
} }
} } else {
else {
$desc .= "\n"; $desc .= "\n";
} }
} }
@ -732,29 +646,25 @@ sub node_to_trapitem {
} }
=head2 node_is_current =head2 node_is_current
Parameters : SNMP::MIB::Node $node Parameters : SNMP::MIB::Node $node
Returns : (int) 0|1 Returns : (int) 0|1
Description : Returns true if the specified OID is not obsolete Description : Returns true if the specified OID is not obsolete
=cut =cut
sub node_is_current { sub node_is_current {
my ($node) = @_; my ($node) = @_;
return ( node_is_valid_trap($node) return (
|| ( defined( $node->{status} ) && $node->{status} ne 'Obsolete' ) ); node_is_valid_trap($node)
|| (defined($node->{ status }) && $node->{ status } ne 'Obsolete')
);
} }
=head2 node_is_valid_scalar =head2 node_is_valid_scalar
Parameters : SNMP::MIB::Node $node Parameters : SNMP::MIB::Node $node
Returns : (int) 0|1 Returns : (int) 0|1
Description : Returns true if the specified OID is current, readable and Description : Returns true if the specified OID is current, readable and
defines a valid value type. defines a valid value type.
=cut =cut
sub node_is_valid_scalar { sub node_is_valid_scalar {
my ($node) = @_; my ($node) = @_;
@ -762,40 +672,33 @@ sub node_is_valid_scalar {
node_is_current($node) node_is_current($node)
&& $node->{ type } && $node->{ type }
&& ( && (
$node->{type} eq 'NOTIF' $node->{ type } eq 'NOTIF' || $node->{ type } eq 'TRAP'
|| $node->{type} eq 'TRAP' || ($node->{ access } eq 'ReadOnly' || $node->{ access } eq 'ReadWrite')
|| ( $node->{access} eq 'ReadOnly'
|| $node->{access} eq 'ReadWrite' )
) )
); );
} }
=head2 node_is_valid_trap =head2 node_is_valid_trap
Parameters : SNMP::MIB::Node $node Parameters : SNMP::MIB::Node $node
Returns : (int) 0|1 Returns : (int) 0|1
Description : Returns true if the specified OID is an SNMP Trap Description : Returns true if the specified OID is an SNMP Trap
=cut =cut
sub node_is_valid_trap { sub node_is_valid_trap {
my ($node) = @_; my ($node) = @_;
return ( defined( $node->{type} ) return (
&& ( $node->{type} eq 'NOTIF' || $node->{type} eq 'TRAP' ) ); defined($node->{ type }) && ($node->{ type } eq 'NOTIF' || $node->{ type } eq 'TRAP')
);
} }
=head2 node_is_valid_table =head2 node_is_valid_table
Parameters : SNMP::MIB::Node $node Parameters : SNMP::MIB::Node $node
Returns : (int) 0|1 Returns : (int) 0|1
Description : Returns true if the specified OID is a valid table which is Description : Returns true if the specified OID is a valid table which is
current, readable and contains a single child (row current, readable and contains a single child (row
definition) definition)
=cut =cut
sub node_is_valid_table { sub node_is_valid_table {
my ($node) = @_; my ($node) = @_;
@ -820,28 +723,23 @@ sub node_is_valid_table {
} }
=head2 build_template =head2 build_template
Parameters : (hash) $template Parameters : (hash) $template
SNMP::MIB::NODE $node SNMP::MIB::NODE $node
Returns : (void) Returns : (void)
Description : Traverses a loaded MIB tree from the specified OID node Description : Traverses a loaded MIB tree from the specified OID node
a populates a Zabbix Template hash with items, discovery a populates a Zabbix Template hash with items, discovery
rules, item prototypes, groups and macros. rules, item prototypes, groups and macros.
=cut =cut
sub build_template { sub build_template {
my ($template, $node) = @_; my ($template, $node) = @_;
# Ignore obsolete OIDs # Ignore obsolete OIDs
if (node_is_current($node)) { if (node_is_current($node)) {
# Create an Item Application name for this node # Create an Item Application name for this node
my $appname = "$node->{ moduleID }::$node->{ parent }->{ label }"; my $appname = "$node->{ moduleID }::$node->{ parent }->{ label }";
# Is this a scalar value OID? # Is this a scalar value OID?
if (node_is_valid_trap($node)) { if (node_is_valid_trap($node)) {
# Convert the SNMP::MIB::Node to a Zabbix Template SNMP Trap Item # Convert the SNMP::MIB::Node to a Zabbix Template SNMP Trap Item
my $item = node_to_trapitem($node); my $item = node_to_trapitem($node);
@ -867,8 +765,7 @@ sub build_template {
} }
} } elsif (node_is_valid_scalar($node)) {
elsif ( node_is_valid_scalar($node) ) {
# Convert the SNMP::MIB::Node to a Zabbix Template Item hash # Convert the SNMP::MIB::Node to a Zabbix Template Item hash
my $item = node_to_item($node); my $item = node_to_item($node);
@ -883,22 +780,18 @@ sub build_template {
# Add item to template # Add item to template
push(@{ $template->{ items } }, $item ); push(@{ $template->{ items } }, $item );
} } elsif (node_is_valid_table($node)) {
elsif ( node_is_valid_table($node) ) {
# Get row OID # Get row OID
my $table = $node; my $table = $node;
my $row = $node->{ children }[0]; my $row = $node->{ children }[0];
# Validate naming standard # Validate naming standard
if ($table->{ label } !~ /Table/) { if ($table->{ label } !~ /Table/) {
print STDERR print STDERR "Warning: $table->{ moduleID }:: $table->{ label } appears to be a table but does not have the 'Table' suffix\n";
"Warning: $table->{ moduleID }:: $table->{ label } appears to be a table but does not have the 'Table' suffix\n";
} }
if ($row->{ label } !~ /Entry/) { if ($row->{ label } !~ /Entry/) {
print STDERR print STDERR "Warning: $row->{ moduleID }:: $row->{ label } appears to be a table entry but does not have the 'Entry; suffix\n";
"Warning: $row->{ moduleID }:: $row->{ label } appears to be a table entry but does not have the 'Entry; suffix\n";
} }
# This is a table. Build a discovery rule # This is a table. Build a discovery rule
@ -914,38 +807,30 @@ sub build_template {
foreach my $column(@{ $row->{ children } }) { foreach my $column(@{ $row->{ children } }) {
if (node_is_valid_scalar($column)) { if (node_is_valid_scalar($column)) {
if($column->{ label } =~ m/Descr$/) { if($column->{ label } =~ m/Descr$/) {
$disc_rule->{snmp_oid} .= $disc_rule->{ snmp_oid } .= "{#SNMPVALUE},$column->{ objectID },";
"{#SNMPVALUE},$column->{ objectID },";
$index = '{#SNMPVALUE}'; $index = '{#SNMPVALUE}';
} }
} }
} }
if ( $opts->{zabbix_ver} == 3 ) { if ( $opts->{zabbix_ver} == 3 ) {
# Define macros in discovery key up to 255 chars # Define macros in discovery key up to 255 chars
# See: https://www.zabbix.com/documentation/3.0/manual/discovery/low_level_discovery#discovery_of_snmp_oids # See: https://www.zabbix.com/documentation/3.0/manual/discovery/low_level_discovery#discovery_of_snmp_oids
foreach my $column(@{ $row->{ children } }) { foreach my $column(@{ $row->{ children } }) {
if (node_is_valid_scalar($column)) { if (node_is_valid_scalar($column)) {
my $new_snmp_oid = my $new_snmp_oid = $disc_rule->{ snmp_oid } . "{#" . uc($column->{ label }) . "}," . $column->{ objectID } . ",";
$disc_rule->{snmp_oid} . "{#"
. uc( $column->{label} ) . "},"
. $column->{objectID} . ",";
if (length($new_snmp_oid) <= 255) { if (length($new_snmp_oid) <= 255) {
$disc_rule->{ snmp_oid } = $new_snmp_oid; $disc_rule->{ snmp_oid } = $new_snmp_oid;
} }
} }
} }
$disc_rule->{snmp_oid} = $disc_rule->{ snmp_oid } = substr($disc_rule->{ snmp_oid }, 0, -1) . "]";
substr( $disc_rule->{snmp_oid}, 0, -1 ) . "]";
} }
else { else {
# find entry index colum # find entry index colum
foreach my $column ( @{ $row->{children} } ) { foreach my $column ( @{ $row->{children} } ) {
if ( node_is_valid_scalar($column) ) { if ( node_is_valid_scalar($column) ) {
if ( $column->{label} =~ m/Index$/ ) { if ( $column->{label} =~ m/Index$/ ) {
#print STDERR #print STDERR
#"Warning: $row->{ moduleID }:: $row->{ label }:: $column->{label} $column->{ objectID }, Index Found\n"; #"Warning: $row->{ moduleID }:: $row->{ label }:: $column->{label} $column->{ objectID }, Index Found\n";
$disc_rule->{snmp_oid} = $column->{objectID}; $disc_rule->{snmp_oid} = $column->{objectID};
@ -957,11 +842,8 @@ sub build_template {
# Fetch an arbitrary column OID for Zabbix to use for discovery # Fetch an arbitrary column OID for Zabbix to use for discovery
my $index_oid = $row->{ children }[0]; my $index_oid = $row->{ children }[0];
if (!defined($index_oid)) { if (!defined($index_oid)) {
print STDERR print STDERR "No index found for table $table->{ moduleID}::$table->{ label } ($table->{ objectID })\n";
"No index found for table $table->{ moduleID}::$table->{ label } ($table->{ objectID })\n"; } else {
}
else {
# Remove unrequired fields # Remove unrequired fields
delete($disc_rule->{ applications }); delete($disc_rule->{ applications });
delete($disc_rule->{ data_type }); delete($disc_rule->{ data_type });
@ -972,31 +854,23 @@ sub build_template {
# Add prototypes for each row column # Add prototypes for each row column
foreach my $column(@{ $row->{ children } }) { foreach my $column(@{ $row->{ children } }) {
if (node_is_valid_scalar($column)) { if (node_is_valid_scalar($column)) {
if ( my $proto = if (my $proto = node_to_item($column, \%item_proto_template)) {
node_to_item( $column, \%item_proto_template ) )
{
$proto->{ name } = "$proto->{ name } for $index"; $proto->{ name } = "$proto->{ name } for $index";
$proto->{ key } = "$column->{ label }\[$index]"; $proto->{ key } = "$column->{ label }\[$index]";
$proto->{snmp_oid} = $proto->{ snmp_oid } = "$proto->{ snmp_oid }.{#SNMPINDEX}";
"$proto->{ snmp_oid }.{#SNMPINDEX}";
# Add item applications to template application list # Add item applications to template application list
$proto->{ applications } = [{ name => $appname }]; $proto->{ applications } = [{ name => $appname }];
$template->{ apptags }->{ $appname } = 1; $template->{ apptags }->{ $appname } = 1;
if ( $opts->{zabbix_ver} == 3 ) { if ( $opts->{zabbix_ver} == 3 ) {
push( push(@{ $disc_rule->{ item_prototypes } }, $proto);
@{ $disc_rule->{item_prototypes} },
$proto
);
} }
else { else {
# No need for Indexer to be added in Zabbix 2.4
if ( $proto->{name} !~ m/Index/ ) { if ( $proto->{name} !~ m/Index/ ) {
push(
@{ $disc_rule->{item_prototypes} }, push(@{ $disc_rule->{ item_prototypes } }, $proto);
$proto
);
} }
} }
} }
@ -1005,12 +879,9 @@ sub build_template {
# Add discovery rule to template # Add discovery rule to template
push(@{ $template->{ discovery_rules } }, $disc_rule); push(@{ $template->{ discovery_rules } }, $disc_rule);
} }
} }
} } else {
else {
# Parse children # Parse children
foreach(@{ $node->{ children } }) { foreach(@{ $node->{ children } }) {
build_template($template, $_); build_template($template, $_);
@ -1024,7 +895,7 @@ SNMP::initMib();
# Verify the specified OID exists # Verify the specified OID exists
if ($opts->{ oid } !~ m/^\./) { if ($opts->{ oid } !~ m/^\./) {
$opts->{oid} = "." . $opts->{oid}; $opts->{ oid } = "." . $opts->{ oid }
} }
my $oid_root = $SNMP::MIB{ $opts->{ oid } }; my $oid_root = $SNMP::MIB{ $opts->{ oid } };
@ -1033,11 +904,9 @@ if ( !$oid_root || $oid_root->{objectID} ne $opts->{oid} ) {
exit 1; exit 1;
# Build a Zabbix template # Build a Zabbix template
} } else {
else {
my $suffix = $opts->{ snmpver } > 2 ? " v$opts->{ snmpver }" : ''; my $suffix = $opts->{ snmpver } > 2 ? " v$opts->{ snmpver }" : '';
my $template_name = $opts->{name} my $template_name = $opts->{ name } || "Template $oid_root->{ moduleID } - $oid_root->{ label }$suffix";
|| "Template $oid_root->{ moduleID } - $oid_root->{ label }$suffix";
my $template = { my $template = {
name => $template_name, name => $template_name,
template => $template_name, template => $template_name,
@ -1045,7 +914,9 @@ else {
apptags => {}, apptags => {},
applications => [], applications => [],
discovery_rules => [], discovery_rules => [],
groups => [ { name => $opts->{group} } ], groups => [{
name => $opts->{ group }
}],
items => [], items => [],
macros => [ macros => [
{ macro => '{$MIB2ZABBIX_CMD}', value => $cmd }, { macro => '{$MIB2ZABBIX_CMD}', value => $cmd },
@ -1058,34 +929,17 @@ else {
# Add SNMP connection macros # Add SNMP connection macros
if($opts->{ snmpver } < 3) { if($opts->{ snmpver } < 3) {
push( push(@{ $template->{ macros } }, { macro => '{$SNMP_COMMUNITY}', value => $opts->{ snmpcomm } });
@{ $template->{macros} }, } elsif($opts->{ snmpver } == 3) {
{ macro => '{$SNMP_COMMUNITY}', value => $opts->{snmpcomm} } push(@{ $template->{ macros } }, { macro => '{$SNMP_USER}', value => $opts->{ v3user } });
); push(@{ $template->{ macros } }, { macro => '{$SNMP_CONTEXT}', value => $opts->{ v3context } });
} push(@{ $template->{ macros } }, { macro => '{$SNMP_AUTHPASS}', value => $opts->{ v3auth_pass } });
elsif ( $opts->{snmpver} == 3 ) { push(@{ $template->{ macros } }, { macro => '{$SNMP_PRIVPASS}', value => $opts->{ v3sec_pass } });
push( };
@{ $template->{macros} },
{ macro => '{$SNMP_USER}', value => $opts->{v3user} }
);
push(
@{ $template->{macros} },
{ macro => '{$SNMP_CONTEXT}', value => $opts->{v3context} }
);
push(
@{ $template->{macros} },
{ macro => '{$SNMP_AUTHPASS}', value => $opts->{v3auth_pass} }
);
push(
@{ $template->{macros} },
{ macro => '{$SNMP_PRIVPASS}', value => $opts->{v3sec_pass} }
);
}
build_template($template, $oid_root, 0); build_template($template, $oid_root, 0);
# Convert applications hash to array # Convert applications hash to array
@{ $template->{applications} } = @{ $template->{ applications } } = map { { name => $_ } } keys %{ $template->{ apptags } };
map { { name => $_ } } keys %{ $template->{apptags} };
delete($template->{ apptags }); delete($template->{ apptags });
# Build XML document # Build XML document
@ -1121,9 +975,7 @@ else {
# Output XML # Output XML
if ( $opts->{zabbix_ver} == 3 ) { if ( $opts->{zabbix_ver} == 3 ) {
XMLout($output_v3,
XMLout(
$output_v3,
OutputFile => \$fh, OutputFile => \$fh,
XMLDecl => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", XMLDecl => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
RootName => 'zabbix_export', RootName => 'zabbix_export',
@ -1146,8 +998,7 @@ else {
); );
} }
else { else {
XMLout( XMLout($output_v2,
$output_v2,
OutputFile => \$fh, OutputFile => \$fh,
XMLDecl => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", XMLDecl => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
RootName => 'zabbix_export', RootName => 'zabbix_export',
@ -1167,7 +1018,6 @@ else {
} }
); );
} }
if ($opts->{ filename }) { if ($opts->{ filename }) {
close $fh; close $fh;
} }