2 # Copyright (C) 2002 Stanislav Sinyagin
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18 # $Id: rrddir2xml.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
19 # Stanislav Sinyagin <ssinyagin@yahoo.com>
21 # Generate Torrus XML configuration from a directory containing RRD files
24 BEGIN { require '@devdiscover_config_pl@'; }
32 use Torrus::ConfigBuilder;
36 my $creator = "Torrus version @VERSION@\n" .
37 "This file was generated by command:\n" .
39 foreach my $arg ( @ARGV )
43 $creator .= ' ' . $arg . ' ';
47 $creator .= "\'" . $arg . "\'\\\n";
50 $creator .= "\nOn " . scalar(localtime(time));
56 my $outfile = 'rrddir.xml';
68 'recursive' => \$recursive,
69 'filter=s' => \$filter,
71 'subtree=s' => \$topsubtree,
72 'split=s' => \$splitexpr,
73 'levels=i' => \$levels,
74 'comment=s' => \$comment,
75 'holtwinters' => \$hwpredict,
76 'verbose' => \$verbose,
80 if( not $ok or not $indir or scalar( @ARGV ) > 0 )
83 "Generate Torrus XML configuration from a directory with RRD files\n";
85 print STDERR "Usage: $0 --dir=path options...\n",
87 " --dir=path directory to read RRD files from\n",
88 " --recursive read the directories recursively\n",
89 " --filter=re filter RE for file and directory names\n",
90 " --out=filename output file [".$outfile."]\n",
91 " --subtree=subtree XML config subtree [".$topsubtree."]\n",
92 " --split=regexp regexp to split file names [".$splitexpr."]\n",
93 " --levels=integer no. of subtree levels [".$levels."]\n",
94 " --comment=text top subtree comment\n",
95 " --holtwinters enable Holt-Winters boundaries diaplay\n",
96 " --verbose print extra information\n",
97 " --debug print debugging information\n";
104 Torrus::Log::setLevel('debug');
108 Torrus::Log::setLevel('verbose');
113 Error('No such directory: ' . $indir);
117 if( $indir !~ /^\// )
119 Error('Input directory must be an absolute path: ' . $indir);
123 # remove trailing slash from $indir
126 if( $topsubtree !~ /^\/[0-9A-Za-z_\-\.\/]*$/ or
127 $topsubtree =~ /\.\./ )
129 Error("Invalid format for subtree name: " . $topsubtree);
134 if( $outfile !~ /^\// )
136 $outfile = $Torrus::Global::siteXmlDir . '/' . $outfile;
140 read_rrd_dir( \%rrdinfos, $indir, $filter, $recursive );
142 Verbose(sprintf('Found %d RRD files', scalar( keys( %rrdinfos ) ) ));
144 my $cb = new Torrus::ConfigBuilder;
145 $cb->addCreatorInfo( $creator );
147 # Chop the first and last slashes
148 my $path = $topsubtree;
152 # generate subtree path XML
153 my $topSubtreeNode = undef;
154 foreach my $subtreeName ( split( '/', $path ) )
156 $topSubtreeNode = $cb->addSubtree( $topSubtreeNode, $subtreeName );
159 if( length( $comment ) > 0 )
161 $cb->addParam( $topSubtreeNode, 'comment', $comment );
164 foreach my $rrdfile ( sort keys %rrdinfos )
166 my @nameparts = split( $splitexpr, $rrdfile, $levels );
168 my $subtreeNode = $topSubtreeNode;
169 foreach my $subtreeName ( @nameparts )
171 $subtreeNode = $cb->addSubtree( $subtreeNode, $subtreeName );
174 my $info = $rrdinfos{$rrdfile};
177 'Directory:' . $info->{'dir'} . ';' .
178 'File:' . $rrdfile . ';';
180 $cb->addParam( $subtreeNode, 'legend', $legend );
183 my $this_rrd_hwpredict = 0;
185 foreach my $prop ( keys %{$info->{'rrdinfo'}} )
187 if( $prop =~ /^ds\[(\S+)\]\./o )
193 if( $prop =~ /^rra\[\d+\]\.cf/o and
194 $info->{'rrdinfo'}->{$prop} eq 'FAILURES' )
196 $this_rrd_hwpredict = 1;
203 $this_rrd_hwpredict = 0;
206 foreach my $dsname ( sort keys %dsnames )
208 my $dslegend = $legend . 'DS:' . $dsname . ';Type:' .
209 $info->{'rrdinfo'}->{'ds['.$dsname.'].type'};
212 'legend' => $dslegend,
213 'ds-type' => 'rrd-file',
214 'leaf-type' => 'rrd-def',
215 'rrd-cf' => 'AVERAGE',
216 'data-file' => $rrdfile,
217 'data-dir' => $info->{'dir'},
219 'rrd-hwpredict' => ($this_rrd_hwpredict ? 'enabled':'disabled')
222 $cb->addLeaf( $subtreeNode, $dsname, $params );
226 my $ok = $cb->toFile( $outfile );
229 Verbose('Wrote ' . $outfile);
233 Error('Cannot write ' . $outfile . ': ' . $!);
245 my $recursive = shift;
247 Debug('Reading directory: ' . $indir);
252 tie( %dir, 'IO::Dir', $indir );
254 foreach my $file ( keys %dir )
256 if( $file =~ /^\./ or $file !~ $filter )
258 Debug('Skipping ' . $file);
262 my $mode = $dir{$file}->mode();
263 if( S_ISDIR( $mode ) )
265 Debug($file . ' is a directory');
266 push( @subdirs, $file );
268 elsif( S_ISREG( $mode ) )
270 Debug($file . ' is a regular file');
271 if( defined( $infos->{$file} ) )
273 Warn("Duplicate file name: $file");
277 my $fullname = $indir . '/' . $file;
278 my $rrdinfo = RRDs::info( $fullname );
279 my $err = RRDs::error();
282 Verbose($fullname . ' is not an RRD file');
286 Debug('Found RRD file: ' . $file);
287 $infos->{$file}->{'fullname'} = $fullname;
288 $infos->{$file}->{'dir'} = $indir;
289 $infos->{$file}->{'rrdinfo'} = $rrdinfo;
297 if( $recursive and scalar( @subdirs ) > 0 )
299 foreach my $subdir ( @subdirs )
301 read_rrd_dir( $infos, $indir . '/' . $subdir,
302 $filter, $recursive );
309 # indent-tabs-mode: nil
310 # perl-indent-level: 4