check_junos_vc.pl 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. #!/usr/bin/perl
  2. #############################################################################
  3. # (c) 2001, 2003 Juniper Networks, Inc. #
  4. # (c) 2011 Sebastian "tokkee" Harl <sh@teamix.net> #
  5. # and team(ix) GmbH, Nuernberg, Germany #
  6. # #
  7. # This file is part of "team(ix) Monitoring Plugins" #
  8. # URL: http://oss.teamix.org/projects/monitoringplugins/ #
  9. # #
  10. # All rights reserved. #
  11. # Redistribution and use in source and binary forms, with or without #
  12. # modification, are permitted provided that the following conditions #
  13. # are met: #
  14. # 1. Redistributions of source code must retain the above copyright #
  15. # notice, this list of conditions and the following disclaimer. #
  16. # 2. Redistributions in binary form must reproduce the above copyright #
  17. # notice, this list of conditions and the following disclaimer in the #
  18. # documentation and/or other materials provided with the distribution. #
  19. # 3. The name of the copyright owner may not be used to endorse or #
  20. # promote products derived from this software without specific prior #
  21. # written permission. #
  22. # #
  23. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
  24. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
  25. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
  26. # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
  27. # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
  28. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
  29. # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
  30. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
  31. # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
  32. # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
  33. # POSSIBILITY OF SUCH DAMAGE. #
  34. #############################################################################
  35. use strict;
  36. use warnings;
  37. use utf8;
  38. use Data::Dumper;
  39. use POSIX qw( :termios_h );
  40. use Nagios::Plugin;
  41. use JUNOS::Device;
  42. binmode STDOUT, ":utf8";
  43. my $valid_checks = "members_count|master|backup|interfaces|version";
  44. # TODO:
  45. # (on newer JUNOS (10.4r5.5))
  46. # request chassis routing-engine master switch check
  47. # -> graceful switchover status
  48. my $plugin = Nagios::Plugin->new(
  49. plugin => 'check_junos_vc',
  50. shortname => 'check_junos_vc',
  51. version => '0.1',
  52. url => 'http://oss.teamix.org/projects/monitoringplugins',
  53. blurb => 'Monitor Juniper™ Switch Virtual Chassis.',
  54. usage =>
  55. "Usage: %s [-v|--verbose] [-H <host>] [-p <port>] [-t <timeout]
  56. [-U <user>] [-P <password] check-tuple [...]",
  57. license =>
  58. "This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
  59. It may be used, redistributed and/or modified under the terms of the 3-Clause
  60. BSD License (see http://opensource.org/licenses/BSD-3-Clause).",
  61. extra => "
  62. This plugin connects to a Juniper™ Switch device and and checks Virtual
  63. Chassis information.
  64. A check-tuple consists of the name of the check and, optionally, a \"target\"
  65. which more closely specifies which characteristics should be checked, and
  66. warning and critical thresholds:
  67. checkname[,target[,warning[,critical]]]
  68. The following checks are available:
  69. * members_count: Total number of members in the Virtual Chassis. If a target
  70. is specified, only peers whose status (NotPrsnt, Prsnt) matches one of the
  71. specified targets are taken into account.
  72. * master, backup: Check the number or assignment of master resp. backup
  73. members. If a target is specified, check that those members whose serial
  74. number matches the specified target have the requested role (master,
  75. backup) assigned to them. Else, check the number of master resp. backup
  76. members against the specified thresholds.
  77. * interfaces: Check that all VCP interfaces are up. If warning or critical
  78. thresholds have been specified, also check the number of VCP interfaces
  79. against the thresholds.
  80. * version: Check the version of all physically connected members.
  81. Warning and critical thresholds may be specified in the format documented at
  82. http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT.",
  83. );
  84. # Predefined arguments (by Nagios::Plugin)
  85. my @predefined_args = qw(
  86. usage
  87. help
  88. version
  89. extra-opts
  90. timeout
  91. verbose
  92. );
  93. my @args = (
  94. {
  95. spec => 'host|H=s',
  96. usage => '-H, --host=HOSTNAME',
  97. desc => 'Hostname/IP of Juniper box to connect to',
  98. default => 'localhost',
  99. },
  100. {
  101. spec => 'port|p=i',
  102. usage => '-p, --port=PORT',
  103. desc => 'Port to connect to',
  104. default => 22,
  105. },
  106. {
  107. spec => 'user|U=s',
  108. usage => '-U, --user=USERNAME',
  109. desc => 'Username to log into box as',
  110. default => 'root',
  111. },
  112. {
  113. spec => 'password|P=s',
  114. usage => '-P, --password=PASSWORD',
  115. desc => 'Password for login username',
  116. default => '<prompt>',
  117. },
  118. );
  119. my %conf = ();
  120. my $junos = undef;
  121. foreach my $arg (@args) {
  122. add_arg($plugin, $arg);
  123. }
  124. $plugin->getopts;
  125. # Initialize this first, so it may be used right away.
  126. $conf{'verbose'} = $plugin->opts->verbose;
  127. foreach my $arg (@args) {
  128. my @c = get_conf($plugin, $arg);
  129. $conf{$c[0]} = $c[1];
  130. }
  131. foreach my $arg (@predefined_args) {
  132. $conf{$arg} = $plugin->opts->$arg;
  133. }
  134. add_checks(\%conf, @ARGV);
  135. if (! $plugin->opts->password) {
  136. my $term = POSIX::Termios->new();
  137. my $lflag;
  138. print "Password: ";
  139. $term->getattr(fileno(STDIN));
  140. $lflag = $term->getlflag;
  141. $term->setlflag($lflag & ~POSIX::ECHO);
  142. $term->setattr(fileno(STDIN), TCSANOW);
  143. $conf{'password'} = <STDIN>;
  144. chomp($conf{'password'});
  145. $term->setlflag($lflag | POSIX::ECHO);
  146. $term->setattr(fileno(STDIN), TCSAFLUSH);
  147. print "\n";
  148. }
  149. verbose(1, "Connecting to host $conf{'host'} as user $conf{'user'}.");
  150. $junos = JUNOS::Device->new(
  151. hostname => $conf{'host'},
  152. login => $conf{'user'},
  153. password => $conf{'password'},
  154. access => 'ssh',
  155. 'ssh-compress' => 0);
  156. if (! ref $junos) {
  157. $plugin->die("ERROR: failed to connect to " . $conf{'host'} . "!");
  158. }
  159. my $vc = undef;
  160. my @vc_members = ();
  161. my $have_vc_members = 0;
  162. foreach my $check (@{$conf{'checks'}}) {
  163. my $code;
  164. my $value;
  165. my @targets = ();
  166. if (defined $check->{'target'}) {
  167. @targets = @{$check->{'target'}};
  168. }
  169. $plugin->set_thresholds(
  170. warning => $check->{'warning'},
  171. critical => $check->{'critical'},
  172. );
  173. if ($check->{'name'} eq 'members_count') {
  174. my @relevant_members = ();
  175. my $value = 0;
  176. my $code;
  177. @vc_members = get_vc_members($junos);
  178. if (scalar(@targets)) {
  179. foreach my $member (@vc_members) {
  180. my $role = get_member_status($member);
  181. if (scalar(grep { $role eq $_ } @targets)) {
  182. push @relevant_members, $member;
  183. $value++;
  184. }
  185. }
  186. }
  187. else {
  188. @relevant_members = @vc_members;
  189. $value = scalar(@vc_members);
  190. }
  191. $code = $plugin->check_threshold($value);
  192. $plugin->add_message($code, "$value " . join(" + ", @targets)
  193. . " member" . (($value == 1) ? "" : "s"));
  194. my $label = 'members';
  195. if (scalar(@targets)) {
  196. $label .= '[' . join('+', @targets) . ']';
  197. }
  198. $plugin->add_perfdata(
  199. label => $label,
  200. value => $value,
  201. min => 0,
  202. max => undef,
  203. uom => '',
  204. threshold => $plugin->threshold(),
  205. );
  206. }
  207. elsif (($check->{'name'} eq 'master') || ($check->{'name'} eq 'backup')) {
  208. my $wanted_role = ($check->{'name'} eq 'master')
  209. ? 'Master' : 'Backup';
  210. my @wanted_members = ();
  211. my $value;
  212. my $code;
  213. @vc_members = get_vc_members($junos);
  214. foreach my $member (@vc_members) {
  215. my $role = get_member_role($member);
  216. if ($role eq $wanted_role) {
  217. push @wanted_members, $member;
  218. }
  219. }
  220. if (scalar(@targets)) {
  221. my @ok_targets = ();
  222. my @fail_targets = ();
  223. $code = UNKNOWN;
  224. foreach my $target (@targets) {
  225. if (scalar(grep { $target eq get_member_serial($_) } @wanted_members)) {
  226. # requested target does have wanted role assigned
  227. if (($code == UNKNOWN) || ($code == OK)) {
  228. $code = OK;
  229. }
  230. else {
  231. # we've had previous errors
  232. $code = WARNING;
  233. }
  234. push @ok_targets, $target;
  235. }
  236. else {
  237. if (($code == OK) || ($code == WARNING)) {
  238. # we've had previous success
  239. $code = WARNING;
  240. }
  241. else {
  242. $code = CRITICAL;
  243. }
  244. push @fail_targets, $target;
  245. }
  246. }
  247. $plugin->add_message($code, scalar(@fail_targets)
  248. . " missing/failed-over " . $check->{'name'}
  249. . ((scalar(@fail_targets) == 1) ? "" : "s")
  250. . (scalar(@fail_targets)
  251. ? " (" . join(", ", @fail_targets) . ")" : "")
  252. . ", " . scalar(@ok_targets) . " active " . $check->{'name'}
  253. . ((scalar(@ok_targets) == 1) ? "" : "s")
  254. . (scalar(@ok_targets)
  255. ? " (" . join(", ", @ok_targets) . ")" : ""));
  256. $plugin->add_perfdata(
  257. label => 'active_' . $check->{'name'},
  258. value => scalar(@ok_targets),
  259. min => 0,
  260. max => undef,
  261. uom => '',
  262. threshold => undef,
  263. );
  264. $plugin->add_perfdata(
  265. label => 'failed_' . $check->{'name'},
  266. value => scalar(@fail_targets),
  267. min => 0,
  268. max => undef,
  269. uom => '',
  270. threshold => undef,
  271. );
  272. }
  273. else {
  274. $value = scalar @wanted_members;
  275. $code = $plugin->check_threshold($value);
  276. $plugin->add_message($code, "$value " . $check->{'name'} . " member"
  277. . (($value == 1) ? "" : "s"));
  278. $plugin->add_perfdata(
  279. label => $check->{'name'},
  280. value => $value,
  281. min => 0,
  282. max => undef,
  283. uom => '',
  284. threshold => $plugin->threshold(),
  285. );
  286. }
  287. }
  288. elsif ($check->{'name'} eq 'interfaces') {
  289. my @up_ifaces = ();
  290. my @down_ifaces = ();
  291. my @vc_interfaces = get_vc_interfaces($junos);
  292. foreach my $iface (@vc_interfaces) {
  293. my $status = get_iface_status($iface);
  294. if ($status eq 'up') {
  295. push @up_ifaces, get_iface_name($iface);
  296. next;
  297. }
  298. # else:
  299. push @down_ifaces, {
  300. name => get_iface_name($iface),
  301. status => $status,
  302. };
  303. }
  304. if (scalar(@down_ifaces)) {
  305. $plugin->add_message(CRITICAL, scalar(@down_ifaces)
  306. . " VCP interface" . ((scalar(@down_ifaces) == 1) ? "" : "s")
  307. . " not up ("
  308. . join(", ",
  309. map { "$_->{'name'} $_->{'status'}" } @down_ifaces)
  310. . ")");
  311. }
  312. elsif ($check->{'warning'} || $check->{'critical'}) {
  313. my $value = scalar @vc_interfaces;
  314. my $code = $plugin->check_threshold($value);
  315. $plugin->add_message($code, "$value VCP interface"
  316. . (($value == 1) ? "" : "s") . " found ("
  317. . scalar(@up_ifaces) . " up, "
  318. . scalar(@down_ifaces) . " down)");
  319. }
  320. elsif (! scalar(@up_ifaces)) {
  321. # no VCP interfaces at all
  322. $plugin->add_message(CRITICAL, "no VCP interfaces found");
  323. }
  324. else {
  325. $plugin->add_message(OK, "all VCP interfaces up");
  326. }
  327. $plugin->add_perfdata(
  328. label => 'vcp_interfaces',
  329. value => scalar(@vc_interfaces),
  330. min => 0,
  331. max => undef,
  332. uom => '',
  333. threshold => $plugin->threshold(),
  334. );
  335. $plugin->add_perfdata(
  336. label => 'up_interfaces',
  337. value => scalar(@up_ifaces),
  338. min => 0,
  339. max => undef,
  340. uom => '',
  341. threshold => undef,
  342. );
  343. $plugin->add_perfdata(
  344. label => 'down_interfaces',
  345. value => scalar(@down_ifaces),
  346. min => 0,
  347. max => undef,
  348. uom => '',
  349. threshold => undef,
  350. );
  351. }
  352. elsif ($check->{'name'} eq 'version') {
  353. my %versions = get_versions($junos);
  354. my @v_keys = keys %versions;
  355. my $first = undef;
  356. my @base_mismatch = ();
  357. my %mismatches = ();
  358. foreach my $k (@v_keys) {
  359. my $base = $versions{$k}->{'base'};
  360. my $other = $versions{$k}->{'other'};
  361. foreach my $o (keys %$other) {
  362. if ($other->{$o} ne $base) {
  363. $mismatches{$k}->{$base} = 1;
  364. $mismatches{$k}->{$other->{$o}} = 1;
  365. }
  366. }
  367. }
  368. $first = shift @v_keys;
  369. $first = $versions{$first};
  370. foreach my $k (@v_keys) {
  371. if ($first->{'base'} ne $versions{$k}->{'base'}) {
  372. push @base_mismatch, $k;
  373. }
  374. }
  375. if (scalar @base_mismatch) {
  376. my @first_match = grep {
  377. $versions{$_}->{'base'} eq $first->{'base'}
  378. } keys %versions;
  379. my %mismatches = ();
  380. foreach my $m (@base_mismatch) {
  381. push @{$mismatches{$versions{$m}->{'base'}}}, $m;
  382. }
  383. $plugin->add_message(CRITICAL, "version mismatch detected: "
  384. . $first->{'base'} . " @ ("
  385. . join(", ", @first_match) . ") != "
  386. . join(" != ", map {
  387. $_ . " @ (" . join(", ", @{$mismatches{$_}}) . ")"
  388. } keys %mismatches));
  389. }
  390. elsif (scalar(keys %mismatches)) {
  391. $plugin->add_message(WARNING, "version mismatches detected: "
  392. . join(" / ", map {
  393. "$_: " . join(" != ", keys %{$mismatches{$_}})
  394. } keys %mismatches));
  395. }
  396. else {
  397. $plugin->add_message(OK, "all members at version "
  398. . $first->{'base'});
  399. }
  400. }
  401. }
  402. # add total numbers to perfdata to ease graphing stuff
  403. if ($have_vc_members) {
  404. $plugin->add_perfdata(
  405. label => 'members',
  406. value => scalar(@vc_members),
  407. min => 0,
  408. max => undef,
  409. uom => '',
  410. threshold => undef,
  411. );
  412. }
  413. my ($code, $msg) = $plugin->check_messages(join => ', ');
  414. $junos->disconnect();
  415. $plugin->nagios_exit($code, $msg);
  416. sub send_query
  417. {
  418. my $device = shift;
  419. my $query = shift;
  420. my $queryargs = shift;
  421. my $res;
  422. my $err;
  423. verbose(3, "Sending query '$query' to router.");
  424. if (ref $queryargs) {
  425. $res = $device->$query(%$queryargs);
  426. } else {
  427. $res = $device->$query();
  428. }
  429. verbose(5, "Got response: " . Dumper(\$res));
  430. if (! ref $res) {
  431. return "ERROR: Failed to execute query '$query'";
  432. }
  433. $err = $res->getFirstError();
  434. if ($err) {
  435. return "ERROR: " . $err->{message};
  436. }
  437. return $res;
  438. }
  439. sub send_command
  440. {
  441. my $device = shift;
  442. my $cmd = shift;
  443. my $res;
  444. my $err;
  445. verbose(3, "Sending command '$cmd' to router.");
  446. $res = $device->command($cmd);
  447. if (! ref $res) {
  448. return "ERROR: Failed to execute command '$cmd'";
  449. }
  450. $err = $res->getFirstError();
  451. if ($err) {
  452. return "ERROR: " . $err->{message};
  453. }
  454. return $res;
  455. }
  456. sub get_vc_information
  457. {
  458. my $device = shift;
  459. my $cmd = "show virtual-chassis status";
  460. my $res = send_command($device, $cmd);
  461. my $err;
  462. if (! ref $res) {
  463. return $res;
  464. }
  465. return $res;
  466. }
  467. sub get_vc_members
  468. {
  469. my $device = shift;
  470. if ($have_vc_members) {
  471. return @vc_members;
  472. }
  473. $vc = get_vc_information($device);
  474. if (! ref $vc) {
  475. $plugin->die($vc);
  476. }
  477. my $vc_id = ($vc->getElementsByTagName('virtual-chassis-id-information'))[0];
  478. $vc_id = ($vc_id->getElementsByTagName('virtual-chassis-id'))[0];
  479. $vc_id = $vc_id->getFirstChild->getNodeValue;
  480. verbose(3, "Analyzing data from virtual chassis $vc_id.");
  481. @vc_members = ($vc->getElementsByTagName('member-list'))[0]->getElementsByTagName('member');
  482. if ($conf{'verbose'} >= 3) {
  483. my @m = map { get_member_id($_) . " => " . get_member_serial($_) }
  484. @vc_members;
  485. verbose(3, "Members: " . join(", ", @m));
  486. }
  487. $have_vc_members = 1;
  488. return @vc_members;
  489. }
  490. sub get_vc_interfaces
  491. {
  492. my $device = shift;
  493. my @ifaces = ();
  494. my $cmd = "get_interface_information";
  495. my %args = ( interface_name => 'vcp*' );
  496. my $res = send_query($device, $cmd, \%args);
  497. if (! ref $res) {
  498. $plugin->die($res);
  499. }
  500. @ifaces = $res->getElementsByTagName('physical-interface');
  501. if ($conf{'verbose'} >= 3) {
  502. my @i = map { get_iface_name($_) . " => " . get_iface_status($_) }
  503. @ifaces;
  504. verbose(3, "VCP Interfaces: " . join(", ", @i));
  505. }
  506. return @ifaces;
  507. }
  508. sub get_versions
  509. {
  510. my $device = shift;
  511. my %versions = ();
  512. my $cmd = "show version";
  513. my $res = send_command($device, $cmd);
  514. my @v = ();
  515. if (! ref $res) {
  516. $plugin->die($res);
  517. }
  518. @v = $res->getElementsByTagName('multi-routing-engine-item');
  519. foreach my $i (@v) {
  520. my $name = get_obj_element($i, 're-name');
  521. my @infos = $i->getElementsByTagName('software-information');
  522. @infos = $infos[0]->getElementsByTagName('package-information');
  523. foreach my $j (@infos) {
  524. my $comment = get_obj_element($j, 'comment');
  525. my ($desc, $version);
  526. $comment =~ m/^(.*) \[([^]]+)\]$/;
  527. $desc = $1;
  528. $version = $2;
  529. if ($desc eq "JUNOS Base OS boot") {
  530. $versions{$name}->{'base'} = $version;
  531. }
  532. else {
  533. $versions{$name}->{'other'}->{$desc} = $version;
  534. }
  535. }
  536. }
  537. return %versions;
  538. }
  539. sub add_arg
  540. {
  541. my $plugin = shift;
  542. my $arg = shift;
  543. my $spec = $arg->{'spec'};
  544. my $help = $arg->{'usage'};
  545. if (defined $arg->{'desc'}) {
  546. my @desc;
  547. if (ref($arg->{'desc'})) {
  548. @desc = @{$arg->{'desc'}};
  549. }
  550. else {
  551. @desc = ( $arg->{'desc'} );
  552. }
  553. foreach my $d (@desc) {
  554. $help .= "\n $d";
  555. }
  556. if (defined $arg->{'default'}) {
  557. $help .= " (default: $arg->{'default'})";
  558. }
  559. }
  560. elsif (defined $arg->{'default'}) {
  561. $help .= "\n (default: $arg->{'default'})";
  562. }
  563. $plugin->add_arg(
  564. spec => $spec,
  565. help => $help,
  566. );
  567. }
  568. sub get_conf
  569. {
  570. my $plugin = shift;
  571. my $arg = shift;
  572. my ($name, undef) = split(m/\|/, $arg->{'spec'});
  573. my $value = $plugin->opts->$name || $arg->{'default'};
  574. if ($name eq 'password') {
  575. verbose(3, "conf: password => "
  576. . (($value eq '<prompt>') ? '<prompt>' : '<hidden>'));
  577. }
  578. else {
  579. verbose(3, "conf: $name => $value");
  580. }
  581. return ($name => $value);
  582. }
  583. sub add_single_check
  584. {
  585. my $conf = shift;
  586. my @check = split(m/,/, shift);
  587. my %c = ();
  588. if ($check[0] !~ m/\b(?:$valid_checks)\b/) {
  589. return "ERROR: invalid check '$check[0]'";
  590. }
  591. $c{'name'} = $check[0];
  592. $c{'target'} = undef;
  593. if (defined($check[1])) {
  594. $c{'target'} = [ split(m/\+/, $check[1]) ];
  595. }
  596. $c{'warning'} = $check[2];
  597. $c{'critical'} = $check[3];
  598. # check for valid thresholds
  599. # set_threshold() will die if any threshold is not valid
  600. $plugin->set_thresholds(
  601. warning => $c{'warning'},
  602. critical => $c{'critical'},
  603. ) || $plugin->die("ERROR: Invalid thresholds: "
  604. . "warning => $c{'warning'}, critical => $c{'critical'}");
  605. push @{$conf->{'checks'}}, \%c;
  606. }
  607. sub add_checks
  608. {
  609. my $conf = shift;
  610. my @checks = @_;
  611. my $err_str = "ERROR:";
  612. if (scalar(@checks) == 0) {
  613. $conf->{'checks'}[0] = {
  614. name => 'members_count',
  615. target => [],
  616. warning => undef,
  617. critical => undef,
  618. };
  619. return 1;
  620. }
  621. $conf->{'checks'} = [];
  622. foreach my $check (@checks) {
  623. my $e;
  624. $e = add_single_check($conf, $check);
  625. if ($e =~ m/^ERROR: (.*)$/) {
  626. $err_str .= " $1,";
  627. }
  628. }
  629. if ($err_str ne "ERROR:") {
  630. $err_str =~ s/,$//;
  631. $plugin->die($err_str);
  632. }
  633. }
  634. sub get_obj_element
  635. {
  636. my $obj = shift;
  637. my $elem = shift;
  638. $elem = $obj->getElementsByTagName($elem);
  639. return $elem->item(0)->getFirstChild->getNodeValue;
  640. }
  641. sub get_member_id
  642. {
  643. my $member = shift;
  644. return get_obj_element($member, 'member-id');
  645. }
  646. sub get_member_serial
  647. {
  648. my $member = shift;
  649. return get_obj_element($member, 'member-serial-number');
  650. }
  651. sub get_member_status
  652. {
  653. my $member = shift;
  654. return get_obj_element($member, 'member-status');
  655. }
  656. sub get_member_role
  657. {
  658. my $member = shift;
  659. my $elem;
  660. $elem = $member->getElementsByTagName('member-role');
  661. if ($elem && $elem->item(0)) {
  662. $elem = $elem->item(0)->getFirstChild->getNodeValue;
  663. # e.g., '*' may be appended to the member-role
  664. $elem =~ s/\W//g;
  665. return $elem;
  666. }
  667. else {
  668. return "";
  669. }
  670. }
  671. sub get_iface_name
  672. {
  673. my $iface = shift;
  674. return get_obj_element($iface, 'name');
  675. }
  676. sub get_iface_status
  677. {
  678. my $iface = shift;
  679. return get_obj_element($iface, 'oper-status');
  680. }
  681. sub verbose
  682. {
  683. my $level = shift;
  684. my @msgs = @_;
  685. if ($level > $conf{'verbose'}) {
  686. return;
  687. }
  688. foreach my $msg (@msgs) {
  689. print "V$level: $msg\n";
  690. }
  691. }