Merge branch 'collectd-5.3' into collectd-5.4
[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 @cpu_instances = ('user', 'nice', 'system', 'idle', 'wait', 'interrupt', 'softirq', 'steal');
31 my @if_instances = ('if_octets', 'if_packets', 'if_errors');
32 my $vzctl = '/usr/sbin/vzctl';
33 my $vzlist = '/usr/sbin/vzlist';
34
35 my $last_stat = {};
36
37 sub openvz_read
38 {
39     my %v = (time => time(), interval => plugin_get_interval());
40     my (@veids, $veid, $name, $key, $val, $i, @lines, @parts, @counters);
41
42     @veids = map { s/ //g; $_; } split(/\n/, `$vzlist -Ho veid`);
43
44     foreach $veid (@veids)
45     {
46         ($name = `$vzlist -Ho name $veid`) =~ s/^\s*(.*?)\s*$/$1/;
47         $name = $veid if ($name =~ /^-$/);
48
49         $v{'host'} = $name;
50
51         #####################################################################
52         # interface
53
54         $v{'plugin'} = 'interface';
55         delete $v{'plugin_instance'};
56
57         @lines = split(/\n/, `$vzctl exec $veid cat /proc/net/dev`);
58         foreach (@lines)
59         {
60             next if (!/:/);                
61
62             @parts = split(/:/);
63             ($key = $parts[0]) =~ s/^\s*(.*?)\s*$/$1/;
64             ($val = $parts[1]) =~ s/^\s*(.*?)\s*$/$1/;
65             @counters = split(/ +/, $val);
66
67             $v{'type_instance'} = $key;
68             for ($key = 0; $key <= $#if_instances; ++$key)
69             {
70                 $v{'type'} = $if_instances[$key];
71                 $v{'values'} = [ $counters[$key], $counters[$key + 8] ];
72                 plugin_dispatch_values(\%v);
73             }
74         }
75
76         #####################################################################
77         # cpu
78
79         $v{'plugin'} = 'cpu';
80         $v{'type'} = 'cpu';
81
82         $i = 0;
83         @lines = split(/\n/, `$vzctl exec $veid cat /proc/stat`);
84         foreach (@lines)
85         {
86             next if (!/^cpu[0-9]/);
87
88             @counters = split(/ +/);
89             shift(@counters);
90
91             # Remove once OpenVZ bug 1376 is resolved
92             if (48485 == $counters[3])
93             {
94                 $counters[3] = $last_stat->{"$veid-$i-idle"};
95                 $counters[4] = $last_stat->{"$veid-$i-wait"};
96             }
97             else
98             {
99                 $last_stat->{"$veid-$i-idle"} = $counters[3];
100                 $last_stat->{"$veid-$i-wait"} = $counters[4];
101             }
102
103             $v{'plugin_instance'} = $i++;
104             for ($key = 0; $key <= $#counters; ++$key)
105             {
106                 $v{'type_instance'} = $cpu_instances[$key];
107                 $v{'values'} = [ $counters[$key] ];
108                 plugin_dispatch_values(\%v);
109             }
110         }
111
112         #####################################################################
113         # df
114
115         $v{'plugin'} = 'df';
116         delete $v{'plugin_instance'};
117         $v{'type'} = 'df';
118
119         $val = join(' ', map { (split)[1] } split(/\n/, `$vzctl exec $veid cat /proc/mounts`));
120         @lines = split(/\n/, `$vzctl exec $veid stat -tf $val`);
121         foreach (@lines)
122         {
123             @parts = split(/ /);
124             next if (0 == $parts[7]);
125
126             $val = substr($parts[0], 1);
127             $val = 'root' if ($val =~ /^$/);
128             $val =~ s#/#-#g;
129
130             $v{'type_instance'} = $val;
131             $v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
132             plugin_dispatch_values(\%v);
133         }
134
135         #####################################################################
136         # load
137
138         $v{'plugin'} = 'load';
139         delete $v{'plugin_instance'};
140         $v{'type'} = 'load';
141         delete $v{'type_instance'};
142
143         @parts = split(/ +/, `$vzctl exec $veid cat /proc/loadavg`);
144         $v{'values'} = [ $parts[0], $parts[1], $parts[2] ];
145         plugin_dispatch_values(\%v);
146
147         #####################################################################
148         # processes
149
150         my $ps_states = { 'paging' => 0, 'blocked' => 0, 'zombies' => 0, 'stopped' => 0,
151             'running' => 0, 'sleeping' => 0 };
152         my $state_map = { 'R' => 'running', 'S' => 'sleeping', 'D' => 'blocked',
153             'Z' => 'zombies', 'T' => 'stopped', 'W' => 'paging' };
154
155         $v{'plugin'} = 'processes';
156         delete $v{'plugin_instance'};
157         $v{'type'} = 'ps_state';
158
159         @lines = map { (split)[2] } split(/\n/, `$vzctl exec $veid cat '/proc/[0-9]*/stat'`);
160         foreach $key (@lines)
161         {
162             ++$ps_states->{$state_map->{$key}};
163         }
164
165         foreach $key (keys %{$ps_states})
166         {
167             $v{'type_instance'} = $key;
168             $v{'values'} = [ $ps_states->{$key} ];
169             plugin_dispatch_values(\%v);
170         }
171
172         #####################################################################
173         # users
174
175         $v{'plugin'} = 'users';
176         delete $v{'plugin_instance'};
177         $v{'type'} = 'users';
178         delete $v{'type_instance'};
179
180         @lines = split(/\n/, `$vzctl exec $veid w -h`);
181         $v{'values'} = [ scalar(@lines) ];
182         plugin_dispatch_values(\%v);
183     }
184
185     return 1;
186 }
187
188 plugin_register(TYPE_READ, 'OpenVZ', 'openvz_read');
189
190 return 1;