#!/usr/bin/perl use strict; use warnings; use JSON; use Getopt::Long; use File::Which; my $json = {}; my $mpath = undef; my $help = 0; my $pretty = 0; GetOptions( "mpath=s" => \$mpath, "help" => \$help, "pretty" => \$pretty ); my $multipathd = which('multipathd'); if (not defined $multipathd){ print 'ZBX_NOTSUPPORTED'; exit 1; } if ($help or not defined $mpath){ print <<_EOF; Usage : $0 --mpath= [--pretty] * --mpath : the name of the device to check * --pretty : output pretty JSON, easier to read for humans * --help : display this help _EOF exit 2; } $json = { mpath => $mpath, size => 0, dm_st => 'unknown', features => '', failures => 0, path_failures => 0, paths_num_total => 0, paths_num_ko => 0, paths_num_active => 0, paths_num_inactive => 0, paths_details => [], paths_with_issue => [], errors => [] }; my @res = qx($multipathd show maps raw format "%n|%N|%S|%f|%t|%x|%0"); if ($? != 0){ push @{$json->{errors}}, "Failed to run multipathd show maps raw format"; } foreach (@res){ chomp; next if $_ !~ /^$mpath\|/; (undef, $json->{paths_num_total}, $json->{size}, $json->{features}, $json->{dm_st}, $json->{failures}, $json->{path_failures}) = split(/\s*\|\s*/, $_); # Cast to int foreach (qw(failures path_failures paths_num_total)){ $json->{$_} = 0 + $json->{$_}; } # Convert size to bytes my $unit = chop $json->{size}; if ($unit eq 'K'){ $json->{size} *= 1024; } elsif ($unit eq 'M'){ $json->{size} *= 1024 * 1024; } elsif ($unit eq 'G'){ $json->{size} *= 1024 * 1024 * 1024; } elsif ($unit eq 'T'){ $json->{size} *= 1024 * 1024 * 1024 * 1024; } elsif ($unit eq 'P'){ $json->{size} *= 1024 * 1024 * 1024 * 1024 * 1024; } # No need to process the other mpath here last; } # Now check status of every path @res = qx($multipathd show paths format "%m|%d|%t|%o|%T|%0|%z"); if ($? != 0){ push @{$json->{errors}}, "Failed to run multipathd show paths format"; } # Skip header line shift @res; foreach (@res){ chomp; next if $_ !~ /^$mpath\|/; my (undef, $dev, $dm_st, $dev_st, $chk_st, $failures, $serial) = split(/\s*\|\s*/, $_); push @{$json->{paths_details}}, { dev => $dev, dm_st => $dm_st, dev_st => $dev_st, chk_st => $chk_st, failures => $failures + 0, serial => $serial }; if ($dm_st eq 'active'){ $json->{paths_num_active} += 1; if ($dev_st ne 'running'){ $json->{paths_num_ko} += 1; push @{$json->{paths_with_issue}}, $dev; push @{$json->{errors}}, "dev $dev is not running"; } elsif ($chk_st ne 'ready' or $failures > 0){ $json->{paths_num_ko} += 1; push @{$json->{paths_with_issue}}, $dev; push @{$json->{errors}}, "dev $dev is not active"; } else { $json->{paths_num_ok} += 1; } } else { $json->{paths_num_inactive} += 1; } } # We want easy usage from zabbix, so turn thos ones to strings $json->{paths_with_issue} = join(',', @{$json->{paths_with_issue}}); $json->{errors} = join(',', @{$json->{errors}}); print to_json($json, { pretty => $pretty }); exit 0;