Code

Merge branch 'collectd-3.11' into collectd-4.0
[collectd.git] / contrib / extractDS.px
1 #!/usr/bin/perl
3 use strict;
4 use warnings;
6 =head1 NAME
8 extractDS.px - Extract a single data-source from an RRD-file
10 =head1 SYNOPSYS
12   extractDS.px -i input.rrd -s source_ds -o output.rrd -d destination_ds
14 =head1 DEPENDENCIES
16 extractDS.px requires Perl and the included L<Getopt::Long> module, as well as
17 the L<XML::Simple> module.
19 =cut
21 use Getopt::Long ('GetOptions');
22 use Data::Dumper ();
24 our $InFile;
25 our $InDS = [];
26 our $OutFile;
27 our $OutDS = [];
29 GetOptions ("infile|i=s" => \$InFile,
30         "inds|s=s" => sub { push (@$InDS, $_[1]); },
31         "outfile|o=s" => \$OutFile,
32         "outds|d=s" => sub { push (@$OutDS, $_[1]); })
33         or exit (1);
35 if (!$InFile || !$OutFile || !@$InDS || !@$OutDS)
36 {
37         print STDERR "Usage: $0 -i <infile> -s <inds> -o <outfile> -d <outds>\n";
38         exit (1);
39 }
40 if (!-f $InFile)
41 {
42         print STDERR "Input file does not exist\n";
43         exit (1);
44 }
45 if (-f $OutFile)
46 {
47         print STDERR "Output file does exist\n";
48         exit (1);
49 }
50 if ((1 + @$InDS) != (1 + @$OutDS))
51 {
52         print STDERR "You need the same amount of in- and out-DSes\n";
53         exit (1);
54 }
56 extract_ds ($InFile, $OutFile);
57 exit (0);
59 {
60 my $ds_index;
61 my $current_index;
62 # state 0 == searching for DS index
63 # state 1 == parse RRA header
64 # state 2 == parse values
65 my $state;
66 my $out_cache;
67 sub handle_line
68 {
69         my $fh = shift;
70         my $line = shift;
72         if (!defined ($state))
73         {
74                 $current_index = -1;
75                 $state = 0;
76                 $out_cache = [];
78                 # $ds_index->[new_index] = old_index
79                 $ds_index = [];
80                 for (my $i = 0; $i < @$InDS; $i++)
81                 {
82                         $ds_index->[$i] = -1;
83                 }
84         }
86         if ($state == 0)
87         {
88                 if ($line =~ m/<ds>/)
89                 {
90                         $current_index++;
91                         $out_cache->[$current_index] = $line;
92                 }
93                 elsif ($line =~ m#<name>\s*([^<\s]+)\s*</name>#)
94                 {
95                         # old_index == $current_index
96                         # new_index == $i
97                         for (my $i = 0; $i < @$InDS; $i++)
98                         {
99                                 next if ($ds_index->[$i] >= 0);
101                                 if ($1 eq $InDS->[$i])
102                                 {
103                                         $line =~ s#<name>\s*([^<\s]+)\s*</name>#<name> $OutDS->[$i] </name>#;
104                                         $ds_index->[$i] = $current_index;
105                                         last;
106                                 }
107                         }
109                         $out_cache->[$current_index] .= $line;
110                 }
111                 elsif ($line =~ m#</ds>#)
112                 {
113                         $out_cache->[$current_index] .= $line;
114                 }
115                 elsif ($line =~ m#<rra>#)
116                 {
117                         # Print out all the DS definitions we need
118                         for (my $new_index = 0; $new_index < @$InDS; $new_index++)
119                         {
120                                 my $old_index = $ds_index->[$new_index];
121                                 print $fh $out_cache->[$old_index];
122                         }
124                         # Clear the cache - it's used in state1, too.
125                         for (my $i = 0; $i <= $current_index; $i++)
126                         {
127                                 $out_cache->[$i] = '';
128                         }
130                         print $fh $line;
131                         $current_index = -1;
132                         $state = 1;
133                 }
134                 elsif ($current_index == -1)
135                 {
136                         # Print all the lines before the first DS definition
137                         print $fh $line;
138                 }
139                 else
140                 {
141                         # Something belonging to a DS-definition
142                         $out_cache->[$current_index] .= $line;
143                 }
144         }
145         elsif ($state == 1)
146         {
147                 if ($line =~ m#<ds>#)
148                 {
149                         $current_index++;
150                         $out_cache->[$current_index] .= $line;
151                 }
152                 elsif ($line =~ m#</cdp_prep>#)
153                 {
154                         # Print out all the DS definitions we need
155                         for (my $new_index = 0; $new_index < @$InDS; $new_index++)
156                         {
157                                 my $old_index = $ds_index->[$new_index];
158                                 print $fh $out_cache->[$old_index];
159                         }
161                         # Clear the cache
162                         for (my $i = 0; $i <= $current_index; $i++)
163                         {
164                                 $out_cache->[$i] = '';
165                         }
167                         print $fh $line;
168                         $current_index = -1;
169                 }
170                 elsif ($line =~ m#<database>#)
171                 {
172                         print $fh $line;
173                         $state = 2;
174                 }
175                 elsif ($current_index == -1)
176                 {
177                         # Print all the lines before the first DS definition
178                         # and after cdp_prep
179                         print $fh $line;
180                 }
181                 else
182                 {
183                         # Something belonging to a DS-definition
184                         $out_cache->[$current_index] .= $line;
185                 }
186         }
187         elsif ($state == 2)
188         {
189                 if ($line =~ m#</database>#)
190                 {
191                         print $fh $line;
192                         $current_index = -1;
193                         $state = 1;
194                 }
195                 else
196                 {
197                         my @values = ();
198                         my $i;
199                         my $output = "\t\t";
201                         if ($line =~ m#(<!-- .*? -->)#)
202                         {
203                                 $output .= "$1 ";
204                         }
205                         $output .= "<row> ";
207                         $i = 0;
208                         while ($line =~ m#<v>\s*([^<\s]+)\s*</v>#g)
209                         {
210                                 $values[$i] = $1;
211                                 $i++;
212                         }
214                         for (my $new_index = 0; $new_index < @$InDS; $new_index++)
215                         {
216                                 my $old_index = $ds_index->[$new_index];
217                                 $output .= '<v> ' . $values[$old_index] . ' </v> ';
218                         }
219                         $output .= "</row>\n";
220                         print $fh $output;
221                 }
222         }
223         else
224         {
225                 die;
226         }
227 }} # handle_line
229 sub extract_ds
231         my $in_file = shift;
232         my $out_file = shift;
234         my $in_fh;
235         my $out_fh;
237         open ($in_fh,  '-|', 'rrdtool', 'dump', $in_file) or die ("open (rrdtool): $!");
238         open ($out_fh, '|-', 'rrdtool', 'restore', '-', $out_file) or die ("open (rrdtool): $!");
240         while (my $line = <$in_fh>)
241         {
242                 handle_line ($out_fh, $line);
243         }
245         close ($in_fh);
246         close ($out_fh);
247 } # extract_ds
249 =head1 AUTHOR
251 Florian octo Forster E<lt>octo at verplant.orgE<gt>