Changeset 1502 for people/jo

Show
Ignore:
Timestamp:
02/29/08 20:15:18 (4 years ago)
Author:
jo
Message:

Merged changes from multilevel-groups-2 and trunk.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • people/jo/multilevel-groups-3/server/Munin.pm.in

    r1440 r1502  
    11package Munin; # -*- perl -*- 
    22# 
    3 # Copyright (C) 2003-2004 Jimmy Olsen, Audun Ytterdal 
     3# Copyright (C) 2003-2007 Jimmy Olsen, Audun Ytterdal 
    44# 
    55# This program is free software; you can redistribute it and/or 
     
    2323 
    2424use Exporter; 
     25 
    2526@ISA = ('Exporter'); 
    2627@EXPORT = ('munin_trend', 
     
    4546           'munin_category_status', 
    4647           'munin_get_picture_filename', 
     48           'munin_get_html_filename', 
    4749           'munin_get_filename', 
    4850           'munin_graph_column_headers', 
    4951           'munin_get_max_label_length', 
    5052           'munin_get_field_order', 
    51            'munin_get_rrd_filename' 
     53           'munin_get_rrd_filename', 
     54           'munin_get_node_name', 
     55           'munin_get_parent_name', 
     56           'munin_get_node_loc', 
     57           'munin_get_node', 
     58           'munin_set_var_loc', 
     59           'munin_set_var', 
     60           'munin_copy_node_toloc', 
     61           'munin_get_separated_node', 
     62           'munin_mkdir_p', 
     63           'munin_find_field', 
     64           'munin_get_parent', 
     65           'munin_get_children', 
     66           'munin_get_node_partialpath' 
    5267           ); 
    5368 
     
    8499        "tls_verify_certificate", "tls_verify_depth", "tls_ca_certificate", 
    85100        "graph_data_size", "colour", "graph_printf", "ok", "unknown", 
    86              "palette" 
     101         "palette", "realservname", "cdef_name", "graphable", "process",  
     102         "realname" 
    87103    ); 
    88104 
     
    90106 
    91107# Fields to copy when "aliasing" a field 
    92 my @copy_fields    = ("label", "draw", "type", "rrdfile", "fieldname", "info"); 
     108my @COPY_FIELDS    = ("label", "draw", "type", "rrdfile", "fieldname", "info");  
    93109 
    94110sub munin_trend { 
     
    110126} 
    111127 
     128# munin_draw_field: Check whether a field will be visible in the graph or not 
     129# Parameters: 
     130# - $hash: A ref to the hash node for the field 
     131# Returns: 
     132# - Success: Boolean; true if field will be graphed, false if not 
     133# - Failure: undef 
    112134sub munin_draw_field { 
    113     my $node    = shift; 
    114     my $service = shift; 
    115     my $field   = shift; 
    116  
    117     $field =~ s/=.*//; 
    118  
    119     print "DEBUG: munin_draw_field: Checking $service -> $field: " . &munin_get_bool_val ($node->{client}->{$service}->{$field.".graph"}, 1) . ".\n" if $DEBUG;; 
    120     return 0 if (exists $node->{client}->{$service}->{$field.".skipdraw"}); 
    121     return (&munin_get_bool_val ($node->{client}->{$service}->{$field.".graph"}, 1)); 
     135    my $hash   = shift; 
     136 
     137    return 0 if munin_get_bool ($hash, "skipdraw", 0); 
     138    return 0 if !munin_get_bool ($hash, "graph", 1); 
     139    return defined $hash->{"label"}; 
    122140} 
    123141 
     
    218236    my ($configfile,$overwrite) = @_; 
    219237    for my $key (keys %$overwrite) { 
     238        next if $key =~ /^#%#/; 
    220239        if (ref $overwrite->{$key}) { 
    221240            &munin_overwrite($overwrite->{$key},$configfile->{$key}); 
     
    233252    $conf ||= $configfile; 
    234253    if (! -r $conf and ! $missingok) { 
    235                ::logger ("munin_readconfig: cannot open '$conf'"); 
    236                return undef; 
     254        ::logger ("munin_readconfig: cannot open '$conf'"); 
     255        return undef; 
    237256    } 
    238257    if (open (CFG, $conf)) 
     
    250269    $config->{'tmpldir'}||= "@@CONFDIR@@/templates/"; 
    251270    $config->{'htmldir'}||= "@@HTMLDIR@@/"; 
     271    $config->{'#%#parent'}= undef; 
     272    $config->{'#%#name'}= "root"; 
    252273    return ($config); 
    253274} 
     
    256277{ 
    257278    my $lines    = shift; 
    258     my $hash     = undef
     279    my $hash     = {}
    259280    my $prefix   = ""; 
    260281    my $prevline = ""; 
     
    263284    { 
    264285        chomp $line; 
    265 #$line =~ s/(^|[^\\])#.*/$1/g if $line =~ /#/;  # Skip comments... 
    266286        if ($line =~ /#/) { 
    267287            next if ($line =~ /^#/); 
     
    367387} 
    368388 
    369 sub munin_set_var_path 
     389  
     390# munin_find_field: Search a hash to find nodes with $field defined 
     391# Parameters:  
     392# - $hash: A hash ref to search 
     393# - $field: The name of the field to search for, or a regex 
     394# - $avoid: [optional] Stop traversing further down if this field is found 
     395# Returns: 
     396# - Success: A ref to an array of the hash nodes containing $field. 
     397# - Failure: undef 
     398sub munin_find_field { 
     399    my $hash  = shift; 
     400    my $field = shift; 
     401    my $avoid = shift; 
     402    my $res = []; 
     403 
     404    if (ref ($field) ne "Regexp") { 
     405        if ($field =~ /^\^/) { 
     406            $field = qr/^$field$/; 
     407        } else { 
     408            $field = qr/$field/; 
     409        } 
     410    } 
     411 
     412    if (ref ($hash) eq "HASH") { 
     413        foreach my $key (keys %{$hash}) { 
     414            next if $key =~ /^#%#/; 
     415            last if defined $avoid and $key eq $avoid; 
     416            if ($key =~ $field) { 
     417                push @$res, $hash; 
     418            } elsif (ref ($hash->{$key}) eq "HASH") { 
     419                push @$res, @{munin_find_field ($hash->{$key}, $field, $avoid)}; 
     420            } 
     421        } 
     422    } 
     423 
     424    return $res; 
     425
     426 
     427# munin_get_children: Get all child hash nodes 
     428# Parameters:  
     429# - $hash: A hash ref to the parent node 
     430# Returns: 
     431# - Success: A ref to an array of the child nodes 
     432# - Failure: undef 
     433sub munin_get_children { 
     434    my $hash  = shift; 
     435    my $res = []; 
     436 
     437    return undef if (ref ($hash) ne "HASH"); 
     438 
     439    foreach my $key (keys %{$hash}) { 
     440        next if $key =~ /^#%#/; 
     441        if (defined $hash->{$key} and ref ($hash->{$key}) eq "HASH") { 
     442            push @$res, $hash->{$key}; 
     443        } 
     444    } 
     445 
     446    return $res; 
     447
     448 
     449# munin_get_separated_node: Copy a node to a separate node without "specials" 
     450# Parameters: 
     451# - $hash: The node to copy 
     452# Returns: 
     453# - Success: A ref to a new node without "#%#"-fields 
     454# - Failure: undef 
     455sub munin_get_separated_node 
     456
     457    my $hash = shift; 
     458    my $ret  = {}; 
     459 
     460    if (ref ($hash) eq "HASH") { 
     461        foreach my $key (keys %$hash) { 
     462            next if $key =~ /^#%#/; 
     463            if (ref ($hash->{$key}) eq "HASH") { 
     464                $ret->{$key} = munin_get_separated_node ($hash->{$key}); 
     465            } else { 
     466                $ret->{$key} = $hash->{$key}; 
     467            } 
     468        } 
     469    } else { 
     470        return undef; 
     471    } 
     472 
     473    return $ret; 
     474
     475 
     476# munin_get_parent_name: Return the name of the parent of the hash node supplied 
     477# Parameters:  
     478# - $hash: A ref to the hash node 
     479# Returns: 
     480# - Success: The name of the parent node 
     481# - Failure: If no parent node exists, "none" is returned. 
     482sub munin_get_parent_name 
     483
     484    my $hash = shift; 
     485 
     486    if (ref ($hash) eq "HASH" and defined $hash->{'#%#parent'}) { 
     487        return munin_get_node_name ($hash->{'#%#parent'}); 
     488    } else {  
     489        return "none"; 
     490    } 
     491
     492 
     493# munin_get_node_name: Return the name of the hash node supplied 
     494# Parameters:  
     495# - $hash: A ref to the hash node 
     496# Returns: 
     497# - Success: The name of the node 
     498sub munin_get_node_name 
     499
     500    my $hash = shift; 
     501 
     502    if (ref ($hash) eq "HASH" and defined $hash->{'#%#name'}) { 
     503        return $hash->{'#%#name'}; 
     504    } else {  
     505        return undef; 
     506    } 
     507
     508 
     509 
     510# munin_get_node_loc: Get location array for hash node 
     511# Parameters:  
     512# - $hash: A ref to the node 
     513# Returns: 
     514# - Success: Ref to an array with the full path of the variable 
     515# - Failure: undef 
     516sub munin_get_node_loc { 
     517    my $hash = shift; 
     518    my $res = []; 
     519 
     520    if (ref ($hash) ne "HASH") { # Not a has node 
     521        return undef; 
     522    } 
     523    if (defined $hash->{'#%#parent'}) { 
     524        $res = munin_get_node_loc ($hash->{'#%#parent'}); 
     525        push @$res, munin_get_node_name ($hash) if defined $res; 
     526    } 
     527    return $res; 
     528
     529 
     530# munin_get_parent: Get parent node of a hash 
     531# Parameters:  
     532# - $hash: A ref to the node 
     533# Returns: 
     534# - Success: Ref to an parent 
     535# - Failure: undef 
     536sub munin_get_parent { 
     537    my $hash = shift; 
     538 
     539    if (ref ($hash) ne "HASH") { # Not a has node 
     540        return undef; 
     541    } 
     542    if (defined $hash->{'#%#parent'}) { 
     543        return $hash->{'#%#parent'}; 
     544    } else { 
     545        return undef; 
     546    } 
     547
     548 
     549# munin_get_node: Gets a node by loc 
     550# Parameters:  
     551# - $hash: A ref to the hash to set the variable in 
     552# - $loc: A ref to an array with the full path of the node 
     553# Returns: 
     554# - Success: The node ref found by $loc 
     555# - Failure: undef 
     556sub munin_get_node 
     557
     558    my $hash = shift; 
     559    my $loc  = shift; 
     560 
     561    foreach my $tmpvar (@$loc) { 
     562        if ($tmpvar !~ /\S/) { 
     563            ::logger ("Error: munin_get_node: Cannot work on hash node \"$tmpvar\""); 
     564            return undef; 
     565        } 
     566        return undef if !exists $hash->{$tmpvar}; 
     567        $hash = $hash->{$tmpvar}; 
     568    } 
     569    return $hash; 
     570
     571 
     572# munin_set_var: sets a variable in a hash 
     573# Parameters:  
     574# - $hash: A ref to the hash to set the variable in 
     575# - $var: The name of the variable 
     576# - $val: The value to set the variable to 
     577# Returns: 
     578# - Success: The $hash we were handed 
     579# - Failure: undef 
     580sub munin_set_var 
    370581{ 
    371582    my $hash = shift; 
     
    373584    my $val  = shift; 
    374585 
    375     print "DEBUG: Setting var \"$var\" = \"$val\"\n" if $DEBUG; 
    376     if ($var =~ /^\s*([^;:]+);([^:]+):(\S+)\s*$/) 
    377     { 
    378         my ($dom, $host, $rest) = ($1, $2, $3); 
    379         my @sp = split (/\./, $rest); 
    380  
    381         if (@sp == 3) 
    382         { 
    383             ::logger ("Warning: Unknown option \"$sp[2]\" in \"$dom;$host:$sp[0].$sp[1].$sp[2]\".") 
    384                 unless defined $legal_expanded{$sp[2]}; 
    385             $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{"$sp[1].$sp[2]"} = $val; 
    386         } 
    387         elsif (@sp == 2) 
    388         { 
    389             ::logger ("Warning: Unknown option \"$sp[1]\" in \"$dom;$host:$sp[0].$sp[1]\".") 
    390                 unless defined $legal_expanded{$sp[1]}; 
    391             $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{$sp[1]} = $val; 
    392         } 
    393         elsif (@sp == 1) 
    394         { 
    395             ::logger ("Warning: Unknown option \"$sp[0]\" in \"$dom;$host:$sp[0]\".") 
    396                 unless defined $legal_expanded{$sp[0]}; 
    397             $hash->{domain}->{$dom}->{node}->{$host}->{$sp[0]} = $val; 
    398         } 
    399         else 
    400         { 
    401             warn "munin_set_var: Malformatted variable path \"$var\"."; 
    402         } 
    403     } 
    404     elsif ($var =~ /^\s*([^;:]+);([^;:]+)\s*$/) 
    405     { 
    406         my ($dom, $rest) = ($1, $2); 
    407         my @sp = split (/\./, $rest); 
    408  
    409         if (@sp == 1) 
    410         { 
    411             ::logger ("Warning: Unknown option \"$sp[0]\" in \"$dom;$sp[0]\".") 
    412                 unless defined $legal_expanded{$sp[0]}; 
    413             $hash->{domain}->{$dom}->{$sp[0]} = $val; 
    414         } 
    415         else 
    416         { 
    417             warn "munin_set_var: Malformatted variable path \"$var\"."; 
    418         } 
    419     } 
    420     elsif ($var =~ /^\s*([^;:\.]+)\s*$/) 
    421     { 
    422         ::logger ("Warning: Unknown option \"$1\" in \"$1\".") 
    423             unless defined $legal_expanded{$1}; 
    424         $hash->{$1} = $val; 
    425     } 
    426     elsif ($var =~ /^\s*([^\.]+)\.([^\.]+)\.([^\.]+)$/) 
    427     { 
    428         ::logger ("Warning: Unknown option \"$1\" in \"$var\".") 
    429             unless defined $legal_expanded{$1}; 
    430         ::logger ("Warning: Unknown option \"$3\" in \"$var\".") 
    431             unless defined $legal_expanded{$3}; 
    432         $hash->{$1}->{$2}->{$3} = $val; 
    433     } 
    434     else 
    435     { 
    436         warn "munin_set_var: Malformatted variable path \"$var\"."; 
     586    return munin_set_var_loc ($hash, [$var], $val); 
     587
     588 
     589# munin_set_var_loc: sets a variable in a hash 
     590# Parameters:  
     591# - $hash: A ref to the hash to set the variable in 
     592# - $loc: A ref to an array with the full path of the variable 
     593# - $val: The value to set the variable to 
     594# Returns: 
     595# - Success: The $hash we were handed 
     596# - Failure: undef 
     597sub munin_set_var_loc 
     598
     599    my $hash = shift; 
     600    my $loc  = shift; 
     601    my $val  = shift; 
     602    my @aloc = @$loc; 
     603 
     604    my $tmpvar = shift @aloc; 
     605    $tmpvar = shift @aloc while (defined $tmpvar and $tmpvar =~ /^#%#/); 
     606    if ($tmpvar !~ /\S/) { 
     607        ::logger ("Error: munin_set_var_loc: Cannot work on hash node \"$tmpvar\""); 
     608        return undef; 
     609    } 
     610    if (@aloc > 0) { 
     611        if (!defined $hash->{$tmpvar}) { # Init the new node 
     612            $hash->{$tmpvar}->{"#%#parent"} = $hash; 
     613            $hash->{$tmpvar}->{"#%#name"} = $tmpvar; 
     614        } 
     615        return munin_set_var_loc ($hash->{$tmpvar}, \@aloc, $val); 
     616    } else { 
     617        ::logger ("Warning: munin_set_var_loc: Setting unknown option \"$tmpvar\".") 
     618            unless defined $legal_expanded{$tmpvar}; 
     619        $hash->{$tmpvar} = $val; 
     620        return $hash; 
     621    } 
     622
     623 
     624# munin_get_node_partialpath: gets a node froma partial path 
     625# Parameters:  
     626# - $hash: A ref to the "current" location in the hash tree 
     627# - $var: A path string with relative location (from the $hash). 
     628# Returns: 
     629# - Success: The node 
     630# - Failure: undef 
     631sub munin_get_node_partialpath 
     632
     633    my $hash = shift; 
     634    my $var  = shift; 
     635    my $ret  = undef; 
     636 
     637    return undef if !defined $hash or ref ($hash) ne "HASH"; 
     638 
     639    my $root    = munin_get_root_node ($hash); 
     640    my $hashloc = munin_get_node_loc ($hash); 
     641    my $varloc  = undef; 
     642 
     643    if ($var =~ /^\s*([^:]+):(\S+)\s*$/) { 
     644        my ($leftstring, $rightstring) = ($1, $2); 
     645 
     646        my @leftarr = split (/;/, $leftstring); 
     647        my @rightarr = split (/\./, $rightstring); 
     648        push @$varloc, @leftarr, @rightarr 
     649    } elsif ($var =~ /^\s*([^;:\.]+)\s*$/) { 
     650        push @$varloc, $var; 
     651    } elsif ($var =~ /^\s*(.+)\.([^\.:;]+)$/) { 
     652        my ($leftstring, $rightstring) = ($1, $2); 
     653 
     654        my @leftarr = split (/;/, $leftstring); 
     655        my @rightarr = split (/\./, $rightstring); 
     656        push @$varloc, @leftarr, @rightarr; 
     657    } elsif ($var =~ /^\s*(\S+)\s*$/) { 
     658        my @leftarr = split (/;/, $1); 
     659        push @$varloc, @leftarr; 
     660    } else { 
     661        ::logger ("Error: munin_get_node_partialpath: Malformatted variable path \"$var\"."); 
     662    } 
     663 
     664    # We've got both parts of the loc (varloc and hashloc) -- let's figure out  
     665    # where they meet up. 
     666    do { 
     667        $ret = munin_get_node ($root, [@$hashloc, @$varloc]); 
     668    } while (!defined $ret and pop @$hashloc); 
     669 
     670    return $ret; 
     671
     672 
     673# munin_set_var_path: sets a variable in a hash 
     674# Parameters:  
     675# - $hash: A ref to the hash to set the variable in 
     676# - $var: A string with the full path of the variable 
     677# - $val: The value to set the variable to 
     678# Returns: 
     679# - Success: The $hash we were handed 
     680# - Failure: The $hash we were handed 
     681sub munin_set_var_path 
     682
     683    my $hash = shift; 
     684    my $var  = shift; 
     685    my $val  = shift; 
     686 
     687    my $result = undef; 
     688 
     689    ::logger ("Debug: munin_set_var_path: Setting var \"$var\" = \"$val\"") if $DEBUG; 
     690    if ($var =~ /^\s*([^:]+):(\S+)\s*$/) { 
     691        my ($leftstring, $rightstring) = ($1, $2); 
     692 
     693        my @leftarr = split (/;/, $leftstring); 
     694        my @rightarr = split (/\./, $rightstring); 
     695        $result = munin_set_var_loc ($hash, [@leftarr, @rightarr], $val); 
     696    } elsif ($var =~ /^\s*([^;:\.]+)\s*$/) { 
     697        $result = munin_set_var_loc ($hash, [$1], $val); 
     698    } elsif ($var =~ /^\s*([^:;]+)$/) { 
     699        my @leftarr = split (/\./, $1); 
     700        $result = munin_set_var_loc ($hash, [@leftarr], $val); 
     701    } elsif ($var =~ /^\s*(.+)\.([^\.:;]+)$/) { 
     702        my ($leftstring, $rightstring) = ($1, $2); 
     703 
     704        my @leftarr = split (/;/, $leftstring); 
     705        my @rightarr = split (/\./, $rightstring); 
     706        $result = munin_set_var_loc ($hash, [@leftarr, @rightarr], $val); 
     707    } elsif ($var =~ /^\s*(\S+)\s*$/) { 
     708        my @leftarr = split (/;/, $1); 
     709        $result = munin_set_var_loc ($hash, [@leftarr], $val); 
     710    } else { 
     711        ::logger ("Error: munin_set_var_path: Malformatted variable path \"$var\"."); 
     712    } 
     713 
     714    if (!defined $result) { 
     715        ::logger ("Error: munin_set_var_path: Failed setting \"$var\" = \"$val\"."); 
    437716    } 
    438717 
     
    440719} 
    441720 
    442 sub munin_writeconfig_loop { 
    443     my ($data,$fh,$pre) = @_; 
    444     $pre |= ""; 
    445  
    446     # Write datafile 
    447     foreach my $a (keys %{$data}) 
    448     { 
    449         if (ref ($data->{$a}) eq "HASH") 
    450         { 
    451             if ($a eq "domain" or $a eq "node" or $a eq "client") 
    452             { 
    453                 &munin_writeconfig_loop ($data->{$a}, $fh, "$pre"); 
    454             } 
    455             elsif ($a eq "contact" and $pre eq "") 
    456             { 
    457                 &munin_writeconfig_loop ($data->{$a}, $fh, "contact."); 
    458             } 
    459             else 
    460             { 
    461                 my $lpre = $pre; 
    462                 if ($lpre eq "") 
    463                 { 
    464                     $lpre = $a.";"; 
    465                 } 
    466                 elsif ($lpre =~ /;$/) 
    467                 { 
    468                     $lpre .= $a.":"; 
    469                 } 
    470                 else 
    471                 { 
    472                     $lpre .= $a."."; 
    473                 } 
    474                 &munin_writeconfig_loop ($data->{$a}, $fh, "$lpre"); 
    475             } 
    476         } 
    477         elsif (defined $data->{$a} and length $data->{$a}) 
    478         { 
    479             next if "$pre$a" eq "version"; # Handled separately 
    480             (my $outstring = $data->{$a}) =~ s/([^\\])#/$1\\#/g; 
    481             print "Writing: $pre$a $outstring\n" if $DEBUG; 
     721# munin_get_root_node: Get the root node of the hash tree 
     722# Parameters: 
     723# - $hash: A hash node to traverse up from 
     724# Returns: 
     725# - Success: A ref to the root hash node 
     726# - Failure: undef 
     727sub munin_get_root_node 
     728
     729    my $hash = shift; 
     730 
     731    return undef if ref ($hash) ne "HASH"; 
     732 
     733    while (defined $hash->{'#%#parent'}) { 
     734        $hash = $hash->{'#%#parent'}; 
     735    } 
     736 
     737    return $hash; 
     738
     739 
     740sub munin_writeconfig_loop  
     741
     742    my ($hash,$fh,$pre) = @_; 
     743 
     744    foreach my $key (keys %$hash) { 
     745        next if $key =~ /#%#/; 
     746        my $path = (defined $pre ? join(';', ($pre, $key)) : $key); 
     747        if (ref ($hash->{$key}) eq "HASH") { 
     748            munin_writeconfig_loop ($hash->{$key}, $fh, $path); 
     749        } else { 
     750            next if !defined $pre and $key eq "version"; # Handled separately 
     751            next if !defined $hash->{$key} or !length $hash->{$key}; 
     752            (my $outstring = $hash->{$key}) =~ s/([^\\])#/$1\\#/g; 
     753            print "Writing: $path $outstring\n" if $DEBUG; 
    482754            if ($outstring =~ /\\$/) 
    483755            { # Backslash as last char has special meaning. Avoid it. 
    484                 print $fh "$pre$a $outstring\\\n";  
     756                print $fh "$path $outstring\\\n";  
    485757            } else { 
    486                 print $fh "$pre$a $outstring\n"; 
     758                print $fh "$path $outstring\n"; 
    487759            } 
    488760        } 
    489761    } 
    490762} 
     763 
    491764sub munin_writeconfig { 
    492765    my ($datafilename,$data,$fh) = @_; 
    493 #   my $datafile = new Config::General(); 
    494 #   $datafile->save_file($datafilename,$data); 
    495766 
    496767    if (!defined $fh) 
     
    506777    print $fh "version $VERSION\n"; 
    507778    # Write datafile 
    508     &munin_writeconfig_loop ($data, $fh, ""); 
     779    &munin_writeconfig_loop ($data, $fh); 
    509780     
    510781    if (defined $fh) 
     
    527798} 
    528799 
     800# munin_get_html_filename: Get the full path-name of an html file 
     801# Parameters: 
     802# - $hash: A ref to the service hash node 
     803# Returns: 
     804# - Success: The file name with full path 
     805# - Failure: undef 
     806sub munin_get_html_filename { 
     807    my $hash    = shift; 
     808    my $loc     = munin_get_node_loc ($hash); 
     809    my $ret     = munin_get ($hash, 'htmldir'); 
     810    my $plugin  = "index"; 
     811 
     812    # Sanitise 
     813    $ret =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g; 
     814    $hash =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
     815    @$loc = map { s/\//_/g; $_ } @$loc; 
     816    @$loc = map { s/^\./_/g; $_ } @$loc; 
     817         
     818    if (defined $hash->{'graph_title'}) { 
     819        $plugin = pop @$loc or return undef; 
     820    } 
     821 
     822    if (@$loc) { # The rest is used as directory names... 
     823        $ret .= "/" . join ('/', @$loc); 
     824    } 
     825 
     826    return "$ret/$plugin.html"; 
     827} 
     828 
     829# munin_get_picture_filename: Get the full path+name of a picture file 
     830# Parameters: 
     831# - $hash: A ref to the service hash node 
     832# - $scale: The scale (day, week, year, month) 
     833# - $sum: [optional] Boolean value, whether it's a sum graph or not. 
     834# Returns: 
     835# - Success: The file name with full path 
     836# - Failure: undef 
    529837sub munin_get_picture_filename { 
    530     my $config  = shift; 
    531     my $domain  = shift; 
    532     my $name    = shift; 
    533     my $service = shift; 
     838    my $hash    = shift; 
    534839    my $scale   = shift; 
    535840    my $sum     = shift; 
    536     my $dir     = $config->{'htmldir'}; 
     841    my $loc     = munin_get_node_loc ($hash); 
     842    my $ret     = munin_get ($hash, 'htmldir'); 
    537843 
    538844    # Sanitise 
    539     $dir =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g; 
    540     $domain =~ s/[^\w_\/"'\[\]\(\)+=\.-]/_/g; 
    541     $name =~ s/[^\w_\/"'\[\]\(\)+=\.-]/_/g; 
    542     $service =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
     845    $ret =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g; 
     846    $hash =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
    543847    $scale =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
    544  
    545     if (defined $sum and $sum) 
    546     { 
    547             return "$dir/$domain/$name-$service-$scale-sum.png"; 
    548     } 
    549     else 
    550     { 
    551             return "$dir/$domain/$name-$service-$scale.png"; 
    552     } 
    553 
    554  
     848    @$loc = map { s/\//_/g; $_ } @$loc; 
     849    @$loc = map { s/^\./_/g; $_ } @$loc; 
     850         
     851    my $plugin = pop @$loc or return undef; 
     852    my $node   = pop @$loc or return undef; 
     853 
     854    if (@$loc) { # The rest is used as directory names... 
     855        $ret .= "/" . join ('/', @$loc); 
     856    } 
     857 
     858    if (defined $sum and $sum) { 
     859            return "$ret/$node/$plugin-$scale-sum.png"; 
     860    } else { 
     861            return "$ret/$node/$plugin-$scale.png"; 
     862    } 
     863
     864 
     865# munin_path_to_loc: Returns a loc array from a path string 
     866# Parameters:  
     867# - $path: A path string 
     868# Returns: 
     869# - Success: A ref to an array with the loc 
     870# - Failure: undef 
     871sub munin_path_to_loc 
     872
     873    my $path = shift; 
     874 
     875    my $result = undef; 
     876 
     877    if ($path =~ /^\s*([^:]+):(\S+)\s*$/) { 
     878        my ($leftstring, $rightstring) = ($1, $2); 
     879 
     880        my @leftarr = split (/;/, $leftstring); 
     881        my @rightarr = split (/\./, $rightstring); 
     882        $result = [@leftarr, @rightarr]; 
     883    } elsif ($path =~ /^\s*([^;:\.]+)\s*$/) { 
     884        $result = [$1]; 
     885    } elsif ($path =~ /^\s*(.+)\.([^\.:;]+)$/) { 
     886        my ($leftstring, $rightstring) = ($1, $2); 
     887 
     888        my @leftarr = split (/;/, $leftstring); 
     889        my @rightarr = split (/\./, $rightstring); 
     890        $result = [@leftarr, @rightarr]; 
     891    } elsif ($path =~ /^\s*(\S+)\s*$/) { 
     892        my @leftarr = split (/;/, $1); 
     893        $result = [@leftarr]; 
     894    } else { 
     895        ::logger ("Error: munin_path_to_loc: Malformatted variable path \"$path\"."); 
     896    } 
     897 
     898    if (!defined $result) { 
     899        ::logger ("Error: munin_path_to_loc: Failed converting \"$path\"."); 
     900    } 
     901 
     902    return $result; 
     903
     904 
     905 
     906# munin_get_filename: Get rrd filename for a field, without any  
     907#                     bells or whistles. Used by munin-update to  
     908#                     figure out which file to update. 
     909# Parameters: 
     910# - $hash: Ref to hash field 
     911# Returns: 
     912# - Success: Full path to rrd file 
     913# - Failure: undef 
    555914sub munin_get_filename { 
    556         my ($config,$domain,$node,$service,$field) = @_; 
    557  
    558         return ($config->{'dbdir'} . "/$domain/$node-$service-$field-" . lc substr (($config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field.".type"}||"GAUGE"), 0,1). ".rrd"); 
    559  
    560 
    561  
     915        my $hash = shift; 
     916        my $loc  = munin_get_node_loc ($hash); 
     917        my $ret  = munin_get ($hash, "dbdir"); 
     918 
     919        if (!defined $loc or !defined $ret) { 
     920            return undef; 
     921        } 
     922 
     923        # Not really a danger (we're not doing this stuff via the shell), so more to avoid  
     924        # confusion with silly filenames 
     925        @$loc = map { s/\//_/g; $_ } @$loc; 
     926        @$loc = map { s/^\./_/g; $_ } @$loc; 
     927         
     928        my $field  = pop @$loc or return undef; 
     929        my $plugin = pop @$loc or return undef; 
     930        my $node   = pop @$loc or return undef; 
     931 
     932        if (@$loc) { # The rest is used as directory names... 
     933            $ret .= "/" . join ('/', @$loc); 
     934        } 
     935 
     936        return ($ret . "/$node-$plugin-$field-" . lc substr (munin_get($hash, "type", "GAUGE"), 0,1). ".rrd"); 
     937 
     938
     939 
     940# munin_get_bool: Get boolean variable 
     941# Parameters: 
     942# - $hash: Ref to hash node 
     943# - $field: Name of field to get 
     944# - $default: [optional] Value to return if $field isn't set 
     945# Returns: 
     946# - Success: 1 or 0 (true or false) 
     947# - Failure: $default if defined, else undef 
    562948sub munin_get_bool 
    563949{ 
    564     my $conf     = shift; 
    565     my $field    = shift; 
    566     my $default  = shift; 
    567     my $domain   = shift; 
    568     my $node     = shift; 
    569     my $service  = shift; 
    570     my $plot     = shift; 
    571  
    572     return undef unless defined $field; 
    573  
    574     my $ans = &munin_get ($conf, $field, $default, $domain, $node, $service, $plot); 
     950    my $hash   = shift; 
     951    my $field  = shift; 
     952    my $default = shift; 
     953 
     954    my $ans = &munin_get ($hash, $field, $default); 
    575955    return undef if not defined $ans; 
    576956 
     
    580960        $ans =~ /^enable$/i or 
    581961        $ans =~ /^enabled$/i 
    582        ) 
    583     { 
    584     return 1; 
    585     } 
    586     elsif ($ans =~ /^no$/i or 
     962       ) { 
     963        return 1; 
     964    } elsif ($ans =~ /^no$/i or 
    587965        $ans =~ /^false$/i or 
    588966        $ans =~ /^off$/i or 
    589967        $ans =~ /^disable$/i or 
    590968        $ans =~ /^disabled$/i 
    591       ) 
    592     { 
    593     return 0; 
    594     } 
    595     elsif ($ans !~ /\D/) 
    596     { 
    597     return $ans; 
    598     } 
    599     else 
    600     { 
    601     return undef; 
     969      ) { 
     970        return 0; 
     971    } elsif ($ans !~ /\D/) { 
     972        return $ans; 
     973    } else { 
     974        return $default; 
    602975    } 
    603976} 
     
    6481021} 
    6491022 
     1023# munin_get: Get variable 
     1024# Parameters: 
     1025# - $hash: Ref to hash node 
     1026# - $field: Name of field to get 
     1027# - $default: [optional] Value to return if $field isn't set 
     1028# Returns: 
     1029# - Success: field contents 
     1030# - Failure: $default if defined, else undef 
    6501031sub munin_get 
    6511032{ 
    652     my $conf     = shift; 
    653     my $field    = shift; 
    654     my $default  = shift; 
    655     my $domain   = shift; 
    656     my $node     = shift; 
    657     my $service  = shift; 
    658     my $plot     = shift; 
    659  
    660     if (defined $field) 
    661     { 
    662         return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$plot.$field"} 
    663                 if (defined $domain and defined $node and defined $service and defined $plot and  
    664                         defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$plot.$field"}); 
    665  
    666          
    667  
    668         return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field} 
    669                 if (defined $domain and defined $node and defined $service and  
    670                         defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field}); 
    671         return $conf->{domain}->{$domain}->{node}->{$node}->{$field} 
    672                 if (defined $domain and defined $node and  
    673                         defined $conf->{domain}->{$domain}->{node}->{$node}->{$field}); 
    674         return $conf->{domain}->{$domain}->{$field} 
    675                 if (defined $domain and defined $conf->{domain}->{$domain}->{$field}); 
    676         return $conf->{$field} 
    677                 if (defined $conf->{$field}); 
    678         return $default; 
    679     } 
    680     else 
    681     { 
    682         return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service} 
    683                 if (defined $domain and defined $node and defined $service and  
    684                         defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}); 
    685         return $conf->{domain}->{$domain}->{node}->{$node} 
    686                 if (defined $domain and defined $node and  
    687                         defined $conf->{domain}->{$domain}->{node}->{$node}); 
    688         return $conf->{domain}->{$domain} 
    689                 if (defined $domain and defined $conf->{domain}->{$domain}); 
    690         return $conf 
    691                 if (defined $conf); 
    692         return $default; 
    693     } 
     1033    my $hash   = shift; 
     1034    my $field  = shift; 
     1035    my $default = shift; 
     1036 
     1037    return $default if (ref ($hash) ne "HASH"); 
     1038    return $hash->{$field} if defined $hash->{$field} and ref($hash->{$field}) ne "HASH"; 
     1039    return $default if not defined $hash->{'#%#parent'}; 
     1040    return munin_get ($hash->{'#%#parent'}, $field, $default); 
     1041
     1042 
     1043# munin_copy_node_toloc: Copy hash node at  
     1044# - $from: Hash node to copy 
     1045# - $to: Where to copy it to 
     1046# - $loc: Path to node under $to 
     1047# Returns: 
     1048# - Success: $to 
     1049# - Failure: undef 
     1050sub munin_copy_node_toloc 
     1051
     1052    my $from = shift; 
     1053    my $to   = shift; 
     1054    my $loc  = shift; 
     1055 
     1056    return undef unless defined $from and defined $to and defined $loc; 
     1057 
     1058    if (ref ($from) eq "HASH") { 
     1059        foreach my $key (keys %$from) { 
     1060            next if $key =~ /^#%#/; 
     1061            if (ref ($from->{$key}) eq "HASH") { 
     1062                munin_copy_node_toloc ($from->{$key}, $to, [@$loc, $key]); 
     1063            } else { 
     1064                munin_set_var_loc ($to, [@$loc, $key], $from->{$key}); 
     1065            } 
     1066        } 
     1067    } else { 
     1068        $to = $from; 
     1069    } 
     1070    return $to; 
     1071
     1072 
     1073# munin_copy_node: Copy hash node 
     1074# - $from: Hash node to copy 
     1075# - $to: Where to copy it to 
     1076# Returns: 
     1077# - Success: $to 
     1078# - Failure: undef 
     1079sub munin_copy_node 
     1080
     1081    my $from = shift; 
     1082    my $to   = shift; 
     1083 
     1084    if (ref ($from) eq "HASH") { 
     1085        foreach my $key (keys %$from) { 
     1086            if (ref ($from->{$key}) eq "HASH") { 
     1087                # Easier to do with the other copy function 
     1088                munin_copy_node_toloc ($from->{$key}, $to, [$key]);  
     1089            } else { 
     1090                munin_set_var_loc ($to, [$key], $from->{$key}); 
     1091            } 
     1092        } 
     1093    } else { 
     1094        $to = $from; 
     1095    } 
     1096    return $to; 
    6941097} 
    6951098 
     
    7221125} 
    7231126 
    724 sub munin_category_status 
    725 
    726     my ($config, $limits, $domain, $node, $category, $check_draw) = @_; 
    727     my $state = "ok"; 
    728  
    729     return undef unless defined $config->{domain}->{$domain}->{node}->{$node}; 
    730     my $snode = $config->{domain}->{$domain}->{node}->{$node}; 
    731  
    732     foreach my $service (keys %{$snode->{client}}) 
    733     { 
    734         next if ((not defined $snode->{client}->{$service}->{graph_category}) and 
    735                 $category ne 'other'); 
    736         next if ((defined $snode->{client}->{$service}->{graph_category}) and  
    737                  ($snode->{client}->{$service}->{graph_category} ne $category)); 
    738  
    739         my $fres  = &munin_service_status ($config, $limits, $domain, $node, $service, $check_draw); 
    740         if (defined $fres) 
    741         { 
    742             if ($fres eq "critical") 
    743             { 
     1127# munin_category_status: Gets current status of a category 
     1128# Parameters:  
     1129# - $hash: A ref to the hash node whose children to check 
     1130# - $limits: A ref to the root node of the limits tree 
     1131# - $category: The category to review 
     1132# - $check_draw: [optional] Ignore undrawn fields 
     1133# Returns: 
     1134# - Success: The status of the field 
     1135# - Failure: undef 
     1136sub munin_category_status { 
     1137    my $hash       = shift || return undef; 
     1138    my $limits     = shift || return undef; 
     1139    my $category   = shift || return undef; 
     1140    my $check_draw = 0; 
     1141    my $state      = "ok"; 
     1142 
     1143    return undef unless (defined $hash and ref ($hash) eq "HASH"); 
     1144 
     1145    foreach my $service (@{munin_get_children ($hash)}) { 
     1146        next if (!defined $service or ref ($service) ne "HASH"); 
     1147        next if (!defined $service->{'graph_title'}); 
     1148        next if ($category ne munin_get ($service, "graph_category", "other")); 
     1149        next if ($check_draw and not munin_get_bool ($service, "graph", 1)); 
     1150 
     1151        my $fres  = munin_service_status ($service, $limits, $check_draw); 
     1152        if (defined $fres) { 
     1153            if ($fres eq "critical") { 
    7441154                $state = $fres; 
    7451155                last; 
    746             } 
    747             elsif ($fres eq "warning") 
    748            
     1156            } elsif ($fres eq "warning") { 
     1157               $state = $fres; 
     1158            } elsif ($fres eq "unknown" and $state eq "ok")
    7491159                $state = $fres; 
    7501160            } 
     
    7551165} 
    7561166 
    757 sub munin_service_status 
    758 
    759     my ($config, $limits, $domain, $node, $service, $check_draw) = @_; 
     1167# munin_field_status: Gets current status of a field 
     1168# Parameters:  
     1169# - $hash: A ref to the field hash node 
     1170# - $limits: A ref to the root node of the limits tree 
     1171# - $check_draw: [optional] Ignore undrawn fields 
     1172# Returns: 
     1173# - Success: The status of the field 
     1174# - Failure: undef 
     1175sub munin_service_status { 
     1176    my ($config, $limits, $check_draw) = @_; 
    7601177    my $state = "ok"; 
    7611178 
    762     return undef unless defined $config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}; 
    763     foreach my $key (keys %{$config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}}) 
    764     { 
    765         next unless $key =~ /^([^\.]+)\.label$/; 
    766         my $field = $1; 
    767         my $fres  = &munin_field_status ($config, $limits, $domain, $node, $service, $field, $check_draw); 
    768         if (defined $fres) 
    769         { 
    770             if ($fres eq "critical") 
    771             { 
     1179    return undef unless defined $config; 
     1180    for my $fieldnode (@{munin_find_field ($config, "label")}) { 
     1181        my $field = munin_get_node_name ($fieldnode); 
     1182        my $fres  = munin_field_status ($fieldnode, $limits, $check_draw); 
     1183        if (defined $fres) { 
     1184            if ($fres eq "critical") { 
    7721185                $state = $fres; 
    7731186                last; 
    774             } 
    775             elsif ($fres eq "warning") 
    776             { 
     1187            } elsif ($fres eq "warning") { 
    7771188                $state = $fres; 
    7781189            } 
     
    7831194} 
    7841195 
    785 sub munin_field_status 
    786 
    787     my ($config, $limits, $domain, $node, $service, $field, $check_draw) = @_; 
     1196# munin_field_status: Gets current status of a field 
     1197# Parameters:  
     1198# - $hash: A ref to the field hash node 
     1199# - $limits: A ref to the root node of the limits tree 
     1200# - $check_draw: [optional] Ignore undrawn fields 
     1201# Returns: 
     1202# - Success: The status of the field 
     1203# - Failure: undef 
     1204sub munin_field_status { 
     1205    my ($hash, $limits, $check_draw) = @_; 
    7881206    my $state = undef; 
    7891207 
    7901208    # Return undef if nagios is turned off, or the field doesn't have any limits 
    791     unless ((defined $config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$field.warning"}) or 
    792         (defined $config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$field.critical"})) 
    793     { 
     1209    if ((!defined munin_get ($hash, "warning", undef)) and (!defined munin_get ($hash, "critical"))) { 
    7941210        return undef; 
    7951211    } 
    7961212 
    797     if (defined $limits->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$field.critical"} and (!defined $check_draw or !$check_draw or  
    798                 &munin_draw_field ($config->{domain}->{$domain}->{node}->{$node}, $service, $field))) 
    799     { 
    800         return "critical"; 
    801     } 
    802     elsif (defined $limits->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$field.warning"} and (!defined $check_draw or !$check_draw or  
    803                 &munin_draw_field ($config->{domain}->{$domain}->{node}->{$node}, $service, $field))) 
    804     { 
    805         return "warning"; 
    806     } 
    807     else 
    808     { 
    809         return "ok"; 
     1213    if (!defined $check_draw or !$check_draw or munin_draw_field ($hash)) { 
     1214        my $loc  = munin_get_node_loc ($hash); 
     1215        my $node = munin_get_node ($limits, $loc); 
     1216        return $node->{"state"} || "ok"; 
    8101217    } 
    8111218} 
     
    8341241} 
    8351242 
     1243# munin_get_max_label_length: Get the length of the longest labe in a graph 
     1244# Parameters: 
     1245# - $hash: the graph in question 
     1246# - $order: A ref to an array of fields (graph_order) 
     1247# Returns: 
     1248# - Success: The length of the longest label in the graph 
     1249# - Failure: undef 
    8361250sub munin_get_max_label_length 
    8371251{ 
    838     my $node    = shift; 
    839     my $config  = shift; 
    840     my $domain  = shift; 
    841     my $host    = shift; 
    8421252    my $service = shift; 
    8431253    my $order   = shift; 
    8441254    my $result  = 0; 
     1255    my $tot     = munin_get ($service, "graph_total"); 
    8451256 
    8461257    for my $field (@$order) { 
    8471258        my $path = undef; 
    8481259        (my $f = $field) =~ s/=.+//; 
    849         next if (exists $node->{client}->{$service}->{$f.".process"} and 
    850                  $node->{client}->{$service}->{$f.".process"} ne "yes"); 
    851         next if (exists $node->{client}->{$service}->{$f.".skipdraw"}); 
    852         next unless (!exists $node->{client}->{$service}->{$f.".graph"} or 
    853                         $node->{client}->{$service}->{$f.".graph"} eq "yes"); 
    854         if ($result < length ($node->{client}->{$service}->{$f.".label"} || $f)) { 
    855             $result = length ($node->{client}->{$service}->{$f.".label"} || $f); 
    856         } 
    857         if (exists $node->{client}->{$service}->{graph_total} and  
    858                 length $node->{client}->{$service}->{graph_total} > $result) 
    859         { 
    860             $result = length $node->{client}->{$service}->{graph_total}; 
    861         } 
     1260        next if (!munin_get_bool ($service->{$f}, "process", 1)); 
     1261        next if (munin_get_bool ($service->{$f}, "skipdraw", 0)); 
     1262        next if (!munin_get_bool ($service->{$f}, "graph", 1)); 
     1263 
     1264        my $len = length (munin_get ($service->{$f}, "label") || $f); 
     1265 
     1266        if ($result < $len) { 
     1267            $result = $len; 
     1268        } 
     1269    } 
     1270    if (defined $tot and length $tot > $result) { 
     1271        $result = length $tot; 
    8621272    } 
    8631273    return $result; 
    8641274} 
    8651275 
     1276# munin_get_field_order: Get the field order in a graph 
     1277# Parameters: 
     1278# - $hash: A hash ref to the service 
     1279# Returns: 
     1280# - Success: A ref to an array of the field names 
     1281# - Failure: undef 
    8661282sub munin_get_field_order 
    8671283{ 
    868     my $node    = shift; 
    869     my $config  = shift; 
    870     my $domain  = shift; 
    871     my $host    = shift; 
    872     my $service = shift; 
     1284    my $hash = shift; 
    8731285    my $result  = []; 
    8741286 
    875     if ($node->{client}->{$service}->{graph_sources})  
    876     { 
    877         foreach my $gs (split /\s+/, $node->{client}->{$service}->{'graph_sources'}) 
    878         { 
     1287    return undef if !defined $hash or ref($hash) ne "HASH"; 
     1288 
     1289    my $order = munin_get ($hash, "graph_order"); 
     1290 
     1291    if (defined $hash->{graph_sources}) { 
     1292        foreach my $gs (split /\s+/, $hash->{'graph_sources'}) { 
    8791293            push (@$result, "-".$gs); 
    8801294        } 
    8811295    }  
    882     if ($node->{client}->{$service}->{graph_order})  
    883     { 
    884         push (@$result, split /\s+/, $node->{client}->{$service}->{'graph_order'}); 
     1296    if (defined $order) { 
     1297        push (@$result, split /\s+/, $order); 
    8851298    }  
    8861299 
    887     for my $key (keys %{$node->{client}->{$service}})  
    888     { 
    889         my ($client,$type)=""; 
    890         ($client,$type) = split /\./,$key; 
    891         if (defined $type and $type eq "label")  
    892         { 
    893             push @$result,$client if !grep /^\Q$client\E(?:=|$)/, @$result;; 
    894         }  
     1300    for my $fieldnode (@{munin_find_field ($hash, "label")}) { 
     1301        my $fieldname = munin_get_node_name ($fieldnode); 
     1302        push @$result,$fieldname if !grep /^\Q$fieldname\E(?:=|$)/, @$result;; 
    8951303    } 
    8961304     
     
    8981306} 
    8991307 
     1308# munin_get_rrd_filename: Get the name of the rrd file corresponding to a  
     1309#                         field. Checks for lots of bells and whistles. 
     1310#                         This function is the correct one to use when  
     1311#                         figuring out where to fetch data from. 
     1312# Parameters: 
     1313# - $field: The hash object of the field 
     1314# - $path: [optional] The path to the field (as given in graph_order/sum/stack/et al) 
     1315# Returns: 
     1316# - Success: A string with the filename of the rrd file 
     1317# - Failure: undef 
    9001318sub munin_get_rrd_filename { 
    901     my $node    = shift; 
    902     my $config  = shift; 
    903     my $domain  = shift; 
    904     my $name    = shift; 
    905     my $service = shift; 
    9061319    my $field   = shift; 
    9071320    my $path    = shift; 
    908     my $result  = "unknown"; 
    909  
    910     if ($node->{client}->{$service}->{$field.".filename"}) 
    911     { 
    912         $result = $node->{client}->{$service}->{$field.".filename"}; 
    913     } 
    914     elsif ($path) 
    915     { 
    916         if (!defined ($node->{client}->{$service}->{$field.".label"})) 
    917         { 
    918             print "DEBUG: Setting label: $field\n" if $DEBUG; 
    919             $node->{client}->{$service}->{$field.".label"} = $field; 
    920         } 
    921  
    922         if ($path =~ /^\s*([^:;]+)[:;]([^:]+):([^:\.]+)[:\.]([^:\.]+)\s*$/) 
    923         { 
    924             $result = munin_get_filename ($config, $1, $2, $3, $4); 
    925             print "\nDEBUG1: Expanding $path...\n" if $DEBUG; 
    926             if (! defined $node->{client}->{$service}->{$field."label"}) 
    927             { 
    928                 for my $f (@copy_fields) 
    929                 { 
    930                     if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    931                             exists $config->{'domain'}->{$1}->{'node'}->{$2}->{'client'}->{$3}->{"$4.$f"}) 
    932                     { 
    933                         $node->{client}->{$service}->{"$field.$f"} = $config->{'domain'}->{$1}->{'node'}->{$2}->{'client'}->{$3}->{"$4.$f"}; 
    934                     } 
    935                 } 
     1321    my $result  = undef; 
     1322    my $name    = munin_get_node_name ($field); 
     1323 
     1324    # Bail out on bad input data 
     1325    return undef if !defined $field or ref ($field) ne "HASH"; 
     1326 
     1327    # If the field has a .filename setting, use it 
     1328    return $result if $result = munin_get ($field, "filename"); 
     1329 
     1330    # Handle custom paths (used in .sum, .stack, graph_order, et al) 
     1331    if (defined $path and length $path) { 
     1332 
     1333        my $sourcenode = munin_get_node_partialpath ($field, $path); 
     1334        $result = munin_get_filename ($sourcenode); 
     1335 
     1336        for my $f (@COPY_FIELDS) { 
     1337            if (not exists $field->{$f} and exists $sourcenode->{$f}) { 
     1338                print "DEBUG: Copying $f...\n" if $DEBUG; 
     1339                munin_set_var_loc ($field, [$f], $sourcenode->{$f}); 
    9361340            } 
    9371341        } 
    938         elsif ($path =~ /^\s*([^:]+):([^:\.]+)[:\.]([^:\.]+)\s*$/) 
    939         { 
    940             print "\nDEBUG2: Expanding $path...\n" if $DEBUG; 
    941             $result = munin_get_filename ($config, $domain, $1, $2, $3); 
    942             for my $f (@copy_fields) 
    943             { 
    944                 if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    945                         exists $config->{'domain'}->{$domain}->{'node'}->{$1}->{'client'}->{$2}->{"$3.$f"}) 
    946                 { 
    947                     print "DEBUG: Copying $f...\n" if $DEBUG; 
    948                     $node->{client}->{$service}->{"$field.$f"} = $config->{'domain'}->{$domain}->{'node'}->{$1}->{'client'}->{$2}->{"$3.$f"}; 
    949                 } 
    950             } 
    951         } 
    952         elsif ($path =~ /^\s*([^:\.]+)[:\.]([^:\.]+)\s*$/) 
    953         { 
    954             print "\nDEBUG3: Expanding $path...\n" if $DEBUG; 
    955             $result = munin_get_filename ($config, $domain, $name, $1, $2); 
    956             for my $f (@copy_fields) 
    957             { 
    958                 if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    959                         exists $node->{client}->{$1}->{"$2.$f"}) 
    960                 { 
    961                     $node->{client}->{$service}->{"$field.$f"} = $node->{client}->{$1}->{"$2.$f"}; 
    962                 } 
    963             } 
    964         } 
    965         elsif ($path =~ /^\s*([^:\.]+)\s*$/) 
    966         { 
    967             print "\nDEBUG4: Expanding $path...\n" if $DEBUG; 
    968             $result = munin_get_filename ($config, $domain, $name, $service, $1); 
    969             for my $f (@copy_fields) 
    970             { 
    971                 if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    972                         exists $node->{client}->{$service}->{"$1.$f"}) 
    973                 { 
    974                     $node->{client}->{$service}->{"$field.$f"} = $node->{client}->{$service}->{"$1.$f"}; 
    975                 } 
    976             } 
    977         } 
    978     } 
    979     else 
    980     { 
    981         print "\nDEBUG5: Doing path...\n" if $DEBUG; 
    982         $result = munin_get_filename($config, $domain,$name,$service,$field); 
     1342    } else { 
     1343        $result = munin_get_filename ($field); 
    9831344    } 
    9841345    return $result; 
    9851346} 
    9861347 
     1348# munin_mkdir_p: Make directory (and path to it) 
     1349# Parameters: 
     1350# - $dirname: Directory to create 
     1351# - $umask: Umask (in addition to the user umask) 
     1352# Returns: 
     1353# - Success: $dirname 
     1354# - Failure: undef 
     1355sub munin_mkdir_p 
     1356{ 
     1357    my $dirname = shift; 
     1358    my $umask   = shift; 
     1359 
     1360    return $dirname if (-e $dirname); 
     1361 
     1362 
     1363    ::logger ("Notice: Created directory \"$dirname\"."); 
     1364    (my $prev = $dirname) =~ s/\/[^\/]+\/?$//; 
     1365    if (munin_mkdir_p ($prev, $umask)) { 
     1366        if (mkdir ($dirname, $umask)) { 
     1367            return $dirname; 
     1368        } else { 
     1369            return undef; 
     1370        } 
     1371    } else { 
     1372        return undef; 
     1373    } 
     1374} 
     1375 
    9871376 
    98813771; 
  • people/jo/multilevel-groups-3/server/munin-domainview.tmpl.in

    r860 r1502  
    44<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> 
    55<head> 
    6   <link rel="stylesheet" href="../style.css" type="text/css" />  
     6  <link rel="stylesheet" href="<TMPL_VAR NAME="CSSPATH">" type="text/css" />  
    77  <meta http-equiv="refresh" content="300" /> 
    8   <title>Munin :: <TMPL_VAR NAME="DOMAIN"></title> 
     8  <title>Munin <TMPL_LOOP NAME="PATH">:: <TMPL_VAR ESCAPE="HTML" NAME="NAME"></TMPL_LOOP></title> 
    99  <meta http-equiv="content-type" content="application/xhtml+xml; charset=iso-8859-1" /> 
    1010  <meta name="author" content="Auto-generated by Munin" /> 
     
    1515    <td rowspan="2"><div class="logo">&nbsp;</div></td> 
    1616    <td valign="top"> 
    17          <h2><a href="../index.html">Overview</a> :: <TMPL_VAR ESCAPE="HTML" NAME="DOMAIN"></h2
     17        <h2><TMPL_LOOP NAME="PATH"><TMPL_IF NAME="PATH"><a href="<TMPL_VAR NAME="PATH">"></TMPL_IF><TMPL_VAR NAME="NAME"><TMPL_IF NAME="PATH"></a> :: </TMPL_IF></TMPL_LOOP></title
    1818    </td>     
    1919  </tr> 
     
    2121  <tr> 
    2222    <td valign="top"> 
    23       <h2><TMPL_VAR ESCAPE="HTML" NAME="DOMAIN"> :: [ <a href="comparison-day.html">day</a> <a href="comparison-week.html">week</a> <a href="comparison-month.html">month</a> <a href="comparison-year.html">year</a> ]</h2> 
     23      <h2><TMPL_VAR ESCAPE="HTML" NAME="NAME"> :: [ <a href="comparison-day.html">day</a> <a href="comparison-week.html">week</a> <a href="comparison-month.html">month</a> <a href="comparison-year.html">year</a> ]</h2> 
    2424    </td> 
    2525  </tr></TMPL_IF> 
     
    3030   <td class="linkbox"> 
    3131 <ul>    
    32   <TMPL_LOOP NAME="NODES"> 
    33   <li><span class="domain"><a href="<TMPL_VAR NAME="NODE">.html"><TMPL_VAR ESCAPE="HTML" NAME="NODE"></a></span> 
     32  <TMPL_LOOP NAME="GROUPS"> 
     33      <li><span class="domain"><a href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
    3434      <ul> 
    35         <TMPL_LOOP NAME="CATEGORIES"> 
    36       <li><span class="domain"><a href="<TMPL_VAR NAME="NODE">.html#<TMPL_VAR NAME="NAME">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
     35          <TMPL_IF NAME="NCATEGORIES"><TMPL_LOOP NAME="CATEGORIES"> 
     36              <li><span class="host"><a href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
     37              <ul> 
     38                  <TMPL_LOOP NAME="SERVICES"> 
     39                      <li><span class="service"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span></li> 
     40                  </TMPL_LOOP>  
     41              </ul> 
     42              </li> 
     43          </TMPL_LOOP></TMPL_IF> 
     44      <TMPL_IF NAME="NGROUPS"> 
     45  <TMPL_LOOP NAME="GROUPS"> 
     46      <li><span class="domain"><a href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
    3747      <ul> 
    38         <TMPL_LOOP NAME="SERVICES"> 
    39         <li><span class="host"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="NODE">-<TMPL_VAR NAME="SERVICE">.html"><TMPL_VAR ESCAPE="HTML" NAME="LABEL"></a></span></li> 
    40         </TMPL_LOOP>  
     48          <TMPL_IF NAME="NCATEGORIES"><TMPL_LOOP NAME="CATEGORIES"> 
     49              <li><span class="host"><a href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
     50              <ul> 
     51                  <TMPL_LOOP NAME="SERVICES"> 
     52                      <li><span class="service"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span></li> 
     53                  </TMPL_LOOP>  
     54              </ul> 
     55              </li> 
     56          </TMPL_LOOP></TMPL_IF> 
     57      <TMPL_IF NAME="NGROUPS"> 
     58  <TMPL_LOOP NAME="GROUPS"> 
     59      <li><span class="domain"><a href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
     60      <ul> 
     61          <TMPL_IF NAME="NCATEGORIES"><TMPL_LOOP NAME="CATEGORIES"> 
     62              <li><span class="host"><a href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span> 
     63              <ul> 
     64                  <TMPL_LOOP NAME="SERVICES"> 
     65                      <li><span class="service"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span></li> 
     66                  </TMPL_LOOP>  
     67              </ul> 
     68              </li> 
     69          </TMPL_LOOP></TMPL_IF> 
     70      <TMPL_IF NAME="NGROUPS"> 
     71      </TMPL_IF> 
    4172      </ul> 
    42    </li> 
    43    </TMPL_LOOP> 
     73      </li> 
     74  </TMPL_LOOP> 
     75      </TMPL_IF> 
    4476      </ul> 
    45    </li> 
    46    </TMPL_LOOP> 
     77      </li> 
     78  </TMPL_LOOP> 
     79      </TMPL_IF> 
     80      </ul> 
     81      </li> 
     82  </TMPL_LOOP> 
    4783 </ul> 
    4884 </td></tr> 
     
    5086 <tr> 
    5187   <td class="linkbox"> 
    52  <TMPL_LOOP NAME="DOMAINS"> 
    53 <a href="../<TMPL_VAR NAME="DOMAIN">/index.html"><TMPL_VAR NAME="DOMAIN"></a> : 
    54     </TMPL_LOOP> 
     88   <TMPL_VAR NAME="PARENT"> :<TMPL_LOOP NAME="PEERS">: <TMPL_IF NAME="LINK"><a href="<TMPL_VAR NAME="LINK">"></TMPL_IF><TMPL_VAR NAME="NAME"><TMPL_IF NAME="LINK"></a></TMPL_IF></a> </TMPL_LOOP> 
    5589 </td> 
    5690 </tr> 
  • people/jo/multilevel-groups-3/server/munin-graph.in

    r1442 r1502  
    214214my $watermark = "Munin $VERSION"; 
    215215 
    216 for my $key ( keys %{$config->{domain}}) { 
    217     my $domain_time= Time::HiRes::time; 
    218     mkdir "$config->{htmldir}/$key",0777; 
    219     logger("Processing domain: $key"); 
    220     &process_domain($key); 
    221     $domain_time = sprintf ("%.2f",(Time::HiRes::time - $domain_time)); 
    222     logger("Processed domain: $key ($domain_time sec)"); 
    223     print STATS "GD|$key|$domain_time\n" unless $skip_stats; 
    224 
    225  
     216# Make array of what is probably needed to graph 
     217my $work_array = []; 
     218if (@limit_hosts) { # Limit what to update if needed 
     219    foreach my $nodename (@limit_hosts) { 
     220        push @$work_array, map { @{munin_find_field ($_->{$nodename}, "graph_title")} } @{munin_find_field($config, $nodename)}; 
     221    } 
     222} else { # ...else just search for all adresses to update 
     223    push @$work_array, @{munin_find_field($config, "graph_title")}; 
     224
     225 
     226 
     227for my $service (@$work_array) { 
     228    process_service ($service); 
     229
    226230 
    227231$graph_time = sprintf ("%.2f",(Time::HiRes::time - $graph_time)); 
     
    236240# ### The End 
    237241 
    238 sub process_domain { 
    239     my ($domain) = @_; 
    240     for my $key ( keys %{$config->{domain}->{$domain}->{node}}) { 
    241         my $node_time= Time::HiRes::time; 
    242  
    243         process_node($domain,$key ,$config->{domain}->{$domain}->{node}->{$key} ); 
    244         $node_time = sprintf ("%.2f",(Time::HiRes::time - $node_time)); 
    245         logger ("Processed node: $key ($node_time sec)"); 
    246         print STATS "GN|$domain|$key|$node_time\n" unless $skip_stats; 
    247     } 
    248 } 
    249  
    250242sub get_title { 
    251     my $node    = shift; 
    252243    my $service = shift; 
    253244    my $scale   = shift; 
    254245 
    255     return ($node->{client}->{$service}->{'graph_title'}? 
    256               $node->{client}->{$service}->{'graph_title'}:$service) . 
    257               " - by $scale"; 
     246    return (munin_get ($service, "graph_title", $service) . " - by $scale"); 
    258247} 
    259248 
    260249sub get_custom_graph_args 
    261250{ 
    262     my $node    = shift; 
    263251    my $service = shift; 
    264252    my $result  = []; 
    265253 
    266     if ($node->{client}->{$service}->{graph_args}) { 
    267         push @$result, split /\s/,$node->{client}->{$service}->{graph_args}; 
     254    my $args    = munin_get ($service, "graph_args"); 
     255    if (defined $args) { 
     256        push @$result, split /\s/,$args; 
    268257        return $result; 
    269     } 
    270     else 
    271     { 
     258    } else { 
    272259        return undef; 
    273260    } 
     
    276263sub get_vlabel 
    277264{ 
    278     my $node    = shift; 
    279265    my $service = shift; 
    280     my $scale   = shift; 
    281  
    282     if ($node->{client}->{$service}->{graph_vlabel}) { 
    283         (my $res = $node->{client}->{$service}->{graph_vlabel}) =~ s/\$\{graph_period\}/$scale/g; 
    284         return $res; 
    285     } 
    286     elsif ($node->{client}->{$service}->{graph_vtitle}) 
    287     { 
    288         return $node->{client}->{$service}->{graph_vtitle}; 
    289     } 
    290     return undef; 
     266    my $scale   = munin_get ($service, "graph_period", "second"); 
     267    my $res     = munin_get ($service, "graph_vlabel", munin_get ($service, "graph_vtitle")); 
     268 
     269    if (defined $res) { 
     270        $res =~ s/\$\{graph_period\}/$scale/g; 
     271    } 
     272    return $res; 
    291273} 
    292274 
    293275sub should_scale 
    294276{ 
    295     my $node    = shift; 
    296277    my $service = shift; 
    297  
    298     if (defined $node->{client}->{$service}->{graph_scale}) 
    299     { 
    300         return &munin_get_bool_val ($node->{client}->{$service}->{graph_scale}, 1); 
    301     } 
    302     elsif (defined $node->{client}->{$service}->{graph_noscale}) 
    303     { 
    304         return ! &munin_get_bool_val ($node->{client}->{$service}->{graph_noscale}, 0); 
    305     } 
    306  
    307     return 1; 
     278    my $ret; 
     279 
     280    if (!defined ($ret = munin_get_bool ($service, "graph_scale"))) { 
     281        $ret = !munin_get_bool ($service, "graph_noscale", 0); 
     282    } 
     283 
     284    return $ret; 
    308285} 
    309286 
    310287sub get_header { 
    311     my $node    = shift; 
    312     my $config  = shift; 
    313     my $domain  = shift; 
    314     my $host    = shift; 
    315288    my $service = shift; 
    316289    my $scale   = shift; 
     
    320293 
    321294    # Picture filename 
    322     push @$result, &munin_get_picture_filename ($config, $domain, $host, $service, $scale, $sum||undef); 
     295    push @$result, munin_get_picture_filename ($service, $scale, $sum||undef); 
    323296 
    324297    # Title 
    325     push @$result, ("--title", &get_title ($node, $service, $scale)); 
     298    push @$result, ("--title", get_title ($service, $scale)); 
    326299 
    327300    # When to start the graph 
     
    329302 
    330303    # Custom graph args, vlabel and graph title 
    331     if (defined ($tmp_field = &get_custom_graph_args ($node, $service))) { 
     304    if (defined ($tmp_field = get_custom_graph_args ($service))) { 
    332305        push (@$result, @{$tmp_field}); 
    333306    } 
    334     if (defined ($tmp_field = &get_vlabel ($node, $service, munin_get ($config, "graph_period", "second", $domain, $host, $service)))) { 
     307    if (defined ($tmp_field = get_vlabel ($service))) { 
    335308        push @$result, ("--vertical-label", $tmp_field); 
    336309    } 
    337310 
    338     push @$result,"--height", &munin_get ($config, "graph_height", "175", $domain, $host, $service); 
    339     push @$result,"--width", &munin_get ($config, "graph_width", "400", $domain, $host, $service); 
     311    push @$result,"--height", munin_get ($service, "graph_height", "175"); 
     312    push @$result,"--width", munin_get ($service, "graph_width", "400"); 
    340313    push @$result,"--imgformat", "PNG"; 
    341314    push @$result,"--lazy" if ($force_lazy); 
    342315 
    343     push (@$result, "--units-exponent", "0")  
    344         if (! &should_scale ($node, $service)); 
     316    push (@$result, "--units-exponent", "0") if (! should_scale ($service)); 
    345317 
    346318    return $result; 
     
    349321sub get_sum_command 
    350322{ 
    351     my $node    = shift; 
    352     my $service = shift; 
    353323    my $field   = shift; 
    354324 
    355     if (defined $node->{client}->{$service}->{$field.".special_sum"}) 
    356     { 
    357         return $node->{client}->{$service}->{$field.".special_sum"}; 
    358     } 
    359     elsif (defined $node->{client}->{$service}->{$field.".sum"}) 
    360     { 
    361         return $node->{client}->{$service}->{$field.".sum"}; 
    362     } 
    363  
    364     return undef; 
     325    if (defined $field->{"special_sum"}) { # Deprecated 
     326        return $field->{"special_sum"}; 
     327    } 
     328 
     329    return munin_get ($field, "sum"); 
    365330} 
    366331 
    367332sub get_stack_command 
    368333{ 
    369     my $node    = shift; 
    370     my $service = shift; 
    371334    my $field   = shift; 
    372335 
    373     if (defined $node->{client}->{$service}->{$field.".special_stack"}) 
    374     { 
    375         return $node->{client}->{$service}->{$field.".special_stack"}; 
    376     } 
    377     elsif (defined $node->{client}->{$service}->{$field.".stack"}) 
    378     { 
    379         return $node->{client}->{$service}->{$field.".stack"}; 
    380     } 
    381  
    382     return undef; 
     336    if (defined $field->{"special_stack"}) { # Deprecated 
     337        return $field->{"special_stack"};  
     338    }  
     339     
     340    return munin_get ($field, "stack"); 
    383341} 
    384342 
    385343sub expand_specials 
    386344{ 
    387     my $node    = shift; 
    388     my $config  = shift; 
    389     my $domain  = shift; 
    390     my $host    = shift; 
    391345    my $service = shift; 
    392346    my $preproc = shift; 
     
    397351    my $fieldnum = 0; 
    398352    for my $field (@$order) { # Search for 'specials'... 
    399  
    400         if ($field =~ /^-(.+)$/) 
    401         { 
     353        my $tmp_field; 
     354 
     355        if ($field =~ /^-(.+)$/) { # Invisible field 
    402356            $field = $1; 
    403             unless (defined $node->{client}->{$service}->{$field.".graph"} or 
    404                     defined $node->{client}->{$service}->{$field.".skipdraw"}) 
    405             { 
    406                 $node->{client}->{$service}->{$field.".graph"} = "no"; 
    407             } 
     357            munin_set_var_loc ($service, [$field, "graph"], "no"); 
    408358        } 
    409359 
    410360        $fieldnum++; 
    411         my $tmp_field; 
    412         if (defined ($tmp_field = &get_stack_command ($node, $service, $field))) 
    413         { 
    414             print "DEBUG: Doing special_stack...\n" if $DEBUG; 
     361        if ($field =~ /^([^=]+)=(.+)$/) { # Aliased in graph_order 
     362            my $fname = $1; 
     363            my $spath = $2; 
     364            my $src   = munin_get_node_partialpath ($service, $spath); 
     365            my $sname = munin_get_node_name ($src); 
     366 
     367            next unless defined $src; 
     368            logger ("Debug: Copying settings from $sname to $fname.") if $DEBUG; 
     369 
     370            foreach my $foption ("draw", "type", "rrdfile", "fieldname", "info") { 
     371                if (!defined $service->{$fname}->{$foption}) { 
     372                    if (defined $src->{$foption}) { 
     373                        munin_set_var_loc ($service, [$fname, $foption], $src->{$foption}); 
     374                    } 
     375                } 
     376            } 
     377 
     378            # cdef is special... 
     379            if (!defined $service->{$fname}->{"cdef"}) { 
     380                if (defined $src->{"cdef"}) { 
     381                    (my $tmpcdef = $src->{"cdef"}) =~ s/([,=])$sname([,=]|$)/$1$fname$2/g; 
     382                    munin_set_var_loc ($service, [$fname, "cdef"], $tmpcdef); 
     383                } 
     384            } 
     385             
     386            munin_set_var_loc ($service, [$fname, "label"], $fname); 
     387            munin_set_var_loc ($service, [$fname, "filename"], munin_get_rrd_filename ($src)); 
     388 
     389        } elsif (defined ($tmp_field = get_stack_command ($service->{$field}))) { 
     390            logger ("DEBUG: expand_specials ($tmp_field): Doing stack...") if $DEBUG; 
    415391            my @spc_stack = (); 
    416             foreach my $pre (split (/\s+/, $tmp_field)) 
    417             { 
     392            foreach my $pre (split (/\s+/, $tmp_field)) { 
    418393                (my $name = $pre) =~ s/=.+//; 
    419                 if (!@spc_stack) 
    420                 { 
    421                     $node->{client}->{$service}->{$name.".draw"} = $node->{client}->{$service}->{$field.".draw"}; 
    422                     $node->{client}->{$service}->{$field.".process"} = "no"; 
    423                 } 
    424                 else 
    425                 { 
    426                     $node->{client}->{$service}->{$name.".draw"} = "STACK"; 
     394                if (!@spc_stack) { 
     395                    munin_set_var_loc ($service, [$name, "draw"], munin_get ($service->{$field}, "draw", "LINE2")); 
     396                    munin_set_var_loc ($service, [$field, "process"], "no"); 
     397                } else { 
     398                    munin_set_var_loc ($service, [$name, "draw"], "STACK"); 
    427399                } 
    428400                push (@spc_stack, $name); 
     
    432404                push @$result, "$name.cdef"; 
    433405 
    434                 $node->{client}->{$service}->{$name.".label"} = $name; 
    435                 $node->{client}->{$service}->{$name.".cdef"} = "$name,UN,0,$name,IF"; 
    436                 if (exists $node->{client}->{$service}->{$field.".cdef"} and !exists $node->{client}->{$service}->{$name.".onlynullcdef"}) 
    437                 { 
    438                     print "NotOnlynullcdef ($field)...\n" if $DEBUG; 
    439                     $node->{client}->{$service}->{$name.".cdef"} .= "," . 
    440                         $node->{client}->{$service}->{$field.".cdef"}; 
    441                     $node->{client}->{$service}->{$name.".cdef"} =~ s/\b$field\b/$name/g; 
    442                 } 
    443                 else 
    444                 { 
    445                     print "Onlynullcdef ($field)...\n" if $DEBUG; 
    446                     $node->{client}->{$service}->{$name.".onlynullcdef"} = 1; 
     406                munin_set_var_loc ($service, [$name, "label"], $name); 
     407                munin_set_var_loc ($service, [$name, "cdef"], "$name,UN,0,$name,IF"); 
     408                if (munin_get ($service->{$field}, "cdef") and !munin_get_bool ($service->{$name}, "onlynullcdef", 0)) { 
     409                    logger ("NotOnlynullcdef ($field)...") if $DEBUG; 
     410                    $service->{$name}->{"cdef"} .= "," . $service->{$field}->{"cdef"}; 
     411                    $service->{$name}->{"cdef"} =~ s/\b$field\b/$name/g; 
     412                } else { 
     413                    logger ("Onlynullcdef ($field)...") if $DEBUG; 
     414                    munin_set_var_loc ($service, [$name, "onlynullcdef"], 1); 
    447415                    push @$result, "$name.onlynullcdef"; 
    448416                } 
    449417            } 
    450         } 
    451         elsif (defined ($tmp_field = &get_sum_command ($node, $service, $field))) 
    452         { 
     418        } elsif (defined ($tmp_field = get_sum_command ($service->{$field}))) { 
    453419            my @spc_stack = (); 
    454420            my $last_name = ""; 
    455             print "DEBUG: Doing special_sum...\n" if $DEBUG; 
    456  
    457                 if (@$order == 1 or  
    458                         @$order == 2 && $node->{client}->{$service}->{$field.".negative"})  
    459                 { 
    460                         $single = 1; 
    461                 } 
     421            logger ("DEBUG: expand_specials ($tmp_field): Doing sum...") if $DEBUG; 
     422 
     423            if (@$order == 1 or (@$order == 2 and munin_get {$field, "negative", 0})) { 
     424                    $single = 1; 
     425            } 
    462426                 
    463             foreach my $pre (split (/\s+/, $tmp_field)) 
    464             { 
     427            foreach my $pre (split (/\s+/, $tmp_field)) { 
    465428                (my $path = $pre) =~ s/.+=//; 
    466429                my $name = "z".$fieldnum."_".scalar (@spc_stack); 
    467430                $last_name = $name; 
    468431 
    469                 $node->{client}->{$service}->{$name.".cdef"}  = "$name,UN,0,$name,IF"
    470                 $node->{client}->{$service}->{$name.".graph"} = "no"
    471                 $node->{client}->{$service}->{$name.".label"} = $name
     432                munin_set_var_loc ($service, [$name, "cdef"], "$name,UN,0,$name,IF")
     433                munin_set_var_loc ($service, [$name, "graph"], "no")
     434                munin_set_var_loc ($service, [$name, "label"], $name)
    472435                push @$result, "$name.cdef"; 
    473436                push @$result, "$name.graph"; 
     
    477440                push (@$preproc, "$name=$pre"); 
    478441            } 
    479             $node->{client}->{$service}->{$last_name.".cdef"} .= 
    480                 "," . join (',+,', @spc_stack[0 .. @spc_stack-2]) . ',+'; 
    481             if (exists $node->{client}->{$service}->{$field.".cdef"} and  
    482                     length $node->{client}->{$service}->{$field.".cdef"}) 
    483             { # Oh bugger... 
    484                 my $tc = $node->{client}->{$service}->{$field.".cdef"}; 
     442            $service->{$last_name}->{"cdef"} .= "," . join (',+,', @spc_stack[0 .. @spc_stack-2]) . ',+'; 
     443 
     444            if (my $tc = munin_get ($service->{$field}, "cdef", 0)) { # Oh bugger... 
    485445                print "Oh bugger...($field)...\n" if $DEBUG; 
    486                 $tc =~ s/\b$field\b/$node->{client}->{$service}->{$last_name.".cdef"}/; 
    487                 $node->{client}->{$service}->{$last_name.".cdef"} = $tc; 
    488             } 
    489             $node->{client}->{$service}->{$field.".process"} = "no"; 
    490             $node->{client}->{$service}->{$last_name.".draw"} = $node->{client}->{$service}->{$field.".draw"}; 
    491             $node->{client}->{$service}->{$last_name.".label"} = $node->{client}->{$service}->{$field.".label"}; 
    492             if (defined $node->{client}->{$service}->{$field.".graph"}) 
    493             { 
    494                 $node->{client}->{$service}->{$last_name.".graph"} = $node->{client}->{$service}->{$field.".graph"}; 
    495             } 
    496             else 
    497             { 
    498                 $node->{client}->{$service}->{$last_name.".graph"} = "yes"; 
    499             } 
    500             if (defined $node->{client}->{$service}->{$field.".negative"}) 
    501             { 
    502                 $node->{client}->{$service}->{$last_name.".negative"} = $node->{client}->{$service}->{$field.".negative"};; 
    503             } 
    504             $node->{client}->{$service}->{$field.".realname"} = $last_name; 
    505             print "Setting node->{client}->{$service}->{$field} -> realname = $last_name...\n" if $DEBUG; 
    506         } 
    507         elsif (defined $node->{client}->{$service}->{$field.".negative"}) 
    508         { 
    509             my $nf = $node->{client}->{$service}->{$field.".negative"}; 
    510             unless (defined $node->{client}->{$service}->{$nf.".graph"} or 
    511                     defined $node->{client}->{$service}->{$nf.".skipdraw"}) 
    512             { 
    513                 $node->{client}->{$service}->{$nf.".graph"} = "no"; 
     446                $tc =~ s/\b$field\b/$service->{$last_name}->{"cdef"}/; 
     447                $service->{$last_name}->{"cdef"} = $tc; 
     448            } 
     449            munin_set_var_loc ($service, [$field, "process"], "no"); 
     450            munin_set_var_loc ($service, [$last_name, "draw"], munin_get ($service->{$field}, "draw")); 
     451            munin_set_var_loc ($service, [$last_name, "label"], munin_get ($service->{$field}, "label")); 
     452            munin_set_var_loc ($service, [$last_name, "graph"], munin_get ($service->{$field}, "graph", "yes")); 
     453 
     454            if (my $tmp = munin_get($service->{$field}, "negative")) { 
     455                munin_set_var_loc ($service, [$last_name, "negative"], $tmp); 
     456            } 
     457 
     458            munin_set_var_loc ($service, [$field, "realname"], $last_name); 
     459 
     460        } elsif (my $nf = munin_get ($service->{$field}, "negative", 0)) { 
     461            if (!munin_get_bool ($service->{$nf}, "graph", 1) or munin_get_bool ($service->{$nf}, "skipdraw", 0)) { 
     462                munin_set_var_loc ($service, [$nf, "graph"], "no"); 
    514463            } 
    515464        } 
     
    520469sub single_value 
    521470{ 
    522     my $node    = shift; 
    523     my $config  = shift; 
    524     my $domain  = shift; 
    525     my $host    = shift; 
    526471    my $service = shift; 
    527     my $field   = shift; 
    528     my $order   = shift; 
    529  
    530     return 1 if @$order == 1; 
    531     return 1 if (@$order == 2 and $node->{client}->{$service}->{$field.".negative"}); 
    532  
    533     my $graphable = 0; 
    534     if (!defined $node->{client}->{$service}->{"graphable"}) 
    535     { 
    536 #       foreach my $field (keys %{$node->{client}->{$service}}) 
    537         foreach my $field (&munin_get_field_order ($node, $config, $domain, $host, $service)) 
    538         { 
    539             print "DEBUG: single_value: Checking field \"$field\".\n" if $DEBUG; 
    540             if ($field =~ /^([^\.]+)\.label/ or $field =~ /=/) 
    541             { 
    542                 $graphable++ if &munin_draw_field ($node, $service, $1); 
    543             } 
    544         } 
    545         $node->{client}->{$service}->{"graphable"} = $graphable; 
    546     } 
    547     return 1 if ($node->{client}->{$service}->{"graphable"} == 1); 
    548      
    549     return 0; 
     472 
     473    my $graphable = munin_get ($service, "graphable", 0);; 
     474    if (!$graphable) { 
     475        foreach my $field (@{munin_get_field_order ($service)}) { 
     476            logger ("DEBUG: single_value: Checking field \"$field\"."); 
     477            $graphable++ if munin_draw_field ($service->{$field}); 
     478        } 
     479        munin_set_var_loc ($service, ["graphable"], $graphable); 
     480    } 
     481    logger ("Debug: service ". join (' :: ', @{munin_get_node_loc ($service)}) ." has $graphable elements."); 
     482    return ($graphable == 1); 
    550483} 
    551484 
     
    561494 
    562495sub process_field { 
    563     my $node    = shift; 
    564     my $service = shift; 
    565496    my $field   = shift; 
    566     return (&munin_get_bool_val ($node->{client}->{$service}->{$field.".process"}, 1)); 
    567 
    568  
    569 sub process_node { 
    570     my ($domain,$name,$node) = @_; 
    571  
    572     # See if we should skip it because of command-line arguments 
    573     return if (@limit_hosts and not grep (/^$name$/, @limit_hosts)); 
     497    return munin_get_bool ($field, "process", 1); 
     498
     499 
     500sub process_service { 
     501    my ($service) = @_; 
    574502 
    575503    # Make my graphs 
    576     logger ("Processing $name") if $DEBUG; 
    577     for my $service (keys %{$node->{client}}) { 
    578         my $service_time= Time::HiRes::time; 
    579         my $lastupdate = 0; 
    580         my $now  = time; 
    581         my $fnum = 0; 
    582         my @rrd; 
    583         my @added = (); 
    584  
    585         # See if we should skip the service 
    586         next if (&skip_service ($node, $service)); 
    587  
    588         my $field_count = 0; 
    589         my $max_field_len = 0; 
    590         my @field_order = (); 
    591         my $rrdname; 
    592         my $force_single_value; 
    593  
    594         # munin_set_context($node,$config,$domain,$name,$service); 
    595  
    596         @field_order =  
    597           @{&munin_get_field_order($node, $config, $domain, $name, 
    598                                    $service, \$force_single_value)}; 
    599  
    600         # Array to keep 'preprocess'ed fields. 
    601         my @rrd_preprocess = (); 
    602         print "DEBUG: Expanding specials \"", 
    603           join("\",\"", @field_order), "\".\n" 
    604             if $DEBUG; 
    605  
    606         @added =  
    607           @{&expand_specials ($node, $config, $domain, $name, 
    608                               $service, \@rrd_preprocess, \@field_order)}; 
    609  
    610         @field_order = (@rrd_preprocess, @field_order); 
    611         print "DEBUG: Checking field lengths \"", 
    612           join("\",\"", @rrd_preprocess), "\".\n" 
    613             if $DEBUG; 
    614  
    615         # Get max label length 
    616         $max_field_len = 
    617           &munin_get_max_label_length ($node, $config, $domain, $name, 
    618                                        $service, \@field_order); 
    619         # my $global_headers = ($max_field_len >= 16); 
    620         # Global headers makes the value tables easier to read no matter how 
    621         # wide the labels are. 
    622         my $global_headers = 1; 
    623  
    624         # Default format for printing under graph. 
    625         my $avgformat; 
    626         my $rrdformat=$avgformat="%6.2lf"; 
    627  
    628         if (exists $node->{client}->{$service}->{graph_args} and 
    629             $node->{client}->{$service}->{graph_args} =~ /--base\s+1024/) { 
    630             # If the base unit is 1024 then 1012.56 is a valid 
    631             # number to show.  That's 7 positions, not 6. 
    632             $rrdformat=$avgformat="%7.2lf"; 
    633         } 
    634  
    635         if (exists $node->{client}->{$service}->{graph_printf} ) { 
    636             # Plugin specified complete printf format 
    637             $rrdformat=$node->{client}->{$service}->{graph_printf}; 
    638         } 
    639  
    640         my $rrdscale = ''; 
    641         $rrdscale = '%s' 
    642           if munin_get_bool_val ($node->{client}->{$service}->{graph_scale},1); 
    643  
    644         # Array to keep negative data until we're finished with positive. 
    645         my @rrd_negatives = (); 
    646         my $filename = "unknown"; 
    647         my %total_pos; 
    648         my %total_neg; 
    649         my $autostacking=0; 
    650         print "DEBUG: Treating fields \"", join "\",\"", @field_order, "\".\n" if $DEBUG; 
    651         for my $field (@field_order) { 
    652             my $path  = undef; 
    653             if ($field =~ s/=(.+)//) { 
    654                 $path = $1; 
    655             } 
    656  
    657             next unless &process_field ($node, $service, $field); 
    658             print "DEBUG: Processing field \"$field\".\n" if $DEBUG; 
    659  
    660             my $fielddraw = munin_get ($config, "draw", "LINE2", $domain, 
    661                                        $name, $service, $field); 
    662  
    663             if ($field_count == 0 and $fielddraw eq 'STACK') { 
    664                 # Illegal -- first field is a STACK 
    665                 logger ("ERROR: First field (\"$field\") of graph \"$domain\"". 
    666                         ":: \"$name\" :: \"$service\" is STACK. STACK can ". 
    667                         "only be drawn after a LINEx or AREA."); 
    668                 $fielddraw = "LINE2"; 
    669             } 
    670  
    671             if ($fielddraw eq 'AREASTACK') { 
    672                 if ($autostacking==0) { 
    673                     $fielddraw='AREA'; 
    674                     $autostacking=1; 
    675                 } else { 
    676                     $fielddraw='STACK'; 
    677                 } 
    678             } 
    679  
    680             if ($fielddraw =~ /LINESTACK(\d+(?:.\d+)?)/ ) { 
    681                 if ($autostacking==0) { 
    682                     $fielddraw="LINE$1"; 
    683                     $autostacking=1; 
    684                 } else { 
    685                     $fielddraw='STACK'; 
    686                 } 
    687             } 
    688  
    689             # Getting name of rrd file 
    690             $filename = &munin_get_rrd_filename ($node, $config, $domain, 
    691                                                  $name, $service, $field, 
    692                                                  $path); 
    693  
    694             my $update = RRDs::last ($filename); 
    695             $update = 0 if ! defined $update; 
    696             if ($update > $lastupdate) { 
    697                 $lastupdate = $update; 
    698             } 
    699  
    700             # It does not look like $fieldname.rrdfield is possible to set 
    701             my $rrdfield = ($node->{client}->{$service}->{$field.".rrdfield"} 
    702                             || "42"); 
    703  
    704             my $single_value = $force_single_value || 
    705               &single_value ($node, $config, $domain, $name, 
    706                              $service, $field, \@field_order); 
    707  
    708             my $has_negative = 
    709               exists $node->{client}->{$service}->{$field.".negative"}; 
    710  
    711             # Trim the fieldname to make room for other field names. 
    712             $rrdname = &get_field_name ($field); 
    713             if ($rrdname ne $field) { 
    714                 # A change was made 
    715                 set_cdef_name ($node->{client}->{$service}, $field, $rrdname); 
    716             } 
    717  
    718             push (@rrd, "DEF:g$rrdname=" . 
    719                   $filename . ":" . $rrdfield . ":AVERAGE"); 
    720             push (@rrd, "DEF:i$rrdname=" . 
    721                   $filename . ":" . $rrdfield . ":MIN"); 
    722             push (@rrd, "DEF:a$rrdname=" . 
    723                   $filename . ":" . $rrdfield . ":MAX"); 
    724  
    725             if (exists $node->{client}->{$service}->{$field.".onlynullcdef"} 
    726                 and 
    727                 $node->{client}->{$service}->{$field.".onlynullcdef"}) { 
    728                 push (@rrd, "CDEF:c$rrdname=g$rrdname" . 
    729                       (($now-$update)>900 ? ",POP,UNKN" : "")); 
    730             } 
    731  
    732             if (($node->{client}->{$service}->{$field.".type"}||"GAUGE") 
    733                 ne "GAUGE" 
    734                 and graph_by_minute ($config, $domain, $name, $service)) { 
    735                 push (@rrd, &expand_cdef($node->{client}->{$service}, 
    736                                          \$rrdname, "$field,60,*")); 
    737             } 
    738  
    739             if ($node->{client}->{$service}->{$field.".cdef"}) { 
    740                 push (@rrd,&expand_cdef($node->{client}->{$service}, 
    741                                         \$rrdname, 
    742                                         $node->{client}->{$service}->{$field.".cdef"})); 
    743                 push (@rrd, "CDEF:c$rrdname=g$rrdname"); 
    744                 print "DEBUG: Field name after cdef set to $rrdname\n" if $DEBUG; 
    745             } elsif (!(exists $node->{client}->{$service}->{$field.".onlynullcdef"} 
    746                        and $node->{client}->{$service}->{$field.".onlynullcdef"})) { 
    747                 push (@rrd, "CDEF:c$rrdname=g$rrdname" . (($now-$update)>900 ? ",POP,UNKN" : "")); 
    748             } 
    749  
    750             next unless &munin_draw_field ($node, $service, $field); 
    751             print "DEBUG: Drawing field \"$field\".\n" if $DEBUG; 
     504    my $sname = munin_get_node_name ($service); 
     505    my $service_time= Time::HiRes::time; 
     506    my $lastupdate = 0; 
     507    my $now  = time; 
     508    my $fnum = 0; 
     509    my @rrd; 
     510    my @added = (); 
     511 
     512    # See if we should skip the service 
     513    return if (skip_service ($service)); 
     514 
     515    my $field_count = 0; 
     516    my $max_field_len = 0; 
     517    my @field_order = (); 
     518    my $rrdname; 
     519    my $force_single_value; 
     520 
     521    @field_order = @{munin_get_field_order($service)}; 
     522 
     523    # Array to keep 'preprocess'ed fields. 
     524    my @rrd_preprocess = (); 
     525    logger ("Debug: Expanding specials for $sname: \"" . join("\",\"", @field_order) . "\".") if $DEBUG; 
     526 
     527    @added = @{&expand_specials ($service, \@rrd_preprocess, \@field_order, \$force_single_value)}; 
     528 
     529    @field_order = (@rrd_preprocess, @field_order); 
     530    logger ("DEBUG: Checking field lengths for $sname: \"" . join("\",\"", @rrd_preprocess) . "\".") if $DEBUG; 
     531 
     532    # Get max label length 
     533    $max_field_len = munin_get_max_label_length ($service, \@field_order); 
     534 
     535    # Global headers makes the value tables easier to read no matter how 
     536    # wide the labels are. 
     537    my $global_headers = 1; 
     538 
     539    # Default format for printing under graph. 
     540    my $avgformat; 
     541    my $rrdformat=$avgformat="%6.2lf"; 
     542 
     543    if (munin_get ($service, "graph_args", "") =~ /--base\s+1024/) { 
     544        # If the base unit is 1024 then 1012.56 is a valid 
     545        # number to show.  That's 7 positions, not 6. 
     546        $rrdformat=$avgformat="%7.2lf"; 
     547    } 
     548 
     549    # Plugin specified complete printf format 
     550    $rrdformat = munin_get ($service, "graph_printf", $rrdformat); 
     551 
     552    my $rrdscale = ''; 
     553    if (munin_get_bool ($service, "graph_scale", 1)) { 
     554        $rrdscale = '%s'; 
     555    } 
     556 
     557    # Array to keep negative data until we're finished with positive. 
     558    my @rrd_negatives = (); 
     559 
     560    my $filename = "unknown"; 
     561    my %total_pos; 
     562    my %total_neg; 
     563    my $autostacking=0; 
     564 
     565    logger ("DEBUG: Treating fields \"" . join ("\",\"", @field_order) . "\".") if $DEBUG; 
     566    for my $fname (@field_order) { 
     567        my $path     = undef; 
     568        my $field    = undef; 
     569 
     570        if ($fname =~ s/=(.+)//) { 
     571            $path = $1; 
     572        } 
     573        $field = munin_get_node ($service, [$fname]); 
     574 
     575        next if (!defined $field or !$field or !process_field ($field)); 
     576        logger ("DEBUG: Processing field \"$fname\" [".munin_get_node_name($field)."].") if $DEBUG; 
     577 
     578        my $fielddraw = munin_get ($field, "draw", "LINE2"); 
     579 
     580        if ($field_count == 0 and $fielddraw eq 'STACK') { 
     581            # Illegal -- first field is a STACK 
     582            logger ("ERROR: First field (\"$fname\") of graph " . join (' :: ', munin_get_node_loc ($service)) . 
     583                    " is STACK. STACK can only be drawn after a LINEx or AREA."); 
     584            $fielddraw = "LINE2"; 
     585        } 
     586 
     587        if ($fielddraw eq 'AREASTACK') { 
     588            if ($autostacking==0) { 
     589                $fielddraw='AREA'; 
     590                $autostacking=1; 
     591            } else { 
     592                $fielddraw='STACK'; 
     593            } 
     594        } 
     595 
     596        if ($fielddraw =~ /LINESTACK(\d+(?:.\d+)?)/ ) { 
     597            if ($autostacking==0) { 
     598                $fielddraw="LINE$1"; 
     599                $autostacking=1; 
     600            } else { 
     601                $fielddraw='STACK'; 
     602            } 
     603        } 
     604 
     605        # Getting name of rrd file 
     606        $filename = munin_get_rrd_filename ($field, $path); 
     607 
     608        my $update = RRDs::last ($filename); 
     609        $update = 0 if ! defined $update; 
     610        if ($update > $lastupdate) { 
     611            $lastupdate = $update; 
     612        } 
     613 
     614        # It does not look like $fieldname.rrdfield is possible to set 
     615        my $rrdfield = munin_get ($field, "rrdfield", "42"); 
     616 
     617        my $single_value = $force_single_value || single_value ($service); 
     618 
     619        my $has_negative = munin_get ($field, "negative"); 
     620 
     621        # Trim the fieldname to make room for other field names. 
     622        $rrdname = &get_field_name ($fname); 
     623        if ($rrdname ne $fname) { 
     624            # A change was made 
     625            munin_set_var ($field, "cdef_name", $rrdname); 
     626        } 
     627 
     628        push (@rrd, "DEF:g$rrdname=" . 
     629              $filename . ":" . $rrdfield . ":AVERAGE"); 
     630        push (@rrd, "DEF:i$rrdname=" . 
     631              $filename . ":" . $rrdfield . ":MIN"); 
     632        push (@rrd, "DEF:a$rrdname=" . 
     633              $filename . ":" . $rrdfield . ":MAX"); 
     634 
     635        if (munin_get_bool ($field, "onlynullcdef", 0)) {  
     636            push (@rrd, "CDEF:c$rrdname=g$rrdname" . (($now-$update)>900 ? ",POP,UNKN" : "")); 
     637        } 
     638 
     639        if (munin_get ($field, "type", "GAUGE") ne "GAUGE" and graph_by_minute ($service)) { 
     640                push (@rrd, expand_cdef($service, \$rrdname, "$fname,60,*")); 
     641        } 
     642 
     643        if (my $tmpcdef = munin_get ($field, "cdef")) { 
     644            push (@rrd,expand_cdef($service, \$rrdname, $tmpcdef)); 
     645            push (@rrd, "CDEF:c$rrdname=g$rrdname"); 
     646            logger ("DEBUG: Field name after cdef set to $rrdname") if $DEBUG; 
     647        } elsif (!munin_get_bool ($field, "onlynullcdef", 0)) { 
     648            push (@rrd, "CDEF:c$rrdname=g$rrdname" . (($now-$update)>900 ? ",POP,UNKN" : "")); 
     649        } 
     650 
     651        next if !munin_draw_field ($field); 
     652        logger ("DEBUG: Drawing field \"$fname\".") if $DEBUG; 
     653 
     654        if ($single_value) { 
     655            # Only one field. Do min/max range.  
     656            push (@rrd, "CDEF:min_max_diff=a$rrdname,i$rrdname,-"); 
     657            push (@rrd, "CDEF:re_zero=min_max_diff,min_max_diff,-") if !munin_get ($field, "negative"); 
     658            push (@rrd, "AREA:i$rrdname#ffffff"); 
     659            push (@rrd, "STACK:min_max_diff$range_colour"); 
     660            push (@rrd, "LINE2:re_zero#000000") if !munin_get ($field, "negative"); 
     661        } 
     662 
     663        if ($has_negative and !@rrd_negatives) { # Push "global" headers... 
     664            push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
     665            push (@rrd, "COMMENT:Cur (-/+)"); 
     666            push (@rrd, "COMMENT:Min (-/+)"); 
     667            push (@rrd, "COMMENT:Avg (-/+)"); 
     668            push (@rrd, "COMMENT:Max (-/+) \\j"); 
     669        } elsif ($global_headers == 1) { 
     670            push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
     671            push (@rrd, "COMMENT: Cur$RRDkludge:"); 
     672            push (@rrd, "COMMENT:Min$RRDkludge:"); 
     673            push (@rrd, "COMMENT:Avg$RRDkludge:"); 
     674            push (@rrd, "COMMENT:Max$RRDkludge:  \\j"); 
     675            $global_headers++; 
     676        } 
     677 
     678        my $colour; 
     679 
     680        if (my $tmpcol = munin_get ($field, "colour")) { 
     681            $colour = "#" . $tmpcol; 
     682        } elsif ($single_value) { 
     683            $colour = $single_colour; 
     684        } else { 
     685            $colour = $COLOUR[$field_count%@COLOUR]; 
     686        } 
     687 
     688        $field_count++; 
     689 
     690        my $tmplabel = munin_get ($field, "label", $fname); 
     691 
     692        push (@rrd, $fielddraw . ":g$rrdname" . $colour . ":" . 
     693            escape ($tmplabel) . (" " x ($max_field_len + 1 - length $tmplabel))); 
     694 
     695        # Check for negative fields (typically network (or disk) traffic) 
     696        if ($has_negative) { 
     697            my $negfieldname = orig_to_cdef ($service, munin_get ($field, "negative")); 
     698            my $negfield     = $service->{$negfieldname}; 
     699            if (my $tmpneg = munin_get ($negfield, "realname")) { 
     700                $negfieldname = $tmpneg; 
     701                $negfield     = $service->{$negfieldname}; 
     702            } 
     703             
     704            if (!@rrd_negatives) { 
     705                # zero-line, to redraw zero afterwards. 
     706                push (@rrd_negatives, "CDEF:re_zero=g$negfieldname,UN,0,0,IF"); 
     707            } 
     708 
     709            push (@rrd_negatives, "CDEF:ng$negfieldname=g$negfieldname,-1,*"); 
    752710 
    753711            if ($single_value) { 
    754712                # Only one field. Do min/max range.      
    755                 push (@rrd, "CDEF:min_max_diff=a$rrdname,i$rrdname,-"); 
    756                 push (@rrd, "CDEF:re_zero=min_max_diff,min_max_diff,-")  
    757                     unless ($node->{client}->{$service}->{$field.".negative"}); 
    758                 push (@rrd, "AREA:i$rrdname#ffffff"); 
    759                 push (@rrd, "STACK:min_max_diff$range_colour"); 
    760                 push (@rrd, "LINE2:re_zero#000000") 
    761                     unless ($node->{client}->{$service}->{$field.".negative"}); 
    762             } 
    763  
    764             if ($has_negative and !@rrd_negatives) { # Push "global" headers... 
    765                 push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
    766                 push (@rrd, "COMMENT:Cur (-/+)"); 
    767                 push (@rrd, "COMMENT:Min (-/+)"); 
    768                 push (@rrd, "COMMENT:Avg (-/+)"); 
    769                 push (@rrd, "COMMENT:Max (-/+) \\j"); 
    770             } elsif ($global_headers == 1) { 
    771                 push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
    772                 push (@rrd, "COMMENT: Cur$RRDkludge:"); 
    773                 push (@rrd, "COMMENT:Min$RRDkludge:"); 
    774                 push (@rrd, "COMMENT:Avg$RRDkludge:"); 
    775                 push (@rrd, "COMMENT:Max$RRDkludge:  \\j"); 
    776                 $global_headers++; 
    777             } 
    778  
    779             my $colour; 
    780  
    781             if (exists $node->{client}->{$service}->{$field.".colour"}) { 
    782                 $colour = "#". 
    783                   $node->{client}->{$service}->{$field.".colour"}; 
    784             } elsif ($single_value) { 
    785                 $colour = $single_colour; 
    786             } else { 
    787                 $colour = $COLOUR[$field_count%@COLOUR]; 
    788             } 
    789  
    790             $field_count++; 
    791  
    792             push (@rrd, $fielddraw . ":g$rrdname" . $colour . ":" . 
    793                   (escape ($node->{client}->{$service}->{"$field.label"}) || escape ($field)) 
    794                   . (" " x ($max_field_len + 1 - 
    795                             length ($node->{client}->{$service}->{"$field.label"} || $field)))); 
    796  
    797             # Check for negative fields (typically network (or disk) traffic) 
    798             if ($has_negative) { 
    799                 my $negfield = &orig_to_cdef ($node->{client}->{$service}, $node->{client}->{$service}->{$field.".negative"}); 
    800                 print "DEBUG: negfield = $negfield\n" if $DEBUG; 
    801                 if (exists $node->{client}->{$service}->{$negfield.".realname"}) { 
    802                     $negfield = $node->{client}->{$service}->{$negfield.".realname"}; 
    803                 } 
    804                  
    805                 if (!@rrd_negatives) { 
    806                     # zero-line, to redraw zero afterwards. 
    807                     push (@rrd_negatives, "CDEF:re_zero=g$negfield,UN,0,0,IF"); 
    808                 } 
    809  
    810                 push (@rrd_negatives, "CDEF:ng$negfield=g$negfield,-1,*"); 
    811  
    812                 if ($single_value) { 
    813                     # Only one field. Do min/max range.  
    814                     push (@rrd, "CDEF:neg_min_max_diff=i$negfield,a$negfield,-"); 
    815                     push (@rrd, "CDEF:ni$negfield=i$negfield,-1,*"); 
    816                     push (@rrd, "AREA:ni$negfield#ffffff"); 
    817                     push (@rrd, "STACK:neg_min_max_diff$range_colour"); 
    818                 } 
    819  
    820                 push (@rrd_negatives, $fielddraw . ":ng$negfield" . $colour ); 
    821  
    822                 # Draw HRULEs 
    823                 my $linedef = munin_get ($config, "line", undef, $domain, $name, $service, $node->{client}->{$service}->{$field.".negative"}); 
    824                 if ($linedef) { 
    825                     my ($number, $ldcolour, $label) = split (/:/, $linedef, 3); 
    826                     push (@rrd_negatives, "HRULE:".$number. 
    827                         ($ldcolour ? "#$ldcolour" : $colour)); 
    828  
    829                 } elsif ($node->{client}->{$service}->{"$negfield.warn"}) { 
    830                     push (@rrd_negatives, "HRULE:".$node->{client}->{$service}->{$node->{client}->{$service}->{$field.".negative"}.".warn"}. 
    831                           (defined $single_value and $single_value) ? "#ff0000" : $colour); 
    832                 } 
    833  
    834                 push (@rrd, "GPRINT:c$negfield:LAST:$rrdformat" . $rrdscale . "/\\g"); 
    835                 push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
    836                 push (@rrd, "GPRINT:i$negfield:MIN:$rrdformat" . $rrdscale . "/\\g"); 
    837                 push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
    838                 push (@rrd, "GPRINT:g$negfield:AVERAGE:$avgformat" . $rrdscale . "/\\g"); 
    839                 push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
    840                 push (@rrd, "GPRINT:a$negfield:MAX:$rrdformat" . $rrdscale . "/\\g"); 
    841                 push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
    842                 push (@{$total_pos{'min'}}, "i$rrdname"); 
    843                 push (@{$total_pos{'avg'}}, "g$rrdname"); 
    844                 push (@{$total_pos{'max'}}, "a$rrdname"); 
    845                 push (@{$total_neg{'min'}}, "i$negfield"); 
    846                 push (@{$total_neg{'avg'}}, "g$negfield"); 
    847                 push (@{$total_neg{'max'}}, "a$negfield"); 
    848             } else { 
    849                 push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers; 
    850                 push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
    851                 push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers; 
    852                 push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
    853                 push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers; 
    854                 push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
    855                 push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers; 
    856                 push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
    857                 push (@{$total_pos{'min'}}, "i$rrdname"); 
    858                 push (@{$total_pos{'avg'}}, "g$rrdname"); 
    859                 push (@{$total_pos{'max'}}, "a$rrdname"); 
    860             } 
     713                push (@rrd, "CDEF:neg_min_max_diff=i$negfieldname,a$negfieldname,-"); 
     714                push (@rrd, "CDEF:ni$negfieldname=i$negfieldname,-1,*"); 
     715                push (@rrd, "AREA:ni$negfieldname#ffffff"); 
     716                push (@rrd, "STACK:neg_min_max_diff$range_colour"); 
     717            } 
     718 
     719            push (@rrd_negatives, $fielddraw . ":ng$negfieldname" . $colour ); 
    861720 
    862721            # Draw HRULEs 
    863             my $linedef = munin_get ($config, "line", undef, $domain, $name, $service, $field); 
     722            my $linedef = munin_get ($negfield, "line"); 
    864723            if ($linedef) { 
    865724                my ($number, $ldcolour, $label) = split (/:/, $linedef, 3); 
    866                 $label =~ s/:/\\:/g if defined $label; 
    867                 push (@rrd, "HRULE:".$number. 
    868                     ($ldcolour ? "#$ldcolour" : 
    869                       ((defined $single_value and $single_value) ? 
    870                        "#ff0000" : $colour)). 
    871                       ((defined $label and length ($label)) ? ":$label" : ""), 
    872                       "COMMENT: \\j" 
    873                     ); 
    874             } elsif ($node->{client}->{$service}->{"$field.warn"}) { 
    875                 push (@rrd,"HRULE:". 
    876                       $node->{client}->{$service}->{"$field.warn"}. 
    877                       ($single_value ? "#ff0000" : $colour)); 
    878             } 
    879         } 
    880  
    881         if (@rrd_negatives) { 
    882             push (@rrd, @rrd_negatives); 
    883             push (@rrd, "LINE2:re_zero#000000"); # Redraw zero. 
    884             if (exists $node->{client}->{$service}->{graph_total} and 
    885                 exists $total_pos{'min'} and exists $total_neg{'min'} and 
    886                 @{$total_pos{'min'}} and @{$total_neg{'min'}}) { 
    887  
    888                 push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 
    889                 push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 
    890                 push (@rrd, "CDEF:apostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'max'}}).(",+" x (@{$total_pos{'max'}}-1))); 
    891                 push (@rrd, "CDEF:inegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'min'}}).(",+" x (@{$total_neg{'min'}}-1))); 
    892                 push (@rrd, "CDEF:gnegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'avg'}}).(",+" x (@{$total_neg{'avg'}}-1))); 
    893                 push (@rrd, "CDEF:anegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'max'}}).(",+" x (@{$total_neg{'max'}}-1))); 
    894                 push (@rrd, "CDEF:dpostotal=ipostotal,UN,ipostotal,UNKN,IF"); 
    895                 push (@rrd, "LINE1:dpostotal#000000:" . $node->{client}->{$service}->{graph_total} . (" " x ($max_field_len - length ($node->{client}->{$service}->{graph_total}) + 1))); 
    896                 push (@rrd, "GPRINT:gnegtotal:LAST:$rrdformat" . $rrdscale . "/\\g"); 
    897                 push (@rrd, "GPRINT:gpostotal:LAST:$rrdformat" . $rrdscale . ""); 
    898                 push (@rrd, "GPRINT:inegtotal:MIN:$rrdformat" . $rrdscale . "/\\g"); 
    899                 push (@rrd, "GPRINT:ipostotal:MIN:$rrdformat" . $rrdscale . ""); 
    900                 push (@rrd, "GPRINT:gnegtotal:AVERAGE:$avgformat" . $rrdscale . "/\\g"); 
    901                 push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale . ""); 
    902                 push (@rrd, "GPRINT:anegtotal:MAX:$rrdformat" . $rrdscale . "/\\g"); 
    903                 push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 
    904             } 
    905         } 
    906         elsif (exists $node->{client}->{$service}->{graph_total} and exists $total_pos{'min'} and @{$total_pos{'min'}}) { 
     725                push (@rrd_negatives, "HRULE:".$number. 
     726                    ($ldcolour ? "#$ldcolour" : $colour)); 
     727 
     728            } elsif (my $tmpwarn = munin_get ($negfield, "warn")) { 
     729                push (@rrd_negatives, "HRULE:".$negfieldname. 
     730                    (defined $single_value and $single_value) ? "#ff0000" : $colour); 
     731            } 
     732 
     733            push (@rrd, "GPRINT:c$negfieldname:LAST:$rrdformat" . $rrdscale . "/\\g"); 
     734            push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
     735            push (@rrd, "GPRINT:i$negfieldname:MIN:$rrdformat" . $rrdscale . "/\\g"); 
     736            push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
     737            push (@rrd, "GPRINT:g$negfieldname:AVERAGE:$avgformat" . $rrdscale . "/\\g"); 
     738            push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
     739            push (@rrd, "GPRINT:a$negfieldname:MAX:$rrdformat" . $rrdscale . "/\\g"); 
     740            push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
     741            push (@{$total_pos{'min'}}, "i$rrdname"); 
     742            push (@{$total_pos{'avg'}}, "g$rrdname"); 
     743            push (@{$total_pos{'max'}}, "a$rrdname"); 
     744            push (@{$total_neg{'min'}}, "i$negfieldname"); 
     745            push (@{$total_neg{'avg'}}, "g$negfieldname"); 
     746            push (@{$total_neg{'max'}}, "a$negfieldname"); 
     747        } else { 
     748            push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers; 
     749            push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
     750            push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers; 
     751            push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
     752            push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers; 
     753            push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
     754            push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers; 
     755            push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
     756            push (@{$total_pos{'min'}}, "i$rrdname"); 
     757            push (@{$total_pos{'avg'}}, "g$rrdname"); 
     758            push (@{$total_pos{'max'}}, "a$rrdname"); 
     759        } 
     760 
     761        # Draw HRULEs 
     762        my $linedef = munin_get ($field, "line"); 
     763        if ($linedef) { 
     764            my ($number, $ldcolour, $label) = split (/:/, $linedef, 3); 
     765            $label =~ s/:/\\:/g if defined $label; 
     766            push (@rrd, "HRULE:".$number. 
     767                ($ldcolour ? "#$ldcolour" : 
     768                  ((defined $single_value and $single_value) ? 
     769                   "#ff0000" : $colour)). 
     770                  ((defined $label and length ($label)) ? ":$label" : ""), 
     771                  "COMMENT: \\j" 
     772                ); 
     773        } elsif (my $tmpwarn = munin_get ($field, "warn")) { 
     774            push (@rrd,"HRULE:".$tmpwarn.($single_value ? "#ff0000" : $colour)); 
     775        } 
     776    } 
     777 
     778    my $graphtotal = munin_get ($service, "graph_total"); 
     779    if (@rrd_negatives) { 
     780        push (@rrd, @rrd_negatives); 
     781        push (@rrd, "LINE2:re_zero#000000"); # Redraw zero. 
     782        if (defined $graphtotal and exists $total_pos{'min'} and  
     783            exists $total_neg{'min'} and 
     784            @{$total_pos{'min'}} and @{$total_neg{'min'}}) { 
     785 
    907786            push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 
    908787            push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 
    909788            push (@rrd, "CDEF:apostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'max'}}).(",+" x (@{$total_pos{'max'}}-1))); 
    910  
     789            push (@rrd, "CDEF:inegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'min'}}).(",+" x (@{$total_neg{'min'}}-1))); 
     790            push (@rrd, "CDEF:gnegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'avg'}}).(",+" x (@{$total_neg{'avg'}}-1))); 
     791            push (@rrd, "CDEF:anegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'max'}}).(",+" x (@{$total_neg{'max'}}-1))); 
    911792            push (@rrd, "CDEF:dpostotal=ipostotal,UN,ipostotal,UNKN,IF"); 
    912             push (@rrd, "LINE1:dpostotal#000000:" . $node->{client}->{$service}->{graph_total} . (" " x ($max_field_len - length ($node->{client}->{$service}->{graph_total}) + 1))); 
    913             push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers
     793            push (@rrd, "LINE1:dpostotal#000000:$graphtotal" . (" " x ($max_field_len - length ($graphtotal) + 1))); 
     794            push (@rrd, "GPRINT:gnegtotal:LAST:$rrdformat" . $rrdscale . "/\\g")
    914795            push (@rrd, "GPRINT:gpostotal:LAST:$rrdformat" . $rrdscale . ""); 
    915             push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers
     796            push (@rrd, "GPRINT:inegtotal:MIN:$rrdformat" . $rrdscale . "/\\g")
    916797            push (@rrd, "GPRINT:ipostotal:MIN:$rrdformat" . $rrdscale . ""); 
    917             push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers
    918             push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale .""); 
    919             push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers
     798            push (@rrd, "GPRINT:gnegtotal:AVERAGE:$avgformat" . $rrdscale . "/\\g")
     799            push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale . ""); 
     800            push (@rrd, "GPRINT:anegtotal:MAX:$rrdformat" . $rrdscale . "/\\g")
    920801            push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 
    921802        } 
    922  
    923         for my $time (keys %times) { 
    924             next unless ($draw{$time}); 
    925             my @complete = (); 
    926             if ($RRDkludge) { 
    927                 push (@complete, 
    928                       '--font' ,'LEGEND:7:@@LIBDIR@@/VeraMono.ttf', 
    929                       '--font' ,'UNIT:7:@@LIBDIR@@/VeraMono.ttf', 
    930                       '--font' ,'AXIS:7:@@LIBDIR@@/VeraMono.ttf'); 
    931             } 
     803    } elsif (defined $graphtotal and exists $total_pos{'min'} and @{$total_pos{'min'}}) { 
     804        push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 
     805        push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 
     806        push (@rrd, "CDEF:apostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'max'}}).(",+" x (@{$total_pos{'max'}}-1))); 
     807 
     808        push (@rrd, "CDEF:dpostotal=ipostotal,UN,ipostotal,UNKN,IF"); 
     809        push (@rrd, "LINE1:dpostotal#000000:$graphtotal" . (" " x ($max_field_len - length ($graphtotal) + 1))); 
     810        push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers; 
     811        push (@rrd, "GPRINT:gpostotal:LAST:$rrdformat" . $rrdscale . ""); 
     812        push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers; 
     813        push (@rrd, "GPRINT:ipostotal:MIN:$rrdformat" . $rrdscale . ""); 
     814        push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers; 
     815        push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale .""); 
     816        push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers; 
     817        push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 
     818    } 
    932819            push(@complete,'-W', $watermark) if $RRDs::VERSION >= 1.2; 
    933820 
    934             logger ("Processing $name -> $time") if $DEBUG; 
    935  
    936             # Do the header (title, vtitle, size, etc...) 
    937             push @complete, @{&get_header ($node, $config, $domain, $name, $service, $time)}; 
    938             if ($LINEkluge) { 
    939                 @rrd = map { s/LINE3:/LINE2.2:/; $_; } @rrd; 
    940                 @rrd = map { s/LINE2:/LINE1.6:/; $_; } @rrd; 
    941                 # LINE1 is thin enough. 
    942             } 
    943             push @complete, @rrd; 
    944  
    945             push (@complete, "COMMENT:Last update$RRDkludge: " .  
    946                   RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
     821    for my $time (keys %times) { 
     822        next unless ($draw{$time}); 
     823        my $picfilename = munin_get_picture_filename ($service, $time); 
     824        (my $picdirname = $picfilename) =~ s/\/[^\/]+$//; 
     825 
     826        my @complete = (); 
     827        if ($RRDkludge) { 
     828            push (@complete, 
     829                  '--font' ,'LEGEND:7:@@LIBDIR@@/VeraMono.ttf', 
     830                  '--font' ,'UNIT:7:@@LIBDIR@@/VeraMono.ttf', 
     831                  '--font' ,'AXIS:7:@@LIBDIR@@/VeraMono.ttf'); 
     832        } 
     833 
     834        # Do the header (title, vtitle, size, etc...) 
     835        push @complete, @{get_header ($service, $time)}; 
     836        if ($LINEkluge) { 
     837            @rrd = map { s/LINE3:/LINE2.2:/; $_; } @rrd; 
     838            @rrd = map { s/LINE2:/LINE1.6:/; $_; } @rrd; 
     839            # LINE1 is thin enough. 
     840        } 
     841        push @complete, @rrd; 
     842 
     843        push (@complete, "COMMENT:Last update$RRDkludge: " .  
     844              RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
     845 
     846        if (time - 300 < $lastupdate) { 
     847            push @complete, "--end", 
     848              (int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
     849        } 
     850        print "\n\nrrdtool \"graph\" \"", 
     851          join ("\"\n\t\"",@complete), "\"\n" if $DEBUG; 
     852 
     853        # Make sure directory exists 
     854        munin_mkdir_p ($picdirname, 0777); 
     855 
     856        RRDs::graph (@complete); 
     857        if (my $ERROR = RRDs::error) { 
     858            logger ("Unable to graph ". munin_get_picture_filename ($service, $time) . ": $ERROR"); 
     859        } elsif ($list_images) { 
     860            # Command-line option to list images created 
     861            print munin_get_picture_filename ($service, $time),"\n"; 
     862        } 
     863    } 
     864 
     865    if (munin_get_bool ($service, "graph_sums", 0)) { 
     866        foreach my $time (keys %sumtimes) { 
     867            my $picfilename = munin_get_picture_filename ($service, $time, 1); 
     868            (my $picdirname = $picfilename) =~ s/\/[^\/]+$//; 
     869            next unless ($draw{"sum".$time}); 
     870            my @rrd_sum; 
     871            push @rrd_sum, @{get_header ($service, $time, 1)}; 
    947872 
    948873            if (time - 300 < $lastupdate) { 
    949                 push @complete, "--end", 
    950                   (int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
    951             } 
    952             print "\n\nrrdtool \"graph\" \"", 
    953               join ("\"\n\t\"",@complete), "\"\n" if $DEBUG; 
    954             RRDs::graph (@complete); 
     874                push @rrd_sum, "--end",(int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
     875            } 
     876            push @rrd_sum, @rrd; 
     877            push (@rrd_sum, "COMMENT:Last update$RRDkludge: " . RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
     878 
     879            my $labelled = 0; 
     880            my @defined = (); 
     881            for (my $index = 0; $index <= $#rrd_sum; $index++) { 
     882                if ($rrd_sum[$index] =~ /^(--vertical-label|-v)$/) { 
     883                    (my $label = munin_get ($service, "graph_vlabel")) =~ s/\$\{graph_period\}/$sumtimes{$time}[0]/g; 
     884                    splice (@rrd_sum, $index, 2, ("--vertical-label", $label)); 
     885                    $index++; 
     886                    $labelled++; 
     887                } elsif ($rrd_sum[$index] =~ /^(LINE[123]|STACK|AREA|GPRINT):([^#:]+)([#:].+)$/) { 
     888                    my ($pre, $fname, $post) = ($1, $2, $3); 
     889                    next if $fname eq "re_zero"; 
     890                    if ($post =~ /^:AVERAGE/) { 
     891                        splice (@rrd_sum, $index, 1, $pre . ":x$fname" . $post); 
     892                        $index++; 
     893                        next; 
     894                    } 
     895                    next if grep /^x$fname$/, @defined; 
     896                    push @defined, "x$fname"; 
     897                    my @replace; 
     898 
     899                    if (munin_get ($service->{$fname}, "type", "GAUGE") ne "GAUGE") { 
     900                        if ($time eq "week") { 
     901                            # Every plot is half an hour. Add two plots and multiply, to get per hour 
     902                            if (graph_by_minute ($service)) { 
     903                                # Already multiplied by 60 
     904                                push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,5,*,6,*"; 
     905                            } else { 
     906                                push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,300,*,6,*"; 
     907                            } 
     908                        } else { 
     909                            # Every plot is one day exactly. Just multiply. 
     910                            if (graph_by_minute ($service)) { 
     911                                # Already multiplied by 60 
     912                                push @replace, "CDEF:x$fname=$fname,5,*,288,*"; 
     913                            } else { 
     914                                push @replace, "CDEF:x$fname=$fname,300,*,288,*"; 
     915                            } 
     916                        } 
     917                    } 
     918                    push @replace, $pre . ":x$fname" . $post; 
     919                    splice (@rrd_sum, $index, 1, @replace); 
     920                    $index++; 
     921                } elsif ($rrd_sum[$index] =~ /^(--lower-limit|--upper-limit|-l|-u)$/) { 
     922                    $index++; 
     923                    $rrd_sum[$index] = $rrd_sum[$index] * 300 * $sumtimes{$time}->[1]; 
     924                } 
     925            } 
     926 
     927            unless ($labelled) { 
     928                my $label = munin_get ($service, "graph_vlabel_sum_$time", $sumtimes{$time}->[0]); 
     929                unshift @rrd_sum, "--vertical-label", $label; 
     930            } 
     931 
     932            print "\n\nrrdtool \"graph\" \"", join ("\"\n\t\"",@rrd_sum), "\"\n" if $DEBUG; 
     933 
     934            # Make sure directory exists 
     935            munin_mkdir_p ($picdirname, 0777); 
     936 
     937            RRDs::graph (@rrd_sum); 
     938 
    955939            if (my $ERROR = RRDs::error) { 
    956                 logger ("Unable to graph $filename: $ERROR"); 
     940                logger ("Unable to graph ". munin_get_picture_filename ($service, $time) . ": $ERROR"); 
    957941            } elsif ($list_images) { 
    958942                # Command-line option to list images created 
    959                 print &munin_get_picture_filename ($config, $domain, $name, 
    960                                                    $service, $time),"\n"; 
    961             } 
    962         } 
    963  
    964         if (&munin_get_bool_val ($node->{client}->{$service}->{"graph_sums"}, 0)) { 
    965             foreach my $time (keys %sumtimes) { 
    966                 next unless ($draw{"sum".$time}); 
    967                 my @rrd_sum; 
    968                 push @rrd_sum, @{&get_header ($node, $config, $domain, $name, $service, $time, 1)}; 
    969  
    970                 if (time - 300 < $lastupdate) { 
    971                     push @rrd_sum, "--end",(int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
    972                 } 
    973                 push @rrd_sum, @rrd; 
    974                 push (@rrd_sum, "COMMENT:Last update$RRDkludge: " . RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
    975  
    976                 my $labelled = 0; 
    977                 my @defined = (); 
    978                 for (my $index = 0; $index <= $#rrd_sum; $index++) { 
    979                     if ($rrd_sum[$index] =~ /^(--vertical-label|-v)$/) { 
    980                         (my $label = $node->{client}->{$service}->{graph_vlabel}) =~ s/\$\{graph_period\}/$sumtimes{$time}[0]/g; 
    981                         splice (@rrd_sum, $index, 2, ("--vertical-label", $label)); 
    982                         $index++; 
    983                         $labelled++; 
    984                     } elsif ($rrd_sum[$index] =~ /^(LINE[123]|STACK|AREA|GPRINT):([^#:]+)([#:].+)$/) { 
    985                         my ($pre, $fname, $post) = ($1, $2, $3); 
    986                         next if $fname eq "re_zero"; 
    987                         if ($post =~ /^:AVERAGE/) { 
    988                             splice (@rrd_sum, $index, 1, $pre . ":x$fname" . $post); 
    989                             $index++; 
    990                             next; 
    991                         } 
    992                         next if grep /^x$fname$/, @defined; 
    993                         push @defined, "x$fname"; 
    994                         my @replace; 
    995  
    996                         if (!defined ($node->{client}->{$service}->{$fname.".type"}) or 
    997                             $node->{client}->{$service}->{$fname.".type"} ne "GAUGE") { 
    998                             if ($time eq "week") { 
    999                                 # Every plot is half an hour. Add two plots and multiply, to get per hour 
    1000                                 if (graph_by_minute ($config, $domain, $name, $service)) { 
    1001                                     # Already multiplied by 60 
    1002                                     push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,5,*,6,*"; 
    1003                                 } else { 
    1004                                     push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,300,*,6,*"; 
    1005                                 } 
    1006                             } else { 
    1007                                 # Every plot is one day exactly. Just multiply. 
    1008                                 if (graph_by_minute ($config, $domain, $name, $service)) { 
    1009                                     # Already multiplied by 60 
    1010                                     push @replace, "CDEF:x$fname=$fname,5,*,288,*"; 
    1011                                 } else { 
    1012                                     push @replace, "CDEF:x$fname=$fname,300,*,288,*"; 
    1013                                 } 
    1014                             } 
    1015                         } 
    1016                         push @replace, $pre . ":x$fname" . $post; 
    1017                         splice (@rrd_sum, $index, 1, @replace); 
    1018                         $index++; 
    1019                     } elsif ($rrd_sum[$index] =~ /^(--lower-limit|--upper-limit|-l|-u)$/) { 
    1020                         $index++; 
    1021                         $rrd_sum[$index] = $rrd_sum[$index] * 300 * $sumtimes{$time}->[1]; 
    1022                     } 
    1023                 } 
    1024  
    1025                 unless ($labelled) { 
    1026                     my $label = $node->{client}->{$service}->{"graph_vlabel_sum_$time"} || $sumtimes{$time}->[0]; 
    1027                     unshift @rrd_sum, "--vertical-label", $label; 
    1028                 } 
    1029  
    1030                 print "\n\nrrdtool \"graph\" \"", join ("\"\n\t\"",@rrd_sum), "\"\n" if $DEBUG; 
    1031                 RRDs::graph (@rrd_sum); 
    1032  
    1033                 if (my $ERROR = RRDs::error) { 
    1034                     logger ("Unable to graph $filename: $ERROR"); 
    1035                 } elsif ($list_images) { 
    1036                     # Command-line option to list images created 
    1037                     print &munin_get_picture_filename ($config, $domain, $name, $service, $time, 1), "\n"; 
    1038                 } 
    1039             } 
    1040         } 
    1041  
    1042         $service_time = sprintf ("%.2f",(Time::HiRes::time - $service_time)); 
    1043         logger ("Graphed service : $service ($service_time sec * 4)"); 
    1044         print STATS "GS|$domain|$name|$service|$service_time\n" unless $skip_stats; 
    1045  
    1046         foreach (@added) { 
    1047             delete $node->{client}->{$service}->{$_} 
    1048               if exists $node->{client}->{$service}->{$_}; 
    1049         } 
    1050         @added = (); 
    1051     } 
     943                print munin_get_picture_filename ($service, $time, 1),"\n"; 
     944            } 
     945        } 
     946    } 
     947 
     948    $service_time = sprintf ("%.2f",(Time::HiRes::time - $service_time)); 
     949    logger ("Graphed service : $sname ($service_time sec * 4)"); 
     950    print STATS "GS|$service_time\n" unless $skip_stats; 
     951 
     952    foreach (@added) { 
     953        delete $service->{$_} if exists $service->{$_}; 
     954    } 
     955    @added = (); 
    1052956} 
    1053957 
    1054958sub graph_by_minute { 
    1055     my $config  = shift; 
    1056     my $domain  = shift; 
    1057     my $name    = shift; 
    1058959    my $service = shift; 
    1059960 
    1060     return (munin_get ($config, "graph_period", "second", $domain, $name, $service) eq "minute"); 
     961    return (munin_get ($service, "graph_period", "second") eq "minute"); 
    1061962} 
    1062963 
    1063964sub orig_to_cdef { 
     965    my $service   = shift; 
     966    my $fieldname = shift; 
     967 
     968    return undef unless ref ($service) eq "HASH"; 
     969 
     970    if (defined $service->{$fieldname}->{"cdef_name"}) { 
     971        return orig_to_cdef ($service, $service->{$fieldname}->{"cdef_name"}); 
     972    } 
     973    return $fieldname; 
     974} 
     975 
     976sub skip_service { 
    1064977    my $service = shift; 
    1065     my $field   = shift; 
    1066  
    1067     if (defined $service->{$field.".cdef_name"}) 
    1068     { 
    1069         return &orig_to_cdef ($service, $service->{$field.".cdef_name"}); 
    1070     } 
    1071     return $field; 
    1072 
    1073  
    1074 sub set_cdef_name { 
    1075     my $service = shift; 
    1076     my $field   = shift; 
    1077     my $new     = shift; 
    1078  
    1079     $service->{$field.".cdef_name"} = $new; 
    1080     print "DEBUG: set_cdef_name from $field to $new.\n" if $DEBUG; 
    1081 
    1082  
    1083 sub skip_service { 
    1084     my $node = shift; 
    1085     my $service = shift; 
    1086  
    1087     # Check to make sure that service exists 
    1088     return 1 unless (ref $node->{client}->{$service}); 
     978    my $sname   = munin_get_node_name ($service); 
     979 
     980    # Skip if we've limited services with cli options 
     981    return 1 if (@limit_services and !grep /^$sname$/, @limit_services); 
     982 
     983    # Always graph if --force is present 
     984    return 0 if $force_graphing; 
    1089985 
    1090986    # See if we should skip it because of conf-options 
    1091     return 1 if ($node->{client}->{$service}->{'graph'} and  
    1092         ($node->{client}->{$service}->{'graph'} eq "no" || 
    1093         ($node->{client}->{$service}->{'graph'} eq "on-demand") && !$force_graphing)); 
    1094  
    1095     # See if we should skip it because of command-line arguments 
    1096     return 1 if (@limit_services and not grep (/^$service$/, @limit_services)); 
     987    return 1 if (munin_get ($service, "graph", "yes") eq "on-demand" or 
     988            !munin_get_bool ($service, "graph", 1)); 
    1097989 
    1098990    # Don't skip 
     
    11091001    my ($max, $min, $avg) = ("CDEF:a$new_field=$cdef", "CDEF:i$new_field=$cdef", "CDEF:g$new_field=$cdef"); 
    11101002 
    1111     foreach my $field (keys %$service) 
    1112     { 
    1113         next unless ($field =~ /^(.+)\.label$/); 
    1114         my $fieldname = $1;              
     1003    foreach my $field (@{munin_find_field ($service, "label")}) { 
     1004        my $fieldname = munin_get_node_name ($field); 
    11151005        my $rrdname = &orig_to_cdef ($service, $fieldname); 
    1116         if ($cdef =~ /\b$fieldname\b/) 
    1117         { 
     1006        if ($cdef =~ /\b$fieldname\b/) { 
    11181007                $max =~ s/([,=])$fieldname([,=]|$)/$1a$rrdname$2/g; 
    11191008                $min =~ s/([,=])$fieldname([,=]|$)/$1i$rrdname$2/g; 
     
    11221011    } 
    11231012 
    1124     &set_cdef_name ($service, $$cfield_ref, $new_field); 
     1013    munin_set_var_loc ($service, [$$cfield_ref, "cdef_name"], $new_field); 
    11251014    $$cfield_ref = $new_field; 
    11261015 
     
    11311020    my $dirname = shift; 
    11321021 
    1133     if (!$log->opened) 
    1134     { 
    1135           unless (open ($log, ">>$dirname/munin-graph.log")) 
    1136           { 
    1137                   print STDERR "Warning: Could not open log file \"$dirname/munin-graph.log\" for writing: $!"; 
    1138           } 
     1022    if (!$log->opened) { 
     1023        unless (open ($log, ">>$dirname/munin-graph.log")) { 
     1024            print STDERR "Warning: Could not open log file \"$dirname/munin-graph.log\" for writing: $!"; 
     1025        } 
     1026    } else { 
     1027        close (STDERR); 
     1028        *STDERR = \$log; 
    11391029    } 
    11401030} 
    11411031 
    11421032sub logger { 
    1143   my ($comment) = @_; 
    1144   my $now = strftime "%b %d %H:%M:%S", localtime; 
    1145  
    1146   print "$now - $comment\n" if $stdout; 
    1147   if ($log->opened) 
    1148   { 
    1149           print $log "$now - $comment\n"; 
    1150   } 
    1151   else 
    1152   { 
    1153           if (defined $config->{logdir}) 
    1154           { 
    1155                   if (open ($log, ">>$config->{logdir}/munin-graph.log")) 
    1156                   { 
    1157                           print $log "$now - $comment\n"; 
    1158                           $log->flush; 
    1159                           close (STDERR); 
    1160                           open (STDERR, ">&", $log); 
    1161                   } 
    1162                   else 
    1163                   { 
    1164                           print STDERR "Warning: Could not open log file \"$config->{logdir}/munin-graph.log\" for writing: $!"; 
    1165                           print STDERR "$now - $comment\n"; 
    1166                   } 
    1167           } 
    1168           else 
    1169           { 
    1170                   print STDERR "$now - $comment\n"; 
    1171           } 
     1033    my ($comment) = @_; 
     1034    my $now = strftime "%b %d %H:%M:%S", localtime; 
     1035 
     1036    print "$now - $comment\n" if $stdout; 
     1037    if ($log->opened) { 
     1038        print $log "$now - $comment\n"; 
     1039    } else { 
     1040        if (defined $config->{logdir}) { 
     1041            if (open ($log, ">>$config->{logdir}/munin-graph.log")) { 
     1042                print $log "$now - $comment\n"; 
     1043                $log->flush; 
     1044                close (STDERR); 
     1045                open (STDERR, ">&", $log); 
     1046            } else { 
     1047                print STDERR "Warning: Could not open log file \"$config->{logdir}/munin-graph.log\" for writing: $!"; 
     1048                print STDERR "$now - $comment\n"; 
     1049            } 
     1050        } else { 
     1051            print STDERR "$now - $comment\n"; 
     1052        } 
    11721053    } 
    11731054} 
  • people/jo/multilevel-groups-3/server/munin-html.in

    r1442 r1502  
    3232my @times = ( "day", "week", "month", "year" ); 
    3333 
     34my @limit_hosts; 
    3435my $DEBUG=0; 
    35 my $VERSION="@@VERSION@@"; 
     36my $VERSION = "@@VERSION@@"; 
    3637my $conffile = "@@CONFDIR@@/munin.conf"; 
    3738my $force_root = 0; 
     
    144145if ($config->{domain_order}) { 
    145146    @domainorder = split /\s+/, $config->{domain_order}; 
    146 } 
    147 foreach my $d (sort (keys %{$config->{domain}})) { 
    148     unless (grep (/^$d$/, @domainorder)) { 
    149         push @domainorder, $d; 
    150     } 
    151147} 
    152148 
     
    165161} 
    166162 
    167 #make domain list 
    168 my @domainlist = map { { DOMAIN => $_ } } @domainorder; 
     163# For timestamping graphs 
    169164my $timestamp = strftime("%Y-%m-%d T %T", localtime); 
    170 for my $domain (@domainorder) { 
    171   logger("processing domain: $domain"); 
    172   my %domain; 
    173   $domain{domain}=$domain; 
    174   my @nodes; 
    175   my %comparisons; 
    176   my @nodeorder = (); 
    177   if ($config->{domain}->{$domain}->{node_order}) { 
    178     @nodeorder = split /\s+/, $config->{domain}->{$domain}->{node_order}; 
    179   } 
    180   foreach my $n (sort (keys %{$config->{domain}->{$domain}->{node}})) { 
    181     unless (grep (/^$n$/, @nodeorder)) { 
    182       push @nodeorder, $n; 
    183     } 
    184   } 
    185   for my $node (@nodeorder) { 
    186     logger("processing node: $node"); 
    187     my %node; 
    188     $node{node}=$node; 
    189     $node{url}="$domain/$node.html"; 
    190     my @services; 
    191     my @categories; 
    192     my %categories; 
    193     my %tmp_cats; 
    194     my @serviceorder; 
    195     if ($config->{domain}->{$domain}->{node}->{$node}->{service_order}) { 
    196       @serviceorder = split /\s+/, 
    197         $config->{domain}->{$domain}->{node}->{$node}->{service_order}; 
    198     } else { 
    199       @serviceorder = sort 
    200         keys %{$config->{domain}->{$domain}->{node}->{$node}->{client}}; 
    201     } 
    202  
    203     for my $service (@serviceorder) { 
    204       logger("processing service: $service"); 
    205       next unless 
    206         defined($config->{domain}->{$domain}->{node}->{$node}->{client}->{$service} ) 
    207         &&  $config->{domain}->{$domain}->{node}->{$node}->{client}->{$service} ne ""; 
    208  
    209       next unless 
    210         munin_get_bool ($config, "graph", 1, $domain, $node, $service); 
    211  
    212       my @service; 
    213       my %service; 
    214       my $fieldnum = 0; 
    215       my @graph_info; 
    216       my @field_info; 
    217       $service{service}=$service; 
    218       $service{label}= 
    219         $config->{domain}->{$domain}->{node}->{$node}->{client}-> 
    220           {$service}->{graph_title}; 
    221  
    222       my $method = &munin_get ($config, "graph_strategy", "cron"); 
    223       if ($method eq "cgi") { 
    224         $service{imgday}=$config->{'cgiurl_graph'}. 
    225           "/$domain/$node/$service-day.png"; 
    226         $service{imgweek}=$config->{'cgiurl_graph'}. 
    227           "/$domain/$node/$service-week.png"; 
    228         $service{imgmonth}=$config->{'cgiurl_graph'}. 
    229           "/$domain/$node/$service-month.png"; 
    230         $service{imgyear}=$config->{'cgiurl_graph'}. 
    231           "/$domain/$node/$service-year.png"; 
    232  
    233         if (&munin_get_bool_val($config->{domain}->{$domain}-> 
    234                                 {node}->{$node}-> 
    235                                 {client}->{$service}->{"graph_sums"}, 0)) { 
    236           $service{imgweeksum} = 
    237             $config->{'cgiurl_graph'}."/$domain/$node/$service-week-sum.png"; 
    238           $service{imgyearsum} = 
    239             $config->{'cgiurl_graph'}."/$domain/$node/$service-year-sum.png"; 
    240         } 
    241  
    242 # There is a disturbance in the force here, the sizes are off. 
    243 #       if (my ($w, $h) = 
    244 #           &calculate_png_size ($config, $domain, $node, $service)) { 
    245 #         for my $scale (@times) { 
    246 #           $service{"img".$scale."width"} = $w; 
    247 #           $service{"img".$scale."height"} = $h; 
    248 #         } 
    249 #         if (&munin_get_bool_val($config->{domain}->{$domain}-> 
    250 #                                 {node}->{$node}-> 
    251 #                                 {client}->{$service}->{"graph_sums"}, 0)) { 
    252 #           for my $scale (["week", "year"]) { 
    253 #             $service{"img".$scale."sumwidth"} = $w; 
    254 #             $service{"img".$scale."sumheight"} = $h; 
    255 #           } 
    256 #         } 
    257 #       } 
    258       } else { 
    259         # graph strategy cron 
    260         $service{imgday}="$node-$service-day.png"; 
    261         $service{imgweek}="$node-$service-week.png"; 
    262         $service{imgmonth}="$node-$service-month.png"; 
    263         $service{imgyear}="$node-$service-year.png"; 
    264  
    265         for my $scale (@times) { 
    266           if (my ($w, $h) = 
    267               &get_png_size(&munin_get_picture_filename($config, $domain, 
    268                                                         $node, $service, 
    269                                                         $scale))) { 
    270             $service{"img".$scale."width"} = $w; 
    271             $service{"img".$scale."height"} = $h; 
    272           } 
    273         } 
    274  
    275         if (&munin_get_bool_val ($config->{domain}->{$domain}-> 
    276                                  {node}->{$node}->{client}-> 
    277                                  {$service}->{"graph_sums"}, 0)) { 
    278           $service{imgweeksum} = "$node-$service-week-sum.png"; 
    279           $service{imgyearsum} = "$node-$service-year-sum.png"; 
    280           for my $scale (["week", "year"]) { 
    281             if (my ($w, $h) = 
    282                 &get_png_size (&munin_get_picture_filename($config,$domain, 
    283                                                            $node, $service, 
    284                                                            $scale, 1))) { 
    285               $service{"img".$scale."sumwidth"} = $w; 
    286               $service{"img".$scale."sumheight"} = $h; 
    287             } 
    288           } 
    289         } 
    290       } 
    291       $service{url}="$node-$service.html"; 
    292       $service{domain}="$domain"; 
    293       $service{node}=$node; 
    294       $service{category}= lc( $config->{domain}->{$domain}-> 
    295                               {node}->{$node}->{client}-> 
    296                               {$service}->{graph_category} || "other" ); 
    297  
    298       # Do "help" section 
    299       if (defined($config->{domain}->{$domain}-> 
    300                   {node}->{$node}-> 
    301                   {client}->{$service}->{graph_info})) { 
    302         my %graph_info; 
    303  
    304         $graph_info{info} = $config->{domain}->{$domain}-> 
    305           {node}->{$node}->{client}->{$service}->{graph_info}; 
    306  
    307         push @{$service{graphinfo}}, \%graph_info; 
    308       } 
    309  
    310       $service{fieldlist} .= "<tr><th align='left' valign='top'>Field</th><th align='left' valign='top'>Type</th><th align='left' valign='top'>Warn</th><th align='left' valign='top'>Crit</th><th></tr>"; 
    311       # foreach my $field (keys %{$config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}}) 
    312       foreach my $f (@{&munin_get_field_order ($config->{domain}->{$domain}->{node}->{$node}, $config, $domain, $node, $service)}) { 
    313         $f =~ s/=(.*)$//; 
    314         my $path = $1; 
    315         next unless &munin_draw_field ($config->{domain}->{$domain}-> 
    316                                        {node}->{$node}, $service, $f); 
    317  
    318         print "DEBUG: single_value: Checking field \"$f\" ($path).\n" 
    319           if $DEBUG; 
    320  
    321         if (defined $path) { 
    322           # HUH? Get the filename and then forget? Some side effect here? 
    323           munin_get_rrd_filename ($config->{domain}->{$domain}-> 
    324                                   {node}->{$node}, $config, $domain, 
    325                                   $node, $service, $f, $path); 
    326         } 
    327  
    328         my %field_info; 
    329         $fieldnum++; 
    330  
    331         $field_info{'hr'}    = 1 unless ($fieldnum % 3); 
    332         $field_info{'field'} = $f; 
    333         $field_info{'label'} = $config->{domain}->{$domain}-> 
    334           {node}->{$node}->{client}->{$service}->{$f.".label"} || $f; 
    335  
    336         $field_info{'type'}  = lc( $config->{domain}->{$domain}-> 
    337                                    {node}->{$node}->{client}->{$service}-> 
    338                                    {$f.".type"} || "GAUGE" ); 
    339  
    340         $field_info{'warn'}  = $config->{domain}->{$domain}-> 
    341           {node}->{$node}->{client}->{$service}->{$f.".warning"} || "None"; 
    342         $field_info{'crit'}  = $config->{domain}->{$domain}-> 
    343           {node}->{$node}->{client}->{$service}->{$f.".critical"} || "None"; 
    344         $field_info{'info'}  = $config->{domain}->{$domain}-> 
    345           {node}->{$node}->{client}->{$service}->{$f.".info"} || ""; 
    346  
    347         my $state = &munin_field_status ($config, $limits, $domain, 
    348                                          $node, $service, $f, 1); 
    349  
    350         if (defined $state) { 
    351           $field_info{'state_warning'}  = 1 if $state eq "warning"; 
    352           $field_info{'state_critical'} = 1 if $state eq "critical"; 
    353           $field_info{'state_unknown'}  = 1 if $state eq "unknown"; 
    354         } 
    355         push @{$service{fieldinfo}}, \%field_info; 
    356       } 
    357  
    358       { 
    359         my $state = &munin_service_status ($config, $limits, $domain, 
    360                                            $node, $service, 1); 
    361         if (defined $state) { 
    362           $service{'state_warning'}  = 1 if $state eq "warning"; 
    363           $service{'state_critical'} = 1 if $state eq "critical"; 
    364           $service{'state_unknown'}  = 1 if $state eq "unknown"; 
    365         } 
    366       } 
    367  
    368       push @services, \%service; 
    369       push @service, \%service; 
    370       push @{$tmp_cats{$service{'category'}}}, \%service; 
    371       $servicetemplate->param(SERVICES => \@service, 
    372                               SERVICE => $service, 
    373                               NODE => $node, 
    374                               DOMAIN => $domain,  
    375                               DOMAINS => \@domainlist,  
    376                               TIMESTAMP => $timestamp); 
    377       open (FILE, ">$config->{htmldir}/$domain/$node-$service.html") or 
    378         die "Cannot open $config->{htmldir}/$domain/$node-$service.html: $!"; 
    379       print FILE $servicetemplate->output; 
    380       close FILE; 
    381     } 
    382     foreach my $key (keys %tmp_cats) { 
    383       next if $key eq "other"; 
    384       my %tmp; 
    385       my $state = &munin_category_status ($config, $limits, $domain, 
    386                                           $node, $key, 1); 
    387       print "DEBUG: Pushing category \"$node\" -> \"$key\"...\n" if $DEBUG; 
    388       if (defined $state) { 
    389         $tmp{'state_warning'}  = 1 if $state eq "warning"; 
    390         $tmp{'state_critical'} = 1 if $state eq "critical"; 
    391         $tmp{'state_unknown'}  = 1 if $state eq "unknown"; 
    392       } 
    393       $tmp{name} = ucfirst $key; 
    394       $tmp{services} = \@{$tmp_cats{$key}}; 
    395       $tmp{node} = $node; 
    396       $tmp{domain} = $domain; 
    397       $categories{ucfirst $key} = \%tmp; 
    398       $comparisons{$key}{$node} = \%tmp; 
    399     } 
    400     if (defined $tmp_cats{'other'}) { 
    401       my $key = 'other'; 
    402       my %tmp; 
    403       my $state = &munin_category_status ($config, $limits, $domain, 
    404                                           $node, $key, 1); 
    405       print "DEBUG: Pushing category \"$node\" -> \"$key\"...\n" if $DEBUG; 
    406       if (defined $state) { 
    407         $tmp{'state_warning'}  = 1 if $state eq "warning"; 
    408         $tmp{'state_critical'} = 1 if $state eq "critical"; 
    409         $tmp{'state_unknown'}  = 1 if $state eq "unknown"; 
    410       } 
    411       $tmp{name} = ucfirst $key; 
    412       $tmp{services} = \@{$tmp_cats{$key}}; 
    413       $tmp{node} = $node; 
    414       $tmp{domain} = $domain; 
    415       $categories{ucfirst $key} = \%tmp; 
    416       $comparisons{'other'}{$node} = \%tmp; 
    417     } 
    418     # Handle category_order 
    419     @categories = (); 
    420     if ($config->{domain}->{$domain}->{node}->{$node}->{category_order}) { 
    421       foreach my $cat (split /\s+/, 
    422                        $config->{domain}->{$domain}-> 
    423                        {node}->{$node}->{category_order}) { 
    424         push @categories, $categories{ucfirst $cat}; 
    425       } 
    426       foreach my $cat (sort keys %categories) { 
    427         push @categories, $categories{$cat} 
    428           unless (grep { $_->{name} eq $cat } @categories); 
    429       } 
    430     } else { 
    431       @categories = map { $categories{$_} } sort keys %categories; 
    432     } 
    433     $nodetemplate->param(SERVICES => \@services, 
    434                          NODE => $node, 
    435                          DOMAIN => $domain, 
    436                          DOMAINS => \@domainlist, 
    437                          TIMESTAMP => $timestamp, 
    438                          CATEGORIES => \@categories); 
    439     open (FILE, ">$config->{htmldir}/$domain/$node.html") or 
    440       die "Cannot open $config->{htmldir}/$domain/$node.html: $!"; 
    441     print FILE $nodetemplate->output; 
    442     close FILE; 
    443     $node{services} = \@services; 
    444     $node{categories} = \@categories; 
    445     $node{domain} = $domain; 
    446     push @nodes,\%node; 
    447  
    448   } 
    449   $domaintemplate->param(NODES => \@nodes, 
    450                          DOMAIN => $domain,  
    451                          DOMAINS => \@domainlist,  
    452                          COMPARE => (&munin_get_bool ($config, "compare", 1, 
    453                                                       $domain) 
    454                                      and @nodeorder > 1), 
    455                          TIMESTAMP => $timestamp); 
    456   open (FILE, ">$config->{htmldir}/$domain/index.html") or 
    457     die "Cannot open $config->{htmldir}/$domain/index.html: $!"; 
    458   print FILE $domaintemplate->output; 
    459   close FILE; 
    460  
    461   $domain{nodes} = \@nodes; 
    462   $domain{domain} = $domain; 
    463   $domain{compare} = (&munin_get_bool ($config, "compare", 1, $domain)  
    464                       and @nodeorder > 1); 
    465  
    466   my @cats = (); 
    467   foreach my $key (sort keys %comparisons) { 
    468     my %cat; 
    469     my %servlist; 
    470     my $nodewidth = 0; 
    471  
    472     foreach my $node (sort keys %{$comparisons{$key}}) { 
    473       foreach my $serv (@{$comparisons{$key}{$node}->{services}}) { 
    474         $servlist{$serv->{service}}{$node} = $serv; 
    475         $nodewidth = $serv->{imgdaywidth} 
    476           if (defined $serv->{imgdaywidth} 
    477               and $serv->{imgdaywidth} > $nodewidth); 
    478       } 
    479     } 
    480     foreach my $sname (sort keys %servlist) { 
    481       my %s; 
    482       foreach my $node (@nodeorder) { 
    483         if (defined $servlist{$sname}{$node}) { 
    484           $servlist{$sname}{$node}->{width} = $nodewidth; 
    485           push (@{$s{nodes}}, $servlist{$sname}{$node}); 
    486         } else { 
    487           my %ts; 
    488           $ts{label} = "Not present"; 
    489           $ts{service} = "$sname"; 
    490           $ts{title} = "Not present"; 
    491           $ts{node} = $node; 
    492           $ts{width} = $nodewidth; 
    493           push (@{$s{nodes}}, \%ts); 
    494         } 
    495       } 
    496       push @{$cat{services}}, \%s; 
    497     } 
    498     $cat{name} = ucfirst $key; 
    499     $cat{numnodes} = @nodeorder; 
    500     $cat{numnodes} = @nodeorder; 
    501     push @cats, \%cat; 
    502   } 
    503  
    504   if (&munin_get_bool ($config, "compare", 1, $domain) and @nodeorder > 1) { 
    505     foreach my $t (@times) { 
    506       $comparisontemplates{$t}->param(DOMAIN => $domain, 
    507                                       DOMAINS => \@domainlist, 
    508                                       TIMESTAMP => $timestamp, 
    509                                       CATEGORIES => \@cats); 
    510       open (FILE, ">$config->{htmldir}/$domain/comparison-$t.html") or 
    511         die "Cannot open $config->{htmldir}/$domain/comparison-$t.html: $!"; 
    512       print FILE $comparisontemplates{$t}->output; 
    513       close FILE; 
    514     } 
    515   } 
    516   push @domains,\%domain; 
    517 
    518  
    519 $template->param(DOMAINS => \@domains,  
    520                  TIMESTAMP => $timestamp); 
    521 open (FILE, ">$config->{htmldir}/index.html") or die "Cannot open $config->{htmldir}/index.html: $!"; 
     165 
     166# Preparing the group tree... 
     167my $groups = get_group_tree ($config); 
     168if (defined $groups->{"name"} and $groups->{"name"} eq "root") { 
     169    $groups = $groups->{"groups"}; # root->groups 
     170
     171 
     172# Draw main index 
     173$template->param(GROUPS    => $groups, 
     174                 TIMESTAMP => $timestamp); 
     175my $filename = munin_get_html_filename ($config); 
     176open (FILE, ">$filename") or 
     177    die "Cannot open $filename for writing: $!"; 
    522178print FILE $template->output; 
    523179close FILE; 
     180 
     181generate_group_templates ($groups); 
    524182 
    525183munin_removelock("$config->{rundir}/munin-html.lock"); 
     
    640298} 
    641299 
     300sub get_peer_nodes { 
     301    my $hash      = shift || return undef; 
     302    my $category  = shift; 
     303    my $ret       = []; 
     304    my $link      = "index.html"; 
     305    my $parent    = munin_get_parent ($hash) || return undef; 
     306    my $me        = munin_get_node_name ($hash); 
     307    my $pchildren = munin_get_children ($parent); 
     308 
     309    foreach my $peer (sort {munin_get_node_name($a) <=> munin_get_node_name($b)} @$pchildren) { 
     310        next unless defined $peer and ref ($peer) eq "HASH"; 
     311        next if defined $category and lc (munin_get ($peer, "graph_category", "other")) ne $category; 
     312        logger ("FNORD! ". munin_get_node_name ($peer)." -- ".munin_get_node_name ($parent)); 
     313        my $peername = munin_get_node_name ($peer); 
     314        next if $peername eq "contact" and munin_get_node_name ($parent) eq "root"; 
     315        if ($peername eq $me) { 
     316            unshift @$ret, { "name" => $peername, "link" => undef }; 
     317        } else { 
     318            if (defined $peer->{'graph_title'}) { 
     319                unshift @$ret, { "name" => $peername, "link" => "$peername.html" }; 
     320            } else { 
     321                unshift @$ret, { "name" => $peername, "link" => "../$peername/index.html" }; 
     322            } 
     323        } 
     324    } 
     325    return $ret; 
     326} 
     327 
     328sub get_group_tree { 
     329    my $hash    = shift; 
     330    my $base    = shift || ""; 
     331    my $graphs  = []; 
     332    my $groups  = []; 
     333    my $cattrav = {}; 
     334    my $cats    = []; 
     335    my $path    = []; 
     336    my $rpath   = undef; 
     337    my $ret     = {}; 
     338    my $csspath; 
     339 
     340    foreach my $child (@{munin_get_children ($hash)}) { 
     341        next unless defined $child and ref ($child) eq "HASH" and keys %$child; 
     342        next if munin_get_node_name ($child) eq "contact"; 
     343        if (defined $child->{"graph_title"}) { 
     344            my $childname = munin_get_node_name ($child); 
     345            my $childnode = generate_service_templates ($child); 
     346            push @$graphs, { "name" => $childname }; 
     347            $childnode->{'name'} = $child->{"graph_title"}; 
     348            $childnode->{'url'} = $base . $childname.".html"; 
     349            for (my $shrinkpath = $childnode->{'url'}, my $counter = 0; $shrinkpath; $shrinkpath =~ s/^[^\/]+\/?//, $counter++) { 
     350                $childnode->{'url'.$counter} = $shrinkpath; 
     351            } 
     352            push @{$cattrav->{ lc munin_get ($child, "graph_category", "other") }}, $childnode; 
     353        } elsif (ref ($child) eq "HASH") { 
     354            push @$groups, get_group_tree ($child, $base . munin_get_node_name ($child) . "/"); 
     355        } 
     356    } 
     357 
     358    # We need the categories in another format. 
     359    foreach my $cat (sort keys %$cattrav) { 
     360        my $obj = {}; 
     361        $obj->{'name'} = $cat; 
     362        $obj->{'url'} = $base."index.html#".$cat; 
     363        $obj->{'services'} = $cattrav->{$cat}; 
     364        $obj->{'state_'.lc munin_category_status ($hash, $limits, $cat, 1)} = 1; 
     365        for (my $shrinkpath = $obj->{'url'}, my $counter = 0; $shrinkpath =~ /\//; $shrinkpath =~ s/^[^\/]+\/*//, $counter++) { 
     366            $obj->{'url'.$counter} = $shrinkpath; 
     367        } 
     368        push @$cats, $obj; 
     369    } 
     370 
     371    # ...and we need a couple of paths available. 
     372    @$path = reverse map { { "name" => $_, "path" => (defined $rpath?($rpath.="../")."index.html":($rpath="")) } } reverse ( "Overview", split ('\/', $base) ); 
     373    ($csspath = $path->[0]->{'path'}) =~ s/index.html$/style.css/; 
     374 
     375    $ret = {  
     376        "name"        => munin_get_node_name ($hash),  
     377        "url"         => $base . "index.html",  
     378        "path"        => $path, 
     379        "depth"       => scalar(split("/",$base."index.html"))-1, 
     380        "filename"    => munin_get_html_filename ($hash), 
     381        "csspath"     => $csspath, 
     382        "groups"      => $groups,  
     383        "graphs"      => $graphs, 
     384        "categories"  => $cats, 
     385        "ngroups"     => scalar (@$groups), 
     386        "ngraphs"     => scalar (@$graphs), 
     387        "ncategories" => scalar (@$cats), 
     388        "peers"       => get_peer_nodes ($hash), 
     389    }; 
     390    if ($ret->{'url'} ne "/index.html") { 
     391        for (my $shrinkpath = $ret->{'url'}, my $counter = 0; $shrinkpath =~ /\//; $shrinkpath =~ s/^[^\/]+\/*//, $counter++) { 
     392            $ret->{'url'.$counter} = $shrinkpath; 
     393        } 
     394    } 
     395 
     396    return $ret; 
     397} 
     398 
     399sub generate_group_templates { 
     400    my $arr = shift || return undef; 
     401    return undef unless ref ($arr) eq "ARRAY"; 
     402 
     403    foreach my $key (@$arr) { 
     404        if (defined $key and ref ($key) eq "HASH") { 
     405            if (defined $key->{'ngroups'} and $key->{'ngroups'}) { 
     406                generate_group_templates ($key->{'groups'}); 
     407 
     408                my $grouptemplate = HTML::Template->new( 
     409                    filename => munin_get ($config, "tmpldir", "")."/munin-domainview.tmpl", 
     410                    die_on_bad_params => 0, 
     411                    loop_context_vars => 1, 
     412                    filter => sub { my $ref=shift; $$ref =~ s/URLX/URL$key->{'depth'}/g; } 
     413                ); 
     414 
     415                $grouptemplate->param ( 
     416                    GROUPS  => $key->{'groups'}, 
     417                    PATH    => $key->{'path'}, 
     418                    CSSPATH => $key->{'csspath'}, 
     419                    PEERS   => $key->{'peers'}, 
     420                    PARENT  => $key->{'path'}->[-2]->{'name'} 
     421                ); 
     422                my $filename = $key->{'filename'}; 
     423                open (FILE, ">$filename") or 
     424                    die "Cannot open $filename for writing: $!"; 
     425                print FILE $grouptemplate->output; 
     426                close FILE; 
     427            }  
     428 
     429            if (defined $key->{'ngraphs'} and $key->{'ngraphs'}) { 
     430                my $graphtemplate = HTML::Template->new( 
     431                    filename => munin_get ($config, "tmpldir", "")."/munin-nodeview.tmpl", 
     432                    die_on_bad_params => 0, 
     433                    loop_context_vars => 1, 
     434                    filter => sub { my $ref=shift; $$ref =~ s/URLX/URL$key->{'depth'}/g; } 
     435                ); 
     436 
     437                $graphtemplate->param ( 
     438                    GROUPS      => $key->{'groups'}, 
     439                    PATH        => $key->{'path'}, 
     440                    CSSPATH     => $key->{'csspath'}, 
     441                    PEERS       => $key->{'peers'}, 
     442                    PARENT      => $key->{'path'}->[-2]->{'name'}, 
     443                    NAME        => $key->{'name'}, 
     444                    CATEGORIES  => $key->{'categories'}, 
     445                    NCATEGORIES => $key->{'ncategories'}, 
     446                ); 
     447                my $filename = $key->{'filename'}; 
     448                open (FILE, ">$filename") or 
     449                    die "Cannot open $filename for writing: $!"; 
     450                print FILE $graphtemplate->output; 
     451                close FILE; 
     452            }  
     453        } 
     454    } 
     455} 
     456 
     457sub generate_service_templates {  
     458 
     459    my $service = shift || return undef; 
     460    return undef unless munin_get_bool ($service, "graph", 1); 
     461 
     462    my %srv; 
     463    my $fieldnum = 0; 
     464    my @graph_info; 
     465    my @field_info; 
     466    my @loc       = munin_get_node_loc ($service); 
     467    my $pathnodes = get_path_nodes ($service); 
     468    my $peers     = get_peer_nodes ($service, lc munin_get ($service, "graph_category", "other")); 
     469    (my $csspath  = $pathnodes->[0]->{'link'}) =~ s/index.html$/style.css/; 
     470 
     471    $srv{'node'}     = munin_get_node_name ($service); 
     472    logger("processing service: $srv{node}"); 
     473    $srv{'service'}  = $service; 
     474    $srv{'label'}    = munin_get ($service, "graph_title"); 
     475    $srv{'category'} = lc( munin_get ($service, "graph_category", "other") ); 
     476 
     477    my $method = munin_get ($service, "graph_strategy", "cron"); 
     478 
     479    $srv{'url'}      = "$srv{node}.html"; 
     480 
     481    my $path = join ('/', @loc); 
     482 
     483    if ($method eq "cgi") { 
     484        $srv{'imgday'}  =$config->{'cgiurl_graph'}."/$path-day.png"; 
     485        $srv{'imgweek'} =$config->{'cgiurl_graph'}."/$path-week.png"; 
     486        $srv{'imgmonth'}=$config->{'cgiurl_graph'}."/$path-month.png"; 
     487        $srv{'imgyear'} =$config->{'cgiurl_graph'}."/$path-year.png"; 
     488 
     489        if (munin_get_bool ($service, "graph_sums", 0)) { 
     490            $srv{'imgweeksum'} = $config->{'cgiurl_graph'}."/$path-week-sum.png"; 
     491            $srv{'imgyearsum'} = $config->{'cgiurl_graph'}."/$path-year-sum.png"; 
     492        } 
     493    } else { 
     494        # graph strategy cron 
     495          
     496        $srv{'imgday'}  ="$srv{node}-day.png"; 
     497        $srv{'imgweek'} ="$srv{node}-week.png"; 
     498        $srv{'imgmonth'}="$srv{node}-month.png"; 
     499        $srv{'imgyear'} ="$srv{node}-year.png"; 
     500 
     501        for my $scale (@times) { 
     502            if (my ($w, $h) = get_png_size(munin_get_picture_filename($service, $scale))) { 
     503                $srv{"img".$scale."width"} = $w; 
     504                $srv{"img".$scale."height"} = $h; 
     505            } 
     506        } 
     507 
     508        if (munin_get_bool ($service, "graph_sums", 0)) { 
     509            $srv{imgweeksum} = "$srv{node}-week-sum.png"; 
     510            $srv{imgyearsum} = "$srv{node}-year-sum.png"; 
     511            for my $scale (["week", "year"]) { 
     512                if (my ($w, $h) = get_png_size (munin_get_picture_filename($service, $scale, 1))) { 
     513                    $srv{"img".$scale."sumwidth"} = $w; 
     514                    $srv{"img".$scale."sumheight"} = $h; 
     515                } 
     516            } 
     517        } 
     518    } 
     519 
     520    # Do "help" section 
     521    if (my $info = munin_get ($service, "graph_info")) { 
     522        my %graph_info; 
     523        $graph_info{info} = $info; 
     524        push @{$srv{graphinfo}}, \%graph_info; 
     525    } 
     526 
     527    $srv{fieldlist} .= "<tr><th align='left' valign='top'>Field</th><th align='left' valign='top'>Type</th><th align='left' valign='top'>Warn</th><th align='left' valign='top'>Crit</th><th></tr>"; 
     528    foreach my $f (@{munin_get_field_order ($service)}) { 
     529        $f =~ s/=(.*)$//; 
     530        my $path = $1; 
     531        next if (!defined $service->{$f}); 
     532        my $fieldobj = $service->{$f}; 
     533        next if (ref ($fieldobj) != "HASH" or !defined $fieldobj->{'label'}); 
     534        next if (!munin_draw_field ($fieldobj)); 
     535 
     536        logger ("DEBUG: single_value: Checking field \"$f\" ($path).") 
     537            if $DEBUG; 
     538 
     539        if (defined $path) { 
     540            # This call is to make sure field settings are copied 
     541            # for aliases, .stack, et al. Todo: put that part of 
     542            # munin_get_rrd_filename into its own functino. 
     543            munin_get_rrd_filename ($f, $path); 
     544        } 
     545 
     546        my %field_info; 
     547        $fieldnum++; 
     548 
     549        $field_info{'hr'}    = 1 unless ($fieldnum % 3); 
     550        $field_info{'field'} = $f; 
     551        $field_info{'label'} = munin_get ($fieldobj, "label", $f); 
     552        $field_info{'type'}  = lc( munin_get ($fieldobj, "type", "GAUGE") ); 
     553        $field_info{'warn'}  = munin_get ($fieldobj, "warning"); 
     554        $field_info{'crit'}  = munin_get ($fieldobj, "critical"); 
     555        $field_info{'info'}  = munin_get ($fieldobj, "info"); 
     556 
     557        my $state = munin_field_status ($fieldobj, $limits, 1); 
     558        logger ("state of ".join('::',@{munin_get_node_loc ($fieldobj)}).": $state"); 
     559 
     560        if (defined $state) { 
     561            $field_info{'state_warning'}  = 1 if $state eq "warning"; 
     562            $field_info{'state_critical'} = 1 if $state eq "critical"; 
     563            $field_info{'state_unknown'}  = 1 if $state eq "unknown"; 
     564        } 
     565        push @{$srv{'fieldinfo'}}, \%field_info; 
     566    } 
     567 
     568    my $state = munin_service_status ($service, $limits, 1); 
     569    if (defined $state) { 
     570        $srv{'state_warning'}  = 1 if $state eq "warning"; 
     571        $srv{'state_critical'} = 1 if $state eq "critical"; 
     572        $srv{'state_unknown'}  = 1 if $state eq "unknown"; 
     573    } 
     574 
     575    $servicetemplate->param(SERVICES  => [\%srv], 
     576                            PATH      => $pathnodes, 
     577                            PEERS     => $peers, 
     578                            CSS       => $csspath, 
     579                            CATEGORY  => ucfirst $srv{'category'}, 
     580                            TIMESTAMP => $timestamp); 
     581    my $filename = munin_get_html_filename ($service); 
     582    open (FILE, ">$filename") or 
     583        die "Cannot open $filename for writing: $!"; 
     584    print FILE $servicetemplate->output; 
     585    close FILE; 
     586 
     587    return \%srv; 
     588} 
     589 
     590sub get_path_nodes { 
     591    my $hash = shift || return undef; 
     592    my $ret  = []; 
     593    my $link = "index.html"; 
     594 
     595    unshift @$ret, { "name" => munin_get_node_name ($hash), "link" => undef }; 
     596    while ($hash = munin_get_parent ($hash)) { 
     597        unshift @$ret, { "name" => munin_get_node_name ($hash), "link" => $link }; 
     598        $link = "../" . $link; 
     599    } 
     600    $ret->[0]->{'name'} = undef; 
     601    return $ret; 
     602} 
     603 
    642604$update_time = sprintf("%.2f",(Time::HiRes::time - $update_time)); 
    643605 
  • people/jo/multilevel-groups-3/server/munin-limits.in

    r1442 r1502  
    100100 
    101101if (!defined $config->{'contact'}->{'nagios'}->{'command'} and 
    102         defined $config->{'nsca'}) 
    103 
     102        defined $config->{'nsca'}) { 
    104103    $config->{'contact'}->{'old-nagios'}->{'command'} = "$config->{nsca} $config->{nsca_server} -c $config->{nsca_config} -to 60"; 
    105104    $config->{'contact'}->{'old-nagios'}->{'always_send'} = "critical warning"; 
    106105} 
    107 if (!defined $config->{'contact'}->{'nagios'}->{'always_send'}) 
    108 
     106if (!defined $config->{'contact'}->{'nagios'}->{'always_send'}) { 
    109107    $config->{'contact'}->{'nagios'}->{'always_send'} = "critical warning"; 
    110108} 
    111109 
    112 for my $domain ( keys %{$config->{domain}}) { 
    113     logger ("processing domain: $domain"); 
    114     process_domain($domain); 
    115 
     110my $defaultcontacts = munin_get ($config, "contacts", ""); 
     111if (!length $defaultcontacts) { 
     112    my @tmpcontacts = (); 
     113    foreach my $cont (@{munin_get_children ($config->{"contact"})}) { 
     114        if (munin_get ($cont, "command")) { 
     115            push @tmpcontacts, munin_get_node_name ($cont); 
     116        } 
     117    } 
     118    $defaultcontacts = join (' ', @tmpcontacts); 
     119
     120munin_set_var_loc ($config, ["contacts"], $defaultcontacts); 
     121logger ("Debug: Set default \"contacts\" to \"$defaultcontacts\"") if $DEBUG; 
     122 
     123# Make array of what needs to be checked 
     124my %work_hash_tmp; 
     125my $work_array = []; 
     126foreach my $workfield (@{munin_find_field ($config, qr/^(critical|warning|crit|warn)/)}) { 
     127    my $parent = munin_get_parent ($workfield); 
     128    if (!defined $work_hash_tmp{$parent}) { 
     129        $work_hash_tmp{$parent} = 1; 
     130        push @$work_array, $parent; 
     131    } 
     132
     133 
     134# Process array containing services we need to check 
     135foreach my $workservice (@$work_array) { 
     136    process_service ($workservice); 
     137
     138 
    116139&munin_writeconfig ("$config->{dbdir}/limits", \%notes); 
    117140 
     
    122145logger("munin-limits finished ($update_time sec)"); 
    123146 
    124 sub process_domain { 
    125     my ($domain) = @_; 
    126     for my $node ( keys %{$config->{domain}->{$domain}->{node}}) { 
    127         if (@limit_hosts and !grep (/^$node$/, @limit_hosts)) 
    128         { 
    129                 logger ("skipping node: $node"); 
    130                 next; 
    131         } 
    132         logger ("processing node: $node"); 
    133         process_node($domain,$node ,$config->{domain}->{$domain}->{node}->{$node} ); 
    134     } 
    135 
    136  
    137 sub process_node { 
    138   my ($domain,$name,$node) = @_; 
    139   for my $client (keys %{$node->{client}}) { 
    140       logger ("processing service: $client") if $DEBUG; 
    141       process_service($domain,$name,$client,$node->{client}->{$client}); 
    142   } 
    143 
     147exit 0; 
    144148 
    145149sub process_service { 
    146     my $critical= undef; 
    147     my ($domain, $name,$clientname,$client) = @_; 
    148     return unless $client; 
    149     for my $service (keys %$client) { 
    150         if ($service =~ /(^.*)\.label/) { 
    151             my $key = $1; 
    152             next unless ((exists $client->{"$key.warning"}) || ($client->{"$key.critical"})); 
    153             logger ("processing field: $key") if $DEBUG; 
    154             if (@limit_services and !grep (/^$service$/, @limit_services)) 
    155             { 
    156                 next; 
     150    my $hash       = shift || return undef; 
     151    my $parentobj  = munin_get_parent ($hash); 
     152    my $gparentobj = munin_get_parent (munin_get_parent ($hash)); 
     153    my $service    = munin_get_node_name ($hash); 
     154    my $parent     = munin_get_node_name ($parentobj); 
     155    my $gparent    = munin_get_node_name ($gparentobj); 
     156    my $children   = munin_get_children ($hash); 
     157 
     158    # Some fields that are nice to have in the plugin output 
     159    $hash->{'fields'} = join (' ', map { munin_get_node_name ($_) } @$children); 
     160    $hash->{'plugin'} = $service; 
     161    $hash->{'graph_title'} = $hash->{'notify_alias'} if defined $hash->{'notify_alias'}; 
     162    $hash->{'host'} = munin_get ($parentobj, "notify_alias", $parent); 
     163    $hash->{'group'} = munin_get ($gparentobj, "notify_alias", $gparent); 
     164    $hash->{'worst'} = "ok"; 
     165    $hash->{'worstid'} = 0 unless defined $hash->{'worstid'}; 
     166 
     167    foreach my $field (@$children) { 
     168        next if (!defined $field or ref ($field) ne "HASH"); 
     169        my $fname   = munin_get_node_name ($field); 
     170        my $warn    = munin_get ($field, "warning", undef); 
     171        my $crit    = munin_get ($field, "critical", undef); 
     172        my $fpath   = munin_get_node_loc ($field); 
     173        my $onfield = munin_get_node ($oldnotes, $fpath); 
     174 
     175        # Skip fields without warning/critical definitions 
     176        next if (!defined $warn and !defined $crit); 
     177 
     178        logger ("processing field: ".join ('::', @$fpath)) if $DEBUG; 
     179        next if (@limit_services and !grep (/^$service$/, @limit_services)); 
     180 
     181        ($warn, $crit) = get_limits ($field); 
     182 
     183        my $filename = munin_get_rrd_filename ($field); 
     184        my $value = munin_fetch("$filename"); 
     185        # De-taint. 
     186        if (!defined $value) { 
     187            $value = "unknown"; 
     188        } else { 
     189            $value = sprintf "%.2f",$value; 
     190        } 
     191 
     192        # Some fields that are nice to have in the plugin output 
     193        $field->{'value'} = $value; 
     194        $field->{'crange'} = (defined $crit->[0]?$crit->[0]:"").":".(defined $crit->[1]?$crit->[1]:""); 
     195        $field->{'wrange'} = (defined $warn->[0]?$warn->[0]:"").":".(defined $warn->[1]?$warn->[1]:""); 
     196 
     197        logger ("value: ". join ('::', @{munin_get_node_loc ($hash)}) .": $value (crit: $crit->[0]:$crit->[1]) (warn: $warn->[0]:$warn->[1])") if $DEBUG; 
     198        if ($value eq "unknown") { 
     199            $crit->[0] ||= ""; 
     200            $crit->[1] ||= ""; 
     201            $hash->{'worst'} = "UNKNOWN" if $hash->{"worst"} eq "OK"; 
     202            $hash->{'worstid'} = 3 if $hash->{"worstid"} == 0; 
     203            munin_set_var_loc (\%notes, [@$fpath, "state"], "unknown"); 
     204            munin_set_var_loc (\%notes, [@$fpath, "unknown"], (defined $field->{"extinfo"} ? "unknown: " . $field->{"extinfo"} : "Value is unknown.")); 
     205 
     206            if (!defined $onfield or !defined $onfield->{"state"} or $onfield->{"state"} ne "unknown") { 
     207                $hash->{'state_changed'} = 1; 
    157208            } 
    158             my $critical; 
    159             my $warning; 
    160             ($warning, $critical) = get_limits ($client, $domain, $name, $clientname, $key); 
    161  
    162             my $filename = "$config->{dbdir}/$domain/$name-$clientname-$key-". 
    163             lc substr (($client->{"$key.type"}||"GAUGE"),0,1) . ".rrd"; 
    164             my $value = &munin_fetch("$filename"); 
    165             # De-taint. 
    166             if (!defined $value) { 
    167                 $value = "unknown"; 
    168             } else { 
    169                 $value = sprintf "%.2f",$value; 
     209        } elsif ((defined ($crit->[0]) and $value < $crit->[0]) or 
     210                (defined ($crit->[1]) and $value > $crit->[1])) { 
     211            $crit->[0] ||= ""; 
     212            $crit->[1] ||= ""; 
     213            $hash->{'worst'} = "CRITICAL"; 
     214            $hash->{'worstid'} = 2; 
     215            munin_set_var_loc (\%notes, [@$fpath, "state"], "critical"); 
     216            munin_set_var_loc (\%notes, [@$fpath, "critical"],  
     217                (defined $field->{"extinfo"}?  
     218                "$value (not in $crit->[0]:$crit->[1]): ". 
     219                $field->{"extinfo"}: 
     220                "Value is $value. Critical range ($crit->[0]:$crit->[1]) exceeded")); 
     221 
     222            if (!defined $onfield or !defined $onfield->{"state"} or $onfield->{"state"} ne "critical") { 
     223                $hash->{'state_changed'} = 1; 
    170224            } 
    171  
    172             # Some fields that are nice to have in the plugin output 
    173             $client->{$key.".value"} = $value; 
    174             $client->{'fields'} = join (' ', map { $_ =~ s/\.label$//; $_} grep (/\.label/, keys %$client)); 
    175             $client->{'plugin'} = $clientname; 
    176             $client->{'graph_title'} = $client->{'notify_alias'} if defined $client->{'notify_alias'}; 
    177             $client->{'host'} = $config->{'domain'}->{$domain}->{'node'}->{$name}->{'notify_alias'} || $name; 
    178             $client->{'group'} = $config->{'domain'}->{$domain}->{'notify_alias'} || $domain; 
    179             $client->{'worst'} = "OK"; 
    180             $client->{'worstid'} = 0 unless defined $client->{'worstid'}; 
    181             $client->{$key.".crange"} = (defined $critical->[0]?$critical->[0]:"").":".(defined $critical->[1]?$critical->[1]:""); 
    182             $client->{$key.".wrange"} = (defined $warning->[0]?$warning->[0]:"").":".(defined $warning->[1]?$warning->[1]:""); 
    183  
    184             logger ("value: $domain -> $name -> $clientname -> $key : $value") if $DEBUG; 
    185             if ($value eq "unknown") { 
    186                 $critical->[0] ||= ""; 
    187                 $critical->[1] ||= ""; 
    188                 $client->{'worst'} = "UNKNOWN" if $client->{"worst"} eq "OK"; 
    189                 $client->{'worstid'} = 3 if $client->{"worstid"} == 0; 
    190                 $notes{$domain}{$name}{$clientname}{"$key.state"} = "unknown"; 
    191                 $notes{$domain}{$name}{$clientname}{"$key.unknown"} =  
    192                 (defined $client->{"$key.extinfo"} ? "unknown: " . $client->{"$key.extinfo"} : "Value is unknown."); 
    193                 if (!defined ($oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"}) or  
    194                         $oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"} ne "unknown") 
    195                 { 
    196                     $client->{'state_changed'} = 1; 
    197                 } 
     225        } elsif ((defined ($warn->[0]) and $value < $warn->[0]) or  
     226                (defined ($warn->[1]) and $value > $warn->[1])) { 
     227            $warn->[0] ||= ""; 
     228            $warn->[1] ||= ""; 
     229            $hash->{'worst'} = "WARNING" if $hash->{"worst"} ne "CRITICAL"; 
     230            $hash->{'worstid'} = 1 if $hash->{"worstid"} != 2; 
     231            munin_set_var_loc (\%notes, [@$fpath, "state"], "warning"); 
     232            munin_set_var_loc (\%notes, [@$fpath, "warning"],  
     233                (defined $field->{"extinfo"}? 
     234                "$value (not in $warn->[0]:$warn->[1]): ". 
     235                $field->{"extinfo"}: 
     236                "Value is $value. Warning range ($warn->[0]:$warn->[1]) exceeded")); 
     237 
     238            if (!defined $onfield or !defined $onfield->{"state"} or $onfield->{"state"} ne "warning") { 
     239                $hash->{'state_changed'} = 1; 
    198240            } 
    199             elsif ((defined ($critical->[0]) and $value < $critical->[0]) or 
    200             (defined ($critical->[1]) and $value > $critical->[1])) { 
    201                 $critical->[0] ||= ""; 
    202                 $critical->[1] ||= ""; 
    203                 $client->{'worst'} = "CRITICAL"; 
    204                 $client->{'worstid'} = 2; 
    205                 $notes{$domain}{$name}{$clientname}{"$key.state"} = "critical"; 
    206                 $notes{$domain}{$name}{$clientname}{"$key.critical"} =  
    207                 (defined $client->{"$key.extinfo"}? 
    208                 "$value (not in $critical->[0]:$critical->[1]): ". 
    209                 $client->{"$key.extinfo"}: 
    210                 "Value is $value. Critical range ($critical->[0]:$critical->[1]) exceeded"); 
    211                 if (!defined ($oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"}) or  
    212                         $oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"} ne "critical") 
    213                 { 
    214                     $client->{'state_changed'} = 1; 
    215                 } 
    216             } 
    217             elsif ((defined ($warning->[0]) and $value < $warning->[0]) or  
    218                 (defined ($warning->[1]) and $value > $warning->[1]))  
    219             { 
    220                 $warning->[0] ||= ""; 
    221                 $warning->[1] ||= ""; 
    222                 $client->{'worst'} = "WARNING" if $client->{"worst"} ne "CRITICAL"; 
    223                 $client->{'worstid'} = 1 if $client->{"worstid"} != 2; 
    224                 $notes{$domain}{$name}{$clientname}{"$key.state"} = "warning"; 
    225                 $notes{$domain}{$name}{$clientname}{"$key.warning"} =  
    226                 (defined $client->{"$key.extinfo"}? 
    227                 "$value (not in $warning->[0]:$warning->[1]): ". 
    228                 $client->{"$key.extinfo"}: 
    229                 "Value is $value. Warning range ($warning->[0]:$warning->[1]) exceeded"); 
    230                 if (!defined ($oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"}) or  
    231                         $oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"} ne "warning") 
    232                 { 
    233                     $client->{'state_changed'} = 1; 
    234                 } 
    235             }  
    236             elsif (defined ($oldnotes->{'domain'}->{$domain}->{'node'}->{$name}->{'client'}->{$clientname}->{"$key.state"}) or 
    237                     $force) 
    238             { 
    239                 $notes{$domain}{$name}{$clientname}{"$key.ok"} = "OK"; 
    240                 $client->{'state_changed'} = 1; 
    241             } 
    242         } 
    243     } 
    244     generate_service_message ($domain, $name, $clientname, $client); 
    245 
    246  
    247 sub get_limits 
    248 
    249     my $client = shift; 
    250     my $domain = shift; 
    251     my $name   = shift; 
    252     my $clientname = shift; 
    253     my $key    = shift; 
     241        } elsif (defined $onfield and defined $onfield->{"state"} or $force) { 
     242            munin_set_var_loc (\%notes, [@$fpath, "state"], "ok"); 
     243            munin_set_var_loc (\%notes, [@$fpath, "ok"], "OK"); 
     244            $hash->{'state_changed'} = 1; 
     245        } 
     246    } 
     247    generate_service_message ($hash); 
     248
     249 
     250sub get_limits { 
     251    my $hash = shift || return undef; 
    254252    my @critical = (undef, undef); 
    255253    my @warning  = (undef, undef); 
    256     if (defined $client->{"$key.critical"} and  
    257         $client->{"$key.critical"} =~ /^\s*([-+\d.]*):([-+\d.]*)\s*$/) 
    258     { 
     254    my $crit = munin_get ($hash, "critical", undef); 
     255    my $warn = munin_get ($hash, "warning", undef); 
     256    my $name = munin_get_node_name ($hash); 
     257 
     258    if (defined $crit and $crit =~ /^\s*([-+\d.]*):([-+\d.]*)\s*$/) { 
    259259        $critical[0] = $1 if length $1; 
    260260        $critical[1] = $2 if length $2; 
    261         logger ("processing critical: $domain -> $name -> $clientname -> $key -> $critical[0] : $critical[1]") if $DEBUG; 
    262     } 
    263     elsif (defined $client->{"$key.critical"} and 
    264         $client->{"$key.critical"} =~ /^\s*([-+\d.]+)\s*$/) 
    265     { 
     261        logger ("processing critical: $name -> $critical[0] : $critical[1]") if $DEBUG; 
     262    } elsif (defined $crit and $crit =~ /^\s*([-+\d.]+)\s*$/) { 
    266263        $critical[1] = $1 if defined $1; 
    267         logger ("processing critical: $domain -> $name -> $clientname -> $key -> $critical[0] : $critical[1]") if $DEBUG; 
    268     } 
    269     elsif (defined $client->{"$key.critical"}) 
    270     { 
     264        logger ("processing critical: $name -> $critical[0] : $critical[1]") if $DEBUG; 
     265    } elsif (defined $crit) { 
    271266        @critical = (0, 0); 
    272         logger ("processing critical: $domain -> $name -> $clientname -> $key -> $critical[0] : $critical[1]") if $DEBUG; 
    273     } 
    274     if (defined $client->{"$key.warning"} and  
    275         $client->{"$key.warning"} =~ /^\s*([-+\d.]*):([-+\d.]*)\s*$/) 
    276     { 
     267        logger ("processing critical: $name -> $critical[0] : $critical[1]") if $DEBUG; 
     268    } 
     269 
     270    if (defined $warn and $warn =~ /^\s*([-+\d.]*):([-+\d.]*)\s*$/) { 
    277271        $warning[0] = $1 if length $1; 
    278272        $warning[1] = $2 if length $2; 
    279         logger ("processing warning: $domain -> $name -> $clientname -> $key -> $warning[0] : $warning[1]") if $DEBUG; 
    280     } 
    281     elsif (defined $client->{"$key.warning"} and 
    282         $client->{"$key.warning"} =~ /^\s*([-+\d.]+)\s*$/) 
    283     { 
     273        logger ("processing warning: $name -> $warning[0] : $warning[1]") if $DEBUG; 
     274    } elsif (defined $warn and $warn =~ /^\s*([-+\d.]+)\s*$/) { 
    284275        $warning[1] = $1 if defined $1; 
    285         logger ("processing warning: $domain -> $name -> $clientname -> $key -> $warning[0] : $warning[1]") if $DEBUG; 
    286     } 
    287     elsif (defined $client->{"$key.warning"}) 
    288     { 
     276        logger ("processing warning: $name -> $warning[0] : $warning[1]") if $DEBUG; 
     277    } elsif (defined $warn) { 
    289278        @warning = (0, 0); 
    290         logger ("processing warning: $domain -> $name -> $clientname -> $key -> $warning[0] : $warning[1]") if $DEBUG; 
     279        logger ("processing warning: $name -> $warning[0] : $warning[1]") if $DEBUG; 
    291280    } 
    292281    return (\@warning, \@critical); 
     
    294283 
    295284sub generate_service_message { 
    296     my $critical= undef; 
    297     my ($domain, $name,$clientname,$client) = @_; 
    298     return unless $client; 
    299     my $worst = ""; 
    300     my %stats = ('critical' => [], 'warning' => [], 'unknown' => [], 'foks' => [], 'ok' => []); 
    301  
    302     logger ("generating service message: $domain -> $name -> $clientname") if $DEBUG; 
    303     foreach my $key (keys %{$notes{$domain}{$name}{$clientname}}) 
    304     { 
    305         if ($key =~ /^([^\.]+)\.critical$/) 
    306         { 
    307             $worst = "critical"; 
    308             push @{$stats{'critical'}}, $1; 
    309         } 
    310         elsif ($key =~ /^([^\.]+)\.warning$/) 
    311         { 
    312             $worst = "warning" if $worst ne "critical"; 
    313             push @{$stats{'warning'}}, $1; 
    314         } 
    315         elsif ($key =~ /^([^\.]+)\.unknown$/) 
    316         { 
    317             $worst = "unknown" if (!$worst or $worst eq "ok"); 
    318             push @{$stats{'unknown'}}, $1; 
    319         } 
    320         elsif ($key =~ /^([^\.]+)\.ok$/) 
    321         { 
    322             $worst = "ok" unless $worst; 
    323             push @{$stats{'ok'}}, $1; 
    324             push @{$stats{'foks'}}, $1; 
    325         } 
    326         else 
    327         { 
    328             push @{$stats{'ok'}}, $1; 
    329         } 
    330     } 
    331     $client->{'cfields'}  = join " ", @{$stats{'critical'}}; 
    332     $client->{'wfields'}  = join " ", @{$stats{'warning'}}; 
    333     $client->{'ufields'}  = join " ", @{$stats{'unknown'}}; 
    334     $client->{'fofields'} = join " ", @{$stats{'foks'}}; 
    335     $client->{'ofields'}  = join " ", @{$stats{'ok'}}; 
    336     $client->{'numcfields'}  = scalar @{$stats{'critical'}}; 
    337     $client->{'numwfields'}  = scalar @{$stats{'warning'}}; 
    338     $client->{'numufields'}  = scalar @{$stats{'unknown'}}; 
    339     $client->{'numfofields'} = scalar @{$stats{'foks'}}; 
    340     $client->{'numofields'}  = scalar @{$stats{'ok'}}; 
    341  
    342     if ($worst) 
    343     { 
    344         foreach my $c (split (/\s+/, munin_get ($config, "contacts", join (' ', keys %{$config->{'contact'}}), $domain, $name, $clientname))) 
    345         { 
    346             next if $c eq "none"; 
    347             next unless defined $config->{'contact'}->{$c}->{'command'}; 
    348             if (@limit_contacts and !grep (/^$c$/, @limit_contacts)) 
    349             { 
    350                 next; 
     285    my $hash       = shift || return undef; 
     286    my $critical   = undef; 
     287    my $worst      = $hash->{"worst"}; 
     288    my %stats      = ('critical' => [], 'warning' => [], 'unknown' => [], 'foks' => [], 'ok' => []); 
     289    my $contacts   = munin_get_children (munin_get_node ($config, ["contact"])); 
     290 
     291    logger ("generating service message: ". join ('::', @{munin_get_node_loc ($hash)})) if $DEBUG; 
     292    foreach my $field (@{munin_get_children ($hash)}) { 
     293        if (defined $field->{"state"}) { 
     294            push @{$stats{$field->{"state"}}}, munin_get_node_name ($field); 
     295            if ($field->{"state"} eq "ok") { 
     296                push @{$stats{"foks"}}, munin_get_node_name ($field); 
    351297            } 
    352             my $obsess = 0; 
    353             if (defined ($config->{'contact'}->{$c}->{'always_send'})) 
    354             { 
    355                 $obsess = grep {scalar(@{$stats{$_}})} (split (/\s+/, lc $config->{'contact'}->{$c}->{'always_send'})); 
     298        } 
     299    } 
     300    $hash->{'cfields'}  = join " ", @{$stats{'critical'}}; 
     301    $hash->{'wfields'}  = join " ", @{$stats{'warning'}}; 
     302    $hash->{'ufields'}  = join " ", @{$stats{'unknown'}}; 
     303    $hash->{'fofields'} = join " ", @{$stats{'foks'}}; 
     304    $hash->{'ofields'}  = join " ", @{$stats{'ok'}}; 
     305    $hash->{'numcfields'}  = scalar @{$stats{'critical'}}; 
     306    $hash->{'numwfields'}  = scalar @{$stats{'warning'}}; 
     307    $hash->{'numufields'}  = scalar @{$stats{'unknown'}}; 
     308    $hash->{'numfofields'} = scalar @{$stats{'foks'}}; 
     309    $hash->{'numofields'}  = scalar @{$stats{'ok'}}; 
     310 
     311    my $contactlist =  munin_get ($hash, "contacts", ""); 
     312    logger ("Contact list for ". join ('::', @{munin_get_node_loc ($hash)}) . ": $contactlist"); 
     313    foreach my $c (split (/\s+/, $contactlist)) { 
     314        next if $c eq "none"; 
     315        my $contactobj = munin_get_node ($config, ["contact", $c]); 
     316        next unless defined $contactobj; 
     317        next unless defined munin_get ($contactobj, "command", undef); 
     318        if (@limit_contacts and !grep (/^$c$/, @limit_contacts)) { 
     319            next; 
     320        } 
     321        my $obsess = 0; 
     322        my $cas = munin_get ($contactobj, "always_send"); 
     323        if (defined $cas) { 
     324            $obsess = grep {scalar(@{$stats{$_}})} (split (/\s+/, lc $cas)); 
     325        } 
     326        logger ("checking if state has changed $c"); 
     327        if (!$hash->{'state_changed'} and !$obsess) { 
     328            next; # No need to send notification 
     329        } 
     330        logger ("state has changed, notifying $c"); 
     331        my $precmd = munin_get ($contactobj, "command"); 
     332        my $pretxt = munin_get ($contactobj, "text", munin_get (munin_get_node ($config, ["contact", "default"]), "text", $default_text{$c} || $default_text{"default"})); 
     333        my $txt = message_expand ($hash, $pretxt, ""); 
     334        my $cmd = message_expand ($hash, $precmd, ""); 
     335        $txt =~ s/\\n/\n/g; 
     336        $txt =~ s/\\t/\t/g; 
     337 
     338        # In some cases we want to reopen the command 
     339        my $maxmess = munin_get ($contactobj, "max_messages", 0); 
     340        my $curmess = munin_get ($contactobj, "num_messages", 0); 
     341        my $curcmd  = munin_get ($contactobj, "pipe_command", undef); 
     342        my $pipe    = munin_get ($contactobj, "pipe", undef); 
     343        if ($maxmess and $curmess >= $maxmess ) { 
     344            close ($pipe); 
     345            $pipe = undef; 
     346            munin_set_var_loc ($contactobj, ["pipe"], undef); 
     347            logger ("Debug: Closing \"$c\" -> command (max number of messages reached).") if $DEBUG; 
     348        } elsif ($curcmd and $curcmd ne $cmd) { 
     349            close ($pipe); 
     350            $pipe = undef; 
     351            munin_set_var_loc ($contactobj, ["pipe"], undef); 
     352            logger ("Debug: Closing \"$c\" -> command (command has changed).") if $DEBUG; 
     353        } 
     354     
     355        if (!defined $pipe) { 
     356            my @cmd = extract_multiple ( 
     357                    message_expand ($hash, $cmd), 
     358                    [ sub { extract_delimited ($_[0], q{"'})}, 
     359                      qr/\S+/ 
     360                    ], 
     361                    undef, 1); 
     362            @cmd = map { s/['"]$//; s/^['"]//; $_ } @cmd; 
     363            $contactobj->{"num_messages"} = 0; 
     364            if ($cmd[0] eq "|") { 
     365                $cmd[0] = "|-"; 
     366            } elsif ($cmd[0] !~ /^[|>]/) { 
     367                unshift (@cmd, "|-"); 
    356368            } 
    357             if (!$client->{'state_changed'} and !$obsess) 
    358             { 
    359                 next; 
    360             } 
    361             my $precmd = $config->{'contact'}->{$c}->{'command'}; 
    362             my $pretxt = ($config->{'contact'}->{$c}->{'text'} || $config->{'contact'}->{'default'}->{'text'} || $default_text{$c} || $default_text{'default'}); 
    363             my $txt = message_expand ($pretxt, $client, ""); 
    364             my $cmd = message_expand ($precmd, $client, ""); 
    365             $txt =~ s/\\n/\n/g; 
    366             $txt =~ s/\\t/\t/g; 
    367  
    368             # In some cases we want to reopen the command 
    369             if ($config->{'contact'}->{$c}->{'max_messages'} and defined ($config->{'contact'}->{$c}->{'num_messages'}) and 
    370                     $config->{'contact'}->{$c}->{'num_messages'} >= $config->{'contact'}->{$c}->{'max_messages'}) 
    371             { 
    372                 close ($config->{'contact'}->{$c}->{'pipe'}); 
    373                 $config->{'contact'}->{$c}->{'pipe'} = undef; 
    374             } 
    375             elsif (defined ($config->{'contact'}->{$c}->{'pipe_command'}) and  
    376                     $config->{'contact'}->{$c}->{'pipe_command'} ne $cmd) 
    377             { 
    378                 close ($config->{'contact'}->{$c}->{'pipe'}); 
    379                 $config->{'contact'}->{$c}->{'pipe'} = undef; 
    380             } 
    381          
    382             my $pipe; 
    383             if (!defined $config->{'contact'}->{$c}->{'pipe'}) 
    384             { 
    385                 my @cmd = extract_multiple ( 
    386                         message_expand ($cmd), 
    387                         [ sub { extract_delimited ($_[0], q{"'})}, 
    388                           qr/\S+/ 
    389                         ], 
    390                         undef, 1); 
    391                 @cmd = map { s/['"]$//; s/^['"]//; $_ } @cmd; 
    392                 $config->{'contact'}->{$c}->{'num_messages'} = 0; 
    393                 if ($cmd[0] eq "|") 
    394                 { 
    395                     $cmd[0] = "|-"; 
    396                 }  
    397                 elsif ($cmd[0] !~ /^[|>]/) 
    398                 { 
    399                     unshift (@cmd, "|-"); 
     369            logger ("Debug: opening \"$c\" for writing: \"" . join('" "',@cmd) . "\".") if $DEBUG; 
     370            if ($cmd[0] eq ">") { 
     371                if (! open ($pipe, join (' ', @cmd))) { 
     372                    logger ("Fatal: Could not open " . join (' ', @cmd[1 .. $#cmd]) . " for writing: $!"); 
     373                    exit 3; 
    400374                } 
    401                 logger ("Debug: opening for writing: \"" . join('" "',@cmd) . "\".") if $DEBUG; 
    402                 if ($cmd[0] eq ">") 
    403                 { 
    404                     if (! open ($pipe, join (' ', @cmd))) 
    405                     { 
    406                         logger ("Fatal: Could not open " . join (' ', @cmd[1 .. $#cmd]) . " for writing: $!"); 
     375            } else { 
     376                my $pid = open ($pipe, "|-"); 
     377                if (!defined $pid) { 
     378                    logger ("Fatal: Unable to  fork: $!"); 
     379                    exit 3; 
     380                } if (!$pid) { # Child 
     381                    # Fork of stdout-to-log filter 
     382                    my $logstdout; 
     383                    my $logstderr; 
     384                    my $logpid = open ($logstdout, "|-"); 
     385                    if (!defined $logpid) { 
     386                        logger ("Fatal: Unable to  fork: $!"); 
    407387                        exit 3; 
     388                    }  
     389                    if (!$logpid) { # Child 
     390                        while (<STDIN>) { 
     391                            chomp; 
     392                            logger ("Command \"$c\" stdout: $_"); 
     393                        } 
     394                        exit 0; 
    408395                    } 
    409                 } 
    410                 else 
    411                 { 
    412                     my $pid = open ($pipe, "|-"); 
    413                     if (!defined $pid) 
    414                     { 
     396                    close (STDOUT); 
     397                    *STDOUT = \$logstdout; 
     398                    $logpid = open ($logstderr, "|-"); 
     399                    if (!defined $logpid) { 
    415400                        logger ("Fatal: Unable to  fork: $!"); 
    416401                        exit 3; 
    417402                    } 
    418                     if (!$pid) # Child 
    419                     { 
    420                         # Fork of stdout-to-log filter 
    421                         my $logstdout; 
    422                         my $logstderr; 
    423                         my $logpid = open ($logstdout, "|-"); 
    424                         if (!defined $logpid) 
    425                         { 
    426                             logger ("Fatal: Unable to  fork: $!"); 
    427                             exit 3; 
     403                    if (!$logpid) { # Child 
     404                        while (<STDIN>) { 
     405                            chomp; 
     406                            logger ("Command \"$c\" stderr: $_"); 
    428407                        } 
    429                         if (!$logpid) # Child 
    430                         { 
    431                             while (<STDIN>) 
    432                             { 
    433                                 chomp; 
    434                                 logger ("Command \"$c\" stdout: $_"); 
    435                             } 
    436                             exit 0; 
    437                         } 
    438                         my $logpid = open ($logstderr, "|-"); 
    439                         if (!defined $logpid) 
    440                         { 
    441                             logger ("Fatal: Unable to  fork: $!"); 
    442                             exit 3; 
    443                         } 
    444                         if (!$logpid) # Child 
    445                         { 
    446                             while (<STDIN>) 
    447                             { 
    448                                 chomp; 
    449                                 logger ("Command \"$c\" stderr: $_"); 
    450                             } 
    451                             exit 0; 
    452                         } 
    453                         open (STDOUT, ">&", $logstdout); 
    454                         open (STDERR, ">&", $logstderr); 
    455  
    456                         exec (@cmd[1 .. $#cmd]) or logger ("Warning: Could not run command \"" . join(' ',@cmd[1 .. $#cmd]) . "\": $!"); 
    457                         exit 5; 
    458                         # NOTREACHED 
     408                        exit 0; 
    459409                    } 
    460                 } 
    461                 $config->{'contact'}->{$c}->{'pipe_command'} = $cmd; 
    462                 $config->{'contact'}->{$c}->{'pipe'} = $pipe; 
    463             }  
    464             $pipe = $config->{'contact'}->{$c}->{'pipe'}; 
    465             logger ("sending message: \"$txt\"") if ($DEBUG); 
    466             print $pipe $txt, "\n" if (defined $pipe); 
    467             $config->{'contact'}->{$c}->{'num_messages'}++; 
    468         } 
     410                    open (STDOUT, ">&", $logstdout); 
     411                    open (STDERR, ">&", $logstderr); 
     412 
     413                    exec (@cmd[1 .. $#cmd]) or logger ("Warning: Could not run command \"" . join(' ',@cmd[1 .. $#cmd]) . "\": $!"); 
     414                    exit 5; 
     415                    # NOTREACHED 
     416                } 
     417            } 
     418            logger ("baz?"); 
     419            munin_set_var_loc ($contactobj, ["pipe_command"], $cmd); 
     420            munin_set_var_loc ($contactobj, ["pipe"], $pipe); 
     421        }  
     422        logger ("sending message: \"$txt\"") if ($DEBUG); 
     423        logger ("bar?"); 
     424        print $pipe $txt, "\n" if (defined $pipe); 
     425        $contactobj->{"num_messages"} = 1 + munin_get ($contactobj, "num_messages", 0); # $num_messages++ 
    469426    } 
    470427} 
     
    472429 
    473430sub message_expand { 
     431    my $hash   = shift; 
    474432    my $text   = shift; 
    475     my $client = shift; 
    476     my $prefix = shift || ""; 
    477433    my @res    = (); 
    478434 
    479435     
    480     while (length ($text)) 
    481     {    
    482         if ($text =~ /^([^\$]+|)(?:\$(\{.*)|)$/) 
    483         { 
     436    while (length ($text)) {    
     437        if ($text =~ /^([^\$]+|)(?:\$(\{.*)|)$/) { 
    484438            push @res, $1; 
    485439            $text = $2; 
    486440        }    
    487441        my @a = extract_bracketed ($text, '{}'); 
    488         if ($a[0] =~ /^\{var:(\S+)\}$/) 
    489         { 
    490             $a[0] = (defined $client->{$prefix.$1} ? $client->{$prefix.$1} : ""); 
    491         } 
    492         elsif ($a[0] =~ /^\{loop<([^>]+)>:\s*(\S+)\s(.+)\}$/) 
    493         { 
     442        if ($a[0] =~ /^\{var:(\S+)\}$/) { 
     443            $a[0] = munin_get ($hash, $1, ""); 
     444        } elsif ($a[0] =~ /^\{loop<([^>]+)>:\s*(\S+)\s(.+)\}$/) { 
    494445            my $d = $1; 
    495446            my $f = $2; 
    496447            my $t = $3; 
     448            my $fields = munin_get ($hash, $f, ""); 
    497449            my @res  = (); 
    498             if (defined $client->{$f}) 
    499            
    500                 foreach my $sub (split /\s+/, $client->{$f}) 
    501                 { 
    502                     push @res, message_expand ($t, $client, $sub."."); 
     450            if ($fields) { 
     451               foreach my $sub (split /\s+/, $fields)
     452                    if (defined $hash->{$sub}) { 
     453                       push @res, message_expand ($hash->{$sub}, $t); 
     454                    } 
    503455                } 
    504456            }  
    505457            $a[0] = join ($d, @res); 
    506         } 
    507         elsif ($a[0] =~ /^\{loop:\s*(\S+)\s(.+)\}$/) 
    508         { 
     458        } elsif ($a[0] =~ /^\{loop:\s*(\S+)\s(.+)\}$/) { 
    509459            my $f = $1; 
    510460            my $t = $2; 
     461            my $fields = munin_get ($hash, $f, ""); 
    511462            my $res  = ""; 
    512             if (defined $client->{$f}) 
    513            
    514                 foreach my $sub (split /\s+/, $client->{$f}) 
    515                 { 
    516                     $res .= message_expand ($t, $client, $sub."."); 
     463            if ($fields) { 
     464               foreach my $sub (split /\s+/, $fields)
     465                    if (defined $hash->{$sub}) { 
     466                       push @res, message_expand ($hash->{$sub}, $t); 
     467                    } 
    517468                } 
    518469            }  
    519470            $a[0] = $res; 
    520         } 
    521         elsif ($a[0] =~ /^\{strtrunc:\s*(\S+)\s(.+)\}$/) 
    522         { 
     471        } elsif ($a[0] =~ /^\{strtrunc:\s*(\S+)\s(.+)\}$/) { 
    523472            my $f = "%.".$1."s"; 
    524473            my $t = $2; 
    525             $a[0] = sprintf ($f, message_expand ($t, $client, $prefix)); 
    526         } 
    527         elsif ($a[0] =~ /^\{if:\s*(\!)?(\S+)\s(.+)\}$/) 
    528         { 
     474            $a[0] = sprintf ($f, message_expand ($hash, $t)); 
     475        } elsif ($a[0] =~ /^\{if:\s*(\!)?(\S+)\s(.+)\}$/) { 
    529476            my $n = $1; 
    530477            my $f = $2; 
    531478            my $t = $3; 
    532479            my $res  = ""; 
    533             my $check = (defined $client->{$prefix.$f} and length($client->{$prefix.$f}) and $client->{$prefix.$f} ne "0"); 
    534  
    535             $check = (!defined $client->{$prefix.$f} or !length($client->{$prefix.$f}) or $client->{$prefix.$f} eq "0") 
    536                 if $n; 
    537  
    538             if ($check) 
    539             { 
    540                 $res .= message_expand ($t, $client, $prefix); 
     480            my $field = munin_get ($hash, $f, 0); 
     481            my $check = ($field ne "0" and length ($field)); 
     482            $check = (!length ($field) or $field eq "0") if $n; 
     483 
     484            if ($check) { 
     485                $res .= message_expand ($hash, $t); 
    541486            }  
    542487            $a[0] = $res; 
     
    552497    # Called from the Munin module when we call munin_config 
    553498    my $dirname = shift; 
    554  
    555499 
    556500    if (!$log->opened) { 
  • people/jo/multilevel-groups-3/server/munin-nodeview.tmpl.in

    r860 r1502  
    44<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> 
    55<head> 
    6   <link rel="stylesheet" href="../style.css" type="text/css" />  
     6  <link rel="stylesheet" href="<TMPL_VAR NAME="CSSPATH">" type="text/css" />  
    77  <meta http-equiv="refresh" content="300" /> 
    8   <title>Munin :: <TMPL_VAR ESCAPE="HTML" NAME="DOMAIN"> :: <TMPL_VAR ESCAPE="HTML" NAME="NODE"></title> 
     8  <title>Munin <TMPL_LOOP NAME="PATH">:: <TMPL_VAR ESCAPE="HTML" NAME="NAME"></TMPL_LOOP></title> 
    99  <meta http-equiv="content-type" content="application/xhtml+xml; charset=iso-8859-1" /> 
    1010  <meta name="author" content="Auto-generated by Munin" /> 
     
    1515    <td rowspan="2"><div class="logo">&nbsp;</div></td> 
    1616    <td valign="top"> 
    17       <h2><a href="../index.html">Overview</a> :: <a href="index.html"> 
    18       <TMPL_VAR ESCAPE="HTML" NAME="DOMAIN"></a> :: <TMPL_VAR ESCAPE="HTML" NAME="NODE"></h2> 
     17       <h2><TMPL_LOOP NAME="PATH"><TMPL_IF NAME="PATH"><a href="<TMPL_VAR NAME="PATH">"></TMPL_IF><TMPL_VAR NAME="NAME"><TMPL_IF NAME="PATH"></a> :: </TMPL_IF></TMPL_LOOP></title> 
    1918    </td>     
    2019  </tr> 
    2120  <tr> 
    2221    <td valign="top"> 
    23       <h2><TMPL_VAR NAME="NODE"> :: [ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="#<TMPL_VAR ESCAPE="HTML" NAME="NAME">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</h2> 
     22      <h2><TMPL_VAR NAME="NAME"><TMPL_IF NAME="NCATEGORIES"> :: [ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="#<TMPL_VAR ESCAPE="HTML" NAME="NAME">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF></h2> 
    2423    </td> 
    2524  </tr> 
     
    3938        <TMPL_LOOP NAME="SERVICES"> 
    4039                  <tr><td></td></tr> 
    41                   <tr><td><div class="lighttext">:: <a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="LABEL"></a></div></td></tr> 
     40                  <tr><td><div class="lighttext">:: <a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URLX">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></div></td></tr> 
    4241          <tr> 
    43             <td><a href="<TMPL_VAR NAME="URL">"><img src="<TMPL_VAR NAME="IMGDAY">" alt="<TMPL_VAR ESCAPE="HTML" NAME="LABEL">" <TMPL_IF NAME="IMGDAYWIDTH">width="<TMPL_VAR NAME="IMGDAYWIDTH">" </TMPL_IF> <TMPL_IF NAME="IMGDAYHEIGHT">height="<TMPL_VAR NAME="IMGDAYHEIGHT">"</TMPL_IF>/></a></td> 
    44             <td><a href="<TMPL_VAR NAME="URL">"><img src="<TMPL_VAR NAME="IMGWEEK">" alt="<TMPL_VAR ESCAPE="HTML" NAME="LABEL">" <TMPL_IF NAME="IMGWEEKWIDTH">width="<TMPL_VAR NAME="IMGWEEKWIDTH">" </TMPL_IF> <TMPL_IF NAME="IMGWEEKHEIGHT">height="<TMPL_VAR NAME="IMGWEEKHEIGHT">"</TMPL_IF>/></a></td> 
     42            <td><a href="<TMPL_VAR NAME="URLX">"><img src="<TMPL_VAR NAME="IMGDAY">" alt="<TMPL_VAR ESCAPE="HTML" NAME="NAME">" <TMPL_IF NAME="IMGDAYWIDTH">width="<TMPL_VAR NAME="IMGDAYWIDTH">" </TMPL_IF> <TMPL_IF NAME="IMGDAYHEIGHT">height="<TMPL_VAR NAME="IMGDAYHEIGHT">"</TMPL_IF>/></a></td> 
     43            <td><a href="<TMPL_VAR NAME="URLX">"><img src="<TMPL_VAR NAME="IMGWEEK">" alt="<TMPL_VAR ESCAPE="HTML" NAME="NAME">" <TMPL_IF NAME="IMGWEEKWIDTH">width="<TMPL_VAR NAME="IMGWEEKWIDTH">" </TMPL_IF> <TMPL_IF NAME="IMGWEEKHEIGHT">height="<TMPL_VAR NAME="IMGWEEKHEIGHT">"</TMPL_IF>/></a></td> 
    4544          </tr> 
    4645        </TMPL_LOOP> 
     
    5251  </TMPL_LOOP> 
    5352  <tr><td class="linkbox"> 
    54  <TMPL_LOOP NAME="DOMAINS"> 
    55 <a href="../<TMPL_VAR NAME="DOMAIN">/index.html"><TMPL_VAR ESCAPE="HTML" NAME="DOMAIN"></a> : 
    56     </TMPL_LOOP> 
     53     <TMPL_VAR NAME="PARENT"> :<TMPL_LOOP NAME="PEERS">: <TMPL_IF NAME="LINK"><a href="<TMPL_VAR NAME="LINK">"></TMPL_IF><TMPL_VAR NAME="NAME"><TMPL_IF NAME="LINK"></a></TMPL_IF></a> </TMPL_LOOP> 
    5754 </td></tr> 
    5855</table> 
  • people/jo/multilevel-groups-3/server/munin-overview.tmpl.in

    r860 r1502  
    1818 </table> 
    1919 <div class="box"> 
    20  <TMPL_LOOP NAME="DOMAINS"> 
     20 <TMPL_LOOP NAME="GROUPS"> 
    2121 <ul> 
    22   <li><span class="domain"><a href="<TMPL_VAR NAME="DOMAIN">/index.html"><TMPL_VAR ESCAPE="HTML" NAME="DOMAIN"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="DOMAIN">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="DOMAIN">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="DOMAIN">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="DOMAIN">/comparison-year.html">year</a> ]</TMPL_IF> 
    23       <ul>       
    24         <TMPL_LOOP NAME="NODES"> 
    25         <li><span class="host"><a href="<TMPL_VAR NAME="DOMAIN">/<TMPL_VAR NAME="NODE">.html"><TMPL_VAR ESCAPE="HTML" NAME="NODE"></a></span> ::  
    26         [ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="DOMAIN">/<TMPL_VAR NAME="NODE">.html#<TMPL_VAR NAME="NAME">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</li> 
    27         </TMPL_LOOP> 
    28       </ul> 
     22  <li><TMPL_IF NAME="NCATEGORIES"><span class="host"><TMPL_ELSE><span class="domain"></TMPL_IF><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="NAME">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="NAME">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="NAME">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="NAME">/comparison-year.html">year</a> ]</TMPL_IF>  <TMPL_IF NAME="NCATEGORIES">[ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF> 
     23      <TMLP_IF NAME="NGROUPS"> 
     24        <TMPL_LOOP NAME="GROUPS"> 
     25          <ul> 
     26            <li><TMPL_IF NAME="NCATEGORIES"><span class="host"><TMPL_ELSE><span class="domain"></TMPL_IF><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="NAME">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="NAME">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="NAME">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="NAME">/comparison-year.html">year</a> ]</TMPL_IF> <TMPL_IF NAME="NCATEGORIES">[ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF> 
     27              <TMLP_IF NAME="NGROUPS"> 
     28                <TMPL_LOOP NAME="GROUPS"> 
     29                  <ul> 
     30                    <li><TMPL_IF NAME="NCATEGORIES"><span class="host"><TMPL_ELSE><span class="domain"></TMPL_IF><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="NAME">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="NAME">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="NAME">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="NAME">/comparison-year.html">year</a> ]</TMPL_IF> <TMPL_IF NAME="NCATEGORIES">[ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF> 
     31              <TMLP_IF NAME="NGROUPS"> 
     32                <TMPL_LOOP NAME="GROUPS"> 
     33                  <ul> 
     34                    <li><TMPL_IF NAME="NCATEGORIES"><span class="host"><TMPL_ELSE><span class="domain"></TMPL_IF><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="NAME">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="NAME">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="NAME">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="NAME">/comparison-year.html">year</a> ]</TMPL_IF> <TMPL_IF NAME="NCATEGORIES">[ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF> 
     35              <TMLP_IF NAME="NGROUPS"> 
     36                <TMPL_LOOP NAME="GROUPS"> 
     37                  <ul> 
     38                    <li><TMPL_IF NAME="NCATEGORIES"><span class="host"><TMPL_ELSE><span class="domain"></TMPL_IF><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="NAME">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="NAME">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="NAME">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="NAME">/comparison-year.html">year</a> ]</TMPL_IF> <TMPL_IF NAME="NCATEGORIES">[ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF> 
     39              <TMLP_IF NAME="NGROUPS"> 
     40                <TMPL_LOOP NAME="GROUPS"> 
     41                  <ul> 
     42                    <li><TMPL_IF NAME="NCATEGORIES"><span class="host"><TMPL_ELSE><span class="domain"></TMPL_IF><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a></span><TMPL_IF NAME="COMPARE"> :: [ <a href="<TMPL_VAR NAME="NAME">/comparison-day.html">day</a> <a href="<TMPL_VAR NAME="NAME">/comparison-week.html">week</a> <a href="<TMPL_VAR NAME="NAME">/comparison-month.html">month</a> <a href="<TMPL_VAR NAME="NAME">/comparison-year.html">year</a> ]</TMPL_IF> <TMPL_IF NAME="NCATEGORIES">[ <TMPL_LOOP NAME="CATEGORIES"><a <TMPL_IF NAME="STATE_WARNING">class="warn"</TMPL_IF> <TMPL_IF NAME="STATE_CRITICAL">class="crit"</TMPL_IF> href="<TMPL_VAR NAME="URL">"><TMPL_VAR ESCAPE="HTML" NAME="NAME"></a> </TMPL_LOOP>]</TMPL_IF> 
     43                    </li> 
     44                  </ul> 
     45                </TMPL_LOOP> 
     46              </TMLP_IF> 
     47                    </li> 
     48                  </ul> 
     49                </TMPL_LOOP> 
     50              </TMLP_IF> 
     51                    </li> 
     52                  </ul> 
     53                </TMPL_LOOP> 
     54              </TMLP_IF> 
     55                    </li> 
     56                  </ul> 
     57                </TMPL_LOOP> 
     58              </TMLP_IF> 
     59            </li> 
     60          </ul> 
     61        </TMPL_LOOP> 
     62      </TMLP_IF> 
    2963   </li> 
    3064 </ul> 
  • people/jo/multilevel-groups-3/server/munin-serviceview.tmpl.in

    r860 r1502  
    44<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> 
    55<head> 
    6   <link rel="stylesheet" href="../style.css" type="text/css" />  
     6  <link rel="stylesheet" href="<TMPL_VAR NAME="CSS">" type="text/css" />  
    77  <meta http-equiv="refresh" content="300" /> 
    8   <title>Munin :: <TMPL_VAR NAME="DOMAIN"> :: <TMPL_VAR NAME="NODE"> :: <TMPL_VAR ESCAPE="HTML" NAME="SERVICE"></title> 
     8  <title><TMPL_LOOP NAME="PATH"><TMPL_IF NAME="name"> :: <TMPL_VAR ESCAPE="HTML" NAME="name"></a><TMPL_ELSE>Munin</TMPL_IF></TMPL_LOOP></title> 
    99  <meta http-equiv="content-type" content="application/xhtml+xml; charset=iso-8859-1" /> 
    1010  <meta name="author" content="Auto-generated by Munin" /> 
     
    1515     <td><div class="logo">&nbsp;</div></td> 
    1616     <td valign="top"> 
    17          <h2><a href="../index.html">Overview</a> :: <a href="index.html"> 
    18 <TMPL_VAR NAME="DOMAIN"></a> ::  
    19 <a href="<TMPL_VAR NAME="NODE">.html"><TMPL_VAR NAME="NODE"></a> :: <TMPL_VAR ESCAPE="HTML" NAME="SERVICE"></h2> 
     17         <h2> 
     18         <TMPL_LOOP NAME="PATH"> 
     19           <TMPL_IF NAME="name"> :: 
     20             <TMPL_IF NAME="link"><A HREF="<TMPL_VAR NAME="link">"></TMPL_IF> 
     21               <TMPL_VAR NAME="name"> 
     22             <TMPL_IF NAME="link"></A></TMPL_IF> 
     23           <TMPL_ELSE> 
     24             <TMPL_IF NAME="link"><A HREF="<TMPL_VAR NAME="link">"></TMPL_IF> 
     25               Overview 
     26             <TMPL_IF NAME="link"></A></TMPL_IF> 
     27           </TMPL_IF> 
     28         </TMPL_LOOP></h2> 
    2029     </td>     
    2130    </tr> 
     
    8291  <tr> 
    8392    <td colspan="2" class="linkbox"> 
    84       <TMPL_LOOP NAME="DOMAINS"> 
    85         <a href="../<TMPL_VAR NAME="DOMAIN">/index.html"><TMPL_VAR NAME="DOMAIN"></a> : 
    86       </TMPL_LOOP> 
     93      <TMPL_VAR NAME="CATEGORY"> :<TMPL_LOOP NAME="PEERS">: <TMPL_IF NAME="LINK"><a href="<TMPL_VAR NAME="LINK">"></TMPL_IF><TMPL_VAR NAME="NAME"><TMPL_IF NAME="LINK"></a></TMPL_IF> </TMPL_LOOP> 
    8794    </td> 
    8895  </tr> 
  • people/jo/multilevel-groups-3/server/munin-update.in

    r1453 r1502  
    159159my $bad_procs = 0; 
    160160my $uaddr; 
    161 if ($do_fork) 
    162 
     161 
     162if ($do_fork)
    163163    # Set up socket 
    164164    $uaddr =  sockaddr_un("$config->{rundir}/$serversocket"); 
     
    172172logger("Starting munin-update"); 
    173173 
    174 for my $key (keys %{$config->{domain}}) { 
    175   my $domain_time = Time::HiRes::time; 
    176   logger ("Processing domain: $key"); 
    177   process_domain($key); 
    178   $domain_time = sprintf ("%.2f",(Time::HiRes::time - $domain_time)); 
    179   print STATS "UD|$key|$domain_time\n";  
    180   logger ("Processed domain: $key ($domain_time sec)"); 
    181 
    182  
    183 #sub REAPER { 
    184 #   my $child; 
    185 #   my $waitedpid; 
    186 #   while (($waitedpid = waitpid(-1,WNOHANG)) > 0) { 
    187 #       logger ("reaped $waitedpid" . ($? ? " with exit $?" : '')); 
    188 #   } 
    189 #   $SIG{CHLD} = \&REAPER;  # loathe sysV 
    190 #} 
    191 
    192 #$SIG{CHLD} = \&REAPER; 
    193  
    194 if ($do_fork) 
    195 
    196     my $timeout_start = time(); 
    197     $SIG{ALRM} = sub { die "Timed out waiting for children. $!\n"}; 
    198     alarm ($TIMEOUT); 
    199  
    200     for (;(scalar (keys %children) - $bad_procs > 0);) 
    201     { 
    202             eval { 
    203                 $SIG{ALRM} = sub { 
    204                     foreach my $key (keys %children) 
    205                     { 
    206                         if (waitpid ($key, WNOHANG) != 0) 
    207                         { 
    208                             my $domain  = $children{$key}->[0]; 
    209                             my $name    = $children{$key}->[1]; 
    210                             my $oldnode = $children{$key}->[3]; 
    211  
    212                             logger ("Reaping child: $domain -> $name."); 
    213                             delete $children{$key}; 
    214                             use_old_config ($domain, $name, $oldnode); 
    215                         } 
    216                     } 
    217                     die; 
    218                 }; 
    219  
    220                 alarm (10); 
    221                 accept (Client, Server); 
    222             }; 
    223             alarm ($TIMEOUT - time() + $timeout_start); 
    224             if ($@) 
    225             { 
    226                 if (@queue and defined $config->{max_processes} and 
    227                         $config->{max_processes}) 
    228                 { 
    229                     while (keys %children < ($config->{max_processes}-1-$bad_procs)) 
    230                     { 
    231                         my $args = pop @queue; 
    232                         logger ("de-queueing new connection: $args->[1]"); 
    233                         do_node($args->[0], $args->[1], $args->[2], $args->[3]); 
     174# Make array of what is probably needed to update 
     175my $work_array = []; 
     176if (@limit_hosts) { # Limit what to update if needed 
     177    foreach my $nodename (@limit_hosts) { 
     178        push @$work_array, map { @{munin_find_field ($_->{$nodename}, "address")} } @{munin_find_field($config, $nodename)}; 
     179    } 
     180} else { # ...else just search for all adresses to update 
     181    push @$work_array, @{munin_find_field($config, "address")}; 
     182
     183 
     184# Go through scheduled work to weed out a few bits, and prepare some info 
     185for my $hashnode (@$work_array) { 
     186    my $loc = munin_get_node_loc($hashnode); 
     187    my $name = munin_get_node_name ($hashnode); 
     188 
     189    # Skip anything that has been disabled with the "update" setting 
     190    if (!munin_get_bool ($hashnode, "update", "true")) { 
     191        logger ("Skipping \"$name\" (update disabled by config)"); 
     192        next; 
     193    } 
     194 
     195    # We need to connect to this node; queue it 
     196    logger ("Queuing \"$name\" for update."); 
     197    push (@queue, [$loc, $hashnode, munin_get_node ($oldconfig, $loc)]); 
     198
     199 
     200my $timeout_start = time(); 
     201$SIG{ALRM} = sub { die "Timed out waiting for children. $!\n"}; 
     202alarm ($TIMEOUT); 
     203 
     204if ($do_fork) { 
     205    # Initially set off a bunch of nodes... 
     206    if (defined $config->{max_processes}) { 
     207        while (keys %children < ($config->{max_processes}-1-$bad_procs)) { 
     208            do_node(@{pop @queue}); 
     209        } 
     210    } else { 
     211        do_node(@{pop @queue}) while @queue; # No limit on number of procs 
     212    } 
     213    # Loop as long as there are kids or queue... 
     214    for (;(scalar (keys %children) - $bad_procs > 0) or @queue;) { 
     215        logger ("Debug: Doing a pass to check children status.") if $DEBUG; 
     216 
     217        eval { # eval to call accept() with a timeout 
     218            $SIG{ALRM} = sub { # If we timeout we need to use the old config 
     219                foreach my $key (keys %children) { 
     220                    if (waitpid ($key, WNOHANG) != 0) { 
     221                        my $loc     = $children{$key}->[0]; 
     222                        my $newnode = $children{$key}->[1]; 
     223                        my $oldnode = $children{$key}->[2]; 
     224                        my $name    = munin_get_node_name ($newnode); 
     225 
     226                        logger ("Reaping child: $name."); 
     227                        delete $children{$key}; 
     228                        munin_copy_node_toloc ($oldnode, $config, $loc); 
    234229                    } 
    235230                } 
    236                 next; 
     231                die; 
     232            }; # end sub 
     233 
     234            alarm (10); 
     235            accept (Client, Server); 
     236        }; # end eval 
     237 
     238        if ($@) { 
     239            if (@queue and defined $config->{max_processes} and $config->{max_processes}) { 
     240                logger ("Debug: Checking whether to spawn off more procs from queue."); 
     241                while (keys %children < ($config->{max_processes}-1-$bad_procs)) { 
     242                    logger ("Debug: Popping queue item and spawning new proc."); 
     243                    do_node(@{pop @queue}); 
     244                } 
    237245            } 
    238             close STDIN; 
    239             open (STDIN,  "<&Client")  || die "can't dup client to stdin"; 
    240              
    241             my $pid; 
    242             my $name; 
    243             my $domain; 
    244             my $tmpref; 
    245                 eval { 
    246                         $tmpref = fd_retrieve (\*STDIN); 
    247                 }; 
    248                 if ($@) 
    249                 { 
    250                         $bad_procs++; 
    251                         logger ("[WARNING] Error communicating with process: $@"); 
    252                 } 
    253                 else 
    254                 { 
    255                         ($pid, $domain, $name) = ($tmpref->[0], $tmpref->[1], $tmpref->[2]); 
    256                         logger ("connection from $domain -> $name ($pid)"); 
    257  
    258                         eval { 
    259                                 $config->{domain}->{$domain}->{node}->{$name} = fd_retrieve (\*STDIN); 
    260                         }; 
    261                         if ($@) 
    262                         { 
    263                                 logger ("[WARNING] Error during fd_retrieve of config: $@"); 
    264  
    265                                 my $domain  = $children{$pid}->[0]; 
    266                                 my $name    = $children{$pid}->[1]; 
    267                                 my $oldnode = $children{$pid}->[3]; 
    268  
    269                                 use_old_config ($domain, $name, $oldnode); 
    270                         } 
    271                         delete $children{$pid}; 
    272                         waitpid ($pid, 0); 
    273                         logger ("connection from $domain -> $name ($pid) closed"); 
    274                 } 
    275             if (@queue and defined $config->{max_processes} and 
    276                     $config->{max_processes} and 
    277                     scalar (keys %children) < (($config->{max_processes})-1-$bad_procs)) 
    278             { 
    279                 my $args = pop @queue; 
    280                 logger ("de-queueing new connection: $args->[1]"); 
    281                 do_node($args->[0], $args->[1], $args->[2], $args->[3]); 
    282                 close (Client); 
     246            next; 
     247        } 
     248 
     249        alarm ($TIMEOUT - time() + $timeout_start); 
     250        close STDIN; 
     251        open (STDIN,  "<&Client")  || die "can't dup client to stdin"; 
     252 
     253        my $pid; 
     254        my $name; 
     255        my $loc; 
     256        my $tmpref; 
     257        eval { 
     258            $tmpref = fd_retrieve (\*STDIN); 
     259        }; 
     260        if ($@) { 
     261            $bad_procs++; 
     262            logger ("[WARNING] Error communicating with process: $@"); 
     263        } else { 
     264            ($pid, $loc, $name) = ($tmpref->[0], $tmpref->[1], $tmpref->[2]); 
     265            logger ("connection from $name ($pid)"); 
     266 
     267            eval { 
     268                my $newnode = fd_retrieve (\*STDIN); 
     269                munin_copy_node_toloc ($newnode, $config, $loc); 
     270            }; 
     271            if ($@) { 
     272                logger ("[WARNING] Error during fd_retrieve of config: $@"); 
     273 
     274                my $loc     = $children{$pid}->[0]; 
     275                my $newnode = $children{$pid}->[1]; 
     276                my $oldnode = $children{$pid}->[2]; 
     277 
     278                munin_copy_node_toloc ($oldnode, $config, $loc); 
    283279            } 
     280            delete $children{$pid}; 
     281            waitpid ($pid, 0); 
     282            logger ("connection from $name ($pid) closed"); 
     283        } 
     284        if (@queue and defined $config->{max_processes} and 
     285            $config->{max_processes} and 
     286            scalar (keys %children) < (($config->{max_processes})-1-$bad_procs)) { 
     287            do_node(@{pop @queue}); 
     288            close (Client); 
     289        } 
    284290    } 
    285291    alarm (0); 
    286 
     292} else { # No forking, just poll the nodes sequentially... 
     293    for (;@queue;) { 
     294        do_node(@{pop @queue}); 
     295    } 
     296
     297 
     298alarm (0); 
    287299 
    288300if ($bad_procs) # Use old configuration for killed children 
     
    290302        foreach my $key (keys %children) 
    291303        { 
    292                 my $domain  = $children{$key}->[0]; 
    293                 my $name    = $children{$key}->[1]; 
    294                 my $node    = $children{$key}->[2]; 
    295                 my $oldnode = $children{$key}->[3]
    296  
    297                 use_old_config ($domain, $name, $oldnode); 
    298                 logger ("Attempting to use old configuration for $domain -> $name."); 
     304                my $loc     = $children{$key}->[0]; 
     305                my $newnode = $children{$key}->[1]; 
     306                my $oldnode = $children{$key}->[2]; 
     307                my $name    = munin_get_node_name ($newnode)
     308 
     309                munin_copy_node_toloc ($oldnode, $config, $loc); 
     310                logger ("Attempting to use old configuration for $name."); 
    299311        } 
    300312} 
    301313 
    302314unlink ("$config->{rundir}/$serversocket"); 
     315 
    303316 
    304317my $overwrite = &munin_readconfig($conffile); 
    305318$config = &munin_overwrite($config,$overwrite); 
    306319 
    307 &compare_configs ($oldconfig, $config); 
     320compare_configs ($oldconfig, $config); 
    308321 
    309322if (&munin_getlock("$config->{rundir}/munin-datafile.lock")) { 
     
    332345    my $just_upgraded = 0; 
    333346 
    334     if (!defined $old->{version} or 
    335             $old->{version} ne $VERSION) 
    336     { 
     347    if (!defined $old->{version} or $old->{version} ne $VERSION) { 
    337348        $just_upgraded = 1; 
    338349    } 
    339350 
    340     foreach my $dom (%{$new->{domain}}) 
    341     { 
    342         foreach my $host (%{$new->{domain}->{$dom}->{node}}) 
    343         { 
    344             foreach my $serv (%{$new->{domain}->{$dom}->{node}->{$host}->{client}}) 
    345             { 
    346                 foreach my $field (%{$new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}}) 
    347                 { 
    348                     next unless $field =~ /\.label$/; 
    349                     $field =~ s/\.label$//; 
    350                     if ($just_upgraded or &is_changed ($old, $new, $dom, $host, $serv, $field, "max")) 
    351                     { 
    352                         &change_max ($config, $dom, $host, $serv, $field,  
    353                                 (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".max"} ? 
    354                                  $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".max"} : undef)); 
    355                     } 
    356                     if ($just_upgraded or &is_changed ($old, $new, $dom, $host, $serv, $field, "min")) 
    357                     { 
    358                         &change_min ($config, $dom, $host, $serv, $field,  
    359                                 (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".min"} ? 
    360                                 $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".min"} : undef)); 
    361                     } 
    362                     if ($just_upgraded or &is_changed ($old, $new, $dom, $host, $serv, $field, "type")) 
    363                     { 
    364                         &change_type ($oldconfig, $config, $dom, $host, $serv, $field,  
    365                                 (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".type"} ? 
    366                                 $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".type"} : undef)); 
    367                     } 
    368                 } 
    369             } 
    370         } 
    371     } 
    372  
    373 
    374  
    375 sub is_changed 
    376 
    377     my $old     = shift; 
    378     my $new     = shift; 
    379     my $dom     = shift; 
    380     my $host    = shift; 
    381     my $serv    = shift; 
    382     my $field   = shift; 
    383     my $setting = shift; 
    384  
    385     if (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) 
    386     { 
    387         if ((!defined $old->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) or 
    388                 ($old->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting} ne 
    389                  $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting} 
    390            )) 
    391         { 
    392             return 1; 
    393         } 
    394     } 
    395  
    396     if (defined $old->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) 
    397     { 
    398         if (!defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) 
    399         { 
    400             return 1; 
    401         } 
    402     } 
    403  
    404     return 0; 
     351    foreach my $node (@{munin_find_field($new, "label")}) { 
     352        my $oldnode = munin_get_node ($old, munin_get_node_loc ($node)); 
     353        my $name    = munin_get_node_name ($node); 
     354        my ($oldval, $newval); 
     355 
     356        $oldval = munin_get ($oldnode, "max", ""); 
     357        $newval = munin_get ($node, "max", ""); 
     358        if ($just_upgraded or $oldval ne $newval) { 
     359            logger ("Notice: compare_configs: $name.max changed from ".(length $oldval?$oldval:"undefined")." to $newval."); 
     360            change_max (munin_get_filename ($node), $newval); 
     361        } 
     362 
     363        $oldval = munin_get ($oldnode, "min", ""); 
     364        $newval = munin_get ($node, "min", ""); 
     365        if ($just_upgraded or $oldval ne $newval) { 
     366            logger ("Notice: compare_configs: $name.min changed from ".(length $oldval?$oldval:"undefined")." to $newval."); 
     367            change_min (munin_get_filename ($node), $newval); 
     368        } 
     369 
     370        $oldval = munin_get ($oldnode, "type", "GAUGE"); 
     371        $newval = munin_get ($node, "type", "GAUGE"); 
     372        if ($just_upgraded or $oldval ne $newval) { 
     373            logger ("Notice: compare_configs: $name.type changed from ".(length $oldval?$oldval:"undefined")." to $newval."); 
     374            change_type (munin_get_filename ($oldnode), munin_get_filename ($node), $newval); 
     375        } 
     376    } 
    405377} 
    406378 
    407379sub change_type 
    408380{ 
    409     my $oconf  = shift; 
    410     my $nconf  = shift; 
    411     my $domain = shift; 
    412     my $host   = shift; 
    413     my $serv   = shift; 
    414     my $field  = shift; 
     381    my $ofile  = shift; 
     382    my $nfile  = shift; 
    415383    my $val    = shift; 
    416     my $ofile  = &munin_get_filename ($oconf, $domain, $host, $serv, $field); 
    417     my $nfile  = &munin_get_filename ($nconf, $domain, $host, $serv, $field); 
    418  
    419     logger ("[WARNING] Changing type of $domain -> $host -> $serv -> $field to " . (defined $val?$val:"GAUGE") . ".\n"); 
    420     RRDs::tune ($ofile, "-d", "42:".(defined $val?$val:"GAUGE")); 
    421     unless (rename ($ofile, $nfile)) 
    422     { 
    423         logger ("[ERROR] Could not rename file: $!\n"); 
    424     } 
     384 
     385    if (defined $ofile and -f $ofile) { 
     386        logger ("[WARNING]: Changing name of $ofile to $nfile"); 
     387        unless (rename ($ofile, $nfile)) { 
     388            logger ("[ERROR]: Could not rename file: $!\n"); 
     389        } 
     390    } 
     391 
     392    logger ("INFO: Changing type of $nfile to " . (defined $val?$val:"GAUGE")); 
     393    RRDs::tune ($nfile, "-d", "42:".(defined $val?$val:"GAUGE")); 
    425394} 
    426395 
    427396sub change_max 
    428397{ 
    429     my $config = shift; 
    430     my $domain = shift; 
    431     my $host   = shift; 
    432     my $serv   = shift; 
    433     my $field  = shift; 
    434     my $val    = shift; 
    435     my $file   = &munin_get_filename ($config, $domain, $host, $serv, $field); 
    436  
    437     logger ("[WARNING] Changing max of $domain -> $host -> $serv -> $field to " . (defined $val?$val:"undef") . ".\n"); 
     398    my $file  = shift; 
     399    my $val   = shift; 
     400 
     401    logger ("[WARNING]: Changing max of \"$file\" to \"$val\".\n"); 
    438402    RRDs::tune ($file, "-a", "42:".(defined $val?$val:"U")); 
    439403} 
     
    441405sub change_min 
    442406{ 
    443     my $config = shift; 
    444     my $domain = shift; 
    445     my $host   = shift; 
    446     my $serv   = shift; 
    447     my $field  = shift; 
    448     my $val    = shift; 
    449     my $file   = &munin_get_filename ($config, $domain, $host, $serv, $field); 
    450  
    451     logger ("[WARNING] Changing min of $domain -> $host -> $serv -> $field to " . (defined $val?$val:"undef") . ".\n"); 
     407    my $file  = shift; 
     408    my $val   = shift; 
     409 
     410    logger ("[WARNING]: Changing min of \"$file\" to \"$val\".\n"); 
    452411    RRDs::tune ($file, "-i", "42:".(defined $val?$val:"U")); 
    453412} 
    454413 
    455 sub process_domain { 
    456   my ($domain) = @_; 
    457   for my $key ( keys %{$config->{domain}->{$domain}->{node}}) { 
    458     if (@limit_hosts and !grep (/^$key$/, @limit_hosts)) 
    459     { 
    460         logger ("Skipping host \"$key\" - not in hostlist\n") if $DEBUG; 
    461         next; 
    462     } 
    463     if (defined $config->{max_processes} and $config->{max_processes} and  
    464             ($config->{max_processes}-1-$bad_procs) < keys %children) 
    465     { 
    466         push (@queue, [$domain, $key, $config->{domain}->{$domain}->{node}->{$key},$oldconfig->{domain}->{$domain}->{node}->{$key}]); 
    467     } 
    468     else 
    469     { 
    470         do_node($domain,$key ,$config->{domain}->{$domain}->{node}->{$key},$oldconfig->{domain}->{$domain}->{node}->{$key}); 
    471     } 
     414sub do_node { 
     415  my ($loc, $newconf, $oldconf) = @_; 
     416  return undef unless munin_get ($newconf, "update", "true"); # Skip unless we're updating it 
     417  return undef unless munin_get ($newconf, "fetch_data", "true"); # Old name for "update" 
     418 
     419  my $name = munin_get ($newconf, "host_name") || munin_get_node_name ($newconf); 
     420 
     421  unless ($newconf->{"address"}) { 
     422      logger("[ERROR] No address defined for node: $name"); 
     423      return undef; 
    472424  } 
    473 
    474  
    475 sub do_node { 
    476   my ($domain, $name, $config, $oldconfig) = @_; 
    477   my $node_time = Time::HiRes::time; 
    478   logger("Processing node: $name"); 
    479   process_node($domain,$name ,$config,$oldconfig); 
    480   $node_time = sprintf ("%.2f",(Time::HiRes::time - $node_time)); 
    481   print STATS "UN|$domain|$name|$node_time\n";  
    482   logger ("Processed node: $name ($node_time sec)"); 
    483 
    484  
    485 sub process_node { 
    486   my ($domain,$name,$node,$oldnode) = @_; 
    487   return if (exists ($node->{fetch_data}) and !$node->{fetch_data}); 
    488   return if (exists ($node->{update}) and $node->{update} ne "yes"); 
    489   unless ($node->{address}) { 
    490       logger("[ERROR] No address defined for node: $name"); 
    491       return; 
    492   } 
     425  logger ("Debug: do_node: Starting on \"$name\".") if $DEBUG; 
    493426 
    494427  # Then we fork... 
     
    498431      if (!defined($pid))  
    499432      { # Something went wrong 
    500               warn "cannot fork: $!";  
     433              logger ("Error: Unable to fork: $!");  
    501434              return;  
    502435      } elsif ($pid)  
    503436      { # I'm the parent 
    504               $children{$pid} = [$domain, $name, $node, $oldnode]; 
     437              $children{$pid} = [$loc, $newconf, $oldconf]; 
    505438              return;  
    506439      } # else I'm the child -- go spawn 
     
    510443 
    511444  # First we get lock... 
    512   unless (&munin_getlock("$config->{rundir}/munin-$domain-$name.lock")) 
    513   { 
    514     logger ("[ERROR] Could not get lock for $node -> $name. Skipping node."); 
    515     if ($do_fork) 
    516     { # Send the old config to the server before we die 
     445  unless (&munin_getlock(munin_get($newconf, "rundir").$newconf->{"address"}.".lock")) { 
     446    logger ("[ERROR] Could not get lock for \"$name\". Skipping node."); 
     447    if ($do_fork) { # Send the old config to the server before we die 
    517448        socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    518         connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
    519         if (ref $oldnode) { 
    520           $config->{domain}->{$domain}->{node}->{$name} = $oldnode
    521           alarm (0); # Don't want to interrupt this. 
    522           my @tmp = ($$, $domain, $name); 
     449        connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
     450        alarm (0); # Don't want to interrupt this. 
     451        my @tmp = ($$, munin_get_node_loc($newconf), $name)
     452        if (ref $oldconf) { 
     453          copy_node ($oldconf, $newconf); 
    523454          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    524           nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
     455          nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    525456          close SOCK; 
     457        } else { # Well, we'll have to give _something_ to the server, or it'll time out. 
     458          socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
     459          connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
     460          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
     461          nstore_fd ({}, \*SOCK); 
    526462        } 
    527463        exit 1; 
    528     } 
    529     else 
    530     { 
     464    } else { 
    531465        return 0; 
    532466    } 
     
    535469  my $socket; 
    536470   
    537   if (&munin_get ($config, "local_address", undef, $domain, $node)) 
     471  if (munin_get ($newconf, "local_address")) 
    538472  { 
    539       $socket = new IO::Socket::INET ('PeerAddr' => "$node->{address}:". 
    540                   ($node->{port} || $config->{domain}->{$domain}->{port} ||  
    541                    $config->{port} || "4949"),  
    542                    'LocalAddr' => &munin_get ($config, "local_address", undef, $domain, $node), 
    543                   'Proto'    => "tcp", "Timeout" => $timeout); 
     473      $socket = new IO::Socket::INET ('PeerAddr' => "$newconf->{address}:". 
     474                  munin_get ($newconf, "port", "4949"),  
     475                  'LocalAddr' => munin_get ($newconf, "local_address", undef), 
     476                  'Proto'    => "tcp", "Timeout" => munin_get($newconf, "timeout", 60)); 
    544477  } else { 
    545       $socket = new IO::Socket::INET ('PeerAddr' => "$node->{address}:". 
    546                   ($node->{port} || $config->{domain}->{$domain}->{port} ||  
    547                    $config->{port} || "4949"),  
    548                   'Proto'    => "tcp", "Timeout" => $timeout); 
     478      $socket = new IO::Socket::INET ('PeerAddr' => "$newconf->{address}:". 
     479                  munin_get ($newconf, "port", "4949"),  
     480                  'Proto'    => "tcp", "Timeout" => munin_get($newconf, "timeout", 60)); 
    549481  } 
    550482  my $err = ($socket ? "" : $!); 
     
    554486      alarm ($timeout); 
    555487 
    556       my @tmp = ($$, $domain, $name); 
     488      my @tmp = ($$, munin_get_node_loc ($newconf), $name); 
    557489 
    558490      if (!$socket) { 
    559         logger ("[ERROR] Could not connect to $name($node->{address}): $err - Attempting to use old configuration"); 
     491        logger ("[ERROR] Could not connect to $name($newconf->{address}): $err - Attempting to use old configuration"); 
    560492        # If we can't reach the client. Using old Configuration. 
    561         if (ref $oldnode) { 
    562           $config->{domain}->{$domain}->{node}->{$name} = $oldnode
     493        if (ref $oldconf) { 
     494          copy_node ($oldconf, $newconf)
    563495          alarm (0); # Don't want to interrupt this. 
    564496          socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    565           connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     497          connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    566498          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    567           nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
    568           alarm ($timeout); 
     499          nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    569500          close SOCK; 
    570         } 
    571         else 
    572         { # Well, we'll have to give _something_ to the server, or it'll time out. 
     501        } else { # Well, we'll have to give _something_ to the server, or it'll time out. 
    573502          socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    574           connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     503          connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    575504          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    576505          nstore_fd ({}, \*SOCK); 
     
    578507      } else { 
    579508                my $ctx; 
    580                 if (!&config_node($domain,$name,$node,$oldnode,$socket)) 
    581                 { 
    582                     $config->{domain}->{$domain}->{node}->{$name} = $oldnode; 
     509                if (!config_node($newconf,$oldconf,$socket)) { 
     510                    copy_node ($oldconf, $newconf); 
    583511                    socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    584                     connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     512                    connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    585513                    nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    586                     nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
     514                    nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    587515                    close SOCK; 
    588516                    exit 1; 
    589517                } 
    590                 &fetch_node($domain,$name,$node,$socket); 
     518                &fetch_node($newconf,$oldconf,$socket); 
    591519#               Net::SSLeay::free ($tls) if ($tls); # Shut down TLS 
    592520                close $socket; 
    593521                alarm (0); # Don't want to interrupt this. 
    594522                socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    595         connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || 
    596           die "connect: $!"; 
     523                connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
    597524                nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    598                nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
     525                nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    599526                alarm ($timeout); 
    600527                close SOCK; 
     
    607534  { 
    608535      if (!$socket) { 
    609         logger ("[ERROR] Could not connect to $name($node->{address}): $err\nAttempting to use old configuration"); 
     536        logger ("[ERROR] Could not connect to $name($newconf->{address}): $err\nAttempting to use old configuration"); 
    610537        # If we can't reach the client. Using old Configuration. 
    611         if (ref $oldnode) { 
    612           $config->{domain}->{$domain}->{node}->{$name} = $oldnode
     538        if (ref $oldconf) { 
     539            copy_node ($oldconf, $newconf)
    613540        } 
    614541      } else { 
    615                 next unless (&config_node($domain,$name,$node,$oldnode,$socket)); 
    616                 &fetch_node($domain,$name,$node,$socket); 
     542                next unless (config_node($newconf,$oldconf,$socket)); 
     543                fetch_node($newconf,$oldconf,$socket); 
    617544#               Net::SSLeay::free ($tls) if ($tls); # Shut down TLS 
    618545                close $socket; 
     
    950877} 
    951878 
    952 sub config_node { 
    953   my ($domain,$name,$node,$oldnode,$socket) = @_; 
    954   my $clientdomain = read_socket_single ($socket); 
    955   my $fetchdomain; 
    956   chomp($clientdomain) if $clientdomain; 
    957   if (!$clientdomain) { 
    958       logger("[WARNING] Got unknown reply from client \"$domain\" -> \"name\" skipping"); 
    959       return 0; 
    960   } 
    961   $clientdomain =~ s/\#.*(?:lrrd|munin) (?:client|node) at //; 
    962   if (exists $node->{'use_node_name'} and $node->{'use_node_name'} =~ /^\s*y(?:es)\s*$/i) 
    963   { 
    964       $fetchdomain = $clientdomain; 
    965   } 
    966   elsif (exists $node->{'use_default_name'} and $node->{'use_default_name'} =~ /^\s*y(?:es)\s*$/i) 
    967   { 
    968       $fetchdomain = $clientdomain; 
    969   } 
    970   else 
    971   { 
    972       $fetchdomain = $name; 
    973   } 
    974   my $nodeconf_time = Time::HiRes::time; 
    975  
    976   # TLS should only be attempted if explicitly enabled. The default value 
    977   # is therefore "disabled" (and not "auto" as before). 
    978   my $tls_requirement = &munin_get ($config,"tls","disabled",$domain, $name); 
    979   logger ("[DEBUG]: TLS set to \"$tls_requirement\".") if $DEBUG; 
    980   if ($tls_requirement ne "disabled") 
    981   { 
    982       my $key; 
    983       my $cert; 
    984       my $depth; 
    985       my $ca_cert; 
    986       my $tls_verify; 
    987       $key = $cert = munin_get ($config, "tls_pem", undef, $domain, $name); 
    988       $key = &munin_get ($config, "tls_private_key", "@@CONFDIR@@/munin.pem", $domain, $name) 
    989           unless defined $key; 
    990       $cert = &munin_get ($config, "tls_certificate", "@@CONFDIR@@/munin.pem", $domain, $name) 
    991           unless defined $cert; 
    992       $ca_cert = &munin_get ($config, "tls_ca_certificate", "@@CONFDIR@@/cacert.pem", $domain, $name) 
    993           unless defined $ca_cert; 
    994       $tls_verify=&munin_get ($config, "tls_verify_certificate", "no", $domain, $name); 
    995       $depth=&munin_get ($config, "tls_verify_depth", 5, $domain, $name); 
    996  
    997       if (!start_tls ($socket, $tls_requirement, $cert, $key, $ca_cert, $tls_verify, $depth)) 
    998       { 
    999           if ($tls_requirement eq "paranoid" or $tls_requirement eq "enabled") 
    1000           { 
    1001               logger ("[ERROR] Could not establish TLS connection to \"$domain :: $name\". Skipping."); 
    1002               exit 13; 
    1003           } 
    1004       } 
    1005   } 
    1006  
    1007   logger("[DEBUG] Configuring node: $name") if $DEBUG; 
    1008   my @services; 
    1009   eval { 
    1010     local $SIG{ALRM} = sub { die "Could not run list on $name ($fetchdomain): $!\n"}; 
    1011     alarm 5; # Should be enough to check the list 
    1012     write_socket_single ($socket, "list $fetchdomain\n"); 
    1013     my $list = read_socket_single ($socket); 
    1014     exit 1 unless defined $list; 
    1015     chomp $list; 
    1016     @services = split / /,$list; 
    1017     alarm 0; 
    1018   }; 
    1019   if ($@) { 
    1020     die unless ($@ =~ m/Could not run list/); 
    1021       logger ("Could not get list from $node->{address}: $!\nAttempting to use old configuration"); 
    1022     if (ref $oldnode) { 
    1023       $config->{domain}->{$domain}->{node}->{$name} = $oldnode; 
    1024     } 
    1025     @services = []; 
    1026   } 
    1027  
    1028   for my $service (@services) { 
    1029     my $servname = $service; 
    1030     my $fields = {}; 
    1031     $servname =~ s/\W/_/g; 
    1032     next if (exists ($node->{client}->{$servname}->{fetch_data}) and 
    1033              $node->{client}->{$servname}->{fetch_data} == 0); 
    1034     next if (exists ($node->{client}->{$servname}->{update}) and  
    1035              $node->{client}->{$servname}->{update} ne "yes"); 
    1036     next if (@limit_services and !grep (/^$servname$/, @limit_services)); 
    1037     my @graph_order = (exists $node->{client}->{$servname}->{graph_order} ?  
    1038                        split (/\s+/, $node->{client}->{$servname}->{graph_order}) : ()); 
    1039     my $serviceconf_time = Time::HiRes::time; 
    1040     if ($servname ne $service) 
    1041     { 
    1042         $node->{client}->{$servname}->{realservname} = $service; 
    1043     } 
    1044     logger("[DEBUG] Configuring service: $name->$servname") if $DEBUG; 
    1045     write_socket_single ($socket, "config $service\n"); 
    1046     my @lines = read_socket($socket); 
    1047     return unless $socket; 
    1048     next unless (@lines); 
    1049     for (@lines) { 
    1050       if (/\# timeout/) { 
    1051         logger("Client reported timeout in configuration of $servname"); 
    1052         if ($oldnode->{client}->{$servname}) { 
    1053           logger("Attempting to use old configuration"); 
    1054           $config->{domain}->{$domain}->{node}->{$name}->{client}->{$servname} = $oldnode->{client}->{$servname}; 
    1055         } else { 
    1056           logger("Skipping configuration of $servname"); 
    1057           delete $node->{client}->{$servname}; 
    1058         } 
    1059       } 
    1060       elsif (/^(\w+)\.(\w+)\s+(.+)/) { 
    1061         my ($client,$type,$value) = ($1,$2,$3); 
    1062         $client = &sanitise_fieldname ($client, $fields); 
    1063         if (($type) and ($type eq "label")) { 
    1064             $value =~ s/\\/_/g; # Sanitise labels 
    1065         } 
    1066         $node->{client}->{$servname}->{$client.".".$type} = "$value"; 
    1067         logger ("[DEBUG] config: $name->$client.$type = $value") if $DEBUG; 
    1068         if (($type) and ($type eq "label")) { 
    1069           push (@graph_order,$client) 
    1070             unless grep (/^$client$/, @graph_order); 
    1071         } 
    1072       } elsif (/(^[^\s\#]+)\s+(.+)/) { 
    1073         my ($keyword) = $1; 
    1074         my ($value) = $2; 
    1075         $node->{client}->{$servname}->{$keyword} = $value; 
    1076         logger ("[DEBUG] Config: $keyword = $value") if $DEBUG; 
    1077         if ($keyword eq "graph_order") { 
    1078           @graph_order = split (/\s+/, $node->{client}->{$servname}->{graph_order}); 
    1079         } 
    1080       } 
    1081     } 
    1082     for my $subservice (keys %{$node->{client}->{$servname}}) { 
    1083       my ($client,$type) = split /\./,$subservice; 
    1084       my ($value) = $node->{client}->{$servname}->{$subservice}; 
    1085       if (($type) and ($type eq "label")) { 
    1086         my $fname = "$config->{dbdir}/$domain/$name-$servname-$client-" .  
    1087             lc substr (($node->{client}->{$servname}->{"$client.type"}||"GAUGE"),0,1). 
    1088             ".rrd"; 
    1089         if (! -f "$fname") { 
    1090           logger ("creating rrd-file for $servname->$subservice"); 
    1091           mkdir "$config->{dbdir}/$domain/",0777; 
    1092           my @args = ("$fname", 
    1093                         "DS:42:".($node->{client}->{$servname}->{"$client.type"} || "GAUGE").":600:". 
    1094                         (defined $node->{client}->{$servname}->{"$client.min"} ?  
    1095                          $node->{client}->{$servname}->{"$client.min"} : 
    1096                          "U") . ":" . ($node->{client}->{$servname}->{"$client.max"} || "U")); 
    1097           my $resolution = &munin_get ($config, "graph_data_size", "normal", $domain, $node, $servname); 
    1098           if ($resolution eq "normal") 
    1099           { 
    1100                 push (@args, 
     879sub config_node  
     880
     881    my ($newconf,$oldconf,$socket) = @_; 
     882    my ($domain,$name,$node,$oldnode,$socket) = @_; 
     883    my $clientdomain = read_socket_single ($socket); 
     884    my $fetchdomain; 
     885    my $name = munin_get_node_name ($newconf); 
     886    chomp($clientdomain) if $clientdomain; 
     887    if (!$clientdomain) { 
     888        logger("[WARNING] Got unknown reply from client \"$name\" skipping"); 
     889        return 0; 
     890    } 
     891    $clientdomain =~ s/\#.*(?:lrrd|munin) (?:client|node) at //; 
     892     
     893    # Decide what to ask for 
     894    if (munin_get ($newconf, "use_node_name")) { 
     895        $fetchdomain = $clientdomain; 
     896    } elsif (munin_get ($newconf, "use_default_name")) { 
     897        $fetchdomain = $clientdomain; 
     898    } else { 
     899        $fetchdomain = $name; 
     900    } 
     901 
     902    # TLS should only be attempted if explicitly enabled. The default value 
     903    # is therefore "disabled" (and not "auto" as before). 
     904    my $tls_requirement = &munin_get ($config, "tls", "disabled"); 
     905    logger ("[DEBUG]: TLS set to \"$tls_requirement\".") if $DEBUG; 
     906    if ($tls_requirement ne "disabled") 
     907    { 
     908        my $key; 
     909        my $cert; 
     910        my $depth; 
     911        my $ca_cert; 
     912        my $tls_verify; 
     913        $key = $cert = munin_get ($config, "tls_pem"); 
     914        $key = &munin_get ($config, "tls_private_key", "@@CONFDIR@@/munin.pem") 
     915          unless defined $key; 
     916        $cert = &munin_get ($config, "tls_certificate", "@@CONFDIR@@/munin.pem") 
     917          unless defined $cert; 
     918        $ca_cert = &munin_get ($config, "tls_ca_certificate", "@@CONFDIR@@/cacert.pem") 
     919           unless defined $ca_cert; 
     920        $tls_verify=&munin_get ($config, "tls_verify_certificate", "no"); 
     921        $depth=&munin_get ($config, "tls_verify_depth", 5); 
     922   
     923        if (!start_tls ($socket, $tls_requirement, $cert, $key, $ca_cert, $tls_verify, $depth)) 
     924        { 
     925          if ($tls_requirement eq "paranoid" or $tls_requirement eq "enabled") 
     926          { 
     927              logger ("[ERROR]: Could not establish TLS connection to \"$name\". Skipping."); 
     928              exit 13; 
     929          } 
     930        } 
     931    } 
     932 
     933    logger("[DEBUG] Configuring node: $name") if $DEBUG; 
     934    my @services; 
     935    eval { 
     936        local $SIG{ALRM} = sub { die "Could not run list on $name ($fetchdomain): $!\n"}; 
     937        alarm 5; # Should be enough to check the list 
     938        write_socket_single ($socket, "list $fetchdomain\n"); 
     939        my $list = read_socket_single ($socket); 
     940        exit 1 unless defined $list; 
     941        chomp $list; 
     942        @services = split / /,$list; 
     943        alarm 0; 
     944    }; 
     945    if ($@) { 
     946        die unless ($@ =~ m/Could not run list/); 
     947        logger ("Error: Could not get list from $newconf->{address}: $!\nAttempting to use old configuration"); 
     948        if (ref $oldconf) { 
     949            copy_node ($oldconf, $newconf); 
     950        } 
     951        @services = []; 
     952    } 
     953 
     954    for my $service (@services) { 
     955        my $servname = $service; 
     956        my $fields = {}; 
     957        $servname =~ s/\W/_/g; 
     958        munin_set_var_loc ($newconf, [$servname, "realservname"], $service); 
     959        logger("[DEBUG] Inspecting possible service: $servname") if $DEBUG; 
     960        next if (!munin_get_bool ($newconf->{$servname}, "update", "true")); 
     961        next if (!munin_get_bool ($newconf->{$servname}, "fetch_data", "true")); 
     962        next if (@limit_services and !grep (/^$servname$/, @limit_services)); 
     963 
     964        my @graph_order = split (/\s+/, munin_get ($newconf->{$service}, "graph_order", "")); 
     965        my $serviceconf_time = Time::HiRes::time; 
     966        logger("[DEBUG] Configuring service: $servname") if $DEBUG; 
     967        write_socket_single ($socket, "config $service\n"); 
     968        my @lines = read_socket($socket); 
     969        return unless $socket; 
     970        next unless (@lines); 
     971        for (@lines) { 
     972            if (/\# timeout/) { 
     973                logger("Client reported timeout in configuration of $servname"); 
     974                if ($oldconf->{$servname}) { 
     975                    logger("Attempting to use old configuration"); 
     976                    copy_node ($newconf->{$servname}, $oldconf->{$servname}); 
     977                } else { 
     978                    logger("Skipping configuration of $servname"); 
     979                    delete $newconf->{$servname}; 
     980                } 
     981            } elsif (/^(\w+)\.(\w+)\s+(.+)/) { 
     982                my ($client,$type,$value) = ($1,$2,$3); 
     983                $client = &sanitise_fieldname ($client, $fields); 
     984                if (($type) and ($type eq "label")) { 
     985                    $value =~ s/\\/_/g; # Sanitise labels 
     986                    push (@graph_order,$client) unless grep (/^$client$/, @graph_order); 
     987                } 
     988                munin_set_var_loc ($newconf, [$servname, $client, $type], "$value"); 
     989                logger ("config: $servname->$client.$type = $value") if $DEBUG; 
     990            } elsif (/(^[^\s\#]+)\s+(.+)/) { 
     991                my ($keyword) = $1; 
     992                my ($value) = $2; 
     993                munin_set_var_loc ($newconf, [$servname, $keyword], "$value"); 
     994                logger ("Config: $servname->$keyword = $value") if $DEBUG; 
     995                if ($keyword eq "graph_order") { 
     996                    @graph_order = split (/\s+/, $value); 
     997                } 
     998            } 
     999        } 
     1000        for my $field (keys %{$newconf->{$servname}}) { 
     1001            # Skip anything that isn't a field 
     1002            next if $field =~ /^#%#/; 
     1003            next unless (ref ($newconf->{$servname}->{$field}) eq "HASH" and 
     1004                    defined ($newconf->{$servname}->{$field}->{"label"})); 
     1005 
     1006            my $fhash = $newconf->{$servname}->{$field}; 
     1007 
     1008            # Check if file exists 
     1009            my $fname = munin_get_filename ($fhash); 
     1010            (my $dirname = $fname) =~ s/\/[^\/]+$//; 
     1011 
     1012            if (! -f "$fname") { 
     1013                logger ("creating rrd-file for $servname->$field: \"$fname\""); 
     1014                munin_mkdir_p ($dirname, 0777); 
     1015                my @args = ("$fname", 
     1016                        "DS:42:".munin_get($fhash, "type", "GAUGE").":600:". 
     1017                        munin_get($fhash, "min", "U") . ":" .  munin_get($fhash, "max", "U")); 
     1018 
     1019                my $resolution = &munin_get ($fhash, "graph_data_size", "normal"); 
     1020                if ($resolution eq "normal") { 
     1021                    push (@args, 
    11011022                        "RRA:AVERAGE:0.5:1:576", # resolution 5 minutes 
    11021023                        "RRA:MIN:0.5:1:576", 
     
    11111032                        "RRA:MIN:0.5:288:450", 
    11121033                        "RRA:MAX:0.5:288:450"); 
    1113           } 
    1114           elsif ($resolution eq "huge") 
    1115           { 
    1116                 push (@args, "RRA:AVERAGE:0.5:1:115200"); # resolution 5 minutes, for 400 days 
    1117                 push (@args, "RRA:MIN:0.5:1:115200"); # Three times? ARGH! 
    1118                 push (@args, "RRA:MAX:0.5:1:115200"); # Three times? ARGH! 
    1119           } 
    1120           RRDs::create @args; 
    1121           if (my $ERROR = RRDs::error) { 
    1122             logger ("[ERROR] In RRD: unable to create \"$fname\": $ERROR"); 
    1123           } 
    1124         } 
    1125     } 
    1126       $node->{client}->{$servname}->{graph_order} = join(' ',@graph_order); 
    1127     } 
    1128     $serviceconf_time = sprintf ("%.2f",(Time::HiRes::time - $serviceconf_time)); 
    1129     print STATS "CS|$domain|$name|$servname|$serviceconf_time\n"; 
    1130     logger ("Configured service: $name -> $servname ($serviceconf_time sec)"); 
    1131   } 
    1132   $nodeconf_time = sprintf ("%.2f",(Time::HiRes::time - $nodeconf_time)); 
    1133   print STATS "CN|$domain|$name|$nodeconf_time\n"; 
     1034                } elsif ($resolution eq "huge") { 
     1035                    push (@args, "RRA:AVERAGE:0.5:1:115200"); # resolution 5 minutes, for 400 days 
     1036                    push (@args, "RRA:MIN:0.5:1:115200"); # Three times? ARGH! 
     1037                    push (@args, "RRA:MAX:0.5:1:115200"); # Three times? ARGH! 
     1038                } 
     1039                RRDs::create @args; 
     1040                if (my $ERROR = RRDs::error) { 
     1041                    logger ("[ERROR] Unable to create \"$fname\": $ERROR"); 
     1042                } 
     1043            } 
     1044        } 
     1045        munin_set_var_loc ($newconf, [$servname, "graph_order"], join(' ',@graph_order)); 
     1046    } 
    11341047    return 0 unless $socket; 
    1135   logger("Configured node: $name ($nodeconf_time sec)")
    1136   return 1; 
    1137 
    1138  
    1139 sub fetch_node
    1140     my ($domain,$name,$node,$socket) = @_; 
    1141     my $nodefetch_time = Time::HiRes::time
     1048    return 1
     1049
     1050 
     1051sub fetch_node  
     1052
     1053    my ($newconf,$oldconf,$socket) = @_; 
     1054    my $name = munin_get_node_name ($newconf)
    11421055    logger("[DEBUG] Fetching node: $name") if $DEBUG; 
    1143     for my $service (keys %{$node->{client}}) { 
    1144         my $servicefetch_time = Time::HiRes::time
    1145         logger("[DEBUG] Fetching service: $name->$service") if $DEBUG
    1146         next if (exists ($node->{client}->{$service}->{fetch_data}) and  
    1147                 $node->{client}->{$service}->{fetch_data} == 0); 
    1148         next if (exists ($node->{client}->{$service}->{update}) and  
    1149                 $node->{client}->{$service}->{update} ne "yes"); 
     1056    for my $service (keys %{$newconf}) { 
     1057        next if ref ($newconf->{$service}) ne "HASH"
     1058        next if $service =~ /^#%#/
     1059        logger("[DEBUG] Fetching service: $service") if $DEBUG; 
     1060        next unless exists ($newconf->{$service}->{"graph_title"}); 
     1061        next unless (munin_get_bool ($newconf->{$service}, "update", "true")); 
     1062        next unless (munin_get_bool ($newconf->{$service}, "fetch_data", "true")); 
    11501063        next if (@limit_services and !grep (/^$service$/, @limit_services)); 
    1151         my $realservname = ( $node->{client}->{$service}->{realservname} || 
    1152                              $service ); 
    1153         delete $node->{client}->{$service}->{realservname} 
    1154           if exists $node->{client}->{$service}->{realservname}; 
     1064 
     1065        # Read (and get rid of) realservname 
     1066        my $realservname = ( $newconf->{$service}->{"realservname"} || $service ); 
     1067        delete $newconf->{$service}->{"realservname"} 
     1068          if exists $newconf->{$service}->{"realservname"}; 
     1069 
    11551070        write_socket_single ($socket, "fetch $realservname\n"); 
    11561071        my @lines = &read_socket($socket); 
     
    11801095 
    11811096                $key = &sanitise_fieldname ($key, $fields); 
    1182                 if (exists $node->{client}->{$service}->{$key.".label"}) { 
    1183                     my $fname = 
    1184                       "$config->{dbdir}/$domain/$name-$service-$key-". 
    1185                         lc 
    1186                           substr(($node->{client}->{$service}->{$key.".type"}|| 
    1187                                   "GAUGE"),0,1).".rrd"; 
     1097                if (exists $newconf->{$service}->{$key}->{"label"}) { 
     1098                    my $fname = munin_get_filename ($newconf->{$service}->{$key}); 
    11881099 
    11891100                    logger("[DEBUG] Updating $fname with $value") if $DEBUG; 
     
    11931104                    } 
    11941105                } else { 
    1195                     logger ("[ERROR] Unable to update $domain -> $name -> $service -> $key: No such field (no \"label\" field defined when running plugin with \"config\")."); 
     1106                    logger ("[ERROR] Unable to update $name -> $service -> $key: No such field (no \"label\" field defined when running plugin with \"config\")."); 
    11961107                } 
    11971108            } elsif (/(\w+)\.extinfo\s+(.+)/) { 
    1198                 $config->{domain}->{$domain}->{node}->{$name}->{client}->{$service}->{$1.".extinfo"} = $2
     1109                munin_set_var_loc ($newconf, [$service, $service, $1, "extinfo"], $2)
    11991110            } 
    12001111        } 
    1201         $servicefetch_time = sprintf ("%.2f",(Time::HiRes::time - $servicefetch_time)); 
    1202         logger ("Fetched service: $name -> $service ($servicefetch_time sec)"); 
    1203         print STATS "FS|$domain|$name|$service|$servicefetch_time\n"; 
    1204     } 
    1205     $nodefetch_time = sprintf ("%.2f",(Time::HiRes::time - $nodefetch_time)); 
    1206     logger ("Fetched node: $name ($nodefetch_time sec)"); 
    1207     print STATS "FN|$domain|$name|$nodefetch_time\n"; 
    1208  
     1112    } 
    12091113    return 1; 
    1210 } 
    1211  
    1212 sub use_old_config 
    1213 { 
    1214     my $domain  = shift; 
    1215     my $name    = shift; 
    1216     my $oldnode = shift; 
    1217  
    1218     $config->{domain}->{$domain}->{node}->{$name} = $oldnode; 
    1219     logger ("Attempting to use old configuration for $domain -> $name."); 
    12201114} 
    12211115 
     
    12831177} 
    12841178 
     1179sub copy_node 
     1180{ 
     1181    my $from = shift; 
     1182    my $to   = shift; 
     1183     
     1184    if (ref ($from) eq "HASH") { 
     1185        foreach my $key (keys %$from) { 
     1186            next if $key =~ /^#%#/; 
     1187            $to->{$key} = $from->{$key}; 
     1188        } 
     1189    } else { 
     1190        $to = $from; 
     1191    } 
     1192    return $to; 
     1193} 
     1194 
    128511951; 
    12861196 
     
    13721282=head1 COPYRIGHT 
    13731283 
    1374 Copyright (C) 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 
     1284Copyright © 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 
    13751285 
    13761286This is free software; see the source for copying conditions. There is 
  • people/jo/multilevel-groups-3/server/style.css

    r860 r1502  
    3838 } 
    3939 
     40.service {  
     41  font-size: x-small; 
     42  font-weight: bold; 
     43 } 
     44 
    4045.center {  
    4146  text-align: center;