diff options
Diffstat (limited to 'torrus/bin/rrddir2xml.in')
-rw-r--r-- | torrus/bin/rrddir2xml.in | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/torrus/bin/rrddir2xml.in b/torrus/bin/rrddir2xml.in new file mode 100644 index 000000000..c82fcf871 --- /dev/null +++ b/torrus/bin/rrddir2xml.in @@ -0,0 +1,311 @@ +#!@PERL@ +# Copyright (C) 2002 Stanislav Sinyagin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +# $Id: rrddir2xml.in,v 1.1 2010-12-27 00:04:01 ivan Exp $ +# Stanislav Sinyagin <ssinyagin@yahoo.com> + +# Generate Torrus XML configuration from a directory containing RRD files +# + +BEGIN { require '@devdiscover_config_pl@'; } + +use strict; +use Getopt::Long; +use IO::Dir; +use Fcntl qw(:mode); +use RRDs; + +use Torrus::ConfigBuilder; +use Torrus::Log; + + +my $creator = "Torrus version @VERSION@\n" . + "This file was generated by command:\n" . + $0 . " \\\n"; +foreach my $arg ( @ARGV ) +{ + if( $arg =~ /^--/ ) + { + $creator .= ' ' . $arg . ' '; + } + else + { + $creator .= "\'" . $arg . "\'\\\n"; + } +} +$creator .= "\nOn " . scalar(localtime(time)); + + +my $indir; +my $recursive = 0; +my $filter = '.*'; +my $outfile = 'rrddir.xml'; +my $topsubtree = '/'; +my $splitexpr = '_+'; +my $levels = 2; +my $hwpredict = 0; +my $comment; +my $debug = 0; +my $verbose = 0; + + +my $ok = GetOptions( + 'dir=s' => \$indir, + 'recursive' => \$recursive, + 'filter=s' => \$filter, + 'out=s' => \$outfile, + 'subtree=s' => \$topsubtree, + 'split=s' => \$splitexpr, + 'levels=i' => \$levels, + 'comment=s' => \$comment, + 'holtwinters' => \$hwpredict, + 'verbose' => \$verbose, + 'debug' => \$debug + ); + +if( not $ok or not $indir or scalar( @ARGV ) > 0 ) +{ + print STDERR + "Generate Torrus XML configuration from a directory with RRD files\n"; + + print STDERR "Usage: $0 --dir=path options...\n", + "Options:\n", + " --dir=path directory to read RRD files from\n", + " --recursive read the directories recursively\n", + " --filter=re filter RE for file and directory names\n", + " --out=filename output file [".$outfile."]\n", + " --subtree=subtree XML config subtree [".$topsubtree."]\n", + " --split=regexp regexp to split file names [".$splitexpr."]\n", + " --levels=integer no. of subtree levels [".$levels."]\n", + " --comment=text top subtree comment\n", + " --holtwinters enable Holt-Winters boundaries diaplay\n", + " --verbose print extra information\n", + " --debug print debugging information\n"; + + exit 1; +} + +if( $debug ) +{ + Torrus::Log::setLevel('debug'); +} +elsif( $verbose ) +{ + Torrus::Log::setLevel('verbose'); +} + +if( not -d $indir ) +{ + Error('No such directory: ' . $indir); + exit 1; +} + +if( $indir !~ /^\// ) +{ + Error('Input directory must be an absolute path: ' . $indir); + exit 1; +} + +# remove trailing slash from $indir +$indir =~ s/\/$//; + +if( $topsubtree !~ /^\/[0-9A-Za-z_\-\.\/]*$/ or + $topsubtree =~ /\.\./ ) +{ + Error("Invalid format for subtree name: " . $topsubtree); + exit 1; +} + + +if( $outfile !~ /^\// ) +{ + $outfile = $Torrus::Global::siteXmlDir . '/' . $outfile; +} + +my %rrdinfos; +read_rrd_dir( \%rrdinfos, $indir, $filter, $recursive ); + +Verbose(sprintf('Found %d RRD files', scalar( keys( %rrdinfos ) ) )); + +my $cb = new Torrus::ConfigBuilder; +$cb->addCreatorInfo( $creator ); + +# Chop the first and last slashes +my $path = $topsubtree; +$path =~ s/^\///; +$path =~ s/\/$//; + +# generate subtree path XML +my $topSubtreeNode = undef; +foreach my $subtreeName ( split( '/', $path ) ) +{ + $topSubtreeNode = $cb->addSubtree( $topSubtreeNode, $subtreeName ); +} + +if( length( $comment ) > 0 ) +{ + $cb->addParam( $topSubtreeNode, 'comment', $comment ); +} + +foreach my $rrdfile ( sort keys %rrdinfos ) +{ + my @nameparts = split( $splitexpr, $rrdfile, $levels ); + + my $subtreeNode = $topSubtreeNode; + foreach my $subtreeName ( @nameparts ) + { + $subtreeNode = $cb->addSubtree( $subtreeNode, $subtreeName ); + } + + my $info = $rrdinfos{$rrdfile}; + + my $legend = + 'Directory:' . $info->{'dir'} . ';' . + 'File:' . $rrdfile . ';'; + + $cb->addParam( $subtreeNode, 'legend', $legend ); + + my %dsnames; + my $this_rrd_hwpredict = 0; + + foreach my $prop ( keys %{$info->{'rrdinfo'}} ) + { + if( $prop =~ /^ds\[(\S+)\]\./o ) + { + $dsnames{$1} = 1; + } + else + { + if( $prop =~ /^rra\[\d+\]\.cf/o and + $info->{'rrdinfo'}->{$prop} eq 'FAILURES' ) + { + $this_rrd_hwpredict = 1; + } + } + } + + if( not $hwpredict ) + { + $this_rrd_hwpredict = 0; + } + + foreach my $dsname ( sort keys %dsnames ) + { + my $dslegend = $legend . 'DS:' . $dsname . ';Type:' . + $info->{'rrdinfo'}->{'ds['.$dsname.'].type'}; + + my $params = { + 'legend' => $dslegend, + 'ds-type' => 'rrd-file', + 'leaf-type' => 'rrd-def', + 'rrd-cf' => 'AVERAGE', + 'data-file' => $rrdfile, + 'data-dir' => $info->{'dir'}, + 'rrd-ds' => $dsname, + 'rrd-hwpredict' => ($this_rrd_hwpredict ? 'enabled':'disabled') + }; + + $cb->addLeaf( $subtreeNode, $dsname, $params ); + } +} + +my $ok = $cb->toFile( $outfile ); +if( $ok ) +{ + Verbose('Wrote ' . $outfile); +} +else +{ + Error('Cannot write ' . $outfile . ': ' . $!); +} + +exit( $ok ? 0:1); + + + +sub read_rrd_dir +{ + my $infos = shift; + my $indir = shift; + my $filter = shift; + my $recursive = shift; + + Debug('Reading directory: ' . $indir); + + my @subdirs; + + my %dir; + tie( %dir, 'IO::Dir', $indir ); + + foreach my $file ( keys %dir ) + { + if( $file =~ /^\./ or $file !~ $filter ) + { + Debug('Skipping ' . $file); + next; + } + + my $mode = $dir{$file}->mode(); + if( S_ISDIR( $mode ) ) + { + Debug($file . ' is a directory'); + push( @subdirs, $file ); + } + elsif( S_ISREG( $mode ) ) + { + Debug($file . ' is a regular file'); + if( defined( $infos->{$file} ) ) + { + Warn("Duplicate file name: $file"); + } + else + { + my $fullname = $indir . '/' . $file; + my $rrdinfo = RRDs::info( $fullname ); + my $err = RRDs::error(); + if( $err ) + { + Verbose($fullname . ' is not an RRD file'); + } + else + { + Debug('Found RRD file: ' . $file); + $infos->{$file}->{'fullname'} = $fullname; + $infos->{$file}->{'dir'} = $indir; + $infos->{$file}->{'rrdinfo'} = $rrdinfo; + } + } + } + } + + untie %dir; + + if( $recursive and scalar( @subdirs ) > 0 ) + { + foreach my $subdir ( @subdirs ) + { + read_rrd_dir( $infos, $indir . '/' . $subdir, + $filter, $recursive ); + } + } +} + +# Local Variables: +# mode: perl +# indent-tabs-mode: nil +# perl-indent-level: 4 +# End: |