use Collectd qw( :all );
-my @cpu_instances = ('user', 'nice', 'system', 'idle', 'wait', 'interrupt', 'softirq', 'steal');
-my @if_instances = ('if_octets', 'if_packets', 'if_errors');
my $vzctl = '/usr/sbin/vzctl';
my $vzlist = '/usr/sbin/vzlist';
-my $last_stat = {};
+# Since OpenVZ is container based, all guests see all the host's CPUs,
+# and would report the same data. So we disable CPU by default.
+my $enable_interface = 1;
+my $enable_cpu = 0;
+my $enable_df = 1;
+my $enable_load = 1;
+my $enable_processes = 1;
+my $enable_users = 1;
-sub openvz_read
-{
- my %v = (time => time(), interval => plugin_get_interval());
- my (@veids, $veid, $name, $key, $val, $i, @lines, @parts, @counters);
+# We probably don't care about loopback transfer
+my @ignored_interfaces = ( "lo" );
- @veids = map { s/ //g; $_; } split(/\n/, `$vzlist -Ho veid`);
+sub interface_read {
+ my ($veid, $name) = @_;
+ my @rx_fields = qw(if_octets if_packets if_errors drop fifo frame compressed multicast);
+ my @tx_fields = qw(if_octets if_packets if_errors drop fifo frame compressed);
+ my %v = _build_report_hash($name);
- foreach $veid (@veids)
- {
- ($name = `$vzlist -Ho name $veid`) =~ s/^\s*(.*?)\s*$/$1/;
- $name = $veid if ($name =~ /^-$/);
+ my @lines = `$vzctl exec $veid cat /proc/net/dev`;
- $v{'host'} = $name;
+ for my $line (@lines) {
+ # skip explanatory text
+ next if $line !~ /:/;
- #####################################################################
- # interface
+ $line =~ s/^\s+|\s+$//g;
- $v{'plugin'} = 'interface';
- delete $v{'plugin_instance'};
+ my ($iface, %rx, %tx);
- @lines = split(/\n/, `$vzctl exec $veid cat /proc/net/dev`);
- foreach (@lines)
- {
- next if (!/:/);
+ # read /proc/net/dev fields
+ ($iface, @rx{@rx_fields}, @tx{@tx_fields}) = split /[: ]+/, $line;
- @parts = split(/:/);
- ($key = $parts[0]) =~ s/^\s*(.*?)\s*$/$1/;
- ($val = $parts[1]) =~ s/^\s*(.*?)\s*$/$1/;
- @counters = split(/ +/, $val);
+ # Skip this interface if it is in the ignored list
+ next if grep { $iface eq $_ } @ignored_interfaces;
- $v{'type_instance'} = $key;
- for ($key = 0; $key <= $#if_instances; ++$key)
- {
- $v{'type'} = $if_instances[$key];
- $v{'values'} = [ $counters[$key], $counters[$key + 8] ];
- plugin_dispatch_values(\%v);
- }
+ for my $instance (qw(if_octets if_packets if_errors)) {
+ plugin_dispatch_values({
+ 'plugin' => 'interface',
+ 'plugin_instance' => $iface,
+ 'type' => $instance,
+ 'values' => [ $rx{$instance}, $tx{$instance} ],
+ %v,
+ });
}
+ }
+}
- #####################################################################
- # cpu
-
- $v{'plugin'} = 'cpu';
- $v{'type'} = 'cpu';
-
- $i = 0;
- @lines = split(/\n/, `$vzctl exec $veid cat /proc/stat`);
- foreach (@lines)
- {
- next if (!/^cpu[0-9]/);
-
- @counters = split(/ +/);
- shift(@counters);
-
- # Remove once OpenVZ bug 1376 is resolved
- if (48485 == $counters[3])
- {
- $counters[3] = $last_stat->{"$veid-$i-idle"};
- $counters[4] = $last_stat->{"$veid-$i-wait"};
- }
- else
- {
- $last_stat->{"$veid-$i-idle"} = $counters[3];
- $last_stat->{"$veid-$i-wait"} = $counters[4];
- }
-
- $v{'plugin_instance'} = $i++;
- for ($key = 0; $key <= $#counters; ++$key)
- {
- $v{'type_instance'} = $cpu_instances[$key];
- $v{'values'} = [ $counters[$key] ];
- plugin_dispatch_values(\%v);
- }
+sub cpu_read {
+ my $veid = shift;
+ my $name = shift;
+ my ($key, $val, $i, @lines, @counters);
+ my @cpu_instances = ('user', 'nice', 'system', 'idle', 'wait', 'interrupt', 'softirq', 'steal');
+ my $last_stat = {};
+ my %v = _build_report_hash($name);
+
+ $v{'plugin'} = 'cpu';
+ $v{'type'} = 'cpu';
+
+ $i = 0;
+ @lines = split(/\n/, `$vzctl exec $veid cat /proc/stat`);
+ foreach (@lines) {
+ next if (!/^cpu[0-9]/);
+
+ @counters = split(/ +/);
+ shift(@counters);
+
+ # Remove once OpenVZ bug 1376 is resolved
+ if (48485 == $counters[3]) {
+ $counters[3] = $last_stat->{"$veid-$i-idle"};
+ $counters[4] = $last_stat->{"$veid-$i-wait"};
+ }
+ else {
+ $last_stat->{"$veid-$i-idle"} = $counters[3];
+ $last_stat->{"$veid-$i-wait"} = $counters[4];
}
- #####################################################################
- # df
+ $v{'plugin_instance'} = $i++;
+ for ($key = 0; $key <= $#counters; ++$key) {
+ $v{'type_instance'} = $cpu_instances[$key];
+ $v{'values'} = [ $counters[$key] ];
+ plugin_dispatch_values(\%v);
+ }
+}
+}
- $v{'plugin'} = 'df';
- delete $v{'plugin_instance'};
- $v{'type'} = 'df';
+sub df_read {
+ my $veid = shift;
+ my $name = shift;
+ my ($key, $val, @lines, @parts);
+ my %v = _build_report_hash($name);
- $val = join(' ', map { (split)[1] } split(/\n/, `$vzctl exec $veid cat /proc/mounts`));
- @lines = split(/\n/, `$vzctl exec $veid stat -tf $val`);
- foreach (@lines)
- {
- @parts = split(/ /);
- next if (0 == $parts[7]);
+ $v{'plugin'} = 'df';
+ delete $v{'plugin_instance'};
+ $v{'type'} = 'df';
- $val = substr($parts[0], 1);
- $val = 'root' if ($val =~ /^$/);
- $val =~ s#/#-#g;
+ $val = join(' ', map { (split)[1] } split(/\n/, `$vzctl exec $veid cat /proc/mounts`));
+ @lines = split(/\n/, `$vzctl exec $veid stat -tf $val`);
+ foreach (@lines) {
+ @parts = split(/ /);
+ next if (0 == $parts[7]);
- $v{'type_instance'} = $val;
- $v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
- plugin_dispatch_values(\%v);
- }
+ $val = substr($parts[0], 1);
+ $val = 'root' if ($val =~ /^$/);
+ $val =~ s#/#-#g;
+
+ $v{'type_instance'} = $val;
+ $v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
+ plugin_dispatch_values(\%v);
+}
+}
- #####################################################################
- # load
+sub load_read {
+ my $veid = shift;
+ my $name = shift;
+ my ($key, $val, @lines, @parts);
+ my %v = _build_report_hash($name);
- $v{'plugin'} = 'load';
- delete $v{'plugin_instance'};
- $v{'type'} = 'load';
- delete $v{'type_instance'};
+ $v{'plugin'} = 'load';
+ delete $v{'plugin_instance'};
+ $v{'type'} = 'load';
+ delete $v{'type_instance'};
- @parts = split(/ +/, `$vzctl exec $veid cat /proc/loadavg`);
- $v{'values'} = [ $parts[0], $parts[1], $parts[2] ];
+ @parts = split(/ +/, `$vzctl exec $veid cat /proc/loadavg`);
+ $v{'values'} = [ $parts[0], $parts[1], $parts[2] ];
+ plugin_dispatch_values(\%v);
+}
+
+sub processes_read {
+ my $veid = shift;
+ my $name = shift;
+ my ($key, $val, @lines);
+ my %v = _build_report_hash($name);
+
+ my $ps_states = { 'paging' => 0, 'blocked' => 0, 'zombies' => 0, 'stopped' => 0,
+ 'running' => 0, 'sleeping' => 0 };
+ my $state_map = { 'R' => 'running', 'S' => 'sleeping', 'D' => 'blocked',
+ 'Z' => 'zombies', 'T' => 'stopped', 'W' => 'paging' };
+
+ $v{'plugin'} = 'processes';
+ delete $v{'plugin_instance'};
+ $v{'type'} = 'ps_state';
+
+ @lines = map { (split)[2] } split(/\n/, `$vzctl exec $veid cat '/proc/[0-9]*/stat'`);
+ foreach $key (@lines) {
+ ++$ps_states->{$state_map->{$key}};
+ }
+
+ foreach $key (keys %{$ps_states}) {
+ $v{'type_instance'} = $key;
+ $v{'values'} = [ $ps_states->{$key} ];
plugin_dispatch_values(\%v);
+}
+}
- #####################################################################
- # processes
+sub users_read {
+ my $veid = shift;
+ my $name = shift;
+ my ($key, $val, @lines);
+ my %v = _build_report_hash($name);
- my $ps_states = { 'paging' => 0, 'blocked' => 0, 'zombies' => 0, 'stopped' => 0,
- 'running' => 0, 'sleeping' => 0 };
- my $state_map = { 'R' => 'running', 'S' => 'sleeping', 'D' => 'blocked',
- 'Z' => 'zombies', 'T' => 'stopped', 'W' => 'paging' };
+ $v{'plugin'} = 'users';
+ delete $v{'plugin_instance'};
+ $v{'type'} = 'users';
+ delete $v{'type_instance'};
- $v{'plugin'} = 'processes';
- delete $v{'plugin_instance'};
- $v{'type'} = 'ps_state';
+ @lines = split(/\n/, `$vzctl exec $veid w -h`);
+ $v{'values'} = [ scalar(@lines) ];
+ plugin_dispatch_values(\%v);
+}
+
+sub _build_report_hash {
+ my $name = shift;
+ return (time => time(), interval => plugin_get_interval(), host => $name);
+}
- @lines = map { (split)[2] } split(/\n/, `$vzctl exec $veid cat '/proc/[0-9]*/stat'`);
- foreach $key (@lines)
- {
- ++$ps_states->{$state_map->{$key}};
+sub openvz_read {
+ my (@veids, $veid, $name);
+
+ @veids = map { s/ //g; $_; } split(/\n/, `$vzlist -Ho veid`);
+
+ foreach $veid (@veids) {
+ ($name = `$vzlist -Ho name $veid`) =~ s/^\s*(.*?)\s*$/$1/;
+ ($name = `$vzlist -Ho hostname $veid`) =~ s/^\s*(.*?)\s*$/$1/ if($name =~ /^-$/);
+ $name = $veid if ($name =~ /^-$/);
+
+ if($enable_interface) {
+ interface_read($veid, $name);
}
- foreach $key (keys %{$ps_states})
- {
- $v{'type_instance'} = $key;
- $v{'values'} = [ $ps_states->{$key} ];
- plugin_dispatch_values(\%v);
+ if($enable_cpu) {
+ cpu_read($veid, $name);
}
- #####################################################################
- # users
+ if($enable_df) {
+ df_read($veid, $name);
+ }
- $v{'plugin'} = 'users';
- delete $v{'plugin_instance'};
- $v{'type'} = 'users';
- delete $v{'type_instance'};
+ if($enable_load) {
+ load_read($veid, $name);
+ }
- @lines = split(/\n/, `$vzctl exec $veid w -h`);
- $v{'values'} = [ scalar(@lines) ];
- plugin_dispatch_values(\%v);
- }
+ if($enable_processes) {
+ processes_read($veid, $name);
+ }
- return 1;
+ if($enable_users) {
+ users_read($veid, $name);
+ }
+
+ return 1;
+ }
}
plugin_register(TYPE_READ, 'OpenVZ', 'openvz_read');