Playbooks to a new Lilik
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

409 lines
15 KiB

  1. #!/usr/bin/perl -w
  2. # Heavily based on the script from:
  3. # check_mem.pl Copyright (C) 2000 Dan Larsson <dl@tyfon.net>
  4. # heavily modified by
  5. # Justin Ellison <justin@techadvise.com>
  6. #
  7. # The MIT License (MIT)
  8. # Copyright (c) 2011 justin@techadvise.com
  9. # Permission is hereby granted, free of charge, to any person obtaining a copy of this
  10. # software and associated documentation files (the "Software"), to deal in the Software
  11. # without restriction, including without limitation the rights to use, copy, modify,
  12. # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  13. # permit persons to whom the Software is furnished to do so, subject to the following conditions:
  14. # The above copyright notice and this permission notice shall be included in all copies
  15. # or substantial portions of the Software.
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  17. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  18. # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  19. # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
  20. # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21. # OTHER DEALINGS IN THE SOFTWARE.
  22. # Tell Perl what we need to use
  23. use strict;
  24. use Getopt::Std;
  25. #TODO - Convert to Nagios::Plugin
  26. #TODO - Use an alarm
  27. # Predefined exit codes for Nagios
  28. use vars qw($opt_c $opt_f $opt_u $opt_w $opt_C $opt_v $opt_h %exit_codes);
  29. %exit_codes = ('UNKNOWN' , 3,
  30. 'OK' , 0,
  31. 'WARNING' , 1,
  32. 'CRITICAL', 2,
  33. );
  34. # Get our variables, do our checking:
  35. init();
  36. # Get the numbers:
  37. my ($free_memory_kb,$used_memory_kb,$caches_kb,$hugepages_kb) = get_memory_info();
  38. print "$free_memory_kb Free\n$used_memory_kb Used\n$caches_kb Cache\n" if ($opt_v);
  39. print "$hugepages_kb Hugepages\n" if ($opt_v and $opt_h);
  40. if ($opt_C) { #Do we count caches as free?
  41. $used_memory_kb -= $caches_kb;
  42. $free_memory_kb += $caches_kb;
  43. }
  44. if ($opt_h) {
  45. $used_memory_kb -= $hugepages_kb;
  46. }
  47. print "$used_memory_kb Used (after Hugepages)\n" if ($opt_v);
  48. # Round to the nearest KB
  49. $free_memory_kb = sprintf('%d',$free_memory_kb);
  50. $used_memory_kb = sprintf('%d',$used_memory_kb);
  51. $caches_kb = sprintf('%d',$caches_kb);
  52. # Tell Nagios what we came up with
  53. tell_nagios($used_memory_kb,$free_memory_kb,$caches_kb,$hugepages_kb);
  54. sub tell_nagios {
  55. my ($used,$free,$caches,$hugepages) = @_;
  56. # Calculate Total Memory
  57. my $total = $free + $used;
  58. print "$total Total\n" if ($opt_v);
  59. my $perf_warn;
  60. my $perf_crit;
  61. if ( $opt_u ) {
  62. $perf_warn = int(${total} * $opt_w / 100);
  63. $perf_crit = int(${total} * $opt_c / 100);
  64. } else {
  65. $perf_warn = int(${total} * ( 100 - $opt_w ) / 100);
  66. $perf_crit = int(${total} * ( 100 - $opt_c ) / 100);
  67. }
  68. my $perfdata = "|TOTAL=${total}KB;;;; USED=${used}KB;${perf_warn};${perf_crit};; FREE=${free}KB;;;; CACHES=${caches}KB;;;;";
  69. $perfdata .= " HUGEPAGES=${hugepages}KB;;;;" if ($opt_h);
  70. if ($opt_f) {
  71. my $percent = sprintf "%.1f", ($free / $total * 100);
  72. if ($percent <= $opt_c) {
  73. finish("CRITICAL - $percent% ($free kB) free!$perfdata",$exit_codes{'CRITICAL'});
  74. }
  75. elsif ($percent <= $opt_w) {
  76. finish("WARNING - $percent% ($free kB) free!$perfdata",$exit_codes{'WARNING'});
  77. }
  78. else {
  79. finish("OK - $percent% ($free kB) free.$perfdata",$exit_codes{'OK'});
  80. }
  81. }
  82. elsif ($opt_u) {
  83. my $percent = sprintf "%.1f", ($used / $total * 100);
  84. if ($percent >= $opt_c) {
  85. finish("CRITICAL - $percent% ($used kB) used!$perfdata",$exit_codes{'CRITICAL'});
  86. }
  87. elsif ($percent >= $opt_w) {
  88. finish("WARNING - $percent% ($used kB) used!$perfdata",$exit_codes{'WARNING'});
  89. }
  90. else {
  91. finish("OK - $percent% ($used kB) used.$perfdata",$exit_codes{'OK'});
  92. }
  93. }
  94. }
  95. # Show usage
  96. sub usage() {
  97. print "\ncheck_mem.pl v1.0 - Nagios Plugin\n\n";
  98. print "usage:\n";
  99. print " check_mem.pl -<f|u> -w <warnlevel> -c <critlevel>\n\n";
  100. print "options:\n";
  101. print " -f Check FREE memory\n";
  102. print " -u Check USED memory\n";
  103. print " -C Count OS caches as FREE memory\n";
  104. print " -h Remove hugepages from the total memory count\n";
  105. print " -w PERCENT Percent free/used when to warn\n";
  106. print " -c PERCENT Percent free/used when critical\n";
  107. print "\nCopyright (C) 2000 Dan Larsson <dl\@tyfon.net>\n";
  108. print "check_mem.pl comes with absolutely NO WARRANTY either implied or explicit\n";
  109. print "This program is licensed under the terms of the\n";
  110. print "MIT License (check source code for details)\n";
  111. exit $exit_codes{'UNKNOWN'};
  112. }
  113. sub get_memory_info {
  114. my $used_memory_kb = 0;
  115. my $free_memory_kb = 0;
  116. my $total_memory_kb = 0;
  117. my $caches_kb = 0;
  118. my $hugepages_nr = 0;
  119. my $hugepages_size = 0;
  120. my $hugepages_kb = 0;
  121. my $uname;
  122. if ( -e '/usr/bin/uname') {
  123. $uname = `/usr/bin/uname -a`;
  124. }
  125. elsif ( -e '/bin/uname') {
  126. $uname = `/bin/uname -a`;
  127. }
  128. else {
  129. die "Unable to find uname in /usr/bin or /bin!\n";
  130. }
  131. print "uname returns $uname" if ($opt_v);
  132. if ( $uname =~ /Linux/ ) {
  133. my @meminfo = `/bin/cat /proc/meminfo`;
  134. foreach (@meminfo) {
  135. chomp;
  136. if (/^Mem(Total|Free):\s+(\d+) kB/) {
  137. my $counter_name = $1;
  138. if ($counter_name eq 'Free') {
  139. $free_memory_kb = $2;
  140. }
  141. elsif ($counter_name eq 'Total') {
  142. $total_memory_kb = $2;
  143. }
  144. }
  145. elsif (/^(Buffers|Cached|SReclaimable):\s+(\d+) kB/) {
  146. $caches_kb += $2;
  147. }
  148. elsif (/^Shmem:\s+(\d+) kB/) {
  149. $caches_kb -= $1;
  150. }
  151. # These variables will most likely be overwritten once we look into
  152. # /sys/kernel/mm/hugepages, unless we are running on linux <2.6.27
  153. # and have to rely on them
  154. elsif (/^HugePages_Total:\s+(\d+)/) {
  155. $hugepages_nr = $1;
  156. }
  157. elsif (/^Hugepagesize:\s+(\d+) kB/) {
  158. $hugepages_size = $1;
  159. }
  160. }
  161. $hugepages_kb = $hugepages_nr * $hugepages_size;
  162. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  163. # Read hugepages info from the newer sysfs interface if available
  164. my $hugepages_sysfs_dir = '/sys/kernel/mm/hugepages';
  165. if ( -d $hugepages_sysfs_dir ) {
  166. # Reset what we read from /proc/meminfo
  167. $hugepages_kb = 0;
  168. opendir(my $dh, $hugepages_sysfs_dir)
  169. || die "Can't open $hugepages_sysfs_dir: $!";
  170. while (my $entry = readdir $dh) {
  171. if ($entry =~ /^hugepages-(\d+)kB/) {
  172. $hugepages_size = $1;
  173. my $hugepages_nr_file = "$hugepages_sysfs_dir/$entry/nr_hugepages";
  174. open(my $fh, '<', $hugepages_nr_file)
  175. || die "Can't open $hugepages_nr_file for reading: $!";
  176. $hugepages_nr = <$fh>;
  177. close($fh);
  178. $hugepages_kb += $hugepages_nr * $hugepages_size;
  179. }
  180. }
  181. closedir($dh);
  182. }
  183. }
  184. elsif ( $uname =~ /HP-UX/ ) {
  185. # HP-UX, thanks to Christoph Fürstaller
  186. my @meminfo = `/usr/bin/sudo /usr/local/bin/kmeminfo`;
  187. foreach (@meminfo) {
  188. chomp;
  189. if (/^Physical memory\s\s+=\s+(\d+)\s+(\d+.\d)g/) {
  190. $total_memory_kb = ($2 * 1024 * 1024);
  191. }
  192. elsif (/^Free memory\s\s+=\s+(\d+)\s+(\d+.\d)g/) {
  193. $free_memory_kb = ($2 * 1024 * 1024);
  194. }
  195. }
  196. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  197. }
  198. elsif ( $uname =~ /FreeBSD/ ) {
  199. # The FreeBSD case. 2013-03-19 www.claudiokuenzler.com
  200. # free mem = Inactive*Page Size + Cache*Page Size + Free*Page Size
  201. my $pagesize = `sysctl vm.stats.vm.v_page_size`;
  202. $pagesize =~ s/[^0-9]//g;
  203. my $mem_inactive = 0;
  204. my $mem_cache = 0;
  205. my $mem_free = 0;
  206. my $mem_total = 0;
  207. my $free_memory = 0;
  208. my @meminfo = `/sbin/sysctl vm.stats.vm`;
  209. foreach (@meminfo) {
  210. chomp;
  211. if (/^vm.stats.vm.v_inactive_count:\s+(\d+)/) {
  212. $mem_inactive = ($1 * $pagesize);
  213. }
  214. elsif (/^vm.stats.vm.v_cache_count:\s+(\d+)/) {
  215. $mem_cache = ($1 * $pagesize);
  216. }
  217. elsif (/^vm.stats.vm.v_free_count:\s+(\d+)/) {
  218. $mem_free = ($1 * $pagesize);
  219. }
  220. elsif (/^vm.stats.vm.v_page_count:\s+(\d+)/) {
  221. $mem_total = ($1 * $pagesize);
  222. }
  223. }
  224. $free_memory = $mem_inactive + $mem_cache + $mem_free;
  225. $free_memory_kb = ( $free_memory / 1024);
  226. $total_memory_kb = ( $mem_total / 1024);
  227. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  228. $caches_kb = ($mem_cache / 1024);
  229. }
  230. elsif ( $uname =~ /joyent/ ) {
  231. # The SmartOS case. 2014-01-10 www.claudiokuenzler.com
  232. # free mem = pagesfree * pagesize
  233. my $pagesize = `pagesize`;
  234. my $phys_pages = `kstat -p unix:0:system_pages:pagestotal | awk '{print \$NF}'`;
  235. my $free_pages = `kstat -p unix:0:system_pages:pagesfree | awk '{print \$NF}'`;
  236. my $arc_size = `kstat -p zfs:0:arcstats:size | awk '{print \$NF}'`;
  237. my $arc_size_kb = $arc_size / 1024;
  238. print "Pagesize is $pagesize" if ($opt_v);
  239. print "Total pages is $phys_pages" if ($opt_v);
  240. print "Free pages is $free_pages" if ($opt_v);
  241. print "Arc size is $arc_size" if ($opt_v);
  242. $caches_kb += $arc_size_kb;
  243. $total_memory_kb = $phys_pages * $pagesize / 1024;
  244. $free_memory_kb = $free_pages * $pagesize / 1024;
  245. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  246. }
  247. elsif ( $uname =~ /SunOS/ ) {
  248. eval "use Sun::Solaris::Kstat";
  249. if ($@) { #Kstat not available
  250. if ($opt_C) {
  251. print "You can't report on Solaris caches without Sun::Solaris::Kstat available!\n";
  252. exit $exit_codes{UNKNOWN};
  253. }
  254. my @vmstat = `/usr/bin/vmstat 1 2`;
  255. my $line;
  256. foreach (@vmstat) {
  257. chomp;
  258. $line = $_;
  259. }
  260. $free_memory_kb = (split(/ /,$line))[5] / 1024;
  261. my @prtconf = `/usr/sbin/prtconf`;
  262. foreach (@prtconf) {
  263. if (/^Memory size: (\d+) Megabytes/) {
  264. $total_memory_kb = $1 * 1024;
  265. }
  266. }
  267. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  268. }
  269. else { # We have kstat
  270. my $kstat = Sun::Solaris::Kstat->new();
  271. my $phys_pages = ${kstat}->{unix}->{0}->{system_pages}->{physmem};
  272. my $free_pages = ${kstat}->{unix}->{0}->{system_pages}->{freemem};
  273. # We probably should account for UFS caching here, but it's unclear
  274. # to me how to determine UFS's cache size. There's inode_cache,
  275. # and maybe the physmem variable in the system_pages module??
  276. # In the real world, it looks to be so small as not to really matter,
  277. # so we don't grab it. If someone can give me code that does this,
  278. # I'd be glad to put it in.
  279. my $arc_size = (exists ${kstat}->{zfs} && ${kstat}->{zfs}->{0}->{arcstats}->{size}) ?
  280. ${kstat}->{zfs}->{0}->{arcstats}->{size} / 1024
  281. : 0;
  282. $caches_kb += $arc_size;
  283. my $pagesize = `pagesize`;
  284. $total_memory_kb = $phys_pages * $pagesize / 1024;
  285. $free_memory_kb = $free_pages * $pagesize / 1024;
  286. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  287. }
  288. }
  289. elsif ( $uname =~ /Darwin/ ) {
  290. $total_memory_kb = (split(/ /,`/usr/sbin/sysctl hw.memsize`))[1]/1024;
  291. my $pagesize = (split(/ /,`/usr/sbin/sysctl hw.pagesize`))[1];
  292. $caches_kb = 0;
  293. my @vm_stat = `/usr/bin/vm_stat`;
  294. foreach (@vm_stat) {
  295. chomp;
  296. if (/^(Pages free):\s+(\d+)\.$/) {
  297. $free_memory_kb = $2*$pagesize/1024;
  298. }
  299. # 'caching' concept works different on MACH
  300. # this should be a reasonable approximation
  301. elsif (/^Pages (inactive|purgable):\s+(\d+).$/) {
  302. $caches_kb += $2*$pagesize/1024;
  303. }
  304. }
  305. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  306. }
  307. elsif ( $uname =~ /AIX/ ) {
  308. my @meminfo = `/usr/bin/vmstat -vh`;
  309. foreach (@meminfo) {
  310. chomp;
  311. if (/^\s*([0-9.]+)\s+(.*)/) {
  312. my $counter_name = $2;
  313. if ($counter_name eq 'memory pages') {
  314. $total_memory_kb = $1*4;
  315. }
  316. if ($counter_name eq 'free pages') {
  317. $free_memory_kb = $1*4;
  318. }
  319. if ($counter_name eq 'file pages') {
  320. $caches_kb = $1*4;
  321. }
  322. if ($counter_name eq 'Number of 4k page frames loaned') {
  323. $free_memory_kb += $1*4;
  324. }
  325. }
  326. }
  327. $used_memory_kb = $total_memory_kb - $free_memory_kb;
  328. }
  329. else {
  330. if ($opt_C) {
  331. print "You can't report on $uname caches!\n";
  332. exit $exit_codes{UNKNOWN};
  333. }
  334. my $command_line = `vmstat | tail -1 | awk '{print \$4,\$5}'`;
  335. chomp $command_line;
  336. my @memlist = split(/ /, $command_line);
  337. # Define the calculating scalars
  338. $used_memory_kb = $memlist[0]/1024;
  339. $free_memory_kb = $memlist[1]/1024;
  340. $total_memory_kb = $used_memory_kb + $free_memory_kb;
  341. }
  342. return ($free_memory_kb,$used_memory_kb,$caches_kb,$hugepages_kb);
  343. }
  344. sub init {
  345. # Get the options
  346. if ($#ARGV le 0) {
  347. &usage;
  348. }
  349. else {
  350. getopts('c:fuChvw:');
  351. }
  352. # Shortcircuit the switches
  353. if (!$opt_w or $opt_w == 0 or !$opt_c or $opt_c == 0) {
  354. print "*** You must define WARN and CRITICAL levels!\n";
  355. &usage;
  356. }
  357. elsif (!$opt_f and !$opt_u) {
  358. print "*** You must select to monitor either USED or FREE memory!\n";
  359. &usage;
  360. }
  361. # Check if levels are sane
  362. if ($opt_w <= $opt_c and $opt_f) {
  363. print "*** WARN level must not be less than CRITICAL when checking FREE memory!\n";
  364. &usage;
  365. }
  366. elsif ($opt_w >= $opt_c and $opt_u) {
  367. print "*** WARN level must not be greater than CRITICAL when checking USED memory!\n";
  368. &usage;
  369. }
  370. }
  371. sub finish {
  372. my ($msg,$state) = @_;
  373. print "$msg\n";
  374. exit $state;
  375. }