Code

3bf4b9e01c402758976095c7b470ecbb58e3c493
[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 XML::Simple (qw(xml_in xml_out));
23 use Data::Dumper ();
25 our $InFile;
26 our $InDS = [];
27 our $OutFile;
28 our $OutDS = [];
30 GetOptions ("infile|i=s" => \$InFile,
31         "inds|s=s" => sub { push (@$InDS, $_[1]); },
32         "outfile|o=s" => \$OutFile,
33         "outds|d=s" => sub { push (@$OutDS, $_[1]); })
34         or exit (1);
36 if (!$InFile || !$OutFile || !@$InDS || !@$OutDS)
37 {
38         print STDERR "Usage: $0 -i <infile> -s <inds> -o <outfile> -d <outds>\n";
39         exit (1);
40 }
41 if (!-f $InFile)
42 {
43         print STDERR "Input file does not exist\n";
44         exit (1);
45 }
46 if (-f $OutFile)
47 {
48         print STDERR "Output file does exist\n";
49         exit (1);
50 }
51 if ((1 + @$InDS) != (1 + @$OutDS))
52 {
53         print STDERR "You need the same amount of in- and out-DSes\n";
54         exit (1);
55 }
57 extract_ds ($InFile, $OutFile);
58 exit (0);
60 {
61 my $ds_index;
62 my $current_index;
63 # state 0 == searching for DS index
64 # state 1 == parse RRA header
65 # state 2 == parse values
66 my $state;
67 my $out_cache;
68 sub handle_line
69 {
70         my $fh = shift;
71         my $line = shift;
73         if (!defined ($state))
74         {
75                 $current_index = -1;
76                 $state = 0;
77                 $out_cache = [];
79                 # $ds_index->[new_index] = old_index
80                 $ds_index = [];
81                 for (my $i = 0; $i < @$InDS; $i++)
82                 {
83                         $ds_index->[$i] = -1;
84                 }
85         }
87         if ($state == 0)
88         {
89                 if ($line =~ m/<ds>/)
90                 {
91                         $current_index++;
92                         $out_cache->[$current_index] = $line;
93                 }
94                 elsif ($line =~ m#<name>\s*([^<\s]+)\s*</name>#)
95                 {
96                         # old_index == $current_index
97                         # new_index == $i
98                         for (my $i = 0; $i < @$InDS; $i++)
99                         {
100                                 next if ($ds_index->[$i] >= 0);
102                                 if ($1 eq $InDS->[$i])
103                                 {
104                                         $line =~ s#<name>\s*([^<\s]+)\s*</name>#<name> $OutDS->[$i] </name>#;
105                                         $ds_index->[$i] = $current_index;
106                                         last;
107                                 }
108                         }
110                         $out_cache->[$current_index] .= $line;
111                 }
112                 elsif ($line =~ m#</ds>#)
113                 {
114                         $out_cache->[$current_index] .= $line;
115                 }
116                 elsif ($line =~ m#<rra>#)
117                 {
118                         # Print out all the DS definitions we need
119                         for (my $new_index = 0; $new_index < @$InDS; $new_index++)
120                         {
121                                 my $old_index = $ds_index->[$new_index];
122                                 print $fh $out_cache->[$old_index];
123                         }
125                         # Clear the cache - it's used in state1, too.
126                         for (my $i = 0; $i <= $current_index; $i++)
127                         {
128                                 $out_cache->[$i] = '';
129                         }
131                         print $fh $line;
132                         $current_index = -1;
133                         $state = 1;
134                 }
135                 elsif ($current_index == -1)
136                 {
137                         # Print all the lines before the first DS definition
138                         print $fh $line;
139                 }
140                 else
141                 {
142                         # Something belonging to a DS-definition
143                         $out_cache->[$current_index] .= $line;
144                 }
145         }
146         elsif ($state == 1)
147         {
148                 if ($line =~ m#<ds>#)
149                 {
150                         $current_index++;
151                         $out_cache->[$current_index] .= $line;
152                 }
153                 elsif ($line =~ m#</cdp_prep>#)
154                 {
155                         # Print out all the DS definitions we need
156                         for (my $new_index = 0; $new_index < @$InDS; $new_index++)
157                         {
158                                 my $old_index = $ds_index->[$new_index];
159                                 print $fh $out_cache->[$old_index];
160                         }
162                         # Clear the cache
163                         for (my $i = 0; $i <= $current_index; $i++)
164                         {
165                                 $out_cache->[$i] = '';
166                         }
168                         print $fh $line;
169                         $current_index = -1;
170                 }
171                 elsif ($line =~ m#<database>#)
172                 {
173                         print $fh $line;
174                         $state = 2;
175                 }
176                 elsif ($current_index == -1)
177                 {
178                         # Print all the lines before the first DS definition
179                         # and after cdp_prep
180                         print $fh $line;
181                 }
182                 else
183                 {
184                         # Something belonging to a DS-definition
185                         $out_cache->[$current_index] .= $line;
186                 }
187         }
188         elsif ($state == 2)
189         {
190                 if ($line =~ m#</database>#)
191                 {
192                         print $fh $line;
193                         $current_index = -1;
194                         $state = 1;
195                 }
196                 else
197                 {
198                         my @values = ();
199                         my $i;
200                         my $output = "\t\t";
202                         if ($line =~ m#(<!-- .*? -->)#)
203                         {
204                                 $output .= "$1 ";
205                         }
206                         $output .= "<row> ";
208                         $i = 0;
209                         while ($line =~ m#<v>\s*([^<\s]+)\s*</v>#g)
210                         {
211                                 $values[$i] = $1;
212                                 $i++;
213                         }
215                         for (my $new_index = 0; $new_index < @$InDS; $new_index++)
216                         {
217                                 my $old_index = $ds_index->[$new_index];
218                                 $output .= '<v> ' . $values[$old_index] . ' </v> ';
219                         }
220                         $output .= "</row>\n";
221                         print $fh $output;
222                 }
223         }
224         else
225         {
226                 die;
227         }
228 }} # handle_line
230 sub extract_ds
232         my $in_file = shift;
233         my $out_file = shift;
235         my $in_fh;
236         my $out_fh;
238         open ($in_fh,  '-|', 'rrdtool', 'dump', $in_file) or die ("open (rrdtool): $!");
239         open ($out_fh, '|-', 'rrdtool', 'restore', '-', $out_file) or die ("open (rrdtool): $!");
241         while (my $line = <$in_fh>)
242         {
243                 handle_line ($out_fh, $line);
244         }
246         close ($in_fh);
247         close ($out_fh);
248 } # extract_ds
250 =head1 AUTHOR
252 Florian octo Forster E<lt>octo at verplant.orgE<gt>