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