Changeset 1344
- Timestamp:
- 14/10/07 20:44:34 (4 years ago)
- Files:
-
- people/jo/multilevel-groups-2/server/Munin.pm.in (modified) (20 diffs)
- people/jo/multilevel-groups-2/server/munin-graph.in (modified) (14 diffs)
- people/jo/multilevel-groups-2/server/munin-update.in (modified) (18 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
people/jo/multilevel-groups-2/server/Munin.pm.in
r1288 r1344 24 24 25 25 use Exporter; 26 use Data::Dumper; 27 26 28 @ISA = ('Exporter'); 27 29 @EXPORT = ('munin_trend', … … 50 52 'munin_get_max_label_length', 51 53 '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' 53 64 ); 54 65 … … 84 95 "version", "tls_certificate", "tls_private_key", "tls_pem", 85 96 "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" 87 99 ); 88 100 … … 90 102 91 103 # Fields to copy when "aliasing" a field 92 my @ copy_fields= ("label", "draw", "type", "rrdfile", "fieldname", "info");104 my @COPY_FIELDS = ("label", "draw", "type", "rrdfile", "fieldname", "info"); 93 105 94 106 … … 111 123 } 112 124 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 113 131 sub 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"}; 123 137 } 124 138 … … 219 233 my ($configfile,$overwrite) = @_; 220 234 for my $key (keys %$overwrite) { 235 next if $key =~ /^#%#/; 221 236 if (ref $overwrite->{$key}) { 222 237 &munin_overwrite($overwrite->{$key},$configfile->{$key}); … … 234 249 $conf ||= $configfile; 235 250 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; 238 253 } 239 254 if (open (CFG, $conf)) … … 246 261 247 262 # 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"; 252 267 $config->{'htmldir'}||= "@@HTMLDIR@@/"; 268 $config->{'#%#parent'}= undef; 269 $config->{'#%#name'}= "root"; 253 270 return ($config); 254 271 } … … 257 274 { 258 275 my $lines = shift; 259 my $hash = undef;276 my $hash = {}; 260 277 my $prefix = ""; 261 278 my $prevline = ""; … … 264 281 { 265 282 chomp $line; 266 #$line =~ s/(^|[^\\])#.*/$1/g if $line =~ /#/; # Skip comments... 267 if ($line =~ /#/) 283 if ($line =~ /#/) # Skip comments... 268 284 { 269 285 next if ($line =~ /^#/); … … 297 313 { 298 314 $prefix = $1; 299 if ($prefix =~ /^([^: ;]+);([^:;]+)$/)315 if ($prefix =~ /^([^:]+);([^:;]+)$/) 300 316 { 301 317 $prefix .= ":"; 302 318 } 303 elsif ($prefix =~ /^([^: ;]+);$/)319 elsif ($prefix =~ /^([^:]+);$/) 304 320 { 305 321 $prefix .= ""; 306 322 } 307 elsif ($prefix =~ /^([^: ;]+);([^:;]+):(.*)$/)323 elsif ($prefix =~ /^([^:]+);([^:;]+):(.*)$/) 308 324 { 309 325 $prefix .= "."; … … 389 405 } 390 406 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 416 sub 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 445 sub 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 471 sub 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 488 sub 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 510 sub 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 534 sub munin_set_var 392 535 { 393 536 my $hash = shift; … … 395 538 my $val = shift; 396 539 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 551 sub 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 583 sub 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 633 sub 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\"."); 459 665 } 460 666 … … 462 668 } 463 669 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 676 sub 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 689 sub 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; 504 703 if ($outstring =~ /\\$/) 505 704 { # Backslash as last char has special meaning. Avoid it. 506 print $fh "$p re$a$outstring\\\n";705 print $fh "$path $outstring\\\n"; 507 706 } else { 508 print $fh "$pre$a $outstring\n"; 509 } 510 } 511 } 512 } 707 print $fh "$path $outstring\n"; 708 } 709 } 710 } 711 } 712 513 713 sub munin_writeconfig { 514 714 my ($datafilename,$data,$fh) = @_; 515 # my $datafile = new Config::General();516 # $datafile->save_file($datafilename,$data);517 715 518 716 if (!defined $fh) … … 528 726 print $fh "version $VERSION\n"; 529 727 # Write datafile 530 &munin_writeconfig_loop ($data, $fh , "");728 &munin_writeconfig_loop ($data, $fh); 531 729 532 730 if (defined $fh) … … 549 747 } 550 748 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 551 757 sub munin_get_picture_filename { 552 my $config = shift; 553 my $domain = shift; 554 my $name = shift; 555 my $service = shift; 758 my $hash = shift; 556 759 my $scale = shift; 557 760 my $sum = shift; 558 my $dir = $config->{'htmldir'}; 761 my $loc = munin_get_node_loc ($hash); 762 my $ret = munin_get ($hash, 'htmldir'); 559 763 560 764 # 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; 565 767 $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 791 sub 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 577 834 sub 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 584 868 sub munin_get_bool 585 869 { 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); 597 875 return undef if not defined $ans; 598 876 … … 602 880 $ans =~ /^enable$/i or 603 881 $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 609 885 $ans =~ /^false$/i or 610 886 $ans =~ /^off$/i or 611 887 $ans =~ /^disable$/i or 612 888 $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; 624 895 } 625 896 } … … 670 941 } 671 942 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 672 951 sub munin_get 673 952 { 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 970 sub 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 998 sub 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; 716 1016 } 717 1017 … … 856 1156 } 857 1157 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 858 1165 sub munin_get_max_label_length 859 1166 { 860 my $node = shift;861 my $config = shift;862 my $domain = shift;863 my $host = shift;864 1167 my $service = shift; 865 1168 my $order = shift; 866 1169 my $result = 0; 1170 my $tot = munin_get ($service, "graph_total"); 867 1171 868 1172 for my $field (@$order) { 869 1173 my $path = undef; 870 1174 (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; 884 1187 } 885 1188 return $result; 886 1189 } 887 1190 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 888 1197 sub munin_get_field_order 889 1198 { 890 my $node = shift; 891 my $config = shift; 892 my $domain = shift; 893 my $host = shift; 894 my $service = shift; 1199 my $hash = shift; 895 1200 my $result = []; 896 1201 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'}) { 901 1208 push (@$result, "-".$gs); 902 1209 } 903 1210 } 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); 907 1213 } 908 1214 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;; 917 1218 } 918 1219 … … 920 1221 } 921 1222 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 922 1233 sub munin_get_rrd_filename { 923 my $node = shift;924 my $config = shift;925 my $domain = shift;926 my $name = shift;927 my $service = shift;928 1234 my $field = shift; 929 1235 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); 1005 1259 } 1006 1260 return $result; 1007 1261 } 1008 1262 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 1270 sub 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 1009 1291 1010 1292 1; people/jo/multilevel-groups-2/server/munin-graph.in
r1214 r1344 30 30 use Getopt::Long; 31 31 use Time::HiRes; 32 use Data::Dumper qw(Dumper); 32 33 33 34 my $graph_time= Time::HiRes::time; … … 185 186 ); 186 187 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 189 my $work_array = []; 190 if (@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 199 for my $service (@$work_array) { 200 process_service ($service); 201 } 197 202 198 203 $graph_time = sprintf ("%.2f",(Time::HiRes::time - $graph_time)); … … 203 208 close $log; 204 209 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 218 210 sub get_title { 219 my $node = shift;220 211 my $service = shift; 221 212 my $scale = shift; 222 213 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"); 226 215 } 227 216 228 217 sub get_custom_graph_args 229 218 { 230 my $node = shift;231 219 my $service = shift; 232 220 my $result = []; 233 221 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; 236 225 return $result; 237 } 238 else 239 { 226 } else { 240 227 return undef; 241 228 } … … 244 231 sub get_vlabel 245 232 { 246 my $node = shift;247 233 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; 259 241 } 260 242 261 243 sub should_scale 262 244 { 263 my $node = shift;264 245 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; 276 253 } 277 254 278 255 sub get_header { 279 my $node = shift;280 my $config = shift;281 my $domain = shift;282 my $host = shift;283 256 my $service = shift; 284 257 my $scale = shift; … … 288 261 289 262 # 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); 291 264 292 265 # Title 293 push @$result, ("--title", &get_title ($node,$service, $scale));266 push @$result, ("--title", get_title ($service, $scale)); 294 267 295 268 # When to start the graph … … 297 270 298 271 # 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))) { 300 273 push (@$result, @{$tmp_field}); 301 274 } 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))) { 303 276 push @$result, ("--vertical-label", $tmp_field); 304 277 } 305 278 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"); 308 281 push @$result,"--imgformat", "PNG"; 309 282 push @$result,"--lazy" if ($force_lazy); 310 283 311 push (@$result, "--units-exponent", "0") 312 if (! &should_scale ($node, $service)); 284 push (@$result, "--units-exponent", "0") if (! should_scale ($service)); 313 285 314 286 return $result; … … 317 289 sub get_sum_command 318 290 { 319 my $node = shift;320 my $service = shift;321 291 my $field = shift; 322 292 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"); 333 298 } 334 299 335 300 sub get_stack_command 336 301 { 337 my $node = shift;338 my $service = shift;339 302 my $field = shift; 340 303 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"); 351 309 } 352 310 353 311 sub expand_specials 354 312 { 355 my $node = shift;356 my $config = shift;357 my $domain = shift;358 my $host = shift;359 313 my $service = shift; 360 314 my $preproc = shift; … … 365 319 my $fieldnum = 0; 366 320 for my $field (@$order) { # Search for 'specials'... 367 368 if ($field =~ /^-(.+)$/) 369 {321 my $tmp_field; 322 323 if ($field =~ /^-(.+)$/) { # Invisible field 370 324 $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"); 376 326 } 377 327 378 328 $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; 383 359 my @spc_stack = (); 384 foreach my $pre (split (/\s+/, $tmp_field)) 385 { 360 foreach my $pre (split (/\s+/, $tmp_field)) { 386 361 (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"); 395 367 } 396 368 push (@spc_stack, $name); … … 400 372 push @$result, "$name.cdef"; 401 373 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); 415 383 push @$result, "$name.onlynullcdef"; 416 384 } 417 385 } 418 } 419 elsif (defined ($tmp_field = &get_sum_command ($node, $service, $field))) 420 { 386 } elsif (defined ($tmp_field = get_sum_command ($service->{$field}))) { 421 387 my @spc_stack = (); 422 388 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 } 430 394 431 foreach my $pre (split (/\s+/, $tmp_field)) 432 { 395 foreach my $pre (split (/\s+/, $tmp_field)) { 433 396 (my $path = $pre) =~ s/.+=//; 434 397 my $name = "z".$fieldnum."_".scalar (@spc_stack); 435 398 $last_name = $name; 436 399 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); 440 403 push @$result, "$name.cdef"; 441 404 push @$result, "$name.graph"; … … 445 408 push (@$preproc, "$name=$pre"); 446 409 } 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... 453 413 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"); 482 431 } 483 432 } … … 488 437 sub single_value 489 438 { 490 my $node = shift;491 my $config = shift;492 my $domain = shift;493 my $host = shift;494 439 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); 518 451 } 519 452 … … 529 462 530 463 sub process_field { 531 my $node = shift;532 my $service = shift;533 464 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 468 sub process_service { 469 my ($service) = @_; 542 470 543 471 # 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,*"); 720 678 721 679 if ($single_value) { 722 680 # 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 ); 829 688 830 689 # Draw HRULEs 831 my $linedef = munin_get ($ config, "line", undef, $domain, $name, $service, $field);690 my $linedef = munin_get ($negfield, "line"); 832 691 if ($linedef) { 833 692 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 875 754 push (@rrd, "CDEF:ipostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'min'}}).(",+" x (@{$total_pos{'min'}}-1))); 876 755 push (@rrd, "CDEF:gpostotal=".join (",", map { "$_,UN,0,$_,IF" } @{$total_pos{'avg'}}).(",+" x (@{$total_pos{'avg'}}-1))); 877 756 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))); 879 760 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"); 882 763 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"); 884 765 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"); 888 769 push (@rrd, "GPRINT:apostotal:MAX:$rrdformat" . $rrdscale . "\\j"); 889 770 } 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)}; 914 839 915 840 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 922 906 if (my $ERROR = RRDs::error) { 923 logger ("Unable to graph $filename: $ERROR");907 logger ("Unable to graph ". munin_get_picture_filename ($service, $time) . ": $ERROR"); 924 908 } elsif ($list_images) { 925 909 # 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 = (); 1019 924 } 1020 925 1021 926 sub graph_by_minute { 1022 my $config = shift;1023 my $domain = shift;1024 my $name = shift;1025 927 my $service = shift; 1026 928 1027 return (munin_get ($ config, "graph_period", "second", $domain, $name, $service) eq "minute");929 return (munin_get ($service, "graph_period", "second") eq "minute"); 1028 930 } 1029 931 1030 932 sub 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 944 sub skip_service { 1031 945 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; 1056 953 1057 954 # 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)); 1064 957 1065 958 # Don't skip … … 1076 969 my ($max, $min, $avg) = ("CDEF:a$new_field=$cdef", "CDEF:i$new_field=$cdef", "CDEF:g$new_field=$cdef"); 1077 970 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); 1082 973 my $rrdname = &orig_to_cdef ($service, $fieldname); 1083 if ($cdef =~ /\b$fieldname\b/) 1084 { 974 if ($cdef =~ /\b$fieldname\b/) { 1085 975 $max =~ s/([,=])$fieldname([,=]|$)/$1a$rrdname$2/g; 1086 976 $min =~ s/([,=])$fieldname([,=]|$)/$1i$rrdname$2/g; … … 1089 979 } 1090 980 1091 &set_cdef_name ($service, $$cfield_ref, $new_field);981 munin_set_var_loc ($service, [$$cfield_ref, "cdef_name"], $new_field); 1092 982 $$cfield_ref = $new_field; 1093 983 people/jo/multilevel-groups-2/server/munin-update.in
r1331 r1344 33 33 use POSIX ":sys_wait_h"; 34 34 use Storable qw(fd_retrieve nstore_fd); 35 use Data::Dumper qw(Dumper); 35 36 36 37 my $TIMEOUT = 240; … … 158 159 my $bad_procs = 0; 159 160 my $uaddr; 160 if ($do_fork) 161 {161 162 if ($do_fork) { 162 163 # Set up socket 163 164 $uaddr = sockaddr_un("$config->{rundir}/$serversocket"); … … 171 172 logger("Starting munin-update"); 172 173 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 175 my $work_array = []; 176 if (@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 185 for 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 200 my $timeout_start = time(); 201 $SIG{ALRM} = sub { die "Timed out waiting for children. $!\n"}; 202 alarm ($TIMEOUT); 203 204 if ($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); 233 229 } 234 230 } 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 } 236 245 } 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); 282 279 } 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 } 283 290 } 284 291 alarm (0); 285 } 292 } else { # No forking, just poll the nodes sequentially... 293 for (;@queue;) { 294 do_node(@{pop @queue}); 295 } 296 } 297 298 alarm (0); 286 299 287 300 if ($bad_procs) # Use old configuration for killed children … … 289 302 foreach my $key (keys %children) 290 303 { 291 my $ domain= $children{$key}->[0];292 my $n ame= $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."); 298 311 } 299 312 } 300 313 301 314 unlink ("$config->{rundir}/$serversocket"); 315 302 316 303 317 my $overwrite = &munin_readconfig($conffile); 304 318 $config = &munin_overwrite($config,$overwrite); 305 319 306 &compare_configs ($oldconfig, $config);320 compare_configs ($oldconfig, $config); 307 321 308 322 if (&munin_getlock("$config->{rundir}/munin-datafile.lock")) … … 330 344 my $just_upgraded = 0; 331 345 332 if (!defined $old->{version} or 333 $old->{version} ne $VERSION) 334 { 346 if (!defined $old->{version} or $old->{version} ne $VERSION) { 335 347 $just_upgraded = 1; 336 348 } 337 349 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 } 403 376 } 404 377 405 378 sub change_type 406 379 { 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; 413 382 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")); 423 393 } 424 394 425 395 sub change_max 426 396 { 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"); 436 401 RRDs::tune ($file, "-a", "42:".(defined $val?$val:"U")); 437 402 } … … 439 404 sub change_min 440 405 { 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"); 450 410 RRDs::tune ($file, "-i", "42:".(defined $val?$val:"U")); 451 411 } 452 412 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 } 413 sub 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; 470 423 } 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; 491 425 492 426 # Then we fork... … … 496 430 if (!defined($pid)) 497 431 { # Something went wrong 498 warn "cannot fork: $!";432 logger ("Error: Unable to fork: $!"); 499 433 return; 500 434 } elsif ($pid) 501 435 { # I'm the parent 502 $children{$pid} = [$ domain, $name, $node, $oldnode];436 $children{$pid} = [$loc, $newconf, $oldconf]; 503 437 return; 504 438 } # else I'm the child -- go spawn … … 508 442 509 443 # 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 515 447 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); 521 453 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; 523 455 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); 524 461 } 525 462 exit 1; 526 } 527 else 528 { 463 } else { 529 464 return 0; 530 465 } … … 533 468 my $socket; 534 469 535 if ( &munin_get ($config, "local_address", undef, $domain, $node))470 if (munin_get ($newconf, "local_address")) 536 471 { 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)); 542 476 } 543 477 else 544 478 { 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)); 549 482 } 550 483 my $err = ($socket ? "" : $!); … … 555 488 alarm ($timeout); 556 489 557 my @tmp = ($$, $domain, $name);490 my @tmp = ($$, munin_get_node_loc ($newconf), $name); 558 491 559 492 if (!$socket) { 560 logger ("[ERROR] Could not connect to $name($n ode->{address}): $err - Attempting to use old configuration");493 logger ("[ERROR] Could not connect to $name($newconf->{address}): $err - Attempting to use old configuration"); 561 494 # If we can't reach the client. Using old Configuration. 562 if (ref $old node) {563 $config->{domain}->{$domain}->{node}->{$name} = $oldnode;495 if (ref $oldconf) { 496 copy_node ($oldconf, $newconf); 564 497 alarm (0); # Don't want to interrupt this. 565 498 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: $!"; 567 500 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; 570 502 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. 574 504 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: $!"; 576 506 nstore_fd \@tmp, \*SOCK || die "Could not nstore_fd: $!"; 577 507 nstore_fd ({}, \*SOCK); … … 579 509 } else { 580 510 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); 584 513 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: $!"; 586 515 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; 588 517 close SOCK; 589 518 exit 1; 590 519 } 591 &fetch_node($ domain,$name,$node,$socket);520 &fetch_node($newconf,$oldconf,$socket); 592 521 # Net::SSLeay::free ($tls) if ($tls); # Shut down TLS 593 522 close $socket; 594 523 alarm (0); # Don't want to interrupt this. 595 524 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: $!"; 597 526 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; 599 528 alarm ($timeout); 600 529 close SOCK; … … 606 535 { 607 536 if (!$socket) { 608 logger ("[ERROR] Could not connect to $name($n ode->{address}): $err\nAttempting to use old configuration");537 logger ("[ERROR] Could not connect to $name($newconf->{address}): $err\nAttempting to use old configuration"); 609 538 # If we can't reach the client. Using old Configuration. 610 if (ref $old node) {611 $config->{domain}->{$domain}->{node}->{$name} = $oldnode;539 if (ref $oldconf) { 540 copy_node ($oldconf, $newconf); 612 541 } 613 542 } 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); 616 545 # Net::SSLeay::free ($tls) if ($tls); # Shut down TLS 617 546 close $socket; … … 948 877 } 949 878 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, 879 sub 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, 1097 1018 "RRA:AVERAGE:0.5:1:576", # resolution 5 minutes 1098 1019 "RRA:MIN:0.5:1:576", … … 1107 1028 "RRA:MIN:0.5:288:450", 1108 1029 "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 } 1130 1043 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 $n odefetch_time = Time::HiRes::time;1044 return 1; 1045 } 1046 1047 sub fetch_node 1048 { 1049 my ($newconf,$oldconf,$socket) = @_; 1050 my $name = munin_get_node_name ($newconf); 1138 1051 logger("[DEBUG] Fetching node: $name") if $DEBUG; 1139 for my $service (keys %{$n ode->{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}) and1143 $node->{client}->{$service}->{fetch_data} == 0);1144 next if (exists ($node->{client}->{$service}->{update}) and1145 $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")); 1146 1059 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 1151 1066 write_socket_single ($socket, "fetch $realservname\n"); 1152 1067 my @lines = &read_socket($socket); … … 1176 1091 1177 1092 $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}); 1184 1095 1185 1096 logger("[DEBUG] Updating $fname with $value") if $DEBUG; … … 1189 1100 } 1190 1101 } 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\")."); 1192 1103 } 1193 1104 } 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); 1195 1106 } 1196 1107 } 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 } 1205 1109 return 1; 1206 }1207 1208 sub use_old_config1209 {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.");1216 1110 } 1217 1111 … … 1279 1173 } 1280 1174 1175 sub 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 1281 1191 1; 1282 1192 … … 1368 1278 =head1 COPYRIGHT 1369 1279 1370 Copyright © 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS.1280 Copyright © 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 1371 1281 1372 1282 This is free software; see the source for copying conditions. There is
