[perl_openvz] fix update error
[collectd.git] / bindings / perl / lib / Collectd / Plugins / OpenVZ.pm
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
23 package Collectd::Plugins::OpenVZ;
24
25 use strict;
26 use warnings;
27
28 #use Collectd qw( :all );
29
30 my $vzctl = '/usr/sbin/vzctl';
31 my $vzlist = '/usr/sbin/vzlist';
32
33 # Since OpenVZ is container based, all guests see all the host's CPUs,
34 # and would report the same data. So we disable CPU by default.
35 my $enable_interface = 1;
36 my $enable_cpu       = 0;
37 my $enable_df        = 1;
38 my $enable_load      = 1;
39 my $enable_processes = 1;
40 my $enable_users     = 1;
41
42 # We probably don't care about loopback transfer
43 my @ignored_interfaces = ( "lo" );
44
45 sub interface_read($$) {
46     my $veid = shift;
47     my $name = shift;
48     my ($current_interface, $val, @lines, @parts, @counters, $i);
49     my @if_instances = ('if_octets', 'if_packets', 'if_errors');
50     my %v = _build_report_hash($name);
51
52     $v{'plugin'} = 'interface';
53     delete $v{'plugin_instance'};
54
55     @lines = split(/\n/, `$vzctl exec $veid cat /proc/net/dev`);
56     #$ vzctl exec 1106221 cat /proc/net/dev
57     #Inter-|   Receive                                                |  Transmit
58     # face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
59     #     lo:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
60     #     venet0:    2420      27    0    0    0     0          0         0     2200      29    0    0    0     0       0          0
61     foreach (@lines) {
62         next if (!/:/);
63
64         @parts = split(/:/);
65         ($current_interface = $parts[0]) =~ s/^\s*(.*?)\s*$/$1/;
66         next if grep { $current_interface eq $_ } @ignored_interfaces;
67
68         ($val = $parts[1]) =~ s/^\s*(.*?)\s*$/$1/;
69         @counters = split(/ +/, $val);
70
71         $v{'plugin_instance'} = $current_interface;
72         for ($i= 0; $i <= $#if_instances; ++$i) {
73             $v{'type'} = $if_instances[$i];
74             $v{'values'} = [ $counters[$i], $counters[$i + 8] ];
75             plugin_dispatch_values(\%v);
76     }
77 }
78 }
79
80 sub cpu_read($$) {
81     my $veid = shift;
82     my $name = shift;
83     my ($key, $val, $i, @lines, @counters);
84     my @cpu_instances = ('user', 'nice', 'system', 'idle', 'wait', 'interrupt', 'softirq', 'steal');
85     my $last_stat = {};
86     my %v = _build_report_hash($name);
87
88     $v{'plugin'} = 'cpu';
89     $v{'type'} = 'cpu';
90
91     $i = 0;
92     @lines = split(/\n/, `$vzctl exec $veid cat /proc/stat`);
93     foreach (@lines) {
94         next if (!/^cpu[0-9]/);
95
96         @counters = split(/ +/);
97         shift(@counters);
98
99         # Remove once OpenVZ bug 1376 is resolved
100         if (48485 == $counters[3]) {
101             $counters[3] = $last_stat->{"$veid-$i-idle"};
102             $counters[4] = $last_stat->{"$veid-$i-wait"};
103         }
104         else {
105             $last_stat->{"$veid-$i-idle"} = $counters[3];
106             $last_stat->{"$veid-$i-wait"} = $counters[4];
107         }
108
109         $v{'plugin_instance'} = $i++;
110         for ($key = 0; $key <= $#counters; ++$key) {
111             $v{'type_instance'} = $cpu_instances[$key];
112             $v{'values'} = [ $counters[$key] ];
113             plugin_dispatch_values(\%v);
114     }
115 }
116 }
117
118 sub df_read($$) {
119     my $veid = shift;
120     my $name = shift;
121     my ($key, $val, @lines, @parts);
122     my %v = _build_report_hash($name);
123
124     $v{'plugin'} = 'df';
125     delete $v{'plugin_instance'};
126     $v{'type'} = 'df';
127
128     $val = join(' ', map { (split)[1] } split(/\n/, `$vzctl exec $veid cat /proc/mounts`));
129     @lines = split(/\n/, `$vzctl exec $veid stat -tf $val`);
130     foreach (@lines) {
131         @parts = split(/ /);
132         next if (0 == $parts[7]);
133
134         $val = substr($parts[0], 1);
135         $val = 'root' if ($val =~ /^$/);
136         $val =~ s#/#-#g;
137
138         $v{'type_instance'} = $val;
139         $v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
140         plugin_dispatch_values(\%v);
141 }
142 }
143
144 sub load_read($$) {
145     my $veid = shift;
146     my $name = shift;
147     my ($key, $val, @lines, @parts);
148     my %v = _build_report_hash($name);
149
150     $v{'plugin'} = 'load';
151     delete $v{'plugin_instance'};
152     $v{'type'} = 'load';
153     delete $v{'type_instance'};
154
155     @parts = split(/ +/, `$vzctl exec $veid cat /proc/loadavg`);
156     $v{'values'} = [ $parts[0], $parts[1], $parts[2] ];
157     plugin_dispatch_values(\%v);
158 }
159
160 sub processes_read($$) {
161     my $veid = shift;
162     my $name = shift;
163     my ($key, $val, @lines);
164     my %v = _build_report_hash($name);
165
166     my $ps_states = { 'paging' => 0, 'blocked' => 0, 'zombies' => 0, 'stopped' => 0,
167         'running' => 0, 'sleeping' => 0 };
168     my $state_map = { 'R' => 'running', 'S' => 'sleeping', 'D' => 'blocked',
169         'Z' => 'zombies', 'T' => 'stopped', 'W' => 'paging' };
170
171     $v{'plugin'} = 'processes';
172     delete $v{'plugin_instance'};
173     $v{'type'} = 'ps_state';
174
175     @lines = map { (split)[2] } split(/\n/, `$vzctl exec $veid cat '/proc/[0-9]*/stat'`);
176     foreach $key (@lines) {
177         ++$ps_states->{$state_map->{$key}};
178     }
179
180     foreach $key (keys %{$ps_states}) {
181         $v{'type_instance'} = $key;
182         $v{'values'} = [ $ps_states->{$key} ];
183         plugin_dispatch_values(\%v);
184 }
185 }
186
187 sub users_read($$) {
188     my $veid = shift;
189     my $name = shift;
190     my ($key, $val, @lines);
191     my %v = _build_report_hash($name);
192
193     $v{'plugin'} = 'users';
194     delete $v{'plugin_instance'};
195     $v{'type'} = 'users';
196     delete $v{'type_instance'};
197
198     @lines = split(/\n/, `$vzctl exec $veid w -h`);
199     $v{'values'} = [ scalar(@lines) ];
200     plugin_dispatch_values(\%v);
201 }
202
203 sub _build_report_hash($) {
204     my $name = shift;
205     return (time => time(), interval => plugin_get_interval(), host => $name);
206 }
207
208 sub openvz_read {
209     my (@veids, $veid, $name);
210
211     @veids = map { s/ //g; $_; } split(/\n/, `$vzlist -Ho veid`);
212
213     foreach $veid (@veids) {
214         ($name = `$vzlist -Ho name $veid`) =~ s/^\s*(.*?)\s*$/$1/;
215         ($name = `$vzlist -Ho hostname $veid`) =~ s/^\s*(.*?)\s*$/$1/ if($name =~ /^-$/);
216         $name = $veid if ($name =~ /^-$/);
217
218         if($enable_interface) {
219             interface_read($veid, $name);
220         }
221
222         if($enable_cpu) {
223             cpu_read($veid, $name);
224         }
225
226         if($enable_df) {
227             df_read($veid, $name);
228         }
229
230         if($enable_load) {
231             load_read($veid, $name);
232         }
233
234         if($enable_processes) {
235             processes_read($veid, $name);
236         }
237
238         if($enable_users) {
239             users_read($veid, $name);
240         }
241
242         return 1;
243     }
244 }
245
246 plugin_register(TYPE_READ, 'OpenVZ', 'openvz_read');
247
248 return 1;