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