contrib/: Added `extractDS.px' and `migrate-3-4.px'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Mon, 9 Apr 2007 10:59:14 +0000 (12:59 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Mon, 9 Apr 2007 10:59:14 +0000 (12:59 +0200)
contrib/extractDS.px [new file with mode: 0755]
contrib/migrate-3-4.px [new file with mode: 0755]

diff --git a/contrib/extractDS.px b/contrib/extractDS.px
new file mode 100755 (executable)
index 0000000..5826c65
--- /dev/null
@@ -0,0 +1,206 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+=head1 NAME
+
+extractDS.px - Extract a single data-source from an RRD-file
+
+=head1 SYNOPSYS
+
+  extractDS.px -i input.rrd -s source_ds -o output.rrd -d destination_ds
+
+=head1 DEPENDENCIES
+
+extractDS.px requires Perl and the included L<Getopt::Long> module, as well as
+the L<XML::Simple> module.
+
+=cut
+
+use Getopt::Long ('GetOptions');
+use XML::Simple (qw(xml_in xml_out));
+use Data::Dumper ();
+
+our $InFile;
+our $InDS;
+our $OutFile;
+our $OutDS;
+
+GetOptions ("infile|i=s" => \$InFile,
+       "inds|s=s" => \$InDS,
+       "outfile|o=s" => \$OutFile,
+       "outds|d=s" => \$OutDS) or exit (1);
+
+if (!$InFile || !$OutFile || !$InDS || !$OutDS)
+{
+       print "$InFile $InDS $OutFile $OutDS\n";
+       print STDERR "Usage: $0 -i <infile> -I <inds> -o <outfile> -O <outds>\n";
+       exit (1);
+}
+if (!-f $InFile)
+{
+       print STDERR "Input file does not exist\n";
+       exit (1);
+}
+if (-f $OutFile)
+{
+       print STDERR "Output file does exist\n";
+       exit (1);
+}
+
+extract_ds ($InFile, $OutFile, $InDS, $OutDS);
+exit (0);
+
+{
+my $ds_index = -1;
+my $current_index = -1;
+# state 0 == searching for DS index
+# state 1 == parse RRA header
+# state 2 == parse <ds> in RRA header
+# state 3 == parse values
+my $state = 0;
+my $out_cache = '';
+sub handle_line
+{
+       my $fh = shift;
+       my $line = shift;
+
+       if (!defined ($state))
+       {
+               $ds_index = -1;
+               $current_index = -1;
+               $state = 0;
+               $out_cache = '';
+       }
+
+       if ($state == 0)
+       {
+               if ($line =~ m/<ds>/)
+               {
+                       $out_cache = $line;
+                       $current_index++;
+               }
+               elsif ($line =~ m#<name>\s*([^<\s]+)\s*</name>#)
+               {
+                       if ($1 eq $InDS)
+                       {
+                               $ds_index = $current_index;
+                               $out_cache .= "\t\t<name>$OutDS</name>\n";
+                       }
+               }
+               elsif ($line =~ m#</ds>#)
+               {
+                       $out_cache .= $line;
+                       if ($ds_index == $current_index)
+                       {
+                               print $fh $out_cache;
+                       }
+               }
+               elsif ($line =~ m#<rra>#)
+               {
+                       print $fh $line;
+                       $current_index = -1;
+                       $state = 1;
+               }
+               elsif ($current_index == -1)
+               {
+                       print $fh $line;
+               }
+               else
+               {
+                       $out_cache .= $line;
+               }
+       }
+       elsif ($state == 1)
+       {
+               if ($line =~ m#<ds>#)
+               {
+                       $current_index++;
+                       if ($current_index == $ds_index)
+                       {
+                               print $fh $line;
+                       }
+
+                       if ($line =~ m#</ds>#) { $state = 1; }
+                       else { $state = 2; }
+               }
+               elsif ($line =~ m#<database>#)
+               {
+                       print $fh $line;
+                       $state = 3;
+               }
+               else
+               {
+                       print $fh $line;
+               }
+       }
+       elsif ($state == 2)
+       {
+               if ($current_index == $ds_index)
+               {
+                       print STDERR $line;
+                       print $fh $line;
+               }
+               if ($line =~ m#</ds>#)
+               {
+                       $state = 1;
+               }
+       }
+       else
+       {
+               if ($line =~ m#</database>#)
+               {
+                       print $fh $line;
+                       $current_index = -1;
+                       $state = 1;
+               }
+               else
+               {
+                       my $line_begin = "\t\t";
+                       $current_index = 0;
+                       if ($line =~ m#(<!-- .*? -->)#)
+                       {
+                               $line_begin .= "$1 ";
+                       }
+
+                       while ($line =~ m#<v>\s*([^<\s]+)\s*</v>#)
+                       {
+                               my $value = $1;
+                               if ($current_index == $ds_index)
+                               {
+                                       print $fh "$line_begin<row> <v>$value</v> </row>\n";
+                                       last;
+                               }
+                               $current_index++;
+                       }
+               }
+       }
+}} # handle_line
+
+sub extract_ds
+{
+       my $in_file = shift;
+       my $out_file = shift;
+       my $in_ds = shift;
+       my $out_ds = shift;
+
+       my $in_fh;
+       my $out_fh;
+
+       open ($in_fh,  '-|', 'rrdtool', 'dump', $in_file) or die ("open (rrdtool): $!");
+       open ($out_fh, '|-', 'rrdtool', 'restore', '-', $out_file) or die ("open (rrdtool): $!");
+
+       while (my $line = <$in_fh>)
+       {
+               handle_line ($out_fh, $line);
+       }
+
+       close ($in_fh);
+       close ($out_fh);
+} # extract_ds
+
+=head1 AUTHOR
+
+Florian octo Forster E<lt>octo at verplant.orgE<gt>
+
diff --git a/contrib/migrate-3-4.px b/contrib/migrate-3-4.px
new file mode 100755 (executable)
index 0000000..b656f7f
--- /dev/null
@@ -0,0 +1,320 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Getopt::Long ('GetOptions');
+use Data::Dumper ();
+use File::Basename ('dirname');
+
+our $InDir = '/var/lib/collectd';
+our $OutDir = '/tmp/collectd-4';
+our $Hostname = 'localhost';
+
+# Types:
+# +------------+----------------------+----+----+----+
+# ! Subdir     ! Type                 ! ti ! pi ! ex !
+# +------------+----------------------+----+----+----+
+# ! apache     ! apache_bytes         !    !    !    !
+# ! apache     ! apache_requests      !    !    !    !
+# ! apache     ! apache_scoreboard    ! x  !    !    !
+# ! battery    ! charge               !    ! x  !    !
+# ! apcups     ! charge_percent       !    !    !    !
+# !            ! cpu                  ! x  !    ! x  !
+# !            ! cpufreq              ! x  !    !    !
+# ! battery    ! current              !    ! x  !    !
+# ! ntpd       ! delay                ! x  !    !    !
+# !            ! df                   ! x  !    !    !
+# !            ! disk                 ! x  !    !    !
+# ! dns        ! dns_traffic          !    !    !    !
+# ! apple_se.. ! fanspeed             ! x  !    !    !
+# ! mbmon      ! fanspeed             ! x  !    !    !
+# ! apcups     ! frequency            ! x  !    !    !
+# ! ntpd       ! frequency_offset     ! x  !    !    !
+# !            ! hddtemp              ! x  !    !    !
+# ! interface  ! if_errors            !    ! x  !    !
+# ! interface  ! if_packets           !    ! x  !    !
+# !            ! lm_sensors           !    !    !    !
+# !            ! load                 !    !    !    !
+# ! apcups     ! load_percent         !    !    !    !
+# !            ! memory               !    !    !    !
+# !            ! multimeter           !    !    !    !
+# ! mysql      ! mysql_commands       ! x  !    !    !
+# ! mysql      ! mysql_handler        ! x  !    !    !
+# ! mysql      ! mysql_qcache         !    !    !    !
+# ! mysql      ! mysql_threads        !    !    !    !
+# !            ! nfs2_procedures      ! x  !    ! x  !
+# !            ! nfs3_procedures      ! x  !    ! x  !
+# ! dns        ! opcode               ! x  !    !    !
+# !            ! partition            ! x  !    !    !
+# !            ! ping                 ! x  !    !    !
+# !            ! processes            !    !    !    !
+# ! processes  ! ps_count             ! x  !    !    !
+# ! processes  ! ps_cputime           ! x  !    !    !
+# ! processes  ! ps_pagefaults        ! x  !    !    !
+# ! processes  ! ps_rss               ! x  !    !    !
+# ! dns        ! qtype                ! x  !    !    !
+# ! dns        ! rcode                ! x  !    !    !
+# ! (*)        ! sensors              ! x  !    !    !
+# !            ! serial               ! x  !    !    !
+# !            ! swap                 !    !    !    !
+# !            ! tape                 ! x  !    !    !
+# ! apple_se.. ! temperature          ! x  !    !    !
+# ! mbmon      ! temperature          ! x  !    !    !
+# ! ntpd       ! time_dispersion      ! x  !    !    !
+# ! ntpd       ! time_offset          ! x  !    !    !
+# ! apcups     ! timeleft             !    !    !    !
+# !            ! traffic              ! x  !    !    ! ->rx,tx
+# ! vserver    ! traffic              ! x  ! x  !    ! ->rx.tx
+# !            ! users                !    !    !    !
+# ! apucups    ! voltage              ! x  !    !    !
+# ! battery    ! voltage              !    ! x  !    !
+# ! mbmon      ! voltage              ! x  !    !    !
+# ! vserver    ! vs_memory            !    ! x  !    !
+# ! vserver    ! vs_processes         !    ! x  !    !
+# ! vserver    ! vs_threads           !    ! x  !    !
+# !            ! wireless             ! x  !    !    !
+# +------------+----------------------+----+----+----+
+
+our %Subdirs =
+(
+       apache => 0,
+       apcups => 0,
+       apple_sensors => 0,
+       battery => 1,
+       dns => 0,
+       interface => 1,
+       mbmon => 0,
+       mysql => 0,
+       ntpd => 0,
+       processes => 0,
+       sensors => 1,
+       vserver => 1
+);
+
+our %TypeTranslate =
+(
+       cpu => sub { $_ = shift; $_->{'plugin_instance'} = $_->{'type_instance'}; $_->{'type_instance'} = undef; $_; },
+       if_errors => sub { $_ = shift; $_->{'type_instance'} = $_->{'plugin_instance'}; $_->{'plugin_instance'} = undef; $_; },
+       if_packets => sub { $_ = shift; $_->{'type_instance'} = $_->{'plugin_instance'}; $_->{'plugin_instance'} = undef; $_; },
+       nfs2_procedures => sub { $_ = shift; @$_{qw(plugin plugin_instance type type_instance)} = ('nfs', 'v2' . $_->{'type_instance'}, 'nfs_procedure', undef); $_; },
+       nfs3_procedures => sub { $_ = shift; @$_{qw(plugin plugin_instance type type_instance)} = ('nfs', 'v3' . $_->{'type_instance'}, 'nfs_procedure', undef); $_; },
+       partition => sub { $_ = shift; $_->{'plugin'} = 'disk'; $_; },
+       processes => sub { $_ = shift; $_->{'type'} = 'ps_state'; $_; },
+       traffic => sub { $_ = shift; $_->{'plugin'} =~ s/^traffic$/interface/; @$_{qw(plugin_instance type)} = (undef, 'if_octets'); $_; }
+);
+
+our %TypeSplit =
+(
+       cpu => { from => [qw(user nice syst idle wait)], to => 'value', type_instance => [qw(user nice system idle wait)] },
+       nfs3_procedures => { from => [qw(null getattr lookup access readlink
+               read write create mkdir symlink mknod remove rmdir rename link
+               readdir readdirplus fsstat fsinfo pathconf commit)], to => 'value' },
+       nfs2_procedures => { from => [qw(create fsstat getattr link lookup
+               mkdir null read readdir readlink remove rename rmdir root
+               setattr symlink wrcache write)], to => 'value' },
+       processes => { from => [qw(running sleeping zombies stopped paging blocked)], to => 'value' },
+       swap => { from => [qw(cached free used resv)], to => 'value', type_instance => [qw(cached free used reserved)] }
+);
+
+our %TypeRename =
+(
+       traffic => { from => [qw(incoming outgoing)], to => [qw(rx tx)] }
+);
+
+GetOptions ("indir|i=s" => \$InDir,
+       "outdir|o=s" => \$OutDir,
+       "hostname=s" => \$Hostname) or exit (1);
+
+die "No such directory: $InDir" if (!-d $InDir);
+if (!-e $OutDir)
+{
+       mkdir ($OutDir) or die ("mkdir ($OutDir): $!");
+}
+die "Not a directory: $OutDir" if (!-d $OutDir);
+
+our @Files = ();
+our %OutDirs = ();
+
+@Files = find_files ();
+
+for (@Files)
+{
+       my $orig_filename = $_;
+       my $orig = parse_file ($orig_filename);
+       my $dest = translate_file ($orig);
+       my $dest_filename = get_filename ($dest);
+
+       my $dest_directory = dirname ($dest_filename);
+       if (!exists ($OutDirs{$dest_directory}))
+       {
+               print "[ -d '$OutDir/$dest_directory' ] || mkdir -p '$OutDir/$dest_directory'\n";
+               $OutDirs{$dest_directory} = 1;
+       }
+
+       if (exists ($TypeSplit{$orig->{'type'}}))
+       {
+               my $src_dses = $TypeSplit{$orig->{'type'}}->{'from'};
+               my $dst_ds = $TypeSplit{$orig->{'type'}}->{'to'};
+               my $type_instances = exists ($TypeSplit{$orig->{'type'}}->{'type_instance'})
+                       ? $TypeSplit{$orig->{'type'}}->{'type_instance'}
+                       : $TypeSplit{$orig->{'type'}}->{'from'};
+
+               for (my $i = 0; $i < @$src_dses; $i++)
+               {
+                       my $src_ds = $src_dses->[$i];
+                       $dest->{'type_instance'} = $type_instances->[$i];
+                       $dest_filename = get_filename ($dest);
+                       print "./extractDS.px -i '$InDir/$orig_filename' -s '$src_ds' -o '$OutDir/$dest_filename' -d '$dst_ds'\n";
+               }
+       }
+       elsif (exists ($TypeRename{$orig->{'type'}}))
+       {
+               my $src_dses = $TypeRename{$orig->{'type'}}->{'from'};
+               my $dst_dses = $TypeRename{$orig->{'type'}}->{'to'};
+               my @sed_prog = ();
+
+               for (my $i = 0; $i < @$src_dses; $i++)
+               {
+                       push (@sed_prog, 's/^' . $src_dses->[$i] . '$/' . $dst_dses->[$i] . '/g;');
+               }
+
+               print "rrdtool dump '$InDir/$orig_filename' | sed -e '" . join (' ', @sed_prog) . "' | rrdtool restore - '$OutDir/$dest_filename'\n";
+       }
+       else
+       {
+               print "cp '$InDir/$orig_filename' '$OutDir/$dest_filename'\n";
+       }
+}
+
+exit (0);
+
+sub translate_file
+{
+       my $orig = shift;
+       my $dest = {};
+       %$dest = %$orig;
+
+       if (defined ($TypeTranslate{$orig->{'type'}}))
+       {
+               $TypeTranslate{$orig->{'type'}}->($dest);
+       }
+
+       return ($dest);
+} # translate_file
+
+sub get_filename
+{
+       my $args = shift;
+       my $filename = $args->{'host'}
+       . '/' . $args->{'plugin'} . (defined ($args->{'plugin_instance'}) ? '-'.$args->{'plugin_instance'} : '')
+       . '/' . $args->{'type'} . (defined ($args->{'type_instance'}) ? '-'.$args->{'type_instance'} : '') . '.rrd';
+
+       return ($filename);
+}
+
+sub parse_file
+{
+       my $fullname = shift;
+       my @parts = split ('/', $fullname);
+
+       my $filename;
+
+       my $host;
+       my $plugin;
+       my $plugin_instance;
+       my $type;
+       my $type_instance;
+
+       $filename = pop (@parts);
+
+       if ($filename =~ m/^([^-]+)(?:-(.*))?\.rrd$/)
+       {
+               $type = $1;
+               $type_instance = $2;
+       }
+       else
+       {
+               return;
+       }
+
+       if (@parts)
+       {
+               my $dirname = pop (@parts);
+               my $regex_str = join ('|', keys (%Subdirs));
+               if ($dirname =~ m/^($regex_str)(?:-(.*))?$/)
+               {
+                       $plugin = $1;
+                       $plugin_instance = $2;
+               }
+               else
+               {
+                       push (@parts, $dirname);
+               }
+       }
+       if (!$plugin)
+       {
+               $plugin = $type;
+       }
+
+       if (@parts)
+       {
+               $host = pop (@parts);
+       }
+       else
+       {
+               $host = $Hostname;
+       }
+
+       return
+       ({
+               host => $host,
+               plugin => $plugin,
+               plugin_instance => $plugin_instance,
+               type => $type,
+               type_instance => $type_instance
+       });
+} # parse_file
+
+sub find_files
+{
+       my $reldir = @_ ? shift : '';
+       my $absdir = $InDir . ($reldir ? "/$reldir" : '');
+
+       my $dh;
+
+       my @files = ();
+       my @dirs = ();
+
+       opendir ($dh, $absdir) or die ("opendir ($absdir): $!");
+       while (my $file = readdir ($dh))
+       {
+               next if ($file =~ m/^\./);
+               next if (-l "$absdir/$file");
+               if (-d "$absdir/$file")
+               {
+                       push (@dirs, ($reldir ? "$reldir/" : '') . $file);
+               }
+               elsif ($file =~ m/\.rrd$/)
+               {
+                       push (@files, ($reldir ? "$reldir/" : '') . $file);
+               }
+       }
+       closedir ($dh);
+
+       for (my $i = 0; $i < @dirs; $i++)
+       {
+               push (@files, find_files ($dirs[$i]));
+       }
+
+       return (@files);
+} # find_files
+
+sub special_cpu
+{
+       my %file_orig = @_;
+       my %file_dest = %file_orig;
+
+       $file_dest{'plugin_instance'} = $file_dest{'type_instance'}
+
+}