Changeset 1344

Show
Ignore:
Timestamp:
14/10/07 20:44:34 (4 years ago)
Author:
jo
Message:

Merged multilevel-groups branch into trunk changes (into multileve-groups-2 branch).

Files:

Legend:

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

    r1288 r1344  
    2424 
    2525use Exporter; 
     26use Data::Dumper; 
     27 
    2628@ISA = ('Exporter'); 
    2729@EXPORT = ('munin_trend',  
     
    5052           'munin_get_max_label_length', 
    5153           'munin_get_field_order', 
    52            'munin_get_rrd_filename' 
     54           'munin_get_rrd_filename', 
     55           'munin_find_field', 
     56           'munin_get_node_name', 
     57           'munin_get_node_loc', 
     58           'munin_get_node', 
     59           'munin_set_var_loc', 
     60           'munin_copy_node_toloc', 
     61           'munin_get_separated_node', 
     62           'munin_mkdir_p', 
     63           'munin_get_node_partialpath' 
    5364           ); 
    5465 
     
    8495        "version", "tls_certificate", "tls_private_key", "tls_pem",  
    8596        "tls_verify_certificate", "tls_verify_depth", "graph_data_size", 
    86         "colour", "graph_printf", "ok", "unknown" 
     97        "colour", "graph_printf", "ok", "unknown", "realservname", "cdef_name", 
     98        "graphable", "process", "realname" 
    8799    ); 
    88100 
     
    90102 
    91103# Fields to copy when "aliasing" a field 
    92 my @copy_fields    = ("label", "draw", "type", "rrdfile", "fieldname", "info");  
     104my @COPY_FIELDS    = ("label", "draw", "type", "rrdfile", "fieldname", "info");  
    93105 
    94106 
     
    111123} 
    112124 
     125# munin_draw_field: Check whether a field will be visible in the graph or not 
     126# Parameters: 
     127# - $hash: A ref to the hash node for the field 
     128# Returns: 
     129# - Success: Boolean; true if field will be graphed, false if not 
     130# - Failure: undef 
    113131sub munin_draw_field { 
    114     my $node    = shift; 
    115     my $service = shift; 
    116     my $field   = shift; 
    117  
    118     $field =~ s/=.*//; 
    119  
    120     print "DEBUG: munin_draw_field: Checking $service -> $field: " . &munin_get_bool_val ($node->{client}->{$service}->{$field.".graph"}, 1) . ".\n" if $DEBUG;; 
    121     return 0 if (exists $node->{client}->{$service}->{$field.".skipdraw"}); 
    122     return (&munin_get_bool_val ($node->{client}->{$service}->{$field.".graph"}, 1)); 
     132    my $hash   = shift; 
     133 
     134    return 0 if munin_get_bool ($hash, "skipdraw", 0); 
     135    return 0 if !munin_get_bool ($hash, "graph", 1); 
     136    return defined $hash->{"label"}; 
    123137} 
    124138 
     
    219233    my ($configfile,$overwrite) = @_; 
    220234    for my $key (keys %$overwrite) { 
     235        next if $key =~ /^#%#/; 
    221236        if (ref $overwrite->{$key}) { 
    222237            &munin_overwrite($overwrite->{$key},$configfile->{$key}); 
     
    234249    $conf ||= $configfile; 
    235250    if (! -r $conf and ! $missingok) { 
    236                ::logger ("munin_readconfig: cannot open '$conf'"); 
    237                return undef; 
     251        ::logger ("munin_readconfig: cannot open '$conf'"); 
     252        return undef; 
    238253    } 
    239254    if (open (CFG, $conf)) 
     
    246261 
    247262    # Some important defaults before we return... 
    248     $config->{'rundir'} ||= "/tmp/"; 
    249     $config->{'dbdir'}  ||= "/var/lib/munin/"; 
    250     $config->{'logdir'} ||= "/var/log/"; 
    251     $config->{'tmpldir'}||= "/etc/munin/templates/"; 
     263    $config->{'rundir'} ||= "@@STATEDIR@@"; 
     264    $config->{'dbdir'}  ||= "@@DBDIR@@"; 
     265    $config->{'logdir'} ||= "@@LOGDIR@@"; 
     266    $config->{'tmpldir'}||= "@@CONFDIR@@/templates"; 
    252267    $config->{'htmldir'}||= "@@HTMLDIR@@/"; 
     268    $config->{'#%#parent'}= undef; 
     269    $config->{'#%#name'}= "root"; 
    253270    return ($config); 
    254271} 
     
    257274{ 
    258275    my $lines    = shift; 
    259     my $hash     = undef
     276    my $hash     = {}
    260277    my $prefix   = ""; 
    261278    my $prevline = ""; 
     
    264281    { 
    265282        chomp $line; 
    266 #$line =~ s/(^|[^\\])#.*/$1/g if $line =~ /#/;  # Skip comments... 
    267         if ($line =~ /#/) 
     283        if ($line =~ /#/) # Skip comments... 
    268284        {  
    269285            next if ($line =~ /^#/); 
     
    297313        { 
    298314            $prefix = $1; 
    299             if ($prefix =~ /^([^:;]+);([^:;]+)$/) 
     315            if ($prefix =~ /^([^:]+);([^:;]+)$/) 
    300316            { 
    301317                $prefix .= ":"; 
    302318            } 
    303             elsif ($prefix =~ /^([^:;]+);$/) 
     319            elsif ($prefix =~ /^([^:]+);$/) 
    304320            { 
    305321                $prefix .= ""; 
    306322            } 
    307             elsif ($prefix =~ /^([^:;]+);([^:;]+):(.*)$/) 
     323            elsif ($prefix =~ /^([^:]+);([^:;]+):(.*)$/) 
    308324            { 
    309325                $prefix .= "."; 
     
    389405} 
    390406 
    391 sub munin_set_var_path 
     407  
     408# munin_find_field: Search a hash to find nodes with $field defined 
     409# Parameters:  
     410# - $hash: A hash ref to search 
     411# - $field: The name of the field to search for 
     412# - $avoid: [optional] Stop traversing further down if this field is found 
     413# Returns: 
     414# - Success: A ref to an array of the hash nodes containing $field. 
     415# - Failure: undef 
     416sub munin_find_field 
     417
     418    my $hash  = shift; 
     419    my $field = shift; 
     420    my $avoid = shift; 
     421    my $res = []; 
     422 
     423    if (ref ($hash) eq "HASH") { 
     424        ::logger ("Debug: Searching for $field in " . join ('::', @{munin_get_node_loc ($hash)})); 
     425        foreach my $key (keys %{$hash}) { 
     426            next if $key =~ /^#%#/; 
     427            last if defined $avoid and $key eq $avoid; 
     428            if ($key eq $field) { 
     429                push @$res, $hash; 
     430            } elsif (ref ($hash->{$key}) eq "HASH") { 
     431                push @$res, @{munin_find_field ($hash->{$key}, $field, $avoid)}; 
     432            } 
     433        } 
     434    } 
     435 
     436    return $res; 
     437
     438 
     439# munin_get_separated_node: Copy a node to a separate node without "specials" 
     440# Parameters: 
     441# - $hash: The node to copy 
     442# Returns: 
     443# - Success: A ref to a new node without "#%#"-fields 
     444# - Failure: undef 
     445sub munin_get_separated_node 
     446
     447    my $hash = shift; 
     448    my $ret  = {}; 
     449 
     450    if (ref ($hash) eq "HASH") { 
     451        foreach my $key (keys %$hash) { 
     452            next if $key =~ /^#%#/; 
     453            if (ref ($hash->{$key}) eq "HASH") { 
     454                $ret->{$key} = munin_get_separated_node ($hash->{$key}); 
     455            } else { 
     456                $ret->{$key} = $hash->{$key}; 
     457            } 
     458        } 
     459    } else { 
     460        return undef; 
     461    } 
     462 
     463    return $ret; 
     464
     465 
     466# munin_get_node_name: Return the name of the hash node supplied 
     467# Parameters:  
     468# - $hash: A ref to the hash node 
     469# Returns: 
     470# - Success: The name of the node 
     471sub munin_get_node_name 
     472
     473    my $hash = shift; 
     474 
     475    if (ref ($hash) eq "HASH" and defined $hash->{'#%#name'}) { 
     476        return $hash->{'#%#name'}; 
     477    } else {  
     478        return undef; 
     479    } 
     480
     481 
     482# munin_get_node_loc: Get location array for hash node 
     483# Parameters:  
     484# - $hash: A ref to the node 
     485# Returns: 
     486# - Success: Ref to an array with the full path of the variable 
     487# - Failure: undef 
     488sub munin_get_node_loc 
     489
     490    my $hash = shift; 
     491    my $res = []; 
     492 
     493    if (ref ($hash) ne "HASH") { # Not a has node 
     494        return undef; 
     495    } 
     496    if (defined $hash->{'#%#parent'}) { 
     497        $res = munin_get_node_loc ($hash->{'#%#parent'}); 
     498        push @$res, munin_get_node_name ($hash) if defined $res; 
     499    } 
     500    return $res; 
     501
     502 
     503# munin_get_node: Gets a node by loc 
     504# Parameters:  
     505# - $hash: A ref to the hash to set the variable in 
     506# - $loc: A ref to an array with the full path of the node 
     507# Returns: 
     508# - Success: The node ref found by $loc 
     509# - Failure: undef 
     510sub munin_get_node 
     511
     512    my $hash = shift; 
     513    my $loc  = shift; 
     514 
     515    while (my $tmpvar = shift @$loc) { 
     516        if ($tmpvar !~ /\S/) { 
     517            ::logger ("Error: munin_get_node: Cannot work on hash node \"$tmpvar\""); 
     518            return undef; 
     519        } 
     520        return undef if !exists $hash->{$tmpvar}; 
     521        return $hash->{$tmpvar} if @$loc <= 0; 
     522        $hash = $hash->{$tmpvar}; 
     523    } 
     524
     525 
     526# munin_set_var: sets a variable in a hash 
     527# Parameters:  
     528# - $hash: A ref to the hash to set the variable in 
     529# - $var: The name of the variable 
     530# - $val: The value to set the variable to 
     531# Returns: 
     532# - Success: The $hash we were handed 
     533# - Failure: undef 
     534sub munin_set_var 
    392535{ 
    393536    my $hash = shift; 
     
    395538    my $val  = shift; 
    396539 
    397     print "DEBUG: Setting var \"$var\" = \"$val\"\n" if $DEBUG; 
    398     if ($var =~ /^\s*([^;:]+);([^:]+):(\S+)\s*$/) 
    399     { 
    400         my ($dom, $host, $rest) = ($1, $2, $3); 
    401         my @sp = split (/\./, $rest); 
    402  
    403         if (@sp == 3) 
    404         { 
    405             ::logger ("Warning: Unknown option \"$sp[2]\" in \"$dom;$host:$sp[0].$sp[1].$sp[2]\".") 
    406                 unless defined $legal_expanded{$sp[2]}; 
    407             $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{"$sp[1].$sp[2]"} = $val; 
    408         } 
    409         elsif (@sp == 2) 
    410         { 
    411             ::logger ("Warning: Unknown option \"$sp[1]\" in \"$dom;$host:$sp[0].$sp[1]\".") 
    412                 unless defined $legal_expanded{$sp[1]}; 
    413             $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{$sp[1]} = $val; 
    414         } 
    415         elsif (@sp == 1) 
    416         { 
    417             ::logger ("Warning: Unknown option \"$sp[0]\" in \"$dom;$host:$sp[0]\".") 
    418                 unless defined $legal_expanded{$sp[0]}; 
    419             $hash->{domain}->{$dom}->{node}->{$host}->{$sp[0]} = $val; 
    420         } 
    421         else 
    422         { 
    423             warn "munin_set_var: Malformatted variable path \"$var\"."; 
    424         } 
    425     } 
    426     elsif ($var =~ /^\s*([^;:]+);([^;:]+)\s*$/) 
    427     { 
    428         my ($dom, $rest) = ($1, $2); 
    429         my @sp = split (/\./, $rest); 
    430  
    431         if (@sp == 1) 
    432         { 
    433             ::logger ("Warning: Unknown option \"$sp[0]\" in \"$dom;$sp[0]\".") 
    434                 unless defined $legal_expanded{$sp[0]}; 
    435             $hash->{domain}->{$dom}->{$sp[0]} = $val; 
    436         } 
    437         else 
    438         { 
    439             warn "munin_set_var: Malformatted variable path \"$var\"."; 
    440         } 
    441     } 
    442     elsif ($var =~ /^\s*([^;:\.]+)\s*$/) 
    443     { 
    444         ::logger ("Warning: Unknown option \"$1\" in \"$1\".") 
    445             unless defined $legal_expanded{$1}; 
    446         $hash->{$1} = $val; 
    447     } 
    448     elsif ($var =~ /^\s*([^\.]+)\.([^\.]+)\.([^\.]+)$/) 
    449     { 
    450         ::logger ("Warning: Unknown option \"$1\" in \"$var\".") 
    451             unless defined $legal_expanded{$1}; 
    452         ::logger ("Warning: Unknown option \"$3\" in \"$var\".") 
    453             unless defined $legal_expanded{$3}; 
    454         $hash->{$1}->{$2}->{$3} = $val; 
    455     } 
    456     else 
    457     { 
    458         warn "munin_set_var: Malformatted variable path \"$var\"."; 
     540    return munin_set_var_loc ($hash, [$var], $val); 
     541
     542 
     543# munin_set_var_loc: sets a variable in a hash 
     544# Parameters:  
     545# - $hash: A ref to the hash to set the variable in 
     546# - $loc: A ref to an array with the full path of the variable 
     547# - $val: The value to set the variable to 
     548# Returns: 
     549# - Success: The $hash we were handed 
     550# - Failure: undef 
     551sub munin_set_var_loc 
     552
     553    my $hash = shift; 
     554    my $loc  = shift; 
     555    my $val  = shift; 
     556 
     557    my $tmpvar = shift @$loc; 
     558    if ($tmpvar !~ /\S/) { 
     559        ::logger ("Error: munin_set_var_loc: Cannot work on hash node \"$tmpvar\""); 
     560        return undef; 
     561    } 
     562    if (@$loc > 0) { 
     563        if (!defined $hash->{$tmpvar}) { # Init the new node 
     564            $hash->{$tmpvar}->{"#%#parent"} = $hash; 
     565            $hash->{$tmpvar}->{"#%#name"} = $tmpvar; 
     566        } 
     567        return munin_set_var_loc ($hash->{$tmpvar}, $loc, $val); 
     568    } else { 
     569        ::logger ("Warning: munin_set_var_loc: Setting unknown option \"$tmpvar\".") 
     570            unless defined $legal_expanded{$tmpvar}; 
     571        $hash->{$tmpvar} = $val; 
     572        return $hash; 
     573    } 
     574
     575 
     576# munin_get_node_partialpath: gets a node froma partial path 
     577# Parameters:  
     578# - $hash: A ref to the "current" location in the hash tree 
     579# - $var: A path string with relative location (from the $hash). 
     580# Returns: 
     581# - Success: The node 
     582# - Failure: undef 
     583sub munin_get_node_partialpath 
     584
     585    my $hash = shift; 
     586    my $var  = shift; 
     587    my $ret  = undef; 
     588 
     589    return undef if !defined $hash or ref ($hash) ne "HASH"; 
     590 
     591    my $root    = munin_get_root_node ($hash); 
     592    my $hashloc = munin_get_node_loc ($hash); 
     593    my $varloc  = undef; 
     594 
     595    if ($var =~ /^\s*([^:]+):(\S+)\s*$/) { 
     596        my ($leftstring, $rightstring) = ($1, $2); 
     597 
     598        my @leftarr = split (/;/, $leftstring); 
     599        my @rightarr = split (/\./, $rightstring); 
     600        push @$varloc, @leftarr, @rightarr 
     601    } elsif ($var =~ /^\s*([^;:\.]+)\s*$/) { 
     602        push @$varloc, $var; 
     603    } elsif ($var =~ /^\s*(.+)\.([^\.:;]+)$/) { 
     604        my ($leftstring, $rightstring) = ($1, $2); 
     605 
     606        my @leftarr = split (/;/, $leftstring); 
     607        my @rightarr = split (/\./, $rightstring); 
     608        push @$varloc, @leftarr, @rightarr; 
     609    } elsif ($var =~ /^\s*(\S+)\s*$/) { 
     610        my @leftarr = split (/;/, $1); 
     611        push @$varloc, @leftarr; 
     612    } else { 
     613        ::logger ("Error: munin_get_node_partialpath: Malformatted variable path \"$var\"."); 
     614    } 
     615 
     616    # We've got both parts of the loc (varloc and hashloc) -- let's figure out  
     617    # where they meet up. 
     618    do { 
     619        $ret = munin_get_node ($root, [@$hashloc, @$varloc]); 
     620    } while (!defined $ret and pop @$hashloc); 
     621 
     622    return $ret; 
     623
     624 
     625# munin_set_var_path: sets a variable in a hash 
     626# Parameters:  
     627# - $hash: A ref to the hash to set the variable in 
     628# - $var: A string with the full path of the variable 
     629# - $val: The value to set the variable to 
     630# Returns: 
     631# - Success: The $hash we were handed 
     632# - Failure: The $hash we were handed 
     633sub munin_set_var_path 
     634
     635    my $hash = shift; 
     636    my $var  = shift; 
     637    my $val  = shift; 
     638 
     639    my $result = undef; 
     640 
     641    ::logger ("Debug: munin_set_var_path: Setting var \"$var\" = \"$val\"") if $DEBUG; 
     642    if ($var =~ /^\s*([^:]+):(\S+)\s*$/) { 
     643        my ($leftstring, $rightstring) = ($1, $2); 
     644 
     645        my @leftarr = split (/;/, $leftstring); 
     646        my @rightarr = split (/\./, $rightstring); 
     647        $result = munin_set_var_loc ($hash, [@leftarr, @rightarr], $val); 
     648    } elsif ($var =~ /^\s*([^;:\.]+)\s*$/) { 
     649        $result = munin_set_var_loc ($hash, [$1], $val); 
     650    } elsif ($var =~ /^\s*(.+)\.([^\.:;]+)$/) { 
     651        my ($leftstring, $rightstring) = ($1, $2); 
     652 
     653        my @leftarr = split (/;/, $leftstring); 
     654        my @rightarr = split (/\./, $rightstring); 
     655        $result = munin_set_var_loc ($hash, [@leftarr, @rightarr], $val); 
     656    } elsif ($var =~ /^\s*(\S+)\s*$/) { 
     657        my @leftarr = split (/;/, $1); 
     658        $result = munin_set_var_loc ($hash, [@leftarr], $val); 
     659    } else { 
     660        ::logger ("Error: munin_set_var_path: Malformatted variable path \"$var\"."); 
     661    } 
     662 
     663    if (!defined $result) { 
     664        ::logger ("Error: munin_set_var_path: Failed setting \"$var\" = \"$val\"."); 
    459665    } 
    460666 
     
    462668} 
    463669 
    464 sub munin_writeconfig_loop { 
    465     my ($data,$fh,$pre) = @_; 
    466     $pre |= ""; 
    467  
    468     # Write datafile 
    469     foreach my $a (keys %{$data}) 
    470     { 
    471         if (ref ($data->{$a}) eq "HASH") 
    472         { 
    473             if ($a eq "domain" or $a eq "node" or $a eq "client") 
    474             { 
    475                 &munin_writeconfig_loop ($data->{$a}, $fh, "$pre"); 
    476             } 
    477             elsif ($a eq "contact" and $pre eq "") 
    478             { 
    479                 &munin_writeconfig_loop ($data->{$a}, $fh, "contact."); 
    480             } 
    481             else 
    482             { 
    483                 my $lpre = $pre; 
    484                 if ($lpre eq "") 
    485                 { 
    486                     $lpre = $a.";"; 
    487                 } 
    488                 elsif ($lpre =~ /;$/) 
    489                 { 
    490                     $lpre .= $a.":"; 
    491                 } 
    492                 else 
    493                 { 
    494                     $lpre .= $a."."; 
    495                 } 
    496                 &munin_writeconfig_loop ($data->{$a}, $fh, "$lpre"); 
    497             } 
    498         } 
    499         elsif (defined $data->{$a} and length $data->{$a}) 
    500         { 
    501             next if "$pre$a" eq "version"; # Handled separately 
    502             (my $outstring = $data->{$a}) =~ s/([^\\])#/$1\\#/g; 
    503             print "Writing: $pre$a $outstring\n" if $DEBUG; 
     670# munin_get_root_node: Get the root node of the hash tree 
     671# Parameters: 
     672# - $hash: A hash node to traverse up from 
     673# Returns: 
     674# - Success: A ref to the root hash node 
     675# - Failure: undef 
     676sub munin_get_root_node 
     677
     678    my $hash = shift; 
     679 
     680    return undef if ref ($hash) ne "HASH"; 
     681 
     682    while (defined $hash->{'#%#parent'}) { 
     683        $hash = $hash->{'#%#parent'}; 
     684    } 
     685 
     686    return $hash; 
     687
     688 
     689sub munin_writeconfig_loop  
     690
     691    my ($hash,$fh,$pre) = @_; 
     692 
     693    foreach my $key (keys %$hash) { 
     694        next if $key =~ /#%#/; 
     695        my $path = (defined $pre ? join(';', ($pre, $key)) : $key); 
     696        if (ref ($hash->{$key}) eq "HASH") { 
     697            munin_writeconfig_loop ($hash->{$key}, $fh, $path); 
     698        } else { 
     699            next if !defined $pre and $key eq "version"; # Handled separately 
     700            next if !defined $hash->{$key} or !length $hash->{$key}; 
     701            (my $outstring = $hash->{$key}) =~ s/([^\\])#/$1\\#/g; 
     702            print "Writing: $path $outstring\n" if $DEBUG; 
    504703            if ($outstring =~ /\\$/) 
    505704            { # Backslash as last char has special meaning. Avoid it. 
    506                 print $fh "$pre$a $outstring\\\n";  
     705                print $fh "$path $outstring\\\n";  
    507706            } else { 
    508                 print $fh "$pre$a $outstring\n"; 
    509             } 
    510         } 
    511     } 
    512 
     707                print $fh "$path $outstring\n"; 
     708            } 
     709        } 
     710    } 
     711
     712 
    513713sub munin_writeconfig { 
    514714    my ($datafilename,$data,$fh) = @_; 
    515 #   my $datafile = new Config::General(); 
    516 #   $datafile->save_file($datafilename,$data); 
    517715 
    518716    if (!defined $fh) 
     
    528726    print $fh "version $VERSION\n"; 
    529727    # Write datafile 
    530     &munin_writeconfig_loop ($data, $fh, ""); 
     728    &munin_writeconfig_loop ($data, $fh); 
    531729     
    532730    if (defined $fh) 
     
    549747} 
    550748 
     749# munin_get_picture_filename: Get the full path+name of a picture file 
     750# Parameters: 
     751# - $hash: A ref to the service hash node 
     752# - $scale: The scale (day, week, year, month) 
     753# - $sum: [optional] Boolean value, whether it's a sum graph or not. 
     754# Returns: 
     755# - Success: The file name with full path 
     756# - Failure: undef 
    551757sub munin_get_picture_filename { 
    552     my $config  = shift; 
    553     my $domain  = shift; 
    554     my $name    = shift; 
    555     my $service = shift; 
     758    my $hash    = shift; 
    556759    my $scale   = shift; 
    557760    my $sum     = shift; 
    558     my $dir     = $config->{'htmldir'}; 
     761    my $loc     = munin_get_node_loc ($hash); 
     762    my $ret     = munin_get ($hash, 'htmldir'); 
    559763 
    560764    # Sanitise 
    561     $dir =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g; 
    562     $domain =~ s/[^\w_\/"'\[\]\(\)+=\.-]/_/g; 
    563     $name =~ s/[^\w_\/"'\[\]\(\)+=\.-]/_/g; 
    564     $service =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
     765    $ret =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g; 
     766    $hash =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
    565767    $scale =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g; 
    566  
    567     if (defined $sum and $sum) 
    568     { 
    569             return "$dir/$domain/$name-$service-$scale-sum.png"; 
    570     } 
    571     else 
    572     { 
    573             return "$dir/$domain/$name-$service-$scale.png"; 
    574     } 
    575 
    576  
     768    @$loc = map { s/\//_/g; $_ } @$loc; 
     769    @$loc = map { s/^\./_/g; $_ } @$loc; 
     770         
     771    my $plugin = pop @$loc or return undef; 
     772    my $node   = pop @$loc or return undef; 
     773 
     774    if (@$loc) { # The rest is used as directory names... 
     775        $ret .= "/" . join ('/', @$loc); 
     776    } 
     777 
     778    if (defined $sum and $sum) { 
     779            return "$ret/$node-$plugin-$scale-sum.png"; 
     780    } else { 
     781            return "$ret/$node-$plugin-$scale.png"; 
     782    } 
     783
     784 
     785# munin_path_to_loc: Returns a loc array from a path string 
     786# Parameters:  
     787# - $path: A path string 
     788# Returns: 
     789# - Success: A ref to an array with the loc 
     790# - Failure: undef 
     791sub munin_path_to_loc 
     792
     793    my $path = shift; 
     794 
     795    my $result = undef; 
     796 
     797    if ($path =~ /^\s*([^:]+):(\S+)\s*$/) { 
     798        my ($leftstring, $rightstring) = ($1, $2); 
     799 
     800        my @leftarr = split (/;/, $leftstring); 
     801        my @rightarr = split (/\./, $rightstring); 
     802        $result = [@leftarr, @rightarr]; 
     803    } elsif ($path =~ /^\s*([^;:\.]+)\s*$/) { 
     804        $result = [$1]; 
     805    } elsif ($path =~ /^\s*(.+)\.([^\.:;]+)$/) { 
     806        my ($leftstring, $rightstring) = ($1, $2); 
     807 
     808        my @leftarr = split (/;/, $leftstring); 
     809        my @rightarr = split (/\./, $rightstring); 
     810        $result = [@leftarr, @rightarr]; 
     811    } elsif ($path =~ /^\s*(\S+)\s*$/) { 
     812        my @leftarr = split (/;/, $1); 
     813        $result = [@leftarr]; 
     814    } else { 
     815        ::logger ("Error: munin_path_to_loc: Malformatted variable path \"$path\"."); 
     816    } 
     817 
     818    if (!defined $result) { 
     819        ::logger ("Error: munin_path_to_loc: Failed converting \"$path\"."); 
     820    } 
     821 
     822    return $result; 
     823
     824 
     825 
     826# munin_get_filename: Get rrd filename for a field, without any  
     827#                     bells or whistles. Used by munin-update to  
     828#                     figure out which file to update. 
     829# Parameters: 
     830# - $hash: Ref to hash field 
     831# Returns: 
     832# - Success: Full path to rrd file 
     833# - Failure: undef 
    577834sub munin_get_filename { 
    578         my ($config,$domain,$node,$service,$field) = @_; 
    579  
    580         return ($config->{'dbdir'} . "/$domain/$node-$service-$field-" . lc substr (($config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field.".type"}||"GAUGE"), 0,1). ".rrd"); 
    581  
    582 
    583  
     835        my $hash = shift; 
     836        my $loc  = munin_get_node_loc ($hash); 
     837        my $ret  = munin_get ($hash, "dbdir"); 
     838 
     839        if (!defined $loc or !defined $ret) { 
     840            return undef; 
     841        } 
     842 
     843        # Not really a danger (we're not doing this stuff via the shell), so more to avoid  
     844        # confusion with silly filenames 
     845        @$loc = map { s/\//_/g; $_ } @$loc; 
     846        @$loc = map { s/^\./_/g; $_ } @$loc; 
     847         
     848        my $field  = pop @$loc or return undef; 
     849        my $plugin = pop @$loc or return undef; 
     850        my $node   = pop @$loc or return undef; 
     851 
     852        if (@$loc) { # The rest is used as directory names... 
     853            $ret .= "/" . join ('/', @$loc); 
     854        } 
     855 
     856        return ($ret . "/$node-$plugin-$field-" . lc substr (munin_get($hash, "type", "GAUGE"), 0,1). ".rrd"); 
     857 
     858
     859 
     860# munin_get_bool: Get boolean variable 
     861# Parameters: 
     862# - $hash: Ref to hash node 
     863# - $field: Name of field to get 
     864# - $default: [optional] Value to return if $field isn't set 
     865# Returns: 
     866# - Success: 1 or 0 (true or false) 
     867# - Failure: $default if defined, else undef 
    584868sub munin_get_bool 
    585869{ 
    586     my $conf     = shift; 
    587     my $field    = shift; 
    588     my $default  = shift; 
    589     my $domain   = shift; 
    590     my $node     = shift; 
    591     my $service  = shift; 
    592     my $plot     = shift; 
    593  
    594     return undef unless defined $field; 
    595  
    596     my $ans = &munin_get ($conf, $field, $default, $domain, $node, $service, $plot); 
     870    my $hash   = shift; 
     871    my $field  = shift; 
     872    my $default = shift; 
     873 
     874    my $ans = &munin_get ($hash, $field, $default); 
    597875    return undef if not defined $ans; 
    598876 
     
    602880        $ans =~ /^enable$/i or 
    603881        $ans =~ /^enabled$/i 
    604        ) 
    605     { 
    606     return 1; 
    607     } 
    608     elsif ($ans =~ /^no$/i or 
     882       ) { 
     883        return 1; 
     884    } elsif ($ans =~ /^no$/i or 
    609885        $ans =~ /^false$/i or 
    610886        $ans =~ /^off$/i or 
    611887        $ans =~ /^disable$/i or 
    612888        $ans =~ /^disabled$/i 
    613       ) 
    614     { 
    615     return 0; 
    616     } 
    617     elsif ($ans !~ /\D/) 
    618     { 
    619     return $ans; 
    620     } 
    621     else 
    622     { 
    623     return undef; 
     889      ) { 
     890        return 0; 
     891    } elsif ($ans !~ /\D/) { 
     892        return $ans; 
     893    } else { 
     894        return $default; 
    624895    } 
    625896} 
     
    670941} 
    671942 
     943# munin_get: Get variable 
     944# Parameters: 
     945# - $hash: Ref to hash node 
     946# - $field: Name of field to get 
     947# - $default: [optional] Value to return if $field isn't set 
     948# Returns: 
     949# - Success: field contents 
     950# - Failure: $default if defined, else undef 
    672951sub munin_get 
    673952{ 
    674     my $conf     = shift; 
    675     my $field    = shift; 
    676     my $default  = shift; 
    677     my $domain   = shift; 
    678     my $node     = shift; 
    679     my $service  = shift; 
    680     my $plot     = shift; 
    681  
    682     if (defined $field) 
    683     { 
    684         return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$plot.$field"} 
    685                 if (defined $domain and defined $node and defined $service and defined $plot and  
    686                         defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$plot.$field"}); 
    687  
    688          
    689  
    690         return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field} 
    691                 if (defined $domain and defined $node and defined $service and  
    692                         defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field}); 
    693         return $conf->{domain}->{$domain}->{node}->{$node}->{$field} 
    694                 if (defined $domain and defined $node and  
    695                         defined $conf->{domain}->{$domain}->{node}->{$node}->{$field}); 
    696         return $conf->{domain}->{$domain}->{$field} 
    697                 if (defined $domain and defined $conf->{domain}->{$domain}->{$field}); 
    698         return $conf->{$field} 
    699                 if (defined $conf->{$field}); 
    700         return $default; 
    701     } 
    702     else 
    703     { 
    704         return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service} 
    705                 if (defined $domain and defined $node and defined $service and  
    706                         defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}); 
    707         return $conf->{domain}->{$domain}->{node}->{$node} 
    708                 if (defined $domain and defined $node and  
    709                         defined $conf->{domain}->{$domain}->{node}->{$node}); 
    710         return $conf->{domain}->{$domain} 
    711                 if (defined $domain and defined $conf->{domain}->{$domain}); 
    712         return $conf 
    713                 if (defined $conf); 
    714         return $default; 
    715     } 
     953    my $hash   = shift; 
     954    my $field  = shift; 
     955    my $default = shift; 
     956 
     957    return $default if (ref ($hash) ne "HASH"); 
     958    return $hash->{$field} if defined $hash->{$field} and ref($hash->{$field}) ne "HASH"; 
     959    return $default if not defined $hash->{'#%#parent'}; 
     960    return munin_get ($hash->{'#%#parent'}, $field, $default); 
     961
     962 
     963# munin_copy_node_toloc: Copy hash node at  
     964# - $from: Hash node to copy 
     965# - $to: Where to copy it to 
     966# - $loc: Path to node under $to 
     967# Returns: 
     968# - Success: $to 
     969# - Failure: undef 
     970sub munin_copy_node_toloc 
     971
     972    my $from = shift; 
     973    my $to   = shift; 
     974    my $loc  = shift; 
     975 
     976    return undef unless defined $from and defined $to and defined $loc; 
     977 
     978    if (ref ($from) eq "HASH") { 
     979        foreach my $key (keys %$from) { 
     980            if (ref ($from->{$key}) eq "HASH") { 
     981                munin_copy_node_toloc ($from->{$key}, $to, [@$loc, $key]); 
     982            } else { 
     983                munin_set_var_loc ($to, [@$loc, $key], $from->{$key}); 
     984            } 
     985        } 
     986    } else { 
     987        $to = $from; 
     988    } 
     989    return $to; 
     990
     991 
     992# munin_copy_node: Copy hash node 
     993# - $from: Hash node to copy 
     994# - $to: Where to copy it to 
     995# Returns: 
     996# - Success: $to 
     997# - Failure: undef 
     998sub munin_copy_node 
     999
     1000    my $from = shift; 
     1001    my $to   = shift; 
     1002 
     1003    if (ref ($from) eq "HASH") { 
     1004        foreach my $key (keys %$from) { 
     1005            if (ref ($from->{$key}) eq "HASH") { 
     1006                # Easier to do with the other copy function 
     1007                munin_copy_node_toloc ($from->{$key}, $to, [$key]);  
     1008            } else { 
     1009                munin_set_var_loc ($to, [$key], $from->{$key}); 
     1010            } 
     1011        } 
     1012    } else { 
     1013        $to = $from; 
     1014    } 
     1015    return $to; 
    7161016} 
    7171017 
     
    8561156} 
    8571157 
     1158# munin_get_max_label_length: Get the length of the longest labe in a graph 
     1159# Parameters: 
     1160# - $hash: the graph in question 
     1161# - $order: A ref to an array of fields (graph_order) 
     1162# Returns: 
     1163# - Success: The length of the longest label in the graph 
     1164# - Failure: undef 
    8581165sub munin_get_max_label_length 
    8591166{ 
    860     my $node    = shift; 
    861     my $config  = shift; 
    862     my $domain  = shift; 
    863     my $host    = shift; 
    8641167    my $service = shift; 
    8651168    my $order   = shift; 
    8661169    my $result  = 0; 
     1170    my $tot     = munin_get ($service, "graph_total"); 
    8671171 
    8681172    for my $field (@$order) { 
    8691173        my $path = undef; 
    8701174        (my $f = $field) =~ s/=.+//; 
    871         next if (exists $node->{client}->{$service}->{$f.".process"} and 
    872                  $node->{client}->{$service}->{$f.".process"} ne "yes"); 
    873         next if (exists $node->{client}->{$service}->{$f.".skipdraw"}); 
    874         next unless (!exists $node->{client}->{$service}->{$f.".graph"} or 
    875                         $node->{client}->{$service}->{$f.".graph"} eq "yes"); 
    876         if ($result < length ($node->{client}->{$service}->{$f.".label"} || $f)) { 
    877             $result = length ($node->{client}->{$service}->{$f.".label"} || $f); 
    878         } 
    879         if (exists $node->{client}->{$service}->{graph_total} and  
    880                 length $node->{client}->{$service}->{graph_total} > $result) 
    881         { 
    882             $result = length $node->{client}->{$service}->{graph_total}; 
    883         } 
     1175        next if (!munin_get_bool ($service->{$f}, "process", 1)); 
     1176        next if (munin_get_bool ($service->{$f}, "skipdraw", 0)); 
     1177        next if (!munin_get_bool ($service->{$f}, "graph", 1)); 
     1178 
     1179        my $len = length (munin_get ($service->{$f}, "label") || $f); 
     1180 
     1181        if ($result < $len) { 
     1182            $result = $len; 
     1183        } 
     1184    } 
     1185    if (defined $tot and length $tot > $result) { 
     1186        $result = length $tot; 
    8841187    } 
    8851188    return $result; 
    8861189} 
    8871190 
     1191# munin_get_field_order: Get the field order in a graph 
     1192# Parameters: 
     1193# - $hash: A hash ref to the service 
     1194# Returns: 
     1195# - Success: A ref to an array of the field names 
     1196# - Failure: undef 
    8881197sub munin_get_field_order 
    8891198{ 
    890     my $node    = shift; 
    891     my $config  = shift; 
    892     my $domain  = shift; 
    893     my $host    = shift; 
    894     my $service = shift; 
     1199    my $hash = shift; 
    8951200    my $result  = []; 
    8961201 
    897     if ($node->{client}->{$service}->{graph_sources})  
    898     { 
    899         foreach my $gs (split /\s+/, $node->{client}->{$service}->{'graph_sources'}) 
    900         { 
     1202    return undef if !defined $hash or ref($hash) ne "HASH"; 
     1203 
     1204    my $order = munin_get ($hash, "graph_order"); 
     1205 
     1206    if (defined $hash->{graph_sources}) { 
     1207        foreach my $gs (split /\s+/, $hash->{'graph_sources'}) { 
    9011208            push (@$result, "-".$gs); 
    9021209        } 
    9031210    }  
    904     if ($node->{client}->{$service}->{graph_order})  
    905     { 
    906         push (@$result, split /\s+/, $node->{client}->{$service}->{'graph_order'}); 
     1211    if (defined $order) { 
     1212        push (@$result, split /\s+/, $order); 
    9071213    }  
    9081214 
    909     for my $key (keys %{$node->{client}->{$service}})  
    910     { 
    911         my ($client,$type)=""; 
    912         ($client,$type) = split /\./,$key; 
    913         if (defined $type and $type eq "label")  
    914         { 
    915             push @$result,$client if !grep /^\Q$client\E(?:=|$)/, @$result;; 
    916         }  
     1215    for my $fieldnode (@{munin_find_field ($hash, "label")}) { 
     1216        my $fieldname = munin_get_node_name ($fieldnode); 
     1217        push @$result,$fieldname if !grep /^\Q$fieldname\E(?:=|$)/, @$result;; 
    9171218    } 
    9181219     
     
    9201221} 
    9211222 
     1223# munin_get_rrd_filename: Get the name of the rrd file corresponding to a  
     1224#                         field. Checks for lots of bells and whistles. 
     1225#                         This function is the correct one to use when  
     1226#                         figuring out where to fetch data from. 
     1227# Parameters: 
     1228# - $field: The hash object of the field 
     1229# - $path: [optional] The path to the field (as given in graph_order/sum/stack/et al) 
     1230# Returns: 
     1231# - Success: A string with the filename of the rrd file 
     1232# - Failure: undef 
    9221233sub munin_get_rrd_filename { 
    923     my $node    = shift; 
    924     my $config  = shift; 
    925     my $domain  = shift; 
    926     my $name    = shift; 
    927     my $service = shift; 
    9281234    my $field   = shift; 
    9291235    my $path    = shift; 
    930     my $result  = "unknown"; 
    931  
    932     if ($node->{client}->{$service}->{$field.".filename"}) 
    933     { 
    934         $result = $node->{client}->{$service}->{$field.".filename"}; 
    935     } 
    936     elsif ($path) 
    937     { 
    938         if (!defined ($node->{client}->{$service}->{$field.".label"})) 
    939         { 
    940             print "DEBUG: Setting label: $field\n" if $DEBUG; 
    941             $node->{client}->{$service}->{$field.".label"} = $field; 
    942         } 
    943  
    944         if ($path =~ /^\s*([^:;]+)[:;]([^:]+):([^:\.]+)[:\.]([^:\.]+)\s*$/) 
    945         { 
    946             $result = munin_get_filename ($config, $1, $2, $3, $4); 
    947             print "\nDEBUG1: Expanding $path...\n" if $DEBUG; 
    948             if (! defined $node->{client}->{$service}->{$field."label"}) 
    949             { 
    950                 for my $f (@copy_fields) 
    951                 { 
    952                     if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    953                             exists $config->{'domain'}->{$1}->{'node'}->{$2}->{'client'}->{$3}->{"$4.$f"}) 
    954                     { 
    955                         $node->{client}->{$service}->{"$field.$f"} = $config->{'domain'}->{$1}->{'node'}->{$2}->{'client'}->{$3}->{"$4.$f"}; 
    956                     } 
    957                 } 
    958             } 
    959         } 
    960         elsif ($path =~ /^\s*([^:]+):([^:\.]+)[:\.]([^:\.]+)\s*$/) 
    961         { 
    962             print "\nDEBUG2: Expanding $path...\n" if $DEBUG; 
    963             $result = munin_get_filename ($config, $domain, $1, $2, $3); 
    964             for my $f (@copy_fields) 
    965             { 
    966                 if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    967                         exists $config->{'domain'}->{$domain}->{'node'}->{$1}->{'client'}->{$2}->{"$3.$f"}) 
    968                 { 
    969                     print "DEBUG: Copying $f...\n" if $DEBUG; 
    970                     $node->{client}->{$service}->{"$field.$f"} = $config->{'domain'}->{$domain}->{'node'}->{$1}->{'client'}->{$2}->{"$3.$f"}; 
    971                 } 
    972             } 
    973         } 
    974         elsif ($path =~ /^\s*([^:\.]+)[:\.]([^:\.]+)\s*$/) 
    975         { 
    976             print "\nDEBUG3: Expanding $path...\n" if $DEBUG; 
    977             $result = munin_get_filename ($config, $domain, $name, $1, $2); 
    978             for my $f (@copy_fields) 
    979             { 
    980                 if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    981                         exists $node->{client}->{$1}->{"$2.$f"}) 
    982                 { 
    983                     $node->{client}->{$service}->{"$field.$f"} = $node->{client}->{$1}->{"$2.$f"}; 
    984                 } 
    985             } 
    986         } 
    987         elsif ($path =~ /^\s*([^:\.]+)\s*$/) 
    988         { 
    989             print "\nDEBUG4: Expanding $path...\n" if $DEBUG; 
    990             $result = munin_get_filename ($config, $domain, $name, $service, $1); 
    991             for my $f (@copy_fields) 
    992             { 
    993                 if (not exists $node->{client}->{$service}->{"$field.$f"} and 
    994                         exists $node->{client}->{$service}->{"$1.$f"}) 
    995                 { 
    996                     $node->{client}->{$service}->{"$field.$f"} = $node->{client}->{$service}->{"$1.$f"}; 
    997                 } 
    998             } 
    999         } 
    1000     } 
    1001     else 
    1002     { 
    1003         print "\nDEBUG5: Doing path...\n" if $DEBUG; 
    1004         $result = munin_get_filename($config, $domain,$name,$service,$field); 
     1236    my $result  = undef; 
     1237    my $name    = munin_get_node_name ($field); 
     1238 
     1239    # Bail out on bad input data 
     1240    return undef if !defined $field or ref ($field) ne "HASH"; 
     1241 
     1242    # If the field has a .filename setting, use it 
     1243    return $result if $result = munin_get ($field, "filename"); 
     1244 
     1245    # Handle custom paths (used in .sum, .stack, graph_order, et al) 
     1246    if (defined $path and length $path) { 
     1247 
     1248        my $sourcenode = munin_get_node_partialpath ($field, $path); 
     1249        $result = munin_get_filename ($sourcenode); 
     1250 
     1251        for my $f (@COPY_FIELDS) { 
     1252            if (not exists $field->{$f} and exists $sourcenode->{$f}) { 
     1253                print "DEBUG: Copying $f...\n" if $DEBUG; 
     1254                munin_set_var_loc ($field, [$f], $sourcenode->{$f}); 
     1255            } 
     1256        } 
     1257    } else { 
     1258        $result = munin_get_filename ($field); 
    10051259    } 
    10061260    return $result; 
    10071261} 
    10081262 
     1263# munin_mkdir_p: Make directory (and path to it) 
     1264# Parameters: 
     1265# - $dirname: Directory to create 
     1266# - $umask: Umask (in addition to the user umask) 
     1267# Returns: 
     1268# - Success: $dirname 
     1269# - Failure: undef 
     1270sub munin_mkdir_p 
     1271{ 
     1272    my $dirname = shift; 
     1273    my $umask   = shift; 
     1274 
     1275    return $dirname if (-e $dirname); 
     1276 
     1277 
     1278    ::logger ("Notice: Created directory \"$dirname\"."); 
     1279    (my $prev = $dirname) =~ s/\/[^\/]+\/?$//; 
     1280    if (munin_mkdir_p ($prev, $umask)) { 
     1281        if (mkdir ($dirname, $umask)) { 
     1282            return $dirname; 
     1283        } else { 
     1284            return undef; 
     1285        } 
     1286    } else { 
     1287        return undef; 
     1288    } 
     1289} 
     1290 
    10091291 
    101012921; 
  • people/jo/multilevel-groups-2/server/munin-graph.in

    r1214 r1344  
    3030use Getopt::Long; 
    3131use Time::HiRes; 
     32use Data::Dumper qw(Dumper); 
    3233 
    3334my $graph_time= Time::HiRes::time; 
     
    185186        ); 
    186187 
    187 for my $key ( keys %{$config->{domain}}) { 
    188     my $domain_time= Time::HiRes::time; 
    189     mkdir "$config->{htmldir}/$key",0777; 
    190     logger("Processing domain: $key"); 
    191     &process_domain($key); 
    192     $domain_time = sprintf ("%.2f",(Time::HiRes::time - $domain_time)); 
    193     logger("Processed domain: $key ($domain_time sec)"); 
    194     print STATS "GD|$key|$domain_time\n" unless $skip_stats; 
    195 
    196  
     188# Make array of what is probably needed to graph 
     189my $work_array = []; 
     190if (@limit_hosts) { # Limit what to update if needed 
     191    foreach my $nodename (@limit_hosts) { 
     192        push @$work_array, map { @{munin_find_field ($_->{$nodename}, "graph_title")} } @{munin_find_field($config, $nodename)}; 
     193    } 
     194} else { # ...else just search for all adresses to update 
     195    push @$work_array, @{munin_find_field($config, "graph_title")}; 
     196
     197 
     198 
     199for my $service (@$work_array) { 
     200    process_service ($service); 
     201
    197202 
    198203$graph_time = sprintf ("%.2f",(Time::HiRes::time - $graph_time)); 
     
    203208close $log; 
    204209 
    205 sub process_domain { 
    206     my ($domain) = @_; 
    207     for my $key ( keys %{$config->{domain}->{$domain}->{node}}) { 
    208         my $node_time= Time::HiRes::time; 
    209  
    210         process_node($domain,$key ,$config->{domain}->{$domain}->{node}->{$key} );       
    211         $node_time = sprintf ("%.2f",(Time::HiRes::time - $node_time)); 
    212         logger ("Processed node: $key ($node_time sec)"); 
    213         print STATS "GN|$domain|$key|$node_time\n" unless $skip_stats; 
    214          
    215     } 
    216 } 
    217  
    218210sub get_title { 
    219     my $node    = shift; 
    220211    my $service = shift; 
    221212    my $scale   = shift; 
    222213 
    223     return ($node->{client}->{$service}->{'graph_title'}? 
    224               $node->{client}->{$service}->{'graph_title'}:$service) . 
    225               " - by $scale"; 
     214    return (munin_get ($service, "graph_title", $service) . " - by $scale"); 
    226215} 
    227216 
    228217sub get_custom_graph_args 
    229218{ 
    230     my $node    = shift; 
    231219    my $service = shift; 
    232220    my $result  = []; 
    233221 
    234     if ($node->{client}->{$service}->{graph_args}) { 
    235         push @$result, split /\s/,$node->{client}->{$service}->{graph_args}; 
     222    my $args    = munin_get ($service, "graph_args"); 
     223    if (defined $args) { 
     224        push @$result, split /\s/,$args; 
    236225        return $result; 
    237     } 
    238     else 
    239     { 
     226    } else { 
    240227        return undef; 
    241228    } 
     
    244231sub get_vlabel 
    245232{ 
    246     my $node    = shift; 
    247233    my $service = shift; 
    248     my $scale   = shift; 
    249  
    250     if ($node->{client}->{$service}->{graph_vlabel}) { 
    251         (my $res = $node->{client}->{$service}->{graph_vlabel}) =~ s/\$\{graph_period\}/$scale/g; 
    252         return $res; 
    253     } 
    254     elsif ($node->{client}->{$service}->{graph_vtitle}) 
    255     { 
    256         return $node->{client}->{$service}->{graph_vtitle}; 
    257     } 
    258     return undef; 
     234    my $scale   = munin_get ($service, "graph_period", "second"); 
     235    my $res     = munin_get ($service, "graph_vlabel", munin_get ($service, "graph_vtitle")); 
     236 
     237    if (defined $res) { 
     238        $res =~ s/\$\{graph_period\}/$scale/g; 
     239    } 
     240    return $res; 
    259241} 
    260242 
    261243sub should_scale 
    262244{ 
    263     my $node    = shift; 
    264245    my $service = shift; 
    265  
    266     if (defined $node->{client}->{$service}->{graph_scale}) 
    267     { 
    268         return &munin_get_bool_val ($node->{client}->{$service}->{graph_scale}, 1); 
    269     } 
    270     elsif (defined $node->{client}->{$service}->{graph_noscale}) 
    271     { 
    272         return ! &munin_get_bool_val ($node->{client}->{$service}->{graph_noscale}, 0); 
    273     } 
    274  
    275     return 1; 
     246    my $ret; 
     247 
     248    if (!defined ($ret = munin_get_bool ($service, "graph_scale"))) { 
     249        $ret = !munin_get_bool ($service, "graph_noscale", 0); 
     250    } 
     251 
     252    return $ret; 
    276253} 
    277254 
    278255sub get_header { 
    279     my $node    = shift; 
    280     my $config  = shift; 
    281     my $domain  = shift; 
    282     my $host    = shift; 
    283256    my $service = shift; 
    284257    my $scale   = shift; 
     
    288261 
    289262    # Picture filename 
    290     push @$result, &munin_get_picture_filename ($config, $domain, $host, $service, $scale, $sum||undef); 
     263    push @$result, munin_get_picture_filename ($service, $scale, $sum||undef); 
    291264 
    292265    # Title 
    293     push @$result, ("--title", &get_title ($node, $service, $scale)); 
     266    push @$result, ("--title", get_title ($service, $scale)); 
    294267 
    295268    # When to start the graph 
     
    297270 
    298271    # Custom graph args, vlabel and graph title 
    299     if (defined ($tmp_field = &get_custom_graph_args ($node, $service))) { 
     272    if (defined ($tmp_field = get_custom_graph_args ($service))) { 
    300273        push (@$result, @{$tmp_field}); 
    301274    } 
    302     if (defined ($tmp_field = &get_vlabel ($node, $service, munin_get ($config, "graph_period", "second", $domain, $host, $service)))) { 
     275    if (defined ($tmp_field = get_vlabel ($service))) { 
    303276        push @$result, ("--vertical-label", $tmp_field); 
    304277    } 
    305278 
    306     push @$result,"--height", &munin_get ($config, "graph_height", "175", $domain, $host, $service); 
    307     push @$result,"--width", &munin_get ($config, "graph_width", "400", $domain, $host, $service); 
     279    push @$result,"--height", munin_get ($service, "graph_height", "175"); 
     280    push @$result,"--width", munin_get ($service, "graph_width", "400"); 
    308281    push @$result,"--imgformat", "PNG"; 
    309282    push @$result,"--lazy" if ($force_lazy); 
    310283 
    311     push (@$result, "--units-exponent", "0")  
    312         if (! &should_scale ($node, $service)); 
     284    push (@$result, "--units-exponent", "0") if (! should_scale ($service)); 
    313285 
    314286    return $result; 
     
    317289sub get_sum_command 
    318290{ 
    319     my $node    = shift; 
    320     my $service = shift; 
    321291    my $field   = shift; 
    322292 
    323     if (defined $node->{client}->{$service}->{$field.".special_sum"}) 
    324     { 
    325         return $node->{client}->{$service}->{$field.".special_sum"}; 
    326     } 
    327     elsif (defined $node->{client}->{$service}->{$field.".sum"}) 
    328     { 
    329         return $node->{client}->{$service}->{$field.".sum"}; 
    330     } 
    331  
    332     return undef; 
     293    if (defined $field->{"special_sum"}) { # Deprecated 
     294        return $field->{"special_sum"}; 
     295    } 
     296 
     297    return munin_get ($field, "sum"); 
    333298} 
    334299 
    335300sub get_stack_command 
    336301{ 
    337     my $node    = shift; 
    338     my $service = shift; 
    339302    my $field   = shift; 
    340303 
    341     if (defined $node->{client}->{$service}->{$field.".special_stack"}) 
    342     { 
    343         return $node->{client}->{$service}->{$field.".special_stack"}; 
    344     } 
    345     elsif (defined $node->{client}->{$service}->{$field.".stack"}) 
    346     { 
    347         return $node->{client}->{$service}->{$field.".stack"}; 
    348     } 
    349  
    350     return undef; 
     304    if (defined $field->{"special_stack"}) { # Deprecated 
     305        return $field->{"special_stack"};  
     306    }  
     307     
     308    return munin_get ($field, "stack"); 
    351309} 
    352310 
    353311sub expand_specials 
    354312{ 
    355     my $node    = shift; 
    356     my $config  = shift; 
    357     my $domain  = shift; 
    358     my $host    = shift; 
    359313    my $service = shift; 
    360314    my $preproc = shift; 
     
    365319    my $fieldnum = 0; 
    366320    for my $field (@$order) { # Search for 'specials'... 
    367  
    368         if ($field =~ /^-(.+)$/) 
    369         { 
     321        my $tmp_field; 
     322 
     323        if ($field =~ /^-(.+)$/) { # Invisible field 
    370324            $field = $1; 
    371             unless (defined $node->{client}->{$service}->{$field.".graph"} or 
    372                     defined $node->{client}->{$service}->{$field.".skipdraw"}) 
    373             { 
    374                 $node->{client}->{$service}->{$field.".graph"} = "no"; 
    375             } 
     325            munin_set_var_loc ($service, [$field, "graph"], "no"); 
    376326        } 
    377327 
    378328        $fieldnum++; 
    379         my $tmp_field; 
    380         if (defined ($tmp_field = &get_stack_command ($node, $service, $field))) 
    381         { 
    382             print "DEBUG: Doing special_stack...\n" if $DEBUG; 
     329        if ($field =~ /^([^=]+)=(.+)$/) { # Aliased in graph_order 
     330            my $fname = $1; 
     331            my $spath = $2; 
     332            my $src   = munin_get_node_partialpath ($service, $spath); 
     333            my $sname = munin_get_node_name ($src); 
     334 
     335            next unless defined $src; 
     336            logger ("Debug: Copying settings from $sname to $fname.") if $DEBUG; 
     337 
     338            foreach my $foption ("draw", "type", "rrdfile", "fieldname", "info") { 
     339                if (!defined $service->{$fname}->{$foption}) { 
     340                    if (defined $src->{$foption}) { 
     341                        munin_set_var_loc ($service, [$fname, $foption], $src->{$foption}); 
     342                    } 
     343                } 
     344            } 
     345 
     346            # cdef is special... 
     347            if (!defined $service->{$fname}->{"cdef"}) { 
     348                if (defined $src->{"cdef"}) { 
     349                    (my $tmpcdef = $src->{"cdef"}) =~ s/([,=])$sname([,=]|$)/$1$fname$2/g; 
     350                    munin_set_var_loc ($service, [$fname, "cdef"], $tmpcdef); 
     351                } 
     352            } 
     353             
     354            munin_set_var_loc ($service, [$fname, "label"], $fname); 
     355            munin_set_var_loc ($service, [$fname, "filename"], munin_get_rrd_filename ($src)); 
     356 
     357        } elsif (defined ($tmp_field = get_stack_command ($service->{$field}))) { 
     358            logger ("DEBUG: expand_specials ($tmp_field): Doing stack...") if $DEBUG; 
    383359            my @spc_stack = (); 
    384             foreach my $pre (split (/\s+/, $tmp_field)) 
    385             { 
     360            foreach my $pre (split (/\s+/, $tmp_field)) { 
    386361                (my $name = $pre) =~ s/=.+//; 
    387                 if (!@spc_stack) 
    388                 { 
    389                     $node->{client}->{$service}->{$name.".draw"} = $node->{client}->{$service}->{$field.".draw"}; 
    390                     $node->{client}->{$service}->{$field.".process"} = "no"; 
    391                 } 
    392                 else 
    393                 { 
    394                     $node->{client}->{$service}->{$name.".draw"} = "STACK"; 
     362                if (!@spc_stack) { 
     363                    munin_set_var_loc ($service, [$name, "draw"], munin_get ($service->{$field}, "draw", "LINE2")); 
     364                    munin_set_var_loc ($service, [$field, "process"], "no"); 
     365                } else { 
     366                    munin_set_var_loc ($service, [$name, "draw"], "STACK"); 
    395367                } 
    396368                push (@spc_stack, $name); 
     
    400372                push @$result, "$name.cdef"; 
    401373 
    402                 $node->{client}->{$service}->{$name.".label"} = $name; 
    403                 $node->{client}->{$service}->{$name.".cdef"} = "$name,UN,0,$name,IF"; 
    404                 if (exists $node->{client}->{$service}->{$field.".cdef"} and !exists $node->{client}->{$service}->{$name.".onlynullcdef"}) 
    405                 { 
    406                     print "NotOnlynullcdef ($field)...\n" if $DEBUG; 
    407                     $node->{client}->{$service}->{$name.".cdef"} .= "," . 
    408                         $node->{client}->{$service}->{$field.".cdef"}; 
    409                     $node->{client}->{$service}->{$name.".cdef"} =~ s/\b$field\b/$name/g; 
    410                 } 
    411                 else 
    412                 { 
    413                     print "Onlynullcdef ($field)...\n" if $DEBUG; 
    414                     $node->{client}->{$service}->{$name.".onlynullcdef"} = 1; 
     374                munin_set_var_loc ($service, [$name, "label"], $name); 
     375                munin_set_var_loc ($service, [$name, "cdef"], "$name,UN,0,$name,IF"); 
     376                if (munin_get ($service->{$field}, "cdef") and !munin_get_bool ($service->{$name}, "onlynullcdef", 0)) { 
     377                    logger ("NotOnlynullcdef ($field)...") if $DEBUG; 
     378                    $service->{$name}->{"cdef"} .= "," . $service->{$field}->{"cdef"}; 
     379                    $service->{$name}->{"cdef"} =~ s/\b$field\b/$name/g; 
     380                } else { 
     381                    logger ("Onlynullcdef ($field)...") if $DEBUG; 
     382                    munin_set_var_loc ($service, [$name, "onlynullcdef"], 1); 
    415383                    push @$result, "$name.onlynullcdef"; 
    416384                } 
    417385            } 
    418         } 
    419         elsif (defined ($tmp_field = &get_sum_command ($node, $service, $field))) 
    420         { 
     386        } elsif (defined ($tmp_field = get_sum_command ($service->{$field}))) { 
    421387            my @spc_stack = (); 
    422388            my $last_name = ""; 
    423             print "DEBUG: Doing special_sum...\n" if $DEBUG; 
    424  
    425                 if (@$order == 1 or  
    426                         @$order == 2 && $node->{client}->{$service}->{$field.".negative"})  
    427                 { 
    428                         $single = 1; 
    429                 } 
     389            logger ("DEBUG: expand_specials ($tmp_field): Doing sum...") if $DEBUG; 
     390 
     391            if (@$order == 1 or (@$order == 2 and munin_get {$field, "negative", 0})) { 
     392                    $single = 1; 
     393            } 
    430394                 
    431             foreach my $pre (split (/\s+/, $tmp_field)) 
    432             { 
     395            foreach my $pre (split (/\s+/, $tmp_field)) { 
    433396                (my $path = $pre) =~ s/.+=//; 
    434397                my $name = "z".$fieldnum."_".scalar (@spc_stack); 
    435398                $last_name = $name; 
    436399 
    437                 $node->{client}->{$service}->{$name.".cdef"}  = "$name,UN,0,$name,IF"
    438                 $node->{client}->{$service}->{$name.".graph"} = "no"
    439                 $node->{client}->{$service}->{$name.".label"} = $name
     400                munin_set_var_loc ($service, [$name, "cdef"], "$name,UN,0,$name,IF")
     401                munin_set_var_loc ($service, [$name, "graph"], "no")
     402                munin_set_var_loc ($service, [$name, "label"], $name)
    440403                push @$result, "$name.cdef"; 
    441404                push @$result, "$name.graph"; 
     
    445408                push (@$preproc, "$name=$pre"); 
    446409            } 
    447             $node->{client}->{$service}->{$last_name.".cdef"} .= 
    448                 "," . join (',+,', @spc_stack[0 .. @spc_stack-2]) . ',+'; 
    449             if (exists $node->{client}->{$service}->{$field.".cdef"} and  
    450                     length $node->{client}->{$service}->{$field.".cdef"}) 
    451             { # Oh bugger... 
    452                 my $tc = $node->{client}->{$service}->{$field.".cdef"}; 
     410            $service->{$last_name}->{"cdef"} .= "," . join (',+,', @spc_stack[0 .. @spc_stack-2]) . ',+'; 
     411 
     412            if (my $tc = munin_get ($service->{$field}, "cdef", 0)) { # Oh bugger... 
    453413                print "Oh bugger...($field)...\n" if $DEBUG; 
    454                 $tc =~ s/\b$field\b/$node->{client}->{$service}->{$last_name.".cdef"}/; 
    455                 $node->{client}->{$service}->{$last_name.".cdef"} = $tc; 
    456             } 
    457             $node->{client}->{$service}->{$field.".process"} = "no"; 
    458             $node->{client}->{$service}->{$last_name.".draw"} = $node->{client}->{$service}->{$field.".draw"}; 
    459             $node->{client}->{$service}->{$last_name.".label"} = $node->{client}->{$service}->{$field.".label"}; 
    460             if (defined $node->{client}->{$service}->{$field.".graph"}) 
    461             { 
    462                 $node->{client}->{$service}->{$last_name.".graph"} = $node->{client}->{$service}->{$field.".graph"}; 
    463             } 
    464             else 
    465             { 
    466                 $node->{client}->{$service}->{$last_name.".graph"} = "yes"; 
    467             } 
    468             if (defined $node->{client}->{$service}->{$field.".negative"}) 
    469             { 
    470                 $node->{client}->{$service}->{$last_name.".negative"} = $node->{client}->{$service}->{$field.".negative"};; 
    471             } 
    472             $node->{client}->{$service}->{$field.".realname"} = $last_name; 
    473             print "Setting node->{client}->{$service}->{$field} -> realname = $last_name...\n" if $DEBUG; 
    474         } 
    475         elsif (defined $node->{client}->{$service}->{$field.".negative"}) 
    476         { 
    477             my $nf = $node->{client}->{$service}->{$field.".negative"}; 
    478             unless (defined $node->{client}->{$service}->{$nf.".graph"} or 
    479                     defined $node->{client}->{$service}->{$nf.".skipdraw"}) 
    480             { 
    481                 $node->{client}->{$service}->{$nf.".graph"} = "no"; 
     414                $tc =~ s/\b$field\b/$service->{$last_name}->{"cdef"}/; 
     415                $service->{$last_name}->{"cdef"} = $tc; 
     416            } 
     417            munin_set_var_loc ($service, [$field, "process"], "no"); 
     418            munin_set_var_loc ($service, [$last_name, "draw"], munin_get ($service->{$field}, "draw")); 
     419            munin_set_var_loc ($service, [$last_name, "label"], munin_get ($service->{$field}, "label")); 
     420            munin_set_var_loc ($service, [$last_name, "graph"], munin_get ($service->{$field}, "graph", "yes")); 
     421 
     422            if (my $tmp = munin_get($service->{$field}, "negative")) { 
     423                munin_set_var_loc ($service, [$last_name, "negative"], $tmp); 
     424            } 
     425 
     426            munin_set_var_loc ($service, [$field, "realname"], $last_name); 
     427 
     428        } elsif (my $nf = munin_get ($service->{$field}, "negative", 0)) { 
     429            if (!munin_get_bool ($service->{$nf}, "graph", 1) or munin_get_bool ($service->{$nf}, "skipdraw", 0)) { 
     430                munin_set_var_loc ($service, [$nf, "graph"], "no"); 
    482431            } 
    483432        } 
     
    488437sub single_value 
    489438{ 
    490     my $node    = shift; 
    491     my $config  = shift; 
    492     my $domain  = shift; 
    493     my $host    = shift; 
    494439    my $service = shift; 
    495     my $field   = shift; 
    496     my $order   = shift; 
    497  
    498     return 1 if @$order == 1; 
    499     return 1 if (@$order == 2 and $node->{client}->{$service}->{$field.".negative"}); 
    500  
    501     my $graphable = 0; 
    502     if (!defined $node->{client}->{$service}->{"graphable"}) 
    503     { 
    504 #       foreach my $field (keys %{$node->{client}->{$service}}) 
    505         foreach my $field (&munin_get_field_order ($node, $config, $domain, $host, $service)) 
    506         { 
    507             print "DEBUG: single_value: Checking field \"$field\".\n" if $DEBUG; 
    508             if ($field =~ /^([^\.]+)\.label/ or $field =~ /=/) 
    509             { 
    510                 $graphable++ if &munin_draw_field ($node, $service, $1); 
    511             } 
    512         } 
    513         $node->{client}->{$service}->{"graphable"} = $graphable; 
    514     } 
    515     return 1 if ($node->{client}->{$service}->{"graphable"} == 1); 
    516      
    517     return 0; 
     440 
     441    my $graphable = munin_get ($service, "graphable", 0);; 
     442    if (!$graphable) { 
     443        foreach my $field (@{munin_get_field_order ($service)}) { 
     444            logger ("DEBUG: single_value: Checking field \"$field\"."); 
     445            $graphable++ if munin_draw_field ($service->{$field}); 
     446        } 
     447        munin_set_var_loc ($service, ["graphable"], $graphable); 
     448    } 
     449    logger ("Debug: service ". join (' :: ', @{munin_get_node_loc ($service)}) ." has $graphable elements."); 
     450    return ($graphable == 1); 
    518451} 
    519452 
     
    529462 
    530463sub process_field { 
    531     my $node    = shift; 
    532     my $service = shift; 
    533464    my $field   = shift; 
    534     return (&munin_get_bool_val ($node->{client}->{$service}->{$field.".process"}, 1)); 
    535 
    536  
    537 sub process_node { 
    538     my ($domain,$name,$node) = @_; 
    539  
    540     # See if we should skip it because of command-line arguments 
    541     return if (@limit_hosts and not grep (/^$name$/, @limit_hosts)); 
     465    return munin_get_bool ($field, "process", 1); 
     466
     467 
     468sub process_service { 
     469    my ($service) = @_; 
    542470 
    543471    # Make my graphs 
    544     logger ("Processing $name") if $DEBUG; 
    545     for my $service (keys %{$node->{client}}) { 
    546         my $service_time= Time::HiRes::time; 
    547         my $lastupdate = 0; 
    548         my $now  = time; 
    549         my $fnum = 0; 
    550         my @rrd; 
    551         my @added = (); 
    552  
    553         # See if we should skip the service 
    554         next if (&skip_service ($node, $service)); 
    555  
    556         my $field_count = 0; 
    557         my $max_field_len = 0; 
    558         my @field_order = (); 
    559         my $rrdname; 
    560         my $force_single_value; 
    561  
    562         # munin_set_context($node,$config,$domain,$name,$service); 
    563  
    564         @field_order =  
    565           @{&munin_get_field_order($node, $config, $domain, $name, 
    566                                    $service, \$force_single_value)}; 
    567  
    568         # Array to keep 'preprocess'ed fields. 
    569         my @rrd_preprocess = (); 
    570         print "DEBUG: Expanding specials \"", 
    571           join("\",\"", @field_order), "\".\n" 
    572             if $DEBUG; 
    573  
    574         @added =  
    575           @{&expand_specials ($node, $config, $domain, $name, 
    576                               $service, \@rrd_preprocess, \@field_order)}; 
    577  
    578         @field_order = (@rrd_preprocess, @field_order); 
    579         print "DEBUG: Checking field lengths \"", 
    580           join("\",\"", @rrd_preprocess), "\".\n" 
    581             if $DEBUG; 
    582  
    583         # Get max label length 
    584         $max_field_len = 
    585           &munin_get_max_label_length ($node, $config, $domain, $name, 
    586                                        $service, \@field_order); 
    587         # my $global_headers = ($max_field_len >= 16); 
    588         # Global headers makes the value tables easier to read no matter how 
    589         # wide the labels are. 
    590         my $global_headers = 1; 
    591  
    592         # Default format for printing under graph. 
    593         my $avgformat; 
    594         my $rrdformat=$avgformat="%6.2lf"; 
    595  
    596         if (exists $node->{client}->{$service}->{graph_args} and 
    597             $node->{client}->{$service}->{graph_args} =~ /--base\s+1024/) { 
    598             # If the base unit is 1024 then 1012.56 is a valid 
    599             # number to show.  That's 7 positions, not 6. 
    600             $rrdformat=$avgformat="%7.2lf"; 
    601         } 
    602  
    603         if (exists $node->{client}->{$service}->{graph_printf} ) { 
    604             # Plugin specified complete printf format 
    605             $rrdformat=$node->{client}->{$service}->{graph_printf}; 
    606         } 
    607  
    608         my $rrdscale = ''; 
    609         $rrdscale = '%s' 
    610           if munin_get_bool_val ($node->{client}->{$service}->{graph_scale},1); 
    611  
    612         # Array to keep negative data until we're finished with positive. 
    613         my @rrd_negatives = (); 
    614         my $filename = "unknown"; 
    615         my %total_pos; 
    616         my %total_neg; 
    617         my $autostacking=0; 
    618         print "DEBUG: Treating fields \"", join "\",\"", @field_order, "\".\n" if $DEBUG; 
    619         for my $field (@field_order) { 
    620             my $path  = undef; 
    621             if ($field =~ s/=(.+)//) { 
    622                 $path = $1; 
    623             } 
    624  
    625             next unless &process_field ($node, $service, $field); 
    626             print "DEBUG: Processing field \"$field\".\n" if $DEBUG; 
    627  
    628             my $fielddraw = munin_get ($config, "draw", "LINE2", $domain, 
    629                                        $name, $service, $field); 
    630  
    631             if ($field_count == 0 and $fielddraw eq 'STACK') { 
    632                 # Illegal -- first field is a STACK 
    633                 logger ("ERROR: First field (\"$field\") of graph \"$domain\"". 
    634                         ":: \"$name\" :: \"$service\" is STACK. STACK can ". 
    635                         "only be drawn after a LINEx or AREA."); 
    636                 $fielddraw = "LINE2"; 
    637             } 
    638  
    639             if ($fielddraw eq 'AREASTACK') { 
    640                 if ($autostacking==0) { 
    641                     $fielddraw='AREA'; 
    642                     $autostacking=1; 
    643                 } else { 
    644                     $fielddraw='STACK'; 
    645                 } 
    646             } 
    647  
    648             if ($fielddraw =~ /LINESTACK(\d+(?:.\d+)?)/ ) { 
    649                 if ($autostacking==0) { 
    650                     $fielddraw="LINE$1"; 
    651                     $autostacking=1; 
    652                 } else { 
    653                     $fielddraw='STACK'; 
    654                 } 
    655             } 
    656  
    657             # Getting name of rrd file 
    658             $filename = &munin_get_rrd_filename ($node, $config, $domain, 
    659                                                  $name, $service, $field, 
    660                                                  $path); 
    661  
    662             my $update = RRDs::last ($filename); 
    663             $update = 0 if ! defined $update; 
    664             if ($update > $lastupdate) { 
    665                 $lastupdate = $update; 
    666             } 
    667  
    668             # It does not look like $fieldname.rrdfield is possible to set 
    669             my $rrdfield = ($node->{client}->{$service}->{$field.".rrdfield"} 
    670                             || "42"); 
    671  
    672             my $single_value = $force_single_value || 
    673               &single_value ($node, $config, $domain, $name, 
    674                              $service, $field, \@field_order); 
    675  
    676             my $has_negative = 
    677               exists $node->{client}->{$service}->{$field.".negative"}; 
    678  
    679             # Trim the fieldname to make room for other field names. 
    680             $rrdname = &get_field_name ($field); 
    681             if ($rrdname ne $field) { 
    682                 # A change was made 
    683                 set_cdef_name ($node->{client}->{$service}, $field, $rrdname); 
    684             } 
    685  
    686             push (@rrd, "DEF:g$rrdname=" . 
    687                   $filename . ":" . $rrdfield . ":AVERAGE"); 
    688             push (@rrd, "DEF:i$rrdname=" . 
    689                   $filename . ":" . $rrdfield . ":MIN"); 
    690             push (@rrd, "DEF:a$rrdname=" . 
    691                   $filename . ":" . $rrdfield . ":MAX"); 
    692  
    693             if (exists $node->{client}->{$service}->{$field.".onlynullcdef"} 
    694                 and 
    695                 $node->{client}->{$service}->{$field.".onlynullcdef"}) { 
    696                 push (@rrd, "CDEF:c$rrdname=g$rrdname" . 
    697                       (($now-$update)>900 ? ",POP,UNKN" : "")); 
    698             } 
    699  
    700             if (($node->{client}->{$service}->{$field.".type"}||"GAUGE") 
    701                 ne "GAUGE" 
    702                 and graph_by_minute ($config, $domain, $name, $service)) { 
    703                 push (@rrd, &expand_cdef($node->{client}->{$service}, 
    704                                          \$rrdname, "$field,60,*")); 
    705             } 
    706  
    707             if ($node->{client}->{$service}->{$field.".cdef"}) { 
    708                 push (@rrd,&expand_cdef($node->{client}->{$service}, 
    709                                         \$rrdname, 
    710                                         $node->{client}->{$service}->{$field.".cdef"})); 
    711                 push (@rrd, "CDEF:c$rrdname=g$rrdname"); 
    712                 print "DEBUG: Field name after cdef set to $rrdname\n" if $DEBUG; 
    713             } elsif (!(exists $node->{client}->{$service}->{$field.".onlynullcdef"} 
    714                        and $node->{client}->{$service}->{$field.".onlynullcdef"})) { 
    715                 push (@rrd, "CDEF:c$rrdname=g$rrdname" . (($now-$update)>900 ? ",POP,UNKN" : "")); 
    716             } 
    717  
    718             next unless &munin_draw_field ($node, $service, $field); 
    719             print "DEBUG: Drawing field \"$field\".\n" if $DEBUG; 
     472    my $sname = munin_get_node_name ($service); 
     473    my $service_time= Time::HiRes::time; 
     474    my $lastupdate = 0; 
     475    my $now  = time; 
     476    my $fnum = 0; 
     477    my @rrd; 
     478    my @added = (); 
     479 
     480    # See if we should skip the service 
     481    return if (skip_service ($service)); 
     482 
     483    my $field_count = 0; 
     484    my $max_field_len = 0; 
     485    my @field_order = (); 
     486    my $rrdname; 
     487    my $force_single_value; 
     488 
     489    @field_order = @{munin_get_field_order($service)}; 
     490 
     491    # Array to keep 'preprocess'ed fields. 
     492    my @rrd_preprocess = (); 
     493    logger ("Debug: Expanding specials for $sname: \"" . join("\",\"", @field_order) . "\".") if $DEBUG; 
     494 
     495    @added = @{&expand_specials ($service, \@rrd_preprocess, \@field_order, \$force_single_value)}; 
     496 
     497    @field_order = (@rrd_preprocess, @field_order); 
     498    logger ("DEBUG: Checking field lengths for $sname: \"" . join("\",\"", @rrd_preprocess) . "\".") if $DEBUG; 
     499 
     500    # Get max label length 
     501    $max_field_len = munin_get_max_label_length ($service, \@field_order); 
     502 
     503    # Global headers makes the value tables easier to read no matter how 
     504    # wide the labels are. 
     505    my $global_headers = 1; 
     506 
     507    # Default format for printing under graph. 
     508    my $avgformat; 
     509    my $rrdformat=$avgformat="%6.2lf"; 
     510 
     511    if (munin_get ($service, "graph_args", "") =~ /--base\s+1024/) { 
     512        # If the base unit is 1024 then 1012.56 is a valid 
     513        # number to show.  That's 7 positions, not 6. 
     514        $rrdformat=$avgformat="%7.2lf"; 
     515    } 
     516 
     517    # Plugin specified complete printf format 
     518    $rrdformat = munin_get ($service, "graph_printf", $rrdformat); 
     519 
     520    my $rrdscale = ''; 
     521    if (munin_get_bool ($service, "graph_scale", 1)) { 
     522        $rrdscale = '%s'; 
     523    } 
     524 
     525    # Array to keep negative data until we're finished with positive. 
     526    my @rrd_negatives = (); 
     527 
     528    my $filename = "unknown"; 
     529    my %total_pos; 
     530    my %total_neg; 
     531    my $autostacking=0; 
     532 
     533    logger ("DEBUG: Treating fields \"" . join ("\",\"", @field_order) . "\".") if $DEBUG; 
     534    for my $fname (@field_order) { 
     535        my $path     = undef; 
     536        my $field    = undef; 
     537 
     538        if ($fname =~ s/=(.+)//) { 
     539            $path = $1; 
     540        } 
     541        $field = munin_get_node ($service, [$fname]); 
     542 
     543        next if !process_field ($field); 
     544        logger ("DEBUG: Processing field \"$fname\" [".munin_get_node_name($field)."].") if $DEBUG; 
     545 
     546        my $fielddraw = munin_get ($field, "draw", "LINE2"); 
     547 
     548        if ($field_count == 0 and $fielddraw eq 'STACK') { 
     549            # Illegal -- first field is a STACK 
     550            logger ("ERROR: First field (\"$fname\") of graph " . join (' :: ', munin_get_node_loc ($service)) . 
     551                    " is STACK. STACK can only be drawn after a LINEx or AREA."); 
     552            $fielddraw = "LINE2"; 
     553        } 
     554 
     555        if ($fielddraw eq 'AREASTACK') { 
     556            if ($autostacking==0) { 
     557                $fielddraw='AREA'; 
     558                $autostacking=1; 
     559            } else { 
     560                $fielddraw='STACK'; 
     561            } 
     562        } 
     563 
     564        if ($fielddraw =~ /LINESTACK(\d+(?:.\d+)?)/ ) { 
     565            if ($autostacking==0) { 
     566                $fielddraw="LINE$1"; 
     567                $autostacking=1; 
     568            } else { 
     569                $fielddraw='STACK'; 
     570            } 
     571        } 
     572 
     573        # Getting name of rrd file 
     574        $filename = munin_get_rrd_filename ($field, $path); 
     575 
     576        my $update = RRDs::last ($filename); 
     577        $update = 0 if ! defined $update; 
     578        if ($update > $lastupdate) { 
     579            $lastupdate = $update; 
     580        } 
     581 
     582        # It does not look like $fieldname.rrdfield is possible to set 
     583        my $rrdfield = munin_get ($field, "rrdfield", "42"); 
     584 
     585        my $single_value = $force_single_value || single_value ($service); 
     586 
     587        my $has_negative = munin_get ($field, "negative"); 
     588 
     589        # Trim the fieldname to make room for other field names. 
     590        $rrdname = &get_field_name ($fname); 
     591        if ($rrdname ne $fname) { 
     592            # A change was made 
     593            munin_set_var ($field, "cdef_name", $rrdname); 
     594        } 
     595 
     596        push (@rrd, "DEF:g$rrdname=" . 
     597              $filename . ":" . $rrdfield . ":AVERAGE"); 
     598        push (@rrd, "DEF:i$rrdname=" . 
     599              $filename . ":" . $rrdfield . ":MIN"); 
     600        push (@rrd, "DEF:a$rrdname=" . 
     601              $filename . ":" . $rrdfield . ":MAX"); 
     602 
     603        if (munin_get_bool ($field, "onlynullcdef", 0)) {  
     604            push (@rrd, "CDEF:c$rrdname=g$rrdname" . (($now-$update)>900 ? ",POP,UNKN" : "")); 
     605        } 
     606 
     607        if (munin_get ($field, "type", "GAUGE") ne "GAUGE" and graph_by_minute ($service)) { 
     608                push (@rrd, expand_cdef($service, \$rrdname, "$fname,60,*")); 
     609        } 
     610 
     611        if (my $tmpcdef = munin_get ($field, "cdef")) { 
     612            push (@rrd,expand_cdef($service, \$rrdname, $tmpcdef)); 
     613            push (@rrd, "CDEF:c$rrdname=g$rrdname"); 
     614            logger ("DEBUG: Field name after cdef set to $rrdname") if $DEBUG; 
     615        } elsif (!munin_get_bool ($field, "onlynullcdef", 0)) { 
     616            push (@rrd, "CDEF:c$rrdname=g$rrdname" . (($now-$update)>900 ? ",POP,UNKN" : "")); 
     617        } 
     618 
     619        next if !munin_draw_field ($field); 
     620        logger ("DEBUG: Drawing field \"$fname\".") if $DEBUG; 
     621 
     622        if ($single_value) { 
     623            # Only one field. Do min/max range.  
     624            push (@rrd, "CDEF:min_max_diff=a$rrdname,i$rrdname,-"); 
     625            push (@rrd, "CDEF:re_zero=min_max_diff,min_max_diff,-") if !munin_get ($field, "negative"); 
     626            push (@rrd, "AREA:i$rrdname#ffffff"); 
     627            push (@rrd, "STACK:min_max_diff$range_colour"); 
     628            push (@rrd, "LINE2:re_zero#000000") if !munin_get ($field, "negative"); 
     629        } 
     630 
     631        if ($has_negative and !@rrd_negatives) { # Push "global" headers... 
     632            push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
     633            push (@rrd, "COMMENT:Cur (-/+)"); 
     634            push (@rrd, "COMMENT:Min (-/+)"); 
     635            push (@rrd, "COMMENT:Avg (-/+)"); 
     636            push (@rrd, "COMMENT:Max (-/+) \\j"); 
     637        } elsif ($global_headers == 1) { 
     638            push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
     639            push (@rrd, "COMMENT: Cur$RRDkludge:"); 
     640            push (@rrd, "COMMENT:Min$RRDkludge:"); 
     641            push (@rrd, "COMMENT:Avg$RRDkludge:"); 
     642            push (@rrd, "COMMENT:Max$RRDkludge:  \\j"); 
     643            $global_headers++; 
     644        } 
     645 
     646        my $colour; 
     647 
     648        if (my $tmpcol = munin_get ($field, "colour")) { 
     649            $colour = "#" . $tmpcol; 
     650        } elsif ($single_value) { 
     651            $colour = $single_colour; 
     652        } else { 
     653            $colour = $COLOUR[$field_count%@COLOUR]; 
     654        } 
     655 
     656        $field_count++; 
     657 
     658        my $tmplabel = munin_get ($field, "label", $fname); 
     659 
     660        push (@rrd, $fielddraw . ":g$rrdname" . $colour . ":" . 
     661            escape ($tmplabel) . (" " x ($max_field_len + 1 - length $tmplabel))); 
     662 
     663        # Check for negative fields (typically network (or disk) traffic) 
     664        if ($has_negative) { 
     665            my $negfieldname = orig_to_cdef ($service, munin_get ($field, "negative")); 
     666            my $negfield     = $service->{$negfieldname}; 
     667            if (my $tmpneg = munin_get ($negfield, "realname")) { 
     668                $negfieldname = $tmpneg; 
     669                $negfield     = $service->{$negfieldname}; 
     670            } 
     671             
     672            if (!@rrd_negatives) { 
     673                # zero-line, to redraw zero afterwards. 
     674                push (@rrd_negatives, "CDEF:re_zero=g$negfieldname,UN,0,0,IF"); 
     675            } 
     676 
     677            push (@rrd_negatives, "CDEF:ng$negfieldname=g$negfieldname,-1,*"); 
    720678 
    721679            if ($single_value) { 
    722680                # Only one field. Do min/max range.      
    723                 push (@rrd, "CDEF:min_max_diff=a$rrdname,i$rrdname,-"); 
    724                 push (@rrd, "CDEF:re_zero=min_max_diff,min_max_diff,-")  
    725                     unless ($node->{client}->{$service}->{$field.".negative"}); 
    726                 push (@rrd, "AREA:i$rrdname#ffffff"); 
    727                 push (@rrd, "STACK:min_max_diff$range_colour"); 
    728                 push (@rrd, "LINE2:re_zero#000000") 
    729                     unless ($node->{client}->{$service}->{$field.".negative"}); 
    730             } 
    731  
    732             if ($has_negative and !@rrd_negatives) { # Push "global" headers... 
    733                 push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
    734                 push (@rrd, "COMMENT:Cur (-/+)"); 
    735                 push (@rrd, "COMMENT:Min (-/+)"); 
    736                 push (@rrd, "COMMENT:Avg (-/+)"); 
    737                 push (@rrd, "COMMENT:Max (-/+) \\j"); 
    738             } elsif ($global_headers == 1) { 
    739                 push (@rrd, "COMMENT:" . (" " x $max_field_len)); 
    740                 push (@rrd, "COMMENT: Cur$RRDkludge:"); 
    741                 push (@rrd, "COMMENT:Min$RRDkludge:"); 
    742                 push (@rrd, "COMMENT:Avg$RRDkludge:"); 
    743                 push (@rrd, "COMMENT:Max$RRDkludge:  \\j"); 
    744                 $global_headers++; 
    745             } 
    746  
    747             my $colour; 
    748  
    749             if (exists $node->{client}->{$service}->{$field.".colour"}) { 
    750                 $colour = "#". 
    751                   $node->{client}->{$service}->{$field.".colour"}; 
    752             } elsif ($single_value) { 
    753                 $colour = $single_colour; 
    754             } else { 
    755                 $colour = $COLOUR[$field_count%@COLOUR]; 
    756             } 
    757  
    758             $field_count++; 
    759  
    760             push (@rrd, $fielddraw . ":g$rrdname" . $colour . ":" . 
    761                   (escape ($node->{client}->{$service}->{"$field.label"}) || escape ($field)) 
    762                   . (" " x ($max_field_len + 1 - 
    763                             length ($node->{client}->{$service}->{"$field.label"} || $field)))); 
    764  
    765             # Check for negative fields (typically network (or disk) traffic) 
    766             if ($has_negative) { 
    767                 my $negfield = &orig_to_cdef ($node->{client}->{$service}, $node->{client}->{$service}->{$field.".negative"}); 
    768                 print "DEBUG: negfield = $negfield\n" if $DEBUG; 
    769                 if (exists $node->{client}->{$service}->{$negfield.".realname"}) { 
    770                     $negfield = $node->{client}->{$service}->{$negfield.".realname"}; 
    771                 } 
    772                  
    773                 if (!@rrd_negatives) { 
    774                     # zero-line, to redraw zero afterwards. 
    775                     push (@rrd_negatives, "CDEF:re_zero=g$negfield,UN,0,0,IF"); 
    776                 } 
    777  
    778                 push (@rrd_negatives, "CDEF:ng$negfield=g$negfield,-1,*"); 
    779  
    780                 if ($single_value) { 
    781                     # Only one field. Do min/max range.  
    782                     push (@rrd, "CDEF:neg_min_max_diff=i$negfield,a$negfield,-"); 
    783                     push (@rrd, "CDEF:ni$negfield=i$negfield,-1,*"); 
    784                     push (@rrd, "AREA:ni$negfield#ffffff"); 
    785                     push (@rrd, "STACK:neg_min_max_diff$range_colour"); 
    786                 } 
    787  
    788                 push (@rrd_negatives, $fielddraw . ":ng$negfield" . $colour ); 
    789  
    790                 # Draw HRULEs 
    791                 my $linedef = munin_get ($config, "line", undef, $domain, $name, $service, $node->{client}->{$service}->{$field.".negative"}); 
    792                 if ($linedef) { 
    793                     my ($number, $ldcolour, $label) = split (/:/, $linedef, 3); 
    794                     push (@rrd_negatives, "HRULE:".$number. 
    795                         ($ldcolour ? "#$ldcolour" : $colour)); 
    796  
    797                 } elsif ($node->{client}->{$service}->{"$negfield.warn"}) { 
    798                     push (@rrd_negatives, "HRULE:".$node->{client}->{$service}->{$node->{client}->{$service}->{$field.".negative"}.".warn"}. 
    799                           (defined $single_value and $single_value) ? "#ff0000" : $colour); 
    800                 } 
    801  
    802                 push (@rrd, "GPRINT:c$negfield:LAST:$rrdformat" . $rrdscale . "/\\g"); 
    803                 push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
    804                 push (@rrd, "GPRINT:i$negfield:MIN:$rrdformat" . $rrdscale . "/\\g"); 
    805                 push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
    806                 push (@rrd, "GPRINT:g$negfield:AVERAGE:$avgformat" . $rrdscale . "/\\g"); 
    807                 push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
    808                 push (@rrd, "GPRINT:a$negfield:MAX:$rrdformat" . $rrdscale . "/\\g"); 
    809                 push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
    810                 push (@{$total_pos{'min'}}, "i$rrdname"); 
    811                 push (@{$total_pos{'avg'}}, "g$rrdname"); 
    812                 push (@{$total_pos{'max'}}, "a$rrdname"); 
    813                 push (@{$total_neg{'min'}}, "i$negfield"); 
    814                 push (@{$total_neg{'avg'}}, "g$negfield"); 
    815                 push (@{$total_neg{'max'}}, "a$negfield"); 
    816             } else { 
    817                 push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers; 
    818                 push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
    819                 push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers; 
    820                 push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
    821                 push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers; 
    822                 push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
    823                 push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers; 
    824                 push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
    825                 push (@{$total_pos{'min'}}, "i$rrdname"); 
    826                 push (@{$total_pos{'avg'}}, "g$rrdname"); 
    827                 push (@{$total_pos{'max'}}, "a$rrdname"); 
    828             } 
     681                push (@rrd, "CDEF:neg_min_max_diff=i$negfieldname,a$negfieldname,-"); 
     682                push (@rrd, "CDEF:ni$negfieldname=i$negfieldname,-1,*"); 
     683                push (@rrd, "AREA:ni$negfieldname#ffffff"); 
     684                push (@rrd, "STACK:neg_min_max_diff$range_colour"); 
     685            } 
     686 
     687            push (@rrd_negatives, $fielddraw . ":ng$negfieldname" . $colour ); 
    829688 
    830689            # Draw HRULEs 
    831             my $linedef = munin_get ($config, "line", undef, $domain, $name, $service, $field); 
     690            my $linedef = munin_get ($negfield, "line"); 
    832691            if ($linedef) { 
    833692                my ($number, $ldcolour, $label) = split (/:/, $linedef, 3); 
    834                 $label =~ s/:/\\:/g if defined $label; 
    835                 push (@rrd, "HRULE:".$number. 
    836                     ($ldcolour ? "#$ldcolour" : 
    837                       ((defined $single_value and $single_value) ? 
    838                        "#ff0000" : $colour)). 
    839                       ((defined $label and length ($label)) ? ":$label" : ""), 
    840                       "COMMENT: \\j" 
    841                     ); 
    842             } elsif ($node->{client}->{$service}->{"$field.warn"}) { 
    843                 push (@rrd,"HRULE:". 
    844                       $node->{client}->{$service}->{"$field.warn"}. 
    845                       ($single_value ? "#ff0000" : $colour)); 
    846             } 
    847         } 
    848  
    849         if (@rrd_negatives) { 
    850             push (@rrd, @rrd_negatives); 
    851             push (@rrd, "LINE2:re_zero#000000"); # Redraw zero. 
    852             if (exists $node->{client}->{$service}->{graph_total} and 
    853                 exists $total_pos{'min'} and exists $total_neg{'min'} and 
    854                 @{$total_pos{'min'}} and @{$total_neg{'min'}}) { 
    855  
    856                 push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 
    857                 push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 
    858                 push (@rrd, "CDEF:apostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'max'}}).(",+" x (@{$total_pos{'max'}}-1))); 
    859                 push (@rrd, "CDEF:inegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'min'}}).(",+" x (@{$total_neg{'min'}}-1))); 
    860                 push (@rrd, "CDEF:gnegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'avg'}}).(",+" x (@{$total_neg{'avg'}}-1))); 
    861                 push (@rrd, "CDEF:anegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'max'}}).(",+" x (@{$total_neg{'max'}}-1))); 
    862                 push (@rrd, "CDEF:dpostotal=ipostotal,UN,ipostotal,UNKN,IF"); 
    863                 push (@rrd, "LINE1:dpostotal#000000:" . $node->{client}->{$service}->{graph_total} . (" " x ($max_field_len - length ($node->{client}->{$service}->{graph_total}) + 1))); 
    864                 push (@rrd, "GPRINT:gnegtotal:LAST:$rrdformat" . $rrdscale . "/\\g"); 
    865                 push (@rrd, "GPRINT:gpostotal:LAST:$rrdformat" . $rrdscale . ""); 
    866                 push (@rrd, "GPRINT:inegtotal:MIN:$rrdformat" . $rrdscale . "/\\g"); 
    867                 push (@rrd, "GPRINT:ipostotal:MIN:$rrdformat" . $rrdscale . ""); 
    868                 push (@rrd, "GPRINT:gnegtotal:AVERAGE:$avgformat" . $rrdscale . "/\\g"); 
    869                 push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale . ""); 
    870                 push (@rrd, "GPRINT:anegtotal:MAX:$rrdformat" . $rrdscale . "/\\g"); 
    871                 push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 
    872             } 
    873         } 
    874         elsif (exists $node->{client}->{$service}->{graph_total} and exists $total_pos{'min'} and @{$total_pos{'min'}}) { 
     693                push (@rrd_negatives, "HRULE:".$number. 
     694                    ($ldcolour ? "#$ldcolour" : $colour)); 
     695 
     696            } elsif (my $tmpwarn = munin_get ($negfield, "warn")) { 
     697                push (@rrd_negatives, "HRULE:".$negfieldname. 
     698                    (defined $single_value and $single_value) ? "#ff0000" : $colour); 
     699            } 
     700 
     701            push (@rrd, "GPRINT:c$negfieldname:LAST:$rrdformat" . $rrdscale . "/\\g"); 
     702            push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
     703            push (@rrd, "GPRINT:i$negfieldname:MIN:$rrdformat" . $rrdscale . "/\\g"); 
     704            push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
     705            push (@rrd, "GPRINT:g$negfieldname:AVERAGE:$avgformat" . $rrdscale . "/\\g"); 
     706            push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
     707            push (@rrd, "GPRINT:a$negfieldname:MAX:$rrdformat" . $rrdscale . "/\\g"); 
     708            push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
     709            push (@{$total_pos{'min'}}, "i$rrdname"); 
     710            push (@{$total_pos{'avg'}}, "g$rrdname"); 
     711            push (@{$total_pos{'max'}}, "a$rrdname"); 
     712            push (@{$total_neg{'min'}}, "i$negfieldname"); 
     713            push (@{$total_neg{'avg'}}, "g$negfieldname"); 
     714            push (@{$total_neg{'max'}}, "a$negfieldname"); 
     715        } else { 
     716            push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers; 
     717            push (@rrd, "GPRINT:c$rrdname:LAST:$rrdformat" . $rrdscale . ""); 
     718            push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers; 
     719            push (@rrd, "GPRINT:i$rrdname:MIN:$rrdformat" . $rrdscale . ""); 
     720            push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers; 
     721            push (@rrd, "GPRINT:g$rrdname:AVERAGE:$avgformat" . $rrdscale . ""); 
     722            push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers; 
     723            push (@rrd, "GPRINT:a$rrdname:MAX:$rrdformat" . $rrdscale . "\\j"); 
     724            push (@{$total_pos{'min'}}, "i$rrdname"); 
     725            push (@{$total_pos{'avg'}}, "g$rrdname"); 
     726            push (@{$total_pos{'max'}}, "a$rrdname"); 
     727        } 
     728 
     729        # Draw HRULEs 
     730        my $linedef = munin_get ($field, "line"); 
     731        if ($linedef) { 
     732            my ($number, $ldcolour, $label) = split (/:/, $linedef, 3); 
     733            $label =~ s/:/\\:/g if defined $label; 
     734            push (@rrd, "HRULE:".$number. 
     735                ($ldcolour ? "#$ldcolour" : 
     736                  ((defined $single_value and $single_value) ? 
     737                   "#ff0000" : $colour)). 
     738                  ((defined $label and length ($label)) ? ":$label" : ""), 
     739                  "COMMENT: \\j" 
     740                ); 
     741        } elsif (my $tmpwarn = munin_get ($field, "warn")) { 
     742            push (@rrd,"HRULE:".$tmpwarn.($single_value ? "#ff0000" : $colour)); 
     743        } 
     744    } 
     745 
     746    my $graphtotal = munin_get ($service, "graph_total"); 
     747    if (@rrd_negatives) { 
     748        push (@rrd, @rrd_negatives); 
     749        push (@rrd, "LINE2:re_zero#000000"); # Redraw zero. 
     750        if (defined $graphtotal and exists $total_pos{'min'} and  
     751            exists $total_neg{'min'} and 
     752            @{$total_pos{'min'}} and @{$total_neg{'min'}}) { 
     753 
    875754            push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 
    876755            push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 
    877756            push (@rrd, "CDEF:apostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'max'}}).(",+" x (@{$total_pos{'max'}}-1))); 
    878  
     757            push (@rrd, "CDEF:inegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'min'}}).(",+" x (@{$total_neg{'min'}}-1))); 
     758            push (@rrd, "CDEF:gnegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'avg'}}).(",+" x (@{$total_neg{'avg'}}-1))); 
     759            push (@rrd, "CDEF:anegtotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_neg{'max'}}).(",+" x (@{$total_neg{'max'}}-1))); 
    879760            push (@rrd, "CDEF:dpostotal=ipostotal,UN,ipostotal,UNKN,IF"); 
    880             push (@rrd, "LINE1:dpostotal#000000:" . $node->{client}->{$service}->{graph_total} . (" " x ($max_field_len - length ($node->{client}->{$service}->{graph_total}) + 1))); 
    881             push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers
     761            push (@rrd, "LINE1:dpostotal#000000:$graphtotal" . (" " x ($max_field_len - length ($graphtotal) + 1))); 
     762            push (@rrd, "GPRINT:gnegtotal:LAST:$rrdformat" . $rrdscale . "/\\g")
    882763            push (@rrd, "GPRINT:gpostotal:LAST:$rrdformat" . $rrdscale . ""); 
    883             push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers
     764            push (@rrd, "GPRINT:inegtotal:MIN:$rrdformat" . $rrdscale . "/\\g")
    884765            push (@rrd, "GPRINT:ipostotal:MIN:$rrdformat" . $rrdscale . ""); 
    885             push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers
    886             push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale .""); 
    887             push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers
     766            push (@rrd, "GPRINT:gnegtotal:AVERAGE:$avgformat" . $rrdscale . "/\\g")
     767            push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale . ""); 
     768            push (@rrd, "GPRINT:anegtotal:MAX:$rrdformat" . $rrdscale . "/\\g")
    888769            push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 
    889770        } 
    890  
    891         for my $time (keys %times) { 
    892             next unless ($draw{$time}); 
    893             my @complete = (); 
    894             if ($RRDkludge) { 
    895                 push (@complete, 
    896                       '--font' ,'LEGEND:7:@@LIBDIR@@/VeraMono.ttf', 
    897                       '--font' ,'UNIT:7:@@LIBDIR@@/VeraMono.ttf', 
    898                       '--font' ,'AXIS:7:@@LIBDIR@@/VeraMono.ttf'); 
    899             } 
    900  
    901             logger ("Processing $name -> $time") if $DEBUG; 
    902  
    903             # Do the header (title, vtitle, size, etc...) 
    904             push @complete, @{&get_header ($node, $config, $domain, $name, $service, $time)}; 
    905             if ($LINEkluge) { 
    906                 @rrd = map { s/LINE3:/LINE2.2:/; $_; } @rrd; 
    907                 @rrd = map { s/LINE2:/LINE1.6:/; $_; } @rrd; 
    908                 # LINE1 is thin enough. 
    909             } 
    910             push @complete, @rrd; 
    911  
    912             push (@complete, "COMMENT:Last update$RRDkludge: " .  
    913                   RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
     771    } elsif (defined $graphtotal and exists $total_pos{'min'} and @{$total_pos{'min'}}) { 
     772        push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 
     773        push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 
     774        push (@rrd, "CDEF:apostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'max'}}).(",+" x (@{$total_pos{'max'}}-1))); 
     775 
     776        push (@rrd, "CDEF:dpostotal=ipostotal,UN,ipostotal,UNKN,IF"); 
     777        push (@rrd, "LINE1:dpostotal#000000:$graphtotal" . (" " x ($max_field_len - length ($graphtotal) + 1))); 
     778        push (@rrd, "COMMENT: Cur$RRDkludge:") unless $global_headers; 
     779        push (@rrd, "GPRINT:gpostotal:LAST:$rrdformat" . $rrdscale . ""); 
     780        push (@rrd, "COMMENT: Min$RRDkludge:") unless $global_headers; 
     781        push (@rrd, "GPRINT:ipostotal:MIN:$rrdformat" . $rrdscale . ""); 
     782        push (@rrd, "COMMENT: Avg$RRDkludge:") unless $global_headers; 
     783        push (@rrd, "GPRINT:gpostotal:AVERAGE:$avgformat" . $rrdscale .""); 
     784        push (@rrd, "COMMENT: Max$RRDkludge:") unless $global_headers; 
     785        push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 
     786    } 
     787 
     788    for my $time (keys %times) { 
     789        next unless ($draw{$time}); 
     790        my $picfilename = munin_get_picture_filename ($service, $time); 
     791        (my $picdirname = $picfilename) =~ s/\/[^\/]+$//; 
     792 
     793        my @complete = (); 
     794        if ($RRDkludge) { 
     795            push (@complete, 
     796                  '--font' ,'LEGEND:7:@@LIBDIR@@/VeraMono.ttf', 
     797                  '--font' ,'UNIT:7:@@LIBDIR@@/VeraMono.ttf', 
     798                  '--font' ,'AXIS:7:@@LIBDIR@@/VeraMono.ttf'); 
     799        } 
     800 
     801        # Do the header (title, vtitle, size, etc...) 
     802        push @complete, @{get_header ($service, $time)}; 
     803        if ($LINEkluge) { 
     804            @rrd = map { s/LINE3:/LINE2.2:/; $_; } @rrd; 
     805            @rrd = map { s/LINE2:/LINE1.6:/; $_; } @rrd; 
     806            # LINE1 is thin enough. 
     807        } 
     808        push @complete, @rrd; 
     809 
     810        push (@complete, "COMMENT:Last update$RRDkludge: " .  
     811              RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
     812 
     813        if (time - 300 < $lastupdate) { 
     814            push @complete, "--end", 
     815              (int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
     816        } 
     817        print "\n\nrrdtool \"graph\" \"", 
     818          join ("\"\n\t\"",@complete), "\"\n" if $DEBUG; 
     819 
     820        # Make sure directory exists 
     821        munin_mkdir_p ($picdirname, 0777); 
     822 
     823        RRDs::graph (@complete); 
     824        if (my $ERROR = RRDs::error) { 
     825            logger ("Unable to graph ". munin_get_picture_filename ($service, $time) . ": $ERROR"); 
     826        } elsif ($list_images) { 
     827            # Command-line option to list images created 
     828            print munin_get_picture_filename ($service, $time),"\n"; 
     829        } 
     830    } 
     831 
     832    if (munin_get_bool ($service, "graph_sums", 0)) { 
     833        foreach my $time (keys %sumtimes) { 
     834            my $picfilename = munin_get_picture_filename ($service, $time, 1); 
     835            (my $picdirname = $picfilename) =~ s/\/[^\/]+$//; 
     836            next unless ($draw{"sum".$time}); 
     837            my @rrd_sum; 
     838            push @rrd_sum, @{get_header ($service, $time, 1)}; 
    914839 
    915840            if (time - 300 < $lastupdate) { 
    916                 push @complete, "--end", 
    917                   (int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
    918             } 
    919             print "\n\nrrdtool \"graph\" \"", 
    920               join ("\"\n\t\"",@complete), "\"\n" if $DEBUG; 
    921             RRDs::graph (@complete); 
     841                push @rrd_sum, "--end",(int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
     842            } 
     843            push @rrd_sum, @rrd; 
     844            push (@rrd_sum, "COMMENT:Last update$RRDkludge: " . RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
     845 
     846            my $labelled = 0; 
     847            my @defined = (); 
     848            for (my $index = 0; $index <= $#rrd_sum; $index++) { 
     849                if ($rrd_sum[$index] =~ /^(--vertical-label|-v)$/) { 
     850                    (my $label = munin_get ($service, "graph_vlabel")) =~ s/\$\{graph_period\}/$sumtimes{$time}[0]/g; 
     851                    splice (@rrd_sum, $index, 2, ("--vertical-label", $label)); 
     852                    $index++; 
     853                    $labelled++; 
     854                } elsif ($rrd_sum[$index] =~ /^(LINE[123]|STACK|AREA|GPRINT):([^#:]+)([#:].+)$/) { 
     855                    my ($pre, $fname, $post) = ($1, $2, $3); 
     856                    next if $fname eq "re_zero"; 
     857                    if ($post =~ /^:AVERAGE/) { 
     858                        splice (@rrd_sum, $index, 1, $pre . ":x$fname" . $post); 
     859                        $index++; 
     860                        next; 
     861                    } 
     862                    next if grep /^x$fname$/, @defined; 
     863                    push @defined, "x$fname"; 
     864                    my @replace; 
     865 
     866                    if (munin_get ($service->{$fname}, "type", "GAUGE") ne "GAUGE") { 
     867                        if ($time eq "week") { 
     868                            # Every plot is half an hour. Add two plots and multiply, to get per hour 
     869                            if (graph_by_minute ($service)) { 
     870                                # Already multiplied by 60 
     871                                push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,5,*,6,*"; 
     872                            } else { 
     873                                push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,300,*,6,*"; 
     874                            } 
     875                        } else { 
     876                            # Every plot is one day exactly. Just multiply. 
     877                            if (graph_by_minute ($service)) { 
     878                                # Already multiplied by 60 
     879                                push @replace, "CDEF:x$fname=$fname,5,*,288,*"; 
     880                            } else { 
     881                                push @replace, "CDEF:x$fname=$fname,300,*,288,*"; 
     882                            } 
     883                        } 
     884                    } 
     885                    push @replace, $pre . ":x$fname" . $post; 
     886                    splice (@rrd_sum, $index, 1, @replace); 
     887                    $index++; 
     888                } elsif ($rrd_sum[$index] =~ /^(--lower-limit|--upper-limit|-l|-u)$/) { 
     889                    $index++; 
     890                    $rrd_sum[$index] = $rrd_sum[$index] * 300 * $sumtimes{$time}->[1]; 
     891                } 
     892            } 
     893 
     894            unless ($labelled) { 
     895                my $label = munin_get ($service, "graph_vlabel_sum_$time", $sumtimes{$time}->[0]); 
     896                unshift @rrd_sum, "--vertical-label", $label; 
     897            } 
     898 
     899            print "\n\nrrdtool \"graph\" \"", join ("\"\n\t\"",@rrd_sum), "\"\n" if $DEBUG; 
     900 
     901            # Make sure directory exists 
     902            munin_mkdir_p ($picdirname, 0777); 
     903 
     904            RRDs::graph (@rrd_sum); 
     905 
    922906            if (my $ERROR = RRDs::error) { 
    923                 logger ("Unable to graph $filename: $ERROR"); 
     907                logger ("Unable to graph ". munin_get_picture_filename ($service, $time) . ": $ERROR"); 
    924908            } elsif ($list_images) { 
    925909                # Command-line option to list images created 
    926                 print &munin_get_picture_filename ($config, $domain, $name, 
    927                                                    $service, $time),"\n"; 
    928             } 
    929         } 
    930  
    931         if (&munin_get_bool_val ($node->{client}->{$service}->{"graph_sums"}, 0)) { 
    932             foreach my $time (keys %sumtimes) { 
    933                 next unless ($draw{"sum".$time}); 
    934                 my @rrd_sum; 
    935                 push @rrd_sum, @{&get_header ($node, $config, $domain, $name, $service, $time, 1)}; 
    936  
    937                 if (time - 300 < $lastupdate) { 
    938                     push @rrd_sum, "--end",(int($lastupdate/$resolutions{$time}))*$resolutions{$time}; 
    939                 } 
    940                 push @rrd_sum, @rrd; 
    941                 push (@rrd_sum, "COMMENT:Last update$RRDkludge: " . RRDescape(scalar localtime($lastupdate)) .  "\\r"); 
    942  
    943                 my $labelled = 0; 
    944                 my @defined = (); 
    945                 for (my $index = 0; $index <= $#rrd_sum; $index++) { 
    946                     if ($rrd_sum[$index] =~ /^(--vertical-label|-v)$/) { 
    947                         (my $label = $node->{client}->{$service}->{graph_vlabel}) =~ s/\$\{graph_period\}/$sumtimes{$time}[0]/g; 
    948                         splice (@rrd_sum, $index, 2, ("--vertical-label", $label)); 
    949                         $index++; 
    950                         $labelled++; 
    951                     } elsif ($rrd_sum[$index] =~ /^(LINE[123]|STACK|AREA|GPRINT):([^#:]+)([#:].+)$/) { 
    952                         my ($pre, $fname, $post) = ($1, $2, $3); 
    953                         next if $fname eq "re_zero"; 
    954                         if ($post =~ /^:AVERAGE/) { 
    955                             splice (@rrd_sum, $index, 1, $pre . ":x$fname" . $post); 
    956                             $index++; 
    957                             next; 
    958                         } 
    959                         next if grep /^x$fname$/, @defined; 
    960                         push @defined, "x$fname"; 
    961                         my @replace; 
    962  
    963                         if (!defined ($node->{client}->{$service}->{$fname.".type"}) or 
    964                             $node->{client}->{$service}->{$fname.".type"} ne "GAUGE") { 
    965                             if ($time eq "week") { 
    966                                 # Every plot is half an hour. Add two plots and multiply, to get per hour 
    967                                 if (graph_by_minute ($config, $domain, $name, $service)) { 
    968                                     # Already multiplied by 60 
    969                                     push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,5,*,6,*"; 
    970                                 } else { 
    971                                     push @replace, "CDEF:x$fname=PREV($fname),UN,0,PREV($fname),IF,$fname,+,300,*,6,*"; 
    972                                 } 
    973                             } else { 
    974                                 # Every plot is one day exactly. Just multiply. 
    975                                 if (graph_by_minute ($config, $domain, $name, $service)) { 
    976                                     # Already multiplied by 60 
    977                                     push @replace, "CDEF:x$fname=$fname,5,*,288,*"; 
    978                                 } else { 
    979                                     push @replace, "CDEF:x$fname=$fname,300,*,288,*"; 
    980                                 } 
    981                             } 
    982                         } 
    983                         push @replace, $pre . ":x$fname" . $post; 
    984                         splice (@rrd_sum, $index, 1, @replace); 
    985                         $index++; 
    986                     } elsif ($rrd_sum[$index] =~ /^(--lower-limit|--upper-limit|-l|-u)$/) { 
    987                         $index++; 
    988                         $rrd_sum[$index] = $rrd_sum[$index] * 300 * $sumtimes{$time}->[1]; 
    989                     } 
    990                 } 
    991  
    992                 unless ($labelled) { 
    993                     my $label = $node->{client}->{$service}->{"graph_vlabel_sum_$time"} || $sumtimes{$time}->[0]; 
    994                     unshift @rrd_sum, "--vertical-label", $label; 
    995                 } 
    996  
    997                 print "\n\nrrdtool \"graph\" \"", join ("\"\n\t\"",@rrd_sum), "\"\n" if $DEBUG; 
    998                 RRDs::graph (@rrd_sum); 
    999  
    1000                 if (my $ERROR = RRDs::error) { 
    1001                     logger ("Unable to graph $filename: $ERROR"); 
    1002                 } elsif ($list_images) { 
    1003                     # Command-line option to list images created 
    1004                     print &munin_get_picture_filename ($config, $domain, $name, $service, $time, 1), "\n"; 
    1005                 } 
    1006             } 
    1007         } 
    1008  
    1009         $service_time = sprintf ("%.2f",(Time::HiRes::time - $service_time)); 
    1010         logger ("Graphed service : $service ($service_time sec * 4)"); 
    1011         print STATS "GS|$domain|$name|$service|$service_time\n" unless $skip_stats; 
    1012  
    1013         foreach (@added) { 
    1014             delete $node->{client}->{$service}->{$_} 
    1015               if exists $node->{client}->{$service}->{$_}; 
    1016         } 
    1017         @added = (); 
    1018     } 
     910                print munin_get_picture_filename ($service, $time, 1),"\n"; 
     911            } 
     912        } 
     913    } 
     914 
     915    $service_time = sprintf ("%.2f",(Time::HiRes::time - $service_time)); 
     916    logger ("Graphed service : $sname ($service_time sec * 4)"); 
     917    print STATS "GS|$service_time\n" unless $skip_stats; 
     918 
     919    print "Final look of service subtree: ", Dumper (munin_get_separated_node ($service)), "\n\n"; 
     920    foreach (@added) { 
     921        delete $service->{$_} if exists $service->{$_}; 
     922    } 
     923    @added = (); 
    1019924} 
    1020925 
    1021926sub graph_by_minute { 
    1022     my $config  = shift; 
    1023     my $domain  = shift; 
    1024     my $name    = shift; 
    1025927    my $service = shift; 
    1026928 
    1027     return (munin_get ($config, "graph_period", "second", $domain, $name, $service) eq "minute"); 
     929    return (munin_get ($service, "graph_period", "second") eq "minute"); 
    1028930} 
    1029931 
    1030932sub orig_to_cdef { 
     933    my $service   = shift; 
     934    my $fieldname = shift; 
     935 
     936    return undef unless ref ($service) eq "HASH"; 
     937 
     938    if (defined $service->{$fieldname}->{"cdef_name"}) { 
     939        return orig_to_cdef ($service, $service->{$fieldname}->{"cdef_name"}); 
     940    } 
     941    return $fieldname; 
     942} 
     943 
     944sub skip_service { 
    1031945    my $service = shift; 
    1032     my $field   = shift; 
    1033  
    1034     if (defined $service->{$field.".cdef_name"}) 
    1035     { 
    1036         return &orig_to_cdef ($service, $service->{$field.".cdef_name"}); 
    1037     } 
    1038     return $field; 
    1039 
    1040  
    1041 sub set_cdef_name { 
    1042     my $service = shift; 
    1043     my $field   = shift; 
    1044     my $new     = shift; 
    1045  
    1046     $service->{$field.".cdef_name"} = $new; 
    1047     print "DEBUG: set_cdef_name from $field to $new.\n" if $DEBUG; 
    1048 
    1049  
    1050 sub skip_service { 
    1051     my $node = shift; 
    1052     my $service = shift; 
    1053  
    1054     # Check to make sure that service exists 
    1055     return 1 unless (ref $node->{client}->{$service}); 
     946    my $sname   = munin_get_node_name ($service); 
     947 
     948    # Skip if we've limited services with cli options 
     949    return 1 if (@limit_services and !grep /^$sname$/, @limit_services); 
     950 
     951    # Always graph if --force is present 
     952    return 0 if $force_graphing; 
    1056953 
    1057954    # See if we should skip it because of conf-options 
    1058     return 1 if ($node->{client}->{$service}->{'graph'} and  
    1059         ($node->{client}->{$service}->{'graph'} eq "no" || 
    1060         ($node->{client}->{$service}->{'graph'} eq "on-demand") && !$force_graphing)); 
    1061  
    1062     # See if we should skip it because of command-line arguments 
    1063     return 1 if (@limit_services and not grep (/^$service$/, @limit_services)); 
     955    return 1 if (munin_get ($service, "graph", "yes") eq "on-demand" or 
     956            !munin_get_bool ($service, "graph", 1)); 
    1064957 
    1065958    # Don't skip 
     
    1076969    my ($max, $min, $avg) = ("CDEF:a$new_field=$cdef", "CDEF:i$new_field=$cdef", "CDEF:g$new_field=$cdef"); 
    1077970 
    1078     foreach my $field (keys %$service) 
    1079     { 
    1080         next unless ($field =~ /^(.+)\.label$/); 
    1081         my $fieldname = $1;              
     971    foreach my $field (@{munin_find_field ($service, "label")}) { 
     972        my $fieldname = munin_get_node_name ($field); 
    1082973        my $rrdname = &orig_to_cdef ($service, $fieldname); 
    1083         if ($cdef =~ /\b$fieldname\b/) 
    1084         { 
     974        if ($cdef =~ /\b$fieldname\b/) { 
    1085975                $max =~ s/([,=])$fieldname([,=]|$)/$1a$rrdname$2/g; 
    1086976                $min =~ s/([,=])$fieldname([,=]|$)/$1i$rrdname$2/g; 
     
    1089979    } 
    1090980 
    1091     &set_cdef_name ($service, $$cfield_ref, $new_field); 
     981    munin_set_var_loc ($service, [$$cfield_ref, "cdef_name"], $new_field); 
    1092982    $$cfield_ref = $new_field; 
    1093983 
  • people/jo/multilevel-groups-2/server/munin-update.in

    r1331 r1344  
    3333use POSIX ":sys_wait_h"; 
    3434use Storable qw(fd_retrieve nstore_fd); 
     35use Data::Dumper qw(Dumper); 
    3536 
    3637my $TIMEOUT = 240; 
     
    158159my $bad_procs = 0; 
    159160my $uaddr; 
    160 if ($do_fork) 
    161 
     161 
     162if ($do_fork)
    162163    # Set up socket 
    163164    $uaddr =  sockaddr_un("$config->{rundir}/$serversocket"); 
     
    171172logger("Starting munin-update"); 
    172173 
    173 for my $key (keys %{$config->{domain}}) { 
    174   my $domain_time = Time::HiRes::time; 
    175   logger ("Processing domain: $key"); 
    176   process_domain($key); 
    177   $domain_time = sprintf ("%.2f",(Time::HiRes::time - $domain_time)); 
    178   print STATS "UD|$key|$domain_time\n";  
    179   logger ("Processed domain: $key ($domain_time sec)"); 
    180 
    181  
    182 #sub REAPER { 
    183 #   my $child; 
    184 #   my $waitedpid; 
    185 #   while (($waitedpid = waitpid(-1,WNOHANG)) > 0) { 
    186 #       logger ("reaped $waitedpid" . ($? ? " with exit $?" : '')); 
    187 #   } 
    188 #   $SIG{CHLD} = \&REAPER;  # loathe sysV 
    189 #} 
    190 
    191 #$SIG{CHLD} = \&REAPER; 
    192  
    193 if ($do_fork) 
    194 
    195     my $timeout_start = time(); 
    196     $SIG{ALRM} = sub { die "Timed out waiting for children. $!\n"}; 
    197     alarm ($TIMEOUT); 
    198  
    199     for (;(scalar (keys %children) - $bad_procs > 0);) 
    200     { 
    201             eval { 
    202                 $SIG{ALRM} = sub { 
    203                     foreach my $key (keys %children) 
    204                     { 
    205                         if (waitpid ($key, WNOHANG) != 0) 
    206                         { 
    207                             my $domain  = $children{$key}->[0]; 
    208                             my $name    = $children{$key}->[1]; 
    209                             my $oldnode = $children{$key}->[3]; 
    210  
    211                             logger ("Reaping child: $domain -> $name."); 
    212                             delete $children{$key}; 
    213                             use_old_config ($domain, $name, $oldnode); 
    214                         } 
    215                     } 
    216                     die; 
    217                 }; 
    218  
    219                 alarm (10); 
    220                 accept (Client, Server); 
    221             }; 
    222             alarm ($TIMEOUT - time() + $timeout_start); 
    223             if ($@) 
    224             { 
    225                 if (@queue and defined $config->{max_processes} and 
    226                         $config->{max_processes}) 
    227                 { 
    228                     while (keys %children < ($config->{max_processes}-1-$bad_procs)) 
    229                     { 
    230                         my $args = pop @queue; 
    231                         logger ("de-queueing new connection: $args->[1]"); 
    232                         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); 
    233229                    } 
    234230                } 
    235                 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                } 
    236245            } 
    237             close STDIN; 
    238             open (STDIN,  "<&Client")  || die "can't dup client to stdin"; 
    239              
    240             my $pid; 
    241             my $name; 
    242             my $domain; 
    243             my $tmpref; 
    244                 eval { 
    245                         $tmpref = fd_retrieve (\*STDIN); 
    246                 }; 
    247                 if ($@) 
    248                 { 
    249                         $bad_procs++; 
    250                         logger ("[WARNING] Error communicating with process: $@"); 
    251                 } 
    252                 else 
    253                 { 
    254                         ($pid, $domain, $name) = ($tmpref->[0], $tmpref->[1], $tmpref->[2]); 
    255                         logger ("connection from $domain -> $name ($pid)"); 
    256  
    257                         eval { 
    258                                 $config->{domain}->{$domain}->{node}->{$name} = fd_retrieve (\*STDIN); 
    259                         }; 
    260                         if ($@) 
    261                         { 
    262                                 logger ("[WARNING] Error during fd_retrieve of config: $@"); 
    263  
    264                                 my $domain  = $children{$pid}->[0]; 
    265                                 my $name    = $children{$pid}->[1]; 
    266                                 my $oldnode = $children{$pid}->[3]; 
    267  
    268                                 use_old_config ($domain, $name, $oldnode); 
    269                         } 
    270                         delete $children{$pid}; 
    271                         waitpid ($pid, 0); 
    272                         logger ("connection from $domain -> $name ($pid) closed"); 
    273                 } 
    274             if (@queue and defined $config->{max_processes} and 
    275                     $config->{max_processes} and 
    276                     scalar (keys %children) < (($config->{max_processes})-1-$bad_procs)) 
    277             { 
    278                 my $args = pop @queue; 
    279                 logger ("de-queueing new connection: $args->[1]"); 
    280                 do_node($args->[0], $args->[1], $args->[2], $args->[3]); 
    281                 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); 
    282279            } 
     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        } 
    283290    } 
    284291    alarm (0); 
    285 
     292} else { # No forking, just poll the nodes sequentially... 
     293    for (;@queue;) { 
     294        do_node(@{pop @queue}); 
     295    } 
     296
     297 
     298alarm (0); 
    286299 
    287300if ($bad_procs) # Use old configuration for killed children 
     
    289302        foreach my $key (keys %children) 
    290303        { 
    291                 my $domain  = $children{$key}->[0]; 
    292                 my $name    = $children{$key}->[1]; 
    293                 my $node    = $children{$key}->[2]; 
    294                 my $oldnode = $children{$key}->[3]
    295  
    296                 use_old_config ($domain, $name, $oldnode); 
    297                 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."); 
    298311        } 
    299312} 
    300313 
    301314unlink ("$config->{rundir}/$serversocket"); 
     315 
    302316 
    303317my $overwrite = &munin_readconfig($conffile); 
    304318$config = &munin_overwrite($config,$overwrite); 
    305319 
    306 &compare_configs ($oldconfig, $config); 
     320compare_configs ($oldconfig, $config); 
    307321 
    308322if (&munin_getlock("$config->{rundir}/munin-datafile.lock")) 
     
    330344    my $just_upgraded = 0; 
    331345 
    332     if (!defined $old->{version} or 
    333             $old->{version} ne $VERSION) 
    334     { 
     346    if (!defined $old->{version} or $old->{version} ne $VERSION) { 
    335347        $just_upgraded = 1; 
    336348    } 
    337349 
    338     foreach my $dom (%{$new->{domain}}) 
    339     { 
    340         foreach my $host (%{$new->{domain}->{$dom}->{node}}) 
    341         { 
    342             foreach my $serv (%{$new->{domain}->{$dom}->{node}->{$host}->{client}}) 
    343             { 
    344                 foreach my $field (%{$new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}}) 
    345                 { 
    346                     next unless $field =~ /\.label$/; 
    347                     $field =~ s/\.label$//; 
    348                     if ($just_upgraded or &is_changed ($old, $new, $dom, $host, $serv, $field, "max")) 
    349                     { 
    350                         &change_max ($config, $dom, $host, $serv, $field,  
    351                                 (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".max"} ? 
    352                                  $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".max"} : undef)); 
    353                     } 
    354                     if ($just_upgraded or &is_changed ($old, $new, $dom, $host, $serv, $field, "min")) 
    355                     { 
    356                         &change_min ($config, $dom, $host, $serv, $field,  
    357                                 (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".min"} ? 
    358                                 $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".min"} : undef)); 
    359                     } 
    360                     if ($just_upgraded or &is_changed ($old, $new, $dom, $host, $serv, $field, "type")) 
    361                     { 
    362                         &change_type ($oldconfig, $config, $dom, $host, $serv, $field,  
    363                                 (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".type"} ? 
    364                                 $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".type"} : undef)); 
    365                     } 
    366                 } 
    367             } 
    368         } 
    369     } 
    370  
    371 
    372  
    373 sub is_changed 
    374 
    375     my $old     = shift; 
    376     my $new     = shift; 
    377     my $dom     = shift; 
    378     my $host    = shift; 
    379     my $serv    = shift; 
    380     my $field   = shift; 
    381     my $setting = shift; 
    382  
    383     if (defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) 
    384     { 
    385         if ((!defined $old->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) or 
    386                 ($old->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting} ne 
    387                  $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting} 
    388            )) 
    389         { 
    390             return 1; 
    391         } 
    392     } 
    393  
    394     if (defined $old->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) 
    395     { 
    396         if (!defined $new->{domain}->{$dom}->{node}->{$host}->{client}->{$serv}->{$field.".".$setting}) 
    397         { 
    398             return 1; 
    399         } 
    400     } 
    401  
    402     return 0; 
     350    foreach my $node (@{munin_find_field($new, "label")}) { 
     351        my $oldnode = munin_get_node ($old, munin_get_node_loc ($node)); 
     352        my $name    = munin_get_node_name ($node); 
     353        my ($oldval, $newval); 
     354 
     355        $oldval = munin_get ($oldnode, "max", ""); 
     356        $newval = munin_get ($node, "max", ""); 
     357        if ($just_upgraded or $oldval ne $newval) { 
     358            logger ("Notice: compare_configs: $name.max changed from ".(length $oldval?$oldval:"undefined")." to $newval."); 
     359            change_max (munin_get_filename ($node), $newval); 
     360        } 
     361 
     362        $oldval = munin_get ($oldnode, "min", ""); 
     363        $newval = munin_get ($node, "min", ""); 
     364        if ($just_upgraded or $oldval ne $newval) { 
     365            logger ("Notice: compare_configs: $name.min changed from ".(length $oldval?$oldval:"undefined")." to $newval."); 
     366            change_min (munin_get_filename ($node), $newval); 
     367        } 
     368 
     369        $oldval = munin_get ($oldnode, "type", "GAUGE"); 
     370        $newval = munin_get ($node, "type", "GAUGE"); 
     371        if ($just_upgraded or $oldval ne $newval) { 
     372            logger ("Notice: compare_configs: $name.type changed from ".(length $oldval?$oldval:"undefined")." to $newval."); 
     373            change_type (munin_get_filename ($oldnode), munin_get_filename ($node), $newval); 
     374        } 
     375    } 
    403376} 
    404377 
    405378sub change_type 
    406379{ 
    407     my $oconf  = shift; 
    408     my $nconf  = shift; 
    409     my $domain = shift; 
    410     my $host   = shift; 
    411     my $serv   = shift; 
    412     my $field  = shift; 
     380    my $ofile  = shift; 
     381    my $nfile  = shift; 
    413382    my $val    = shift; 
    414     my $ofile  = &munin_get_filename ($oconf, $domain, $host, $serv, $field); 
    415     my $nfile  = &munin_get_filename ($nconf, $domain, $host, $serv, $field); 
    416  
    417     logger ("[WARNING] Changing type of $domain -> $host -> $serv -> $field to " . (defined $val?$val:"GAUGE") . ".\n"); 
    418     RRDs::tune ($ofile, "-d", "42:".(defined $val?$val:"GAUGE")); 
    419     unless (rename ($ofile, $nfile)) 
    420     { 
    421         logger ("[ERROR] Could not rename file: $!\n"); 
    422     } 
     383 
     384    if (defined $ofile and -f $ofile) { 
     385        logger ("[WARNING]: Changing name of $ofile to $nfile"); 
     386        unless (rename ($ofile, $nfile)) { 
     387            logger ("[ERROR]: Could not rename file: $!\n"); 
     388        } 
     389    } 
     390 
     391    logger ("INFO: Changing type of $nfile to " . (defined $val?$val:"GAUGE")); 
     392    RRDs::tune ($nfile, "-d", "42:".(defined $val?$val:"GAUGE")); 
    423393} 
    424394 
    425395sub change_max 
    426396{ 
    427     my $config = shift; 
    428     my $domain = shift; 
    429     my $host   = shift; 
    430     my $serv   = shift; 
    431     my $field  = shift; 
    432     my $val    = shift; 
    433     my $file   = &munin_get_filename ($config, $domain, $host, $serv, $field); 
    434  
    435     logger ("[WARNING] Changing max of $domain -> $host -> $serv -> $field to " . (defined $val?$val:"undef") . ".\n"); 
     397    my $file  = shift; 
     398    my $val   = shift; 
     399 
     400    logger ("[WARNING]: Changing max of \"$file\" to \"$val\".\n"); 
    436401    RRDs::tune ($file, "-a", "42:".(defined $val?$val:"U")); 
    437402} 
     
    439404sub change_min 
    440405{ 
    441     my $config = shift; 
    442     my $domain = shift; 
    443     my $host   = shift; 
    444     my $serv   = shift; 
    445     my $field  = shift; 
    446     my $val    = shift; 
    447     my $file   = &munin_get_filename ($config, $domain, $host, $serv, $field); 
    448  
    449     logger ("[WARNING] Changing min of $domain -> $host -> $serv -> $field to " . (defined $val?$val:"undef") . ".\n"); 
     406    my $file  = shift; 
     407    my $val   = shift; 
     408 
     409    logger ("[WARNING]: Changing min of \"$file\" to \"$val\".\n"); 
    450410    RRDs::tune ($file, "-i", "42:".(defined $val?$val:"U")); 
    451411} 
    452412 
    453 sub process_domain { 
    454   my ($domain) = @_; 
    455   for my $key ( keys %{$config->{domain}->{$domain}->{node}}) { 
    456     if (@limit_hosts and !grep (/^$key$/, @limit_hosts)) 
    457     { 
    458         logger ("Skipping host \"$key\" - not in hostlist\n") if $DEBUG; 
    459         next; 
    460     } 
    461     if (defined $config->{max_processes} and $config->{max_processes} and  
    462             ($config->{max_processes}-1-$bad_procs) < keys %children) 
    463     { 
    464         push (@queue, [$domain, $key, $config->{domain}->{$domain}->{node}->{$key},$oldconfig->{domain}->{$domain}->{node}->{$key}]); 
    465     } 
    466     else 
    467     { 
    468         do_node($domain,$key ,$config->{domain}->{$domain}->{node}->{$key},$oldconfig->{domain}->{$domain}->{node}->{$key}); 
    469     } 
     413sub do_node { 
     414  my ($loc, $newconf, $oldconf) = @_; 
     415  return undef unless munin_get ($newconf, "update", "true"); # Skip unless we're updating it 
     416  return undef unless munin_get ($newconf, "fetch_data", "true"); # Old name for "update" 
     417 
     418  my $name = munin_get ($newconf, "host_name") || munin_get_node_name ($newconf); 
     419 
     420  unless ($newconf->{"address"}) { 
     421      logger("[ERROR] No address defined for node: $name"); 
     422      return undef; 
    470423  } 
    471 
    472  
    473 sub do_node { 
    474   my ($domain, $name, $config, $oldconfig) = @_; 
    475   my $node_time = Time::HiRes::time; 
    476   logger("Processing node: $name"); 
    477   process_node($domain,$name ,$config,$oldconfig); 
    478   $node_time = sprintf ("%.2f",(Time::HiRes::time - $node_time)); 
    479   print STATS "UN|$domain|$name|$node_time\n";  
    480   logger ("Processed node: $name ($node_time sec)"); 
    481 
    482  
    483 sub process_node { 
    484   my ($domain,$name,$node,$oldnode) = @_; 
    485   return if (exists ($node->{fetch_data}) and !$node->{fetch_data}); 
    486   return if (exists ($node->{update}) and $node->{update} ne "yes"); 
    487   unless ($node->{address}) { 
    488       logger("[ERROR] No address defined for node: $name"); 
    489       return; 
    490   } 
     424  logger ("Debug: do_node: Starting on \"$name\".") if $DEBUG; 
    491425 
    492426  # Then we fork... 
     
    496430      if (!defined($pid))  
    497431      { # Something went wrong 
    498               warn "cannot fork: $!";  
     432              logger ("Error: Unable to fork: $!");  
    499433              return;  
    500434      } elsif ($pid)  
    501435      { # I'm the parent 
    502               $children{$pid} = [$domain, $name, $node, $oldnode]; 
     436              $children{$pid} = [$loc, $newconf, $oldconf]; 
    503437              return;  
    504438      } # else I'm the child -- go spawn 
     
    508442 
    509443  # First we get lock... 
    510   unless (&munin_getlock("$config->{rundir}/munin-$domain-$name.lock")) 
    511   { 
    512     logger ("[ERROR] Could not get lock for $node -> $name. Skipping node."); 
    513     if ($do_fork) 
    514     { # Send the old config to the server before we die 
     444  unless (&munin_getlock(munin_get($newconf, "rundir").$newconf->{"address"}.".lock")) { 
     445    logger ("[ERROR] Could not get lock for \"$name\". Skipping node."); 
     446    if ($do_fork) { # Send the old config to the server before we die 
    515447        socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    516         connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
    517         if (ref $oldnode) { 
    518           $config->{domain}->{$domain}->{node}->{$name} = $oldnode
    519           alarm (0); # Don't want to interrupt this. 
    520           my @tmp = ($$, $domain, $name); 
     448        connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
     449        alarm (0); # Don't want to interrupt this. 
     450        my @tmp = ($$, munin_get_node_loc($newconf), $name)
     451        if (ref $oldconf) { 
     452          copy_node ($oldconf, $newconf); 
    521453          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    522           nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
     454          nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    523455          close SOCK; 
     456        } else { # Well, we'll have to give _something_ to the server, or it'll time out. 
     457          socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
     458          connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
     459          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
     460          nstore_fd ({}, \*SOCK); 
    524461        } 
    525462        exit 1; 
    526     } 
    527     else 
    528     { 
     463    } else { 
    529464        return 0; 
    530465    } 
     
    533468  my $socket; 
    534469   
    535   if (&munin_get ($config, "local_address", undef, $domain, $node)) 
     470  if (munin_get ($newconf, "local_address")) 
    536471  { 
    537       $socket = new IO::Socket::INET ('PeerAddr' => "$node->{address}:". 
    538                   ($node->{port} || $config->{domain}->{$domain}->{port} ||  
    539                    $config->{port} || "4949"),  
    540                    'LocalAddr' => &munin_get ($config, "local_address", undef, $domain, $node), 
    541                   'Proto'    => "tcp", "Timeout" => $timeout); 
     472      $socket = new IO::Socket::INET ('PeerAddr' => "$newconf->{address}:". 
     473                  munin_get ($newconf, "port", "4949"),  
     474                  'LocalAddr' => munin_get ($newconf, "local_address", undef), 
     475                  'Proto'    => "tcp", "Timeout" => munin_get($newconf, "timeout", 60)); 
    542476  } 
    543477  else 
    544478  { 
    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); 
     479      $socket = new IO::Socket::INET ('PeerAddr' => "$newconf->{address}:". 
     480                  munin_get ($newconf, "port", "4949"),  
     481                  'Proto'    => "tcp", "Timeout" => munin_get($newconf, "timeout", 60)); 
    549482  } 
    550483  my $err = ($socket ? "" : $!); 
     
    555488      alarm ($timeout); 
    556489 
    557       my @tmp = ($$, $domain, $name); 
     490      my @tmp = ($$, munin_get_node_loc ($newconf), $name); 
    558491 
    559492      if (!$socket) { 
    560         logger ("[ERROR] Could not connect to $name($node->{address}): $err - Attempting to use old configuration"); 
     493        logger ("[ERROR] Could not connect to $name($newconf->{address}): $err - Attempting to use old configuration"); 
    561494        # If we can't reach the client. Using old Configuration. 
    562         if (ref $oldnode) { 
    563           $config->{domain}->{$domain}->{node}->{$name} = $oldnode
     495        if (ref $oldconf) { 
     496          copy_node ($oldconf, $newconf)
    564497          alarm (0); # Don't want to interrupt this. 
    565498          socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    566           connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     499          connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    567500          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    568           nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
    569           alarm ($timeout); 
     501          nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    570502          close SOCK; 
    571         } 
    572         else 
    573         { # Well, we'll have to give _something_ to the server, or it'll time out. 
     503        } else { # Well, we'll have to give _something_ to the server, or it'll time out. 
    574504          socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    575           connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     505          connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    576506          nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    577507          nstore_fd ({}, \*SOCK); 
     
    579509      } else { 
    580510                my $ctx; 
    581                 if (!&config_node($domain,$name,$node,$oldnode,$socket)) 
    582                 { 
    583                     $config->{domain}->{$domain}->{node}->{$name} = $oldnode; 
     511                if (!config_node($newconf,$oldconf,$socket)) { 
     512                    copy_node ($oldconf, $newconf); 
    584513                    socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    585                     connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     514                    connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    586515                    nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    587                     nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
     516                    nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    588517                    close SOCK; 
    589518                    exit 1; 
    590519                } 
    591                 &fetch_node($domain,$name,$node,$socket); 
     520                &fetch_node($newconf,$oldconf,$socket); 
    592521#               Net::SSLeay::free ($tls) if ($tls); # Shut down TLS 
    593522                close $socket; 
    594523                alarm (0); # Don't want to interrupt this. 
    595524                socket (SOCK, PF_UNIX, SOCK_STREAM, 0)   || die "socket: $!"; 
    596                 connect (SOCK, sockaddr_un ("$config->{rundir}/$serversocket")) || die "connect: $!"; 
     525                connect (SOCK, sockaddr_un (munin_get($newconf, "rundir")."/$serversocket")) || die "connect: $!"; 
    597526                nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 
    598                nstore_fd \%{$config->{domain}->{$domain}->{node}->{$name}}, \*SOCK; 
     527                nstore_fd \%{munin_get_separated_node ($newconf)}, \*SOCK; 
    599528                alarm ($timeout); 
    600529                close SOCK; 
     
    606535  { 
    607536      if (!$socket) { 
    608         logger ("[ERROR] Could not connect to $name($node->{address}): $err\nAttempting to use old configuration"); 
     537        logger ("[ERROR] Could not connect to $name($newconf->{address}): $err\nAttempting to use old configuration"); 
    609538        # If we can't reach the client. Using old Configuration. 
    610         if (ref $oldnode) { 
    611           $config->{domain}->{$domain}->{node}->{$name} = $oldnode
     539        if (ref $oldconf) { 
     540            copy_node ($oldconf, $newconf)
    612541        } 
    613542      } else { 
    614                 next unless (&config_node($domain,$name,$node,$oldnode,$socket)); 
    615                 &fetch_node($domain,$name,$node,$socket); 
     543                next unless (config_node($newconf,$oldconf,$socket)); 
     544                fetch_node($newconf,$oldconf,$socket); 
    616545#               Net::SSLeay::free ($tls) if ($tls); # Shut down TLS 
    617546                close $socket; 
     
    948877} 
    949878 
    950 sub config_node { 
    951   my ($domain,$name,$node,$oldnode,$socket) = @_; 
    952   my $clientdomain = read_socket_single ($socket); 
    953   my $fetchdomain; 
    954   chomp($clientdomain) if $clientdomain; 
    955   if (!$clientdomain) { 
    956       logger("[WARNING] Got unknown reply from client \"$domain\" -> \"name\" skipping"); 
    957       return 0; 
    958   } 
    959   $clientdomain =~ s/\#.*(?:lrrd|munin) (?:client|node) at //; 
    960   if (exists $node->{'use_node_name'} and $node->{'use_node_name'} =~ /^\s*y(?:es)\s*$/i) 
    961   { 
    962       $fetchdomain = $clientdomain; 
    963   } 
    964   elsif (exists $node->{'use_default_name'} and $node->{'use_default_name'} =~ /^\s*y(?:es)\s*$/i) 
    965   { 
    966       $fetchdomain = $clientdomain; 
    967   } 
    968   else 
    969   { 
    970       $fetchdomain = $name; 
    971   } 
    972   my $nodeconf_time = Time::HiRes::time; 
    973  
    974   my $tls_requirement = &munin_get ($config, "tls", "auto", $domain, $name); 
    975   logger ("[DEBUG]: TLS set to \"$tls_requirement\".") if $DEBUG; 
    976   if ($tls_requirement ne "disabled") 
    977   { 
    978       my $key; 
    979       my $cert; 
    980       my $depth; 
    981       my $ca_cert; 
    982       my $tls_verify; 
    983       $key = $cert = munin_get ($config, "tls_pem", undef, $domain, $name); 
    984       $key = &munin_get ($config, "tls_private_key", "@@CONFDIR@@/munin.pem", $domain, $name) 
    985           unless defined $key; 
    986       $cert = &munin_get ($config, "tls_certificate", "@@CONFDIR@@/munin.pem", $domain, $name) 
    987           unless defined $cert; 
    988       $ca_cert = &munin_get ($config, "tls_ca_certificate", "@@CONFDIR@@/cacert.pem", $domain, $name) 
    989           unless defined $ca_cert; 
    990       $tls_verify=&munin_get ($config, "tls_verify_certificate", "no", $domain, $name); 
    991       $depth=&munin_get ($config, "tls_verify_depth", 5, $domain, $name); 
    992  
    993       if (!start_tls ($socket, $tls_requirement, $cert, $key, $ca_cert, $tls_verify, $depth)) 
    994       { 
    995           if ($tls_requirement eq "paranoid" or $tls_requirement eq "enabled") 
    996           { 
    997               logger ("[ERROR] Could not establish TLS connection to \"$domain :: $name\". Skipping."); 
    998               exit 13; 
    999           } 
    1000       } 
    1001   } 
    1002  
    1003   logger("[DEBUG] Configuring node: $name") if $DEBUG; 
    1004   my @services; 
    1005   eval { 
    1006     local $SIG{ALRM} = sub { die "Could not run list on $name ($fetchdomain): $!\n"}; 
    1007     alarm 5; # Should be enough to check the list 
    1008     write_socket_single ($socket, "list $fetchdomain\n"); 
    1009     my $list = read_socket_single ($socket); 
    1010     exit 1 unless defined $list; 
    1011     chomp $list; 
    1012     @services = split / /,$list; 
    1013     alarm 0; 
    1014   }; 
    1015   if ($@) { 
    1016     die unless ($@ =~ m/Could not run list/); 
    1017       logger ("Could not get list from $node->{address}: $!\nAttempting to use old configuration"); 
    1018     if (ref $oldnode) { 
    1019       $config->{domain}->{$domain}->{node}->{$name} = $oldnode; 
    1020     } 
    1021     @services = []; 
    1022   } 
    1023  
    1024   for my $service (@services) { 
    1025     my $servname = $service; 
    1026     my $fields = {}; 
    1027     $servname =~ s/\W/_/g; 
    1028     next if (exists ($node->{client}->{$servname}->{fetch_data}) and 
    1029              $node->{client}->{$servname}->{fetch_data} == 0); 
    1030     next if (exists ($node->{client}->{$servname}->{update}) and  
    1031              $node->{client}->{$servname}->{update} ne "yes"); 
    1032     next if (@limit_services and !grep (/^$servname$/, @limit_services)); 
    1033     my @graph_order = (exists $node->{client}->{$servname}->{graph_order} ?  
    1034                        split (/\s+/, $node->{client}->{$servname}->{graph_order}) : ()); 
    1035     my $serviceconf_time = Time::HiRes::time; 
    1036     if ($servname ne $service) 
    1037     { 
    1038         $node->{client}->{$servname}->{realservname} = $service; 
    1039     } 
    1040     logger("[DEBUG] Configuring service: $name->$servname") if $DEBUG; 
    1041     write_socket_single ($socket, "config $service\n"); 
    1042     my @lines = read_socket($socket); 
    1043     return unless $socket; 
    1044     next unless (@lines); 
    1045     for (@lines) { 
    1046       if (/\# timeout/) { 
    1047         logger("Client reported timeout in configuration of $servname"); 
    1048         if ($oldnode->{client}->{$servname}) { 
    1049           logger("Attempting to use old configuration"); 
    1050           $config->{domain}->{$domain}->{node}->{$name}->{client}->{$servname} = $oldnode->{client}->{$servname}; 
    1051         } else { 
    1052           logger("Skipping configuration of $servname"); 
    1053           delete $node->{client}->{$servname}; 
    1054         } 
    1055       } 
    1056       elsif (/^(\w+)\.(\w+)\s+(.+)/) { 
    1057         my ($client,$type,$value) = ($1,$2,$3); 
    1058         $client = &sanitise_fieldname ($client, $fields); 
    1059         if (($type) and ($type eq "label")) { 
    1060             $value =~ s/\\/_/g; # Sanitise labels 
    1061         } 
    1062         $node->{client}->{$servname}->{$client.".".$type} = "$value"; 
    1063         logger ("[DEBUG] config: $name->$client.$type = $value") if $DEBUG; 
    1064         if (($type) and ($type eq "label")) { 
    1065           push (@graph_order,$client) 
    1066             unless grep (/^$client$/, @graph_order); 
    1067         } 
    1068       } elsif (/(^[^\s\#]+)\s+(.+)/) { 
    1069         my ($keyword) = $1; 
    1070         my ($value) = $2; 
    1071         $node->{client}->{$servname}->{$keyword} = $value; 
    1072         logger ("[DEBUG] Config: $keyword = $value") if $DEBUG; 
    1073         if ($keyword eq "graph_order") { 
    1074           @graph_order = split (/\s+/, $node->{client}->{$servname}->{graph_order}); 
    1075         } 
    1076       } 
    1077     } 
    1078     for my $subservice (keys %{$node->{client}->{$servname}}) { 
    1079       my ($client,$type) = split /\./,$subservice; 
    1080       my ($value) = $node->{client}->{$servname}->{$subservice}; 
    1081       if (($type) and ($type eq "label")) { 
    1082         my $fname = "$config->{dbdir}/$domain/$name-$servname-$client-" .  
    1083             lc substr (($node->{client}->{$servname}->{"$client.type"}||"GAUGE"),0,1). 
    1084             ".rrd"; 
    1085         if (! -f "$fname") { 
    1086           logger ("creating rrd-file for $servname->$subservice"); 
    1087           mkdir "$config->{dbdir}/$domain/",0777; 
    1088           my @args = ("$fname", 
    1089                         "DS:42:".($node->{client}->{$servname}->{"$client.type"} || "GAUGE").":600:". 
    1090                         (defined $node->{client}->{$servname}->{"$client.min"} ?  
    1091                          $node->{client}->{$servname}->{"$client.min"} : 
    1092                          "U") . ":" . ($node->{client}->{$servname}->{"$client.max"} || "U")); 
    1093           my $resolution = &munin_get ($config, "graph_data_size", "normal", $domain, $node, $servname); 
    1094           if ($resolution eq "normal") 
    1095           { 
    1096                 push (@args, 
     879sub config_node  
     880
     881    my ($newconf,$oldconf,$socket) = @_; 
     882    my $clientdomain = read_socket_single ($socket); 
     883    my $fetchdomain; 
     884    my $name = munin_get_node_name ($newconf); 
     885    chomp($clientdomain) if $clientdomain; 
     886    if (!$clientdomain) { 
     887        logger("[WARNING] Got unknown reply from client \"$name\" skipping"); 
     888        return 0; 
     889    } 
     890    $clientdomain =~ s/\#.*(?:lrrd|munin) (?:client|node) at //; 
     891     
     892    # Decide what to ask for 
     893    if (munin_get ($newconf, "use_node_name")) { 
     894        $fetchdomain = $clientdomain; 
     895    } elsif (munin_get ($newconf, "use_default_name")) { 
     896        $fetchdomain = $clientdomain; 
     897    } else { 
     898        $fetchdomain = $name; 
     899    } 
     900 
     901    my $tls_requirement = &munin_get ($config, "tls", "auto"); 
     902    logger ("[DEBUG]: TLS set to \"$tls_requirement\".") if $DEBUG; 
     903    if ($tls_requirement ne "disabled") 
     904    { 
     905        my $key; 
     906        my $cert; 
     907        my $depth; 
     908        my $ca_cert; 
     909        my $tls_verify; 
     910        $key = $cert = munin_get ($config, "tls_pem"); 
     911        $key = &munin_get ($config, "tls_private_key", "@@CONFDIR@@/munin.pem") 
     912          unless defined $key; 
     913        $cert = &munin_get ($config, "tls_certificate", "@@CONFDIR@@/munin.pem") 
     914          unless defined $cert; 
     915        $ca_cert = &munin_get ($config, "tls_ca_certificate", "@@CONFDIR@@/cacert.pem") 
     916           unless defined $ca_cert; 
     917        $tls_verify=&munin_get ($config, "tls_verify_certificate", "no"); 
     918        $depth=&munin_get ($config, "tls_verify_depth", 5); 
     919   
     920        if (!start_tls ($socket, $tls_requirement, $cert, $key, $ca_cert, $tls_verify, $depth)) 
     921        { 
     922          if ($tls_requirement eq "paranoid" or $tls_requirement eq "enabled") 
     923          { 
     924              logger ("[ERROR]: Could not establish TLS connection to \"$name\". Skipping."); 
     925              exit 13; 
     926          } 
     927        } 
     928    } 
     929 
     930    logger("[DEBUG] Configuring node: $name") if $DEBUG; 
     931    my @services; 
     932    eval { 
     933        local $SIG{ALRM} = sub { die "Could not run list on $name ($fetchdomain): $!\n"}; 
     934        alarm 5; # Should be enough to check the list 
     935        write_socket_single ($socket, "list $fetchdomain\n"); 
     936        my $list = read_socket_single ($socket); 
     937        exit 1 unless defined $list; 
     938        chomp $list; 
     939        @services = split / /,$list; 
     940        alarm 0; 
     941    }; 
     942    if ($@) { 
     943        die unless ($@ =~ m/Could not run list/); 
     944        logger ("Error: Could not get list from $newconf->{address}: $!\nAttempting to use old configuration"); 
     945        if (ref $oldconf) { 
     946            copy_node ($oldconf, $newconf); 
     947        } 
     948        @services = []; 
     949    } 
     950 
     951    for my $service (@services) { 
     952        my $servname = $service; 
     953        my $fields = {}; 
     954        $servname =~ s/\W/_/g; 
     955        munin_set_var_loc ($newconf, [$servname, "realservname"], $service); 
     956        logger("[DEBUG] Inspecting possible service: $servname") if $DEBUG; 
     957        next unless (munin_get_bool ($newconf->{$servname}, "update", "true")); 
     958        next unless (munin_get_bool ($newconf->{$servname}, "fetch_data", "true")); 
     959        next if (@limit_services and !grep (/^$servname$/, @limit_services)); 
     960 
     961        my @graph_order = split (/\s+/, munin_get ($newconf->{$service}, "graph_order", "")); 
     962        logger("[DEBUG] Configuring service: $servname") if $DEBUG; 
     963        write_socket_single ($socket, "config $service\n"); 
     964        my @lines = read_socket($socket); 
     965        return unless $socket; 
     966        next unless (@lines); 
     967        for (@lines) { 
     968            if (/\# timeout/) { 
     969                logger("Client reported timeout in configuration of $servname"); 
     970                if ($oldconf->{$servname}) { 
     971                    logger("Attempting to use old configuration"); 
     972                    copy_node ($newconf->{$servname}, $oldconf->{$servname}); 
     973                } else { 
     974                    logger("Skipping configuration of $servname"); 
     975                    delete $newconf->{$servname}; 
     976                } 
     977            } elsif (/^(\w+)\.(\w+)\s+(.+)/) { 
     978                my ($client,$type,$value) = ($1,$2,$3); 
     979                $client = &sanitise_fieldname ($client, $fields); 
     980                if (($type) and ($type eq "label")) { 
     981                    $value =~ s/\\/_/g; # Sanitise labels 
     982                    push (@graph_order,$client) unless grep (/^$client$/, @graph_order); 
     983                } 
     984                munin_set_var_loc ($newconf, [$servname, $client, $type], "$value"); 
     985                logger ("config: $servname->$client.$type = $value") if $DEBUG; 
     986            } elsif (/(^[^\s\#]+)\s+(.+)/) { 
     987                my ($keyword) = $1; 
     988                my ($value) = $2; 
     989                munin_set_var_loc ($newconf, [$servname, $keyword], "$value"); 
     990                logger ("Config: $servname->$keyword = $value") if $DEBUG; 
     991                if ($keyword eq "graph_order") { 
     992                    @graph_order = split (/\s+/, $value); 
     993                } 
     994            } 
     995        } 
     996        for my $field (keys %{$newconf->{$servname}}) { 
     997            # Skip anything that isn't a field 
     998            next if $field =~ /^#%#/; 
     999            next unless (ref ($newconf->{$servname}->{$field}) eq "HASH" and 
     1000                    defined ($newconf->{$servname}->{$field}->{"label"})); 
     1001 
     1002            my $fhash = $newconf->{$servname}->{$field}; 
     1003 
     1004            # Check if file exists 
     1005            my $fname = munin_get_filename ($fhash); 
     1006            (my $dirname = $fname) =~ s/\/[^\/]+$//; 
     1007 
     1008            if (! -f "$fname") { 
     1009                logger ("creating rrd-file for $servname->$field: \"$fname\""); 
     1010                munin_mkdir_p ($dirname, 0777); 
     1011                my @args = ("$fname", 
     1012                        "DS:42:".munin_get($fhash, "type", "GAUGE").":600:". 
     1013                        munin_get($fhash, "min", "U") . ":" .  munin_get($fhash, "max", "U")); 
     1014 
     1015                my $resolution = &munin_get ($fhash, "graph_data_size", "normal"); 
     1016                if ($resolution eq "normal") { 
     1017                    push (@args, 
    10971018                        "RRA:AVERAGE:0.5:1:576", # resolution 5 minutes 
    10981019                        "RRA:MIN:0.5:1:576", 
     
    11071028                        "RRA:MIN:0.5:288:450", 
    11081029                        "RRA:MAX:0.5:288:450"); 
    1109           } 
    1110           elsif ($resolution eq "huge") 
    1111           { 
    1112                 push (@args, "RRA:AVERAGE:0.5:1:115200"); # resolution 5 minutes, for 400 days 
    1113                 push (@args, "RRA:MIN:0.5:1:115200"); # Three times? ARGH! 
    1114                 push (@args, "RRA:MAX:0.5:1:115200"); # Three times? ARGH! 
    1115           } 
    1116           RRDs::create @args; 
    1117           if (my $ERROR = RRDs::error) { 
    1118             logger ("[ERROR] In RRD: unable to create \"$fname\": $ERROR"); 
    1119           } 
    1120         } 
    1121     } 
    1122       $node->{client}->{$servname}->{graph_order} = join(' ',@graph_order); 
    1123     } 
    1124     $serviceconf_time = sprintf ("%.2f",(Time::HiRes::time - $serviceconf_time)); 
    1125     print STATS "CS|$domain|$name|$servname|$serviceconf_time\n"; 
    1126     logger ("Configured service: $name -> $servname ($serviceconf_time sec)"); 
    1127   } 
    1128   $nodeconf_time = sprintf ("%.2f",(Time::HiRes::time - $nodeconf_time)); 
    1129   print STATS "CN|$domain|$name|$nodeconf_time\n"; 
     1030                } elsif ($resolution eq "huge") { 
     1031                    push (@args, "RRA:AVERAGE:0.5:1:115200"); # resolution 5 minutes, for 400 days 
     1032                    push (@args, "RRA:MIN:0.5:1:115200"); # Three times? ARGH! 
     1033                    push (@args, "RRA:MAX:0.5:1:115200"); # Three times? ARGH! 
     1034                } 
     1035                RRDs::create @args; 
     1036                if (my $ERROR = RRDs::error) { 
     1037                    logger ("[ERROR] Unable to create \"$fname\": $ERROR"); 
     1038                } 
     1039            } 
     1040        } 
     1041        munin_set_var_loc ($newconf, [$servname, "graph_order"], join(' ',@graph_order)); 
     1042    } 
    11301043    return 0 unless $socket; 
    1131   logger("Configured node: $name ($nodeconf_time sec)")
    1132   return 1; 
    1133 
    1134  
    1135 sub fetch_node
    1136     my ($domain,$name,$node,$socket) = @_; 
    1137     my $nodefetch_time = Time::HiRes::time
     1044    return 1
     1045
     1046 
     1047sub fetch_node  
     1048
     1049    my ($newconf,$oldconf,$socket) = @_; 
     1050    my $name = munin_get_node_name ($newconf)
    11381051    logger("[DEBUG] Fetching node: $name") if $DEBUG; 
    1139     for my $service (keys %{$node->{client}}) { 
    1140         my $servicefetch_time = Time::HiRes::time
    1141         logger("[DEBUG] Fetching service: $name->$service") if $DEBUG
    1142         next if (exists ($node->{client}->{$service}->{fetch_data}) and  
    1143                 $node->{client}->{$service}->{fetch_data} == 0); 
    1144         next if (exists ($node->{client}->{$service}->{update}) and  
    1145                 $node->{client}->{$service}->{update} ne "yes"); 
     1052    for my $service (keys %{$newconf}) { 
     1053        next if ref ($newconf->{$service}) ne "HASH"
     1054        next if $service =~ /^#%#/
     1055        logger("[DEBUG] Fetching service: $service") if $DEBUG; 
     1056        next unless exists ($newconf->{$service}->{"graph_title"}); 
     1057        next unless (munin_get_bool ($newconf->{$service}, "update", "true")); 
     1058        next unless (munin_get_bool ($newconf->{$service}, "fetch_data", "true")); 
    11461059        next if (@limit_services and !grep (/^$service$/, @limit_services)); 
    1147         my $realservname = ( $node->{client}->{$service}->{realservname} || 
    1148                              $service ); 
    1149         delete $node->{client}->{$service}->{realservname} 
    1150           if exists $node->{client}->{$service}->{realservname}; 
     1060 
     1061        # Read (and get rid of) realservname 
     1062        my $realservname = ( $newconf->{$service}->{"realservname"} || $service ); 
     1063        delete $newconf->{$service}->{"realservname"} 
     1064          if exists $newconf->{$service}->{"realservname"}; 
     1065 
    11511066        write_socket_single ($socket, "fetch $realservname\n"); 
    11521067        my @lines = &read_socket($socket); 
     
    11761091 
    11771092                $key = &sanitise_fieldname ($key, $fields); 
    1178                 if (exists $node->{client}->{$service}->{$key.".label"}) { 
    1179                     my $fname = 
    1180                       "$config->{dbdir}/$domain/$name-$service-$key-". 
    1181                         lc 
    1182                           substr(($node->{client}->{$service}->{$key.".type"}|| 
    1183                                   "GAUGE"),0,1).".rrd"; 
     1093                if (exists $newconf->{$service}->{$key}->{"label"}) { 
     1094                    my $fname = munin_get_filename ($newconf->{$service}->{$key}); 
    11841095 
    11851096                    logger("[DEBUG] Updating $fname with $value") if $DEBUG; 
     
    11891100                    } 
    11901101                } else { 
    1191                     logger ("[ERROR] Unable to update $domain -> $name -> $service -> $key: No such field (no \"label\" field defined when running plugin with \"config\")."); 
     1102                    logger ("[ERROR] Unable to update $name -> $service -> $key: No such field (no \"label\" field defined when running plugin with \"config\")."); 
    11921103                } 
    11931104            } elsif (/(\w+)\.extinfo\s+(.+)/) { 
    1194                 $config->{domain}->{$domain}->{node}->{$name}->{client}->{$service}->{$1.".extinfo"} = $2
     1105                munin_set_var_loc ($newconf, [$service, $service, $1, "extinfo"], $2)
    11951106            } 
    11961107        } 
    1197         $servicefetch_time = sprintf ("%.2f",(Time::HiRes::time - $servicefetch_time)); 
    1198         logger ("Fetched service: $name -> $service ($servicefetch_time sec)"); 
    1199         print STATS "FS|$domain|$name|$service|$servicefetch_time\n"; 
    1200     } 
    1201     $nodefetch_time = sprintf ("%.2f",(Time::HiRes::time - $nodefetch_time)); 
    1202     logger ("Fetched node: $name ($nodefetch_time sec)"); 
    1203     print STATS "FN|$domain|$name|$nodefetch_time\n"; 
    1204  
     1108    } 
    12051109    return 1; 
    1206 } 
    1207  
    1208 sub use_old_config 
    1209 { 
    1210     my $domain  = shift; 
    1211     my $name    = shift; 
    1212     my $oldnode = shift; 
    1213  
    1214     $config->{domain}->{$domain}->{node}->{$name} = $oldnode; 
    1215     logger ("Attempting to use old configuration for $domain -> $name."); 
    12161110} 
    12171111 
     
    12791173} 
    12801174 
     1175sub copy_node 
     1176{ 
     1177    my $from = shift; 
     1178    my $to   = shift; 
     1179     
     1180    if (ref ($from) eq "HASH") { 
     1181        foreach my $key (keys %$from) { 
     1182            next if $key =~ /^#%#/; 
     1183            $to->{$key} = $from->{$key}; 
     1184        } 
     1185    } else { 
     1186        $to = $from; 
     1187    } 
     1188    return $to; 
     1189} 
     1190 
    128111911; 
    12821192 
     
    13681278=head1 COPYRIGHT 
    13691279 
    1370 Copyright © 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 
     1280Copyright © 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 
    13711281 
    13721282This is free software; see the source for copying conditions. There is