1#  Copyright (C) 2002  Stanislav Sinyagin
2#
3#  This program is free software; you can redistribute it and/or modify
4#  it under the terms of the GNU General Public License as published by
5#  the Free Software Foundation; either version 2 of the License, or
6#  (at your option) any later version.
7#
8#  This program is distributed in the hope that it will be useful,
9#  but WITHOUT ANY WARRANTY; without even the implied warranty of
10#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11#  GNU General Public License for more details.
12#
13#  You should have received a copy of the GNU General Public License
14#  along with this program; if not, write to the Free Software
15#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16
17# Stanislav Sinyagin <ssinyagin@k-open.com>
18
19## %Torrus::Global::treeConfig manipulation
20
21package Torrus::SiteConfig;
22
23use strict;
24use warnings;
25
26use Torrus::Log;
27
28our %validDaemonNames = ('collector' => 1,
29                         'monitor'   => 1);
30
31our %mandatoryGraphStyles =
32    (
33     'SingleGraph'     => {'color' => 1, 'line'  => 1},
34     'HWBoundary'     => {'color' => 1, 'line'  => 1},
35     'HWFailure'      => {'color' => 1},
36     'HruleMin'       => {'color' => 1},
37     'HruleNormal'    => {'color' => 1},
38     'HruleMax'       => {'color' => 1},
39     'BpsIn'          => {'color' => 1, 'line'  => 1},
40     'BpsOut'         => {'color' => 1, 'line'  => 1}
41     );
42
43%Torrus::SiteConfig::validLineStyles =
44    (
45     'LINE1' => 1,
46     'LINE2' => 1,
47     'LINE3' => 1,
48     'AREA'  => 1,
49     'STACK' => 1
50     );
51
52## Verify the correctness of %Torrus::Global::treeConfig contents
53
54sub verify
55{
56    my $ok = 1;
57    if( not (scalar( keys %Torrus::Global::treeConfig )) )
58    {
59        Error('%Torrus::Global::treeConfig is not defined or empty');
60        $ok = 0;
61    }
62
63    foreach my $tree ( keys %Torrus::Global::treeConfig )
64    {
65        if( $tree !~ /^[a-zA-Z][a-zA-Z0-9_\-]*$/o )
66        {
67            Error("Invalid tree name: " . $tree);
68            $ok = 0;
69            next;
70        }
71
72        if( not $Torrus::Global::treeConfig{$tree}{'description'} )
73        {
74            Error("Missing description for the tree named \"" . $tree . "\"");
75            $ok = 0;
76        }
77
78        my $xmlfiles = $Torrus::Global::treeConfig{$tree}{'xmlfiles'};
79        if( not ref( $xmlfiles ) or not scalar( @{$xmlfiles} ) )
80        {
81            Error("'xmlfiles' array is not defined for the tree named \"" .
82                  $tree . "\"");
83            $ok = 0;
84        }
85        else
86        {
87            foreach my $file ( @{$xmlfiles} )
88            {
89                $ok = findXMLFile( $file,
90                                   "in the tree named \"" . $tree . "\"" ) ?
91                                       $ok:0;
92            }
93
94            if( ref( $Torrus::Global::treeConfig{$tree}{'run'} ) )
95            {
96                foreach my $daemon
97                    ( keys %{$Torrus::Global::treeConfig{$tree}{'run'}} )
98                {
99                    if( not $validDaemonNames{$daemon} )
100                    {
101                        Error("\"" . $daemon . "\" is not a correct daemon " .
102                              "name in the tree named \"" . $tree . "\"");
103                        $ok = 0;
104                    }
105                }
106            }
107        }
108    }
109
110    foreach my $file ( @Torrus::Global::xmlAlwaysIncludeFirst )
111    {
112        $ok = findXMLFile( $file,
113                           'in @Torrus::Global::xmlAlwaysIncludeFirst' ) ?
114                               $ok:0;
115    }
116    foreach my $file ( @Torrus::Global::xmlAlwaysIncludeLast )
117    {
118        $ok = findXMLFile( $file,
119                           'in @Torrus::Global::xmlAlwaysIncludeLast' ) ?
120                               $ok:0;
121    }
122
123    # Validate the styling profile
124
125    my $file = $Torrus::Global::stylingDir . '/' .
126        $Torrus::Renderer::stylingProfile . '.pl';
127    if( -r $file )
128    {
129        require $file;
130
131        #Color names are always there
132        require $Torrus::Global::stylingDir . '/colornames.pl';
133
134        if( defined($Torrus::Renderer::stylingProfileOverlay) )
135        {
136            my $overlay = $Torrus::Renderer::stylingProfileOverlay;
137            if( -r $overlay )
138            {
139                require $overlay;
140            }
141            else
142            {
143                Error('Error reading styling profile overlay from ' .
144                      $overlay . ': File is not readable');
145                $ok = 0;
146            }
147        }
148
149        my $profile = \%Torrus::Renderer::graphStyles;
150        # Check if mandatory parameters present
151        foreach my $element ( keys %mandatoryGraphStyles )
152        {
153            if( ref( $profile->{$element} ) )
154            {
155                if( $mandatoryGraphStyles{$element}{'color'}
156                    and not defined( $profile->{$element}{'color'} ) )
157                {
158                    Error('Mandatory color for ' . $element .
159                          ' is not defined in ' . $file);
160                    $ok = 0;
161                }
162                if( $mandatoryGraphStyles{$element}{'line'}
163                    and not defined( $profile->{$element}{'line'} ) )
164                {
165                    Error('Mandatory line style for ' . $element .
166                          ' is not defined in ' . $file);
167                    $ok = 0;
168                }
169            }
170            else
171            {
172                Error('Mandatory styling for ' . $element .
173                      ' is not defined in ' . $file);
174                $ok = 0;
175            }
176        }
177        # Check validity of all parameters
178        foreach my $element ( keys %{$profile} )
179        {
180            if( defined( $profile->{$element}{'color'} ) )
181            {
182                my $color = $profile->{$element}{'color'};
183                my $recursionLimit = 100;
184
185                while( $color =~ /^\#\#(\S+)$/ )
186                {
187                    if( $recursionLimit-- <= 0 )
188                    {
189                        Error('Color recursion is too deep');
190                        $ok = 0;
191                    }
192                    else
193                    {
194                        my $colorName = $1;
195                        $color = $profile->{$colorName}{'color'};
196                        if( not defined( $color ) )
197                        {
198                            Error('No color is defined for ' . $colorName);
199                            $ok = 0;
200                        }
201                    }
202                }
203
204                if( $color !~ /^\#[0-9a-fA-F]{6}$/ )
205                {
206                    Error('Invalid color specification for ' . $element .
207                          ' in ' . $file);
208                    $ok = 0;
209                }
210            }
211            if( defined( $profile->{$element}{'line'} ) )
212            {
213                if( not $Torrus::SiteConfig::validLineStyles{
214                    $profile->{$element}{'line'}} )
215                {
216                    Error('Invalid line specification for ' . $element .
217                          ' in ' . $file);
218                    $ok = 0;
219                }
220            }
221        }
222    }
223    else
224    {
225        Error('Error reading styling profile from ' . $file .
226              ': File is not readable');
227        $ok = 0;
228    }
229
230    return $ok;
231}
232
233
234sub findXMLFile
235{
236    my $file = shift;
237    my $msg = shift;
238
239    my $filename;
240    if( defined( $file ) )
241    {
242        my $found = 0;
243        foreach my $dir ( @Torrus::Global::xmlDirs )
244        {
245            $filename = $dir . '/' . $file;
246            if( -r $filename )
247            {
248                $found = 1;
249                last;
250            }
251        }
252
253        if( not $found )
254        {
255            Error("Cannot find file: " . $file);
256            $filename = undef;
257        }
258    }
259    else
260    {
261        Error("File name undefined " . $msg);
262    }
263    return $filename;
264}
265
266
267sub treeExists
268{
269    my $tree = shift;
270    return defined( $Torrus::Global::treeConfig{$tree} );
271}
272
273
274sub listTreeNames
275{
276    return( sort keys %Torrus::Global::treeConfig );
277}
278
279
280sub mayRunCollector
281{
282    my $tree = shift;
283    my $run = $Torrus::Global::treeConfig{$tree}{'run'}{'collector'};
284    return( defined($run) and $run > 0 );
285}
286
287sub collectorInstances
288{
289    my $tree = shift;
290    my $run = $Torrus::Global::treeConfig{$tree}{'run'}{'collector'};
291    return( (defined($run) and $run > 1) ? int($run) : 1 );
292}
293
294sub mayRunMonitor
295{
296    my $tree = shift;
297    return $Torrus::Global::treeConfig{$tree}{'run'}{'monitor'};
298}
299
300
301sub listXmlFiles
302{
303    my $tree = shift;
304    return @{$Torrus::Global::treeConfig{$tree}{'xmlfiles'}};
305}
306
307
308sub treeDescription
309{
310    my $tree = shift;
311    return $Torrus::Global::treeConfig{$tree}{'description'};
312}
313
314
315sub loadStyling
316{
317    require $Torrus::Global::stylingDir . '/' .
318        $Torrus::Renderer::stylingProfile . '.pl';
319
320    require $Torrus::Global::stylingDir . '/colornames.pl';
321
322    if( defined($Torrus::Renderer::stylingProfileOverlay) )
323    {
324        require $Torrus::Renderer::stylingProfileOverlay;
325    }
326    return;
327}
328
329
3301;
331
332
333# Local Variables:
334# mode: perl
335# indent-tabs-mode: nil
336# perl-indent-level: 4
337# End:
338