check_naf_exports.pl 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #!/usr/bin/perl
  2. #####################################################################
  3. # (c) 2012 Sebastian "tokkee" Harl <sh@teamix.net> #
  4. # and team(ix) GmbH, Nuernberg, Germany #
  5. # #
  6. # This file is part of "team(ix) Monitoring Plugins" #
  7. # URL: http://oss.teamix.org/projects/monitoringplugins/ #
  8. # #
  9. # This file is free software: you can redistribute it and/or modify #
  10. # it under the terms of the GNU General Public License as published #
  11. # by the Free Software Foundation, either version 2 of the License, #
  12. # or (at your option) any later version. #
  13. # #
  14. # This file is distributed in the hope that it will be useful, but #
  15. # WITHOUT ANY WARRANTY; without even the implied warranty of #
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  17. # GNU General Public License for more details. #
  18. # #
  19. # You should have received a copy of the GNU General Public License #
  20. # along with this file. If not, see <http://www.gnu.org/licenses/>. #
  21. #####################################################################
  22. use strict;
  23. use warnings;
  24. use utf8;
  25. use FindBin qw( $Bin );
  26. use lib "$Bin/perl/lib";
  27. use Nagios::Plugin::NetApp;
  28. binmode STDOUT, ":utf8";
  29. my $plugin = Nagios::Plugin::NetApp->new(
  30. plugin => 'check_naf_exports',
  31. shortname => 'check_naf_exports',
  32. version => '0.1',
  33. url => 'http://oss.teamix.org/projects/monitoringplugins',
  34. blurb => 'Monitor NetApp™ NFS exports.',
  35. usage =>
  36. "Usage: %s [-v|--verbose] [-H <host>] [-p <port>] [-t <timeout]
  37. [-U <user>] [-P <password] check-tuple [...]",
  38. license =>
  39. "This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
  40. It may be used, redistributed and/or modified under the terms of the GNU
  41. General Public License, either version 2 or (at your option) any later version
  42. (see http://opensource.org/licenses/GPL-2.0).",
  43. extra => "
  44. This plugin connects to a NetApp™ filer and checks NFS exports related issues.
  45. A check-tuple consists of the name of the check and, optionally, a \"target\"
  46. which more closely specifies which characteristics should be checked, and
  47. warning and critical thresholds:
  48. checkname[,target[,warning[,critical]]]
  49. The following checks are available:
  50. * exportfs_consistent: Check if /etc/exports is consistent with the currently
  51. exported filessytems.
  52. Warning and critical thresholds may be specified in the format documented at
  53. http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT.",
  54. );
  55. my %checks = (
  56. exportfs_consistent => \&check_exportfs_consistent,
  57. );
  58. my $srv = undef;
  59. $plugin->add_common_args();
  60. foreach my $check (keys %checks) {
  61. $plugin->add_check_impl($check, $checks{$check});
  62. }
  63. $plugin->set_default_check('exportfs_consistent');
  64. # configure removes any options from @ARGV
  65. $plugin->configure();
  66. $plugin->set_checks(@ARGV);
  67. $srv = $plugin->connect();
  68. $plugin->run_checks();
  69. my ($code, $msg) = $plugin->check_messages(join => ', ');
  70. $plugin->nagios_exit($code, $msg);
  71. sub get_exports_rules
  72. {
  73. my $srv = shift;
  74. my $persistent = shift;
  75. my $res = undef;
  76. $res = $srv->invoke('nfs-exportfs-list-rules', 'persistent', $persistent);
  77. $plugin->die_on_error($res, "Failed to read exports information");
  78. if (! $res->child_get('rules')) {
  79. return ();
  80. }
  81. my %exports = ();
  82. foreach my $rule ($res->child_get('rules')->children_get()) {
  83. my %rule;
  84. my $tmp;
  85. foreach my $info (qw( actual-pathname anon nosuid pathname )) {
  86. $tmp = $rule->child_get_string($info);
  87. if (defined($tmp)) {
  88. $rule{$info} = $tmp;
  89. }
  90. }
  91. foreach my $info (qw( read-only read-write root )) {
  92. my %info = ();
  93. if (! $rule->child_get($info)) {
  94. next;
  95. }
  96. foreach my $host_info ($rule->child_get($info)->children_get()) {
  97. my $host;
  98. my $all_hosts = $host_info->child_get_string('all-hosts');
  99. my $negate = $host_info->child_get_string('negate');
  100. $all_hosts ||= "false";
  101. $negate ||= "false";
  102. if ($all_hosts eq 'true') {
  103. $host = '*';
  104. }
  105. else {
  106. $host = $host_info->child_get_string('name');
  107. }
  108. if ($negate eq 'true') {
  109. $info{$host} = 1;
  110. }
  111. else {
  112. $info{$host} = 0;
  113. }
  114. }
  115. $rule{$info} = \%info;
  116. }
  117. if ($rule->child_get('sec-flavor')) {
  118. my %sec_flavors = map {
  119. $_->child_get_string('flavor') => 1
  120. } $rule->child_get('sec-flavor')->children_get();
  121. $rule{'sec-flavor'} = \%sec_flavors;
  122. }
  123. $exports{$rule{'pathname'}} = \%rule;
  124. }
  125. return %exports;
  126. }
  127. sub check_exportfs_consistent
  128. {
  129. my $plugin = shift;
  130. my $srv = shift;
  131. my @targets = @_;
  132. my %exports = get_exports_rules($srv, 'true');
  133. my %memory = get_exports_rules($srv, 'false');
  134. # diff export rules
  135. foreach my $path (keys %memory) {
  136. if (! defined($exports{$path})) {
  137. $plugin->add_message(CRITICAL,
  138. "$path not exported in /etc/exports");
  139. next;
  140. }
  141. my %export = %{$exports{$path}};
  142. my %mem = %{$memory{$path}};
  143. foreach my $info (qw( actual-pathname anon nosuid pathname )) {
  144. my $e = $export{$info};
  145. my $m = $mem{$info};
  146. if ((! defined($e)) && (! defined($m))) {
  147. next;
  148. }
  149. $e ||= "<empty>";
  150. $m ||= "<empty>";
  151. if ($e ne $m) {
  152. $plugin->add_message(CRITICAL, "$path: $info differ "
  153. . "(exports: $e, exportfs: $m)");
  154. }
  155. }
  156. foreach my $info (qw( read-only read-write root )) {
  157. my $e = $export{$info};
  158. my $m = $mem{$info};
  159. if ((! defined($e)) && (! defined($m))) {
  160. next;
  161. }
  162. foreach my $host (keys %$m) {
  163. if (! defined($e->{$host})) {
  164. $plugin->add_message(CRITICAL, "$path: "
  165. . "$host does not have $info access in /etc/exports");
  166. next;
  167. }
  168. if ($m->{$host} != $e->{$host}) {
  169. $plugin->add_message(CRITICAL, "$path: "
  170. . "$host is negated in "
  171. . ($m->{$host} ? "/etc/exports" : "exportfs info"));
  172. }
  173. }
  174. foreach my $host (keys %$e) {
  175. if (! defined($m->{$host})) {
  176. $plugin->add_message(CRITICAL, "$path: "
  177. . "$host does not have $info access in exportfs info");
  178. }
  179. }
  180. }
  181. my $e = $export{'sec-flavor'};
  182. my $m = $mem{'sec-flavor'};
  183. if (! ((! defined($e)) && (! defined($m)))) {
  184. $e ||= {};
  185. $m ||= {};
  186. foreach my $flavor (keys %$m) {
  187. if (! defined($e->{$flavor})) {
  188. $plugin->add_message(CRITICAL, "$path: "
  189. . "security flavor $flavor is not specified "
  190. . "in /etc/exports");
  191. }
  192. }
  193. foreach my $flavor (keys %$e) {
  194. if (! defined($m->{$flavor})) {
  195. $plugin->add_message(CRITICAL, "$path: "
  196. . "security flavor $flavor is not specified "
  197. . "in exportfs info");
  198. }
  199. }
  200. }
  201. }
  202. foreach my $path (keys %exports) {
  203. if (! defined($memory{$path})) {
  204. $plugin->add_message(CRITICAL,
  205. "$path not exported (according to 'exportfs')");
  206. }
  207. }
  208. }