PageRenderTime 68ms CodeModel.GetById 42ms RepoModel.GetById 0ms app.codeStats 0ms

/bindings/perl/lib/Collectd/Plugins/OpenVZ.pm

https://gitlab.com/cmalfait/collectd
Perl | 247 lines | 170 code | 49 blank | 28 comment | 20 complexity | 175e3a09915f177aedb35428ada62fa1 MD5 | raw file
  1. #
  2. # collectd - OpenVZ collectd plugin
  3. # Copyright (C) 2009 Jonathan Kolb
  4. #
  5. # This program is free software; you can redistribute it and/or modify it under
  6. # the terms of the GNU General Public License as published by the Free Software
  7. # Foundation; either version 2 of the License, or (at your option) any later
  8. # version.
  9. #
  10. # This program is distributed in the hope that it will be useful, but
  11. # WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License along
  16. # with this program; if not, write to the Free Software Foundation, Inc.,
  17. # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. #
  19. # Author:
  20. # Jonathan Kolb <jon at b0g.us>
  21. #
  22. package Collectd::Plugins::OpenVZ;
  23. use strict;
  24. use warnings;
  25. use Collectd qw( :all );
  26. my $vzctl = '/usr/sbin/vzctl';
  27. my $vzlist = '/usr/sbin/vzlist';
  28. # Since OpenVZ is container based, all guests see all the host's CPUs,
  29. # and would report the same data. So we disable CPU by default.
  30. my $enable_interface = 1;
  31. my $enable_cpu = 0;
  32. my $enable_df = 1;
  33. my $enable_load = 1;
  34. my $enable_processes = 1;
  35. my $enable_users = 1;
  36. # We probably don't care about loopback transfer
  37. my @ignored_interfaces = ( "lo" );
  38. sub interface_read {
  39. my ($veid, $name) = @_;
  40. my @rx_fields = qw(if_octets if_packets if_errors drop fifo frame compressed multicast);
  41. my @tx_fields = qw(if_octets if_packets if_errors drop fifo frame compressed);
  42. my %v = _build_report_hash($name);
  43. my @lines = `$vzctl exec $veid cat /proc/net/dev`;
  44. for my $line (@lines) {
  45. # skip explanatory text
  46. next if $line !~ /:/;
  47. $line =~ s/^\s+|\s+$//g;
  48. my ($iface, %rx, %tx);
  49. # read /proc/net/dev fields
  50. ($iface, @rx{@rx_fields}, @tx{@tx_fields}) = split /[: ]+/, $line;
  51. # Skip this interface if it is in the ignored list
  52. next if grep { $iface eq $_ } @ignored_interfaces;
  53. for my $instance (qw(if_octets if_packets if_errors)) {
  54. plugin_dispatch_values({
  55. 'plugin' => 'interface',
  56. 'plugin_instance' => $iface,
  57. 'type' => $instance,
  58. 'values' => [ $rx{$instance}, $tx{$instance} ],
  59. %v,
  60. });
  61. }
  62. }
  63. }
  64. sub cpu_read {
  65. my $veid = shift;
  66. my $name = shift;
  67. my ($key, $val, $i, @lines, @counters);
  68. my @cpu_instances = ('user', 'nice', 'system', 'idle', 'wait', 'interrupt', 'softirq', 'steal');
  69. my $last_stat = {};
  70. my %v = _build_report_hash($name);
  71. $v{'plugin'} = 'cpu';
  72. $v{'type'} = 'cpu';
  73. $i = 0;
  74. @lines = split(/\n/, `$vzctl exec $veid cat /proc/stat`);
  75. foreach (@lines) {
  76. next if (!/^cpu[0-9]/);
  77. @counters = split(/ +/);
  78. shift(@counters);
  79. # Remove once OpenVZ bug 1376 is resolved
  80. if (48485 == $counters[3]) {
  81. $counters[3] = $last_stat->{"$veid-$i-idle"};
  82. $counters[4] = $last_stat->{"$veid-$i-wait"};
  83. }
  84. else {
  85. $last_stat->{"$veid-$i-idle"} = $counters[3];
  86. $last_stat->{"$veid-$i-wait"} = $counters[4];
  87. }
  88. $v{'plugin_instance'} = $i++;
  89. for ($key = 0; $key <= $#counters; ++$key) {
  90. $v{'type_instance'} = $cpu_instances[$key];
  91. $v{'values'} = [ $counters[$key] ];
  92. plugin_dispatch_values(\%v);
  93. }
  94. }
  95. }
  96. sub df_read {
  97. my $veid = shift;
  98. my $name = shift;
  99. my ($key, $val, @lines, @parts);
  100. my %v = _build_report_hash($name);
  101. $v{'plugin'} = 'df';
  102. delete $v{'plugin_instance'};
  103. $v{'type'} = 'df';
  104. $val = join(' ', map { (split)[1] } split(/\n/, `$vzctl exec $veid cat /proc/mounts`));
  105. @lines = split(/\n/, `$vzctl exec $veid stat -tf $val`);
  106. foreach (@lines) {
  107. @parts = split(/ /);
  108. next if (0 == $parts[7]);
  109. $val = substr($parts[0], 1);
  110. $val = 'root' if ($val =~ /^$/);
  111. $val =~ s#/#-#g;
  112. $v{'type_instance'} = $val;
  113. $v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
  114. plugin_dispatch_values(\%v);
  115. }
  116. }
  117. sub load_read {
  118. my $veid = shift;
  119. my $name = shift;
  120. my ($key, $val, @lines, @parts);
  121. my %v = _build_report_hash($name);
  122. $v{'plugin'} = 'load';
  123. delete $v{'plugin_instance'};
  124. $v{'type'} = 'load';
  125. delete $v{'type_instance'};
  126. @parts = split(/ +/, `$vzctl exec $veid cat /proc/loadavg`);
  127. $v{'values'} = [ $parts[0], $parts[1], $parts[2] ];
  128. plugin_dispatch_values(\%v);
  129. }
  130. sub processes_read {
  131. my $veid = shift;
  132. my $name = shift;
  133. my ($key, $val, @lines);
  134. my %v = _build_report_hash($name);
  135. my $ps_states = { 'paging' => 0, 'blocked' => 0, 'zombies' => 0, 'stopped' => 0,
  136. 'running' => 0, 'sleeping' => 0 };
  137. my $state_map = { 'R' => 'running', 'S' => 'sleeping', 'D' => 'blocked',
  138. 'Z' => 'zombies', 'T' => 'stopped', 'W' => 'paging' };
  139. $v{'plugin'} = 'processes';
  140. delete $v{'plugin_instance'};
  141. $v{'type'} = 'ps_state';
  142. @lines = map { (split)[2] } split(/\n/, `$vzctl exec $veid cat '/proc/[0-9]*/stat'`);
  143. foreach $key (@lines) {
  144. ++$ps_states->{$state_map->{$key}};
  145. }
  146. foreach $key (keys %{$ps_states}) {
  147. $v{'type_instance'} = $key;
  148. $v{'values'} = [ $ps_states->{$key} ];
  149. plugin_dispatch_values(\%v);
  150. }
  151. }
  152. sub users_read {
  153. my $veid = shift;
  154. my $name = shift;
  155. my ($key, $val, @lines);
  156. my %v = _build_report_hash($name);
  157. $v{'plugin'} = 'users';
  158. delete $v{'plugin_instance'};
  159. $v{'type'} = 'users';
  160. delete $v{'type_instance'};
  161. @lines = split(/\n/, `$vzctl exec $veid w -h`);
  162. $v{'values'} = [ scalar(@lines) ];
  163. plugin_dispatch_values(\%v);
  164. }
  165. sub _build_report_hash {
  166. my $name = shift;
  167. return (time => time(), interval => plugin_get_interval(), host => $name);
  168. }
  169. sub openvz_read {
  170. my (@veids, $veid, $name);
  171. @veids = map { s/ //g; $_; } split(/\n/, `$vzlist -Ho veid`);
  172. foreach $veid (@veids) {
  173. ($name = `$vzlist -Ho name $veid`) =~ s/^\s*(.*?)\s*$/$1/;
  174. ($name = `$vzlist -Ho hostname $veid`) =~ s/^\s*(.*?)\s*$/$1/ if($name =~ /^-$/);
  175. $name = $veid if ($name =~ /^-$/);
  176. if($enable_interface) {
  177. interface_read($veid, $name);
  178. }
  179. if($enable_cpu) {
  180. cpu_read($veid, $name);
  181. }
  182. if($enable_df) {
  183. df_read($veid, $name);
  184. }
  185. if($enable_load) {
  186. load_read($veid, $name);
  187. }
  188. if($enable_processes) {
  189. processes_read($veid, $name);
  190. }
  191. if($enable_users) {
  192. users_read($veid, $name);
  193. }
  194. return 1;
  195. }
  196. }
  197. plugin_register(TYPE_READ, 'OpenVZ', 'openvz_read');
  198. return 1;