added DC and RACK location from enviroment
[gnt-info] / gnt-monitor
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5 use POSIX;
6
7 my $DEBUG = $ENV{DEBUG} || 0;
8 my $INFLUX = $ENV{INFLUX} || 'http://10.60.0.89:8186/write';
9 my $INTERVAL = $ENV{INTERVAL} || 1;
10 my $DC = $ENV{DC};
11 my $RACK = $ENV{RACK};
12
13 my $node = `hostname -s`;
14 chomp $node;
15
16 use Data::Dump;
17 sub XXX { $DEBUG ? warn "XXX ",Data::Dump::dump( @_ ) : {} };
18
19 my $stat;
20 my $last;
21
22 while(1) {
23
24 my $skip;
25
26 foreach my $instance ( glob '/var/run/ganeti/kvm-hypervisor/pid/*' ) {
27
28         open(my $fh, '<', $instance);
29         my $pid = <$fh>; chomp $pid;
30
31         $instance =~ s{^.*/}{};
32
33         if ( ! -d "/proc/$pid" ) {
34                 $skip->{$instance}++;
35                 XXX $skip;
36                 next;
37         }
38
39         my $vcpu = $last->{$instance}->{vcpu};
40
41         if ( ! $vcpu ) {
42                 foreach my $fd ( glob "/proc/$pid/fd/*" ) {
43                         $vcpu++ if -l $fd && readlink($fd) =~ m/kvm-vcpu/;
44                 }
45
46                 $last->{$instance}->{vcpu} = $vcpu;
47         }
48
49         # https://www.kernel.org/doc/Documentation/filesystems/proc.txt
50         open($fh, '<', "/proc/$pid/stat");
51         my $line = <$fh>; chomp $line;
52         my $gtime = (split(/\s+/,$line))[42]; # guest time of the task in jiffies
53
54         if ( my $last_gtime = $last->{$instance}->{gtime} ) {
55                 my $clock_ticks = POSIX::sysconf( &POSIX::_SC_CLK_TCK ); # clock ticks per second
56
57                 my $cpu = ( ( $gtime - $last_gtime ) * 100 ) / ( $clock_ticks * $vcpu );
58                 $stat->{$instance}->{cpu} = $cpu;
59         }
60
61         $last->{$instance}->{gtime} = $gtime;
62 }
63                 
64
65 foreach my $glob ( glob '/var/run/ganeti/instance-disks/*' ) {
66         my ( $instance, $disk ) = split(/:/,$glob,2);
67         $instance =~ s{^.*/}{};
68
69         next unless exists $stat->{$instance};
70
71         my $dev = readlink $glob;
72         $dev =~ s{^.*dev/}{};
73
74         if ( ! -e "/sys/class/block/$dev" ) {
75                 $skip->{$instance}++;
76                 XXX $skip;
77                 next;
78         }
79
80         open( my $fh, '<', "/sys/class/block/$dev/stat" );
81         my $v = <$fh>; chomp $v; $v =~ s/^\s+//;
82         my @s = split(/\s+/, $v );
83         # https://www.kernel.org/doc/Documentation/block/stat.txt
84         my $d = {
85                 read_io => $s[0],
86                 read_bytes => $s[2] * 512,
87                 read_wait => $s[3],
88                 write_io => $s[4],
89                 write_bytes => $s[6] * 512,
90                 write_wait => $s[7],
91         };
92         if ( my $l = $last->{$instance}->{disk}->[$disk] ) {
93                 my $delta;
94                 $delta->{$_} = $d->{$_} - $l->{$_} foreach keys %$d;
95                 $stat->{$instance}->{disk}->[$disk] = $delta;
96                 $stat->{$instance}->{disk}->[$disk]->{dev} = $dev;
97                 $stat->{$instance}->{disk}->[$disk]->{disk} = $disk;
98         }
99         $last->{$instance}->{disk}->[$disk] = $d;
100
101 }
102
103 foreach my $full_instance ( glob '/var/run/ganeti/kvm-hypervisor/nic/*' ) {
104         my $instance = $full_instance;
105         $instance =~ s{^.*/}{};
106         next unless exists $stat->{$instance};
107
108         foreach my $nic ( glob "$full_instance/*" ) {
109                 open(my $fh, '<', $nic);
110                 my $dev = <$fh>;
111
112                 next unless -e "/sys/class/net/$dev";
113
114                 $nic =~ s{^.*/}{};
115
116                 my $d;
117
118                 foreach my $f (qw( rx_bytes tx_bytes rx_packets tx_packets )) {
119                         open( my $fh, '<', "/sys/class/net/$dev/statistics/$f" );
120                         my $v = <$fh>; chomp $v;
121                         $d->{$f} = $v;
122                 }
123                 if ( my $l = $last->{$instance}->{nic}->[$nic] ) {
124                         $stat->{$instance}->{nic}->[$nic]->{$_} = $d->{$_} - $l->{$_} foreach keys %$d;
125                         $stat->{$instance}->{nic}->[$nic]->{dev} = $dev;
126                         if ( -e "/sys/class/net/$dev/master" ) {
127                                 my $vlan = readlink "/sys/class/net/$dev/master";
128                                 $vlan =~ s/^.*br/br/;
129                                 $stat->{$instance}->{nic}->[$nic]->{vlan} = $vlan;
130                         }
131                 }
132                 $last->{$instance}->{nic}->[$nic] = $d;
133
134         }
135 }
136
137 XXX $stat;
138 #XXX $last;
139
140 open(my $fh, '>', '/dev/shm/ganeti-monitor.influx');
141
142 sub dump4influx {
143         my $hash = shift;
144         my $d = Data::Dump::dump( $hash );
145         $d =~ s/[\s\r\n]+//g;
146         $d =~ s/[\Q[]{}>\E]//g;
147         $d =~ s/=(\d+),/=$1i,/g;
148         $d =~ s/,+$//;
149         return $d;
150 }
151
152 foreach my $instance ( keys %$stat ) {
153
154         next if $skip->{$instance};
155
156         my $location = '';
157         $location .= qq{,dc="$DC"} if $DC;
158         $location .= qq{,rack="$RACK"} if $RACK;
159
160         print $fh qq{cpu,node="$node",instance="$instance"$location cpu=}, $stat->{$instance}->{cpu}, "\n";
161
162         foreach my $disk ( @{ $stat->{$instance}->{disk} } ) {
163                 print $fh qq{disk,node="$node",instance="$instance"$location },dump4influx( $disk ), "\n";
164         }
165
166         foreach my $nic ( @{ $stat->{$instance}->{nic} } ) {
167                 my $vlan = delete $nic->{vlan};
168                 print $fh qq{nic,node="$node",instance="$instance",vlan=${vlan}i$location },dump4influx( $nic ), "\n";
169         }
170
171 }
172
173 close($fh);
174
175 system q{curl -i -XPOST 'http://10.80.3.89:8086/write?db=ganeti' --data-binary '@/dev/shm/ganeti-monitor.influx'};
176
177
178 sleep $INTERVAL;
179 } #/while
180