use different kernels
[gnt-info] / gnt-i
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5
6 my $DEBUG = $ENV{DEBUG} || 0;
7
8 my $hostname = `hostname -s`;
9 chomp $hostname;
10
11 use Data::Dumper;
12 sub XXX { $DEBUG ? warn "XXX ",Dumper( @_ ) : {} };
13
14 my $stat;
15 my $mac_to_name;
16 my $instance_tap;
17 my $tap_instance;
18 my $lines;
19
20 my @nodes = @ARGV;
21
22 @nodes = map { chomp ; $_ } `gnt-node list -o name --no-header` unless @nodes;
23
24 next_node:
25 my $ssh = '';
26 if ( @nodes ) {
27         $hostname = shift @nodes;
28         $ssh = "ssh $hostname ";
29         $hostname =~ s/\..+$//; # -s
30         warn "## hostname $hostname\n";
31 }
32
33 # if prefixed with _ it will be hiddden from output, _args must be last!
34 my @ps_cols = qw( user pid
35         pcpu pmem
36         vsz
37         rss
38         nlwp
39         cputime etimes 
40         maj_flt min_flt
41         psr
42
43         _args);
44
45 sub ps_cols_all { map { my $t = $_; $t =~ s/^_//; $t } @ps_cols };
46 sub ps_cols_visible { 'node', grep { ! /^_/ } @ps_cols, 'rx', 'tx' };
47
48 sub DD_hh_mm_ss {
49         my $t = shift;
50         # [[DD-]hh:]mm:ss.
51         my @f = reverse ( 24, 60, 60, 1 );
52         my @p = reverse split(/[-:]/, $t);
53         my $t_sec = 0;
54
55         for ( 0 .. $#p ) {
56                 my $i = $#p - $_;
57 #warn "### $i $p[$i] $f[$i]\n";
58                 $t_sec += $p[$i];
59                 $t_sec *= $f[$i];
60         }
61
62 #       warn "# DD-hh:mm:ss $t -> $t_sec\n" if $DEBUG;
63         return $t_sec;
64 }
65
66 sub sh {
67         my $cmd = join(' ', @_);
68         $cmd = "$ssh '$cmd'";
69         warn "## $cmd\n";
70         open(my $fh, '-|', $cmd);
71         return $fh;
72 }
73
74 my $ps = sh 'ps --no-headers axwwo ' . join(',', ps_cols_all);
75 while(<$ps>) {
76         chomp;
77         s/^\s*//;
78
79         my %h;
80         @h{@ps_cols} = split(/\s+/, $_, $#ps_cols + 1);
81         $h{cputime} = DD_hh_mm_ss( $h{cputime} );
82
83 #XXX 'h = ', \%h;
84         if ( $h{user} =~ m/gnt/ && $h{_args} =~ m/qemu.*-name\s+(\S+)/ ) {
85
86                 my $name = $1;
87                 $stat->{$name}->{$_} = $h{$_} foreach ps_cols_all;
88
89                 $stat->{$name}->{node} = $hostname;
90
91                 while ( $h{_args} =~ m/mac=([0-9a-fA-F:]+)/g ) {
92                         $mac_to_name->{$hostname}->{$1} = $name;
93                 }
94
95         } else {
96 #               warn "## SKIP [$_]\n";
97                 $stat->{ '__' . $hostname }->{$_} += $h{$_} foreach qw( pcpu pmem vsz rss
98                         nlwp cputime etimes
99                         maj_flt min_flt
100                 );
101                 
102         }
103
104 }
105
106
107 my $tap = sh('grep -H . /var/run/ganeti/kvm-hypervisor/nic/*/*');
108 while(<$tap>) {
109         chomp;
110         my @p = split(/\//,$_);
111 #       warn "## tap ", Dumper( \@p ), "$_\n";
112         push @{ $instance_tap->{$hostname}->{ $p[-2] } }, $p[-1];
113
114         my $if = $p[-1];
115         $if =~ s/\d://;
116         $tap_instance->{$hostname}->{$if} = $p[-2];
117 }
118
119 =for later
120
121 my $ip = sh('ip -s -o link');
122 while(<$ip>) {
123         chomp;
124         if ( m/master\s+(\S+).+ether\s+([0-9a-fA-F:]+).+RX:\s+.+\\\s+(\d+).+TX:\s+.+\\\s+(\d+)/ ) {
125                 my ( $if, $mac, $rx, $tx ) = ( $1, $2, $3, $4 );
126                 if ( my $name = $tap_instance->{$hostname}->{$if} ) {
127                         $stat->{$name}->{link}->{ $if } = [ $rx, $tx ];
128                         warn "## ip $name $ip $mac $rx $tx\n";
129                 } else {
130                         warn "## ip SKIP $if $mac $rx $tx\n"; # XXX if $DEBUG;
131                 }
132         } else {
133                 warn "## SKIP $_\n" if $DEBUG;
134         }
135 }
136
137 =cut
138
139 my $dev = sh 'grep : /proc/net/dev';
140 while(<$dev>) {
141         chomp;
142         s/^\s+//;
143         my @l = split(/[:\s]+/, $_);
144 #warn "XXX $_ -> ",Dumper( \@l );
145         if ( my $instance = $tap_instance->{$hostname}->{ $l[0] } ) {
146                         $stat->{$instance}->{rx} += $l[1];
147                         $stat->{$instance}->{tx} += $l[9];
148         } elsif ( $l[0] =~ m/eth/ ) { # connect hardware eth devices under node
149                         $stat->{ '__' . $hostname }->{rx} += $l[1];
150                         $stat->{ '__' . $hostname }->{tx} += $l[9];
151         }
152 }
153
154
155 goto next_node if @nodes;
156
157
158
159 # dump some useful data structures
160
161 sub tab_dump {
162         my ( $name, $hash ) = @_;
163         warn "# $name\n";
164         foreach my $key ( sort keys %$hash ) {
165                 warn $key, "\t", $hash->{$key}, "\n";
166         }
167 }
168
169
170
171 foreach my $node ( sort keys %$mac_to_name ) {
172         tab_dump "$node mac instance",  $mac_to_name->{$node};
173 }
174 #warn Dumper( $mac_to_name );
175 #tab_dump 'instance_tap', $instance_tap;
176 #warn Dumper( $instance_tap );
177 #warn Dumper( $tap_instance );
178
179
180 warn "# stat ", Dumper( $stat ) if $DEBUG;
181
182
183 # dump tablable ascii output
184
185 #XXX( @ps_cols );
186
187 sub push_line {
188         my @l = @_;
189         foreach my $i ( 0 .. $#l ) {
190                 my $len = length($l[$i]) || 0;
191                 $lines->{len}->[$i] ||= $len;
192                 $lines->{len}->[$i] = $len if $len > $lines->{len}->[$i];
193         }
194         push @{ $lines->{line} }, [ map { ! defined $_ ? '-' : $_ } @l ];
195 }
196
197 push_line '#name', ps_cols_visible;
198
199 foreach my $name ( sort keys %$stat ) {
200 #       printf "%6.2f %6.2f %8d %6d %6s %s\n", ( map { $stat->{$name}->{$_} || '' } qw( pcpu pmem vsz pid user ) ), $name;
201 #       print join("\t", $name, map { $stat->{$name}->{$_} } ps_cols_visible ), "\n";
202         push_line( $name, map { $stat->{$name}->{$_} } ps_cols_visible );
203 }
204
205 #XXX $lines;
206
207 my $fmt = join(' ', map { '%' . $_ . 's' } @{ $lines->{len} } ) . "\n";
208 warn "# fmt = [$fmt]" if $DEBUG;
209 foreach my $line ( @{ $lines->{line} } ) {
210         printf $fmt, @$line;
211 }
212