root/people/snide/pre_1.5/master/lib/Munin/Master/UpdateWorker.pm

Revision 3360, 21.6 kB (checked in by steve.schnepp, 7 months ago)

- completes r3357
- adds an "aligned" suboption to update_rate. Enables to align RRD updates to granularity. (was "discrete" at first)
- also use the "standard" units for update_rate

  • Property svn:keywords set to id
Line 
1 package Munin::Master::UpdateWorker;
2 use base qw(Munin::Master::Worker);
3
4 # $Id$
5
6 use warnings;
7 use strict;
8
9 use Carp;
10 use English qw(-no_match_vars);
11 use Log::Log4perl qw( :easy );
12
13 use File::Basename;
14 use File::Path;
15 use File::Spec;
16 use Munin::Master::Config;
17 use Munin::Master::Node;
18 use Munin::Master::Utils;
19 use RRDs;
20 use Time::HiRes;
21 use Data::Dumper;
22
23 my $config = Munin::Master::Config->instance()->{config};
24
25 sub new {
26     my ($class, $host) = @_;
27
28     my $self = $class->SUPER::new($host->get_full_path);
29     $self->{host} = $host;
30     $self->{node} = Munin::Master::Node->new($host->{address},
31                                              $host->{port},
32                                              $host->{host_name},
33                                              $host);
34
35     return $self;
36 }
37
38
39 sub do_work {
40     my ($self) = @_;
41
42     my $update_time = Time::HiRes::time;
43
44     my $host = $self->{host}{host_name};
45     my $path = $self->{host}->get_full_path;
46     $path =~ s{[:;]}{-}g;
47
48     my $nodedesignation = $host."/".
49         $self->{host}{address}.":".$self->{host}{port};
50
51     my $lock_file = sprintf ('%s/munin-%s.lock',
52                              $config->{rundir},
53                              $path);
54
55     if (!munin_getlock($lock_file)) {
56         WARN "Could not get lock $lock_file for $nodedesignation. Skipping node.";
57         die "Could not get lock $lock_file for $nodedesignation. Skipping node.\n";
58     }
59
60     my %all_service_configs = (
61         data_source => {},
62         global => {},
63         );
64
65     my $done = $self->{node}->do_in_session(sub {
66
67         eval {
68             # A I/O timeout results in a violent exit.  Catch and handle.
69
70             $self->{node}->negotiate_capabilities();
71             # Note: A multigraph plugin can present multiple services.
72             my @plugins =  $self->{node}->list_plugins();
73
74             for my $plugin (@plugins) {
75                 if (%{$config->{limit_services}}) {
76                     next unless $config->{limit_services}{$plugin};
77                 }
78
79                 my %service_config = $self->uw_fetch_service_config($plugin);
80                 unless (%service_config) {
81                     WARN "[WARNING] Service $plugin on $nodedesignation ".
82                         "returned no config";
83                     next;
84                 }
85
86                 # Check if this plugin has already sent its data via a dirtyconfig
87                 my %service_data = $self->handle_dirty_config(\%service_config);
88
89                 # Check if this plugin has to be updated
90                 my $update_rate = get_global_service_value(\%service_config, $plugin, "update_rate", 0);
91                 my ($update_rate_in_seconds, $is_update_aligned) = parse_update_rate($update_rate);
92                 # default is 0 sec : always update when asked
93                 DEBUG "[DEBUG] update_rate $update_rate_in_seconds for $plugin on $nodedesignation";
94                 if ($update_rate_in_seconds
95                         && is_fresh_enough($nodedesignation, $plugin, $update_rate_in_seconds)) {
96                     # It's fresh enough, skip this $service
97                     DEBUG "[DEBUG] $plugin is fresh enough, not updating it";
98                     next;
99                 }
100
101                 if (! %service_data) {
102                         %service_data = $self->{node}->fetch_service_data($plugin);
103                 }
104
105                 # If update_rate is aligned, round the "when" for alignement
106                 if ($is_update_aligned) {
107                         foreach my $service (keys %service_data) {
108                                 my $current_service_data = $service_data{$service};
109                                 foreach my $field (keys %$current_service_data) {
110                                         my $when = $current_service_data->{$field}->{when};
111                                         my $rounded_when = round_to_granularity($when, $update_rate_in_seconds);
112                                         $current_service_data->{$field}->{when} = $rounded_when;
113                                 }
114                         }
115                 }
116
117
118                 # Since different plugins can populate multiple
119                 # positions in the service namespace we'll check for
120                 # collisions and warn of them.
121
122                 for my $service (keys %{$service_config{data_source}}) {
123                     if (defined($all_service_configs{data_source}{$service})) {
124                         WARN "[WARNING] Service collision: plugin $plugin on "
125                             ."$nodedesignation reports $service which already "
126                             ."exists on that host.  Deleting new data.";
127                         delete($service_config{data_source}{$service});
128                     delete($service_data{$service})
129                         if defined $service_data{$service};
130                     }
131                 }
132
133                 # .extinfo fields come from "fetch" but must be saved
134                 # like "config".
135
136                 for my $service (keys %service_data) {
137                     for my $ds (keys %{$service_data{$service}}) {
138                         my $extinfo = $service_data{$service}{$ds}{extinfo};
139                         if (defined $extinfo) {
140                             $service_config{data_source}{$service}{$ds}{extinfo} =
141                                 $extinfo;
142                             DEBUG "[DEBUG] Copied extinfo $extinfo into "
143                                 ."service_config for $service / $ds on "
144                                 .$nodedesignation;
145                         }
146                     }
147                 }
148
149                 $self->_compare_and_act_on_config_changes(\%service_config);
150
151                 %{$all_service_configs{data_source}} = (
152                     %{$all_service_configs{data_source}},
153                     %{$service_config{data_source}});
154
155                 %{$all_service_configs{global}} = (
156                     %{$all_service_configs{global}},
157                     %{$service_config{global}});
158
159                 $self->_update_rrd_files(\%service_config, \%service_data);
160
161             } # for @plugins
162         }; # eval
163
164         if ($EVAL_ERROR) {
165             ERROR "[ERROR] Error in node communication with $nodedesignation: "
166                 .$EVAL_ERROR;
167         }
168
169     }); # do_in_session
170
171     munin_removelock($lock_file);
172
173     # This handles failure in do_in_session,
174     return undef if !$done;
175
176     return {
177         time_used => Time::HiRes::time - $update_time,
178         service_configs => \%all_service_configs,
179     }
180 }
181
182 sub get_global_service_value {
183         my ($service_config, $service, $conf_field_name, $default) = @_;
184         foreach my $array (@{$service_config->{global}{$service}}) {
185                 my ($field_name, $field_value) = @$array;
186                 if ($field_name eq $conf_field_name) {
187                         return $field_value;
188                 }
189         }
190
191         return $default;
192 }
193
194 sub is_fresh_enough {
195         my ($nodedesignation, $service, $update_rate_in_seconds) = @_;
196
197         my $key = "$nodedesignation/$service";
198         DEBUG "is_fresh_enough asked for $key with a rate of $update_rate_in_seconds";
199
200         my %last_updated;
201         # XXX - ugly hack. Should be refactored to use a a common state provider
202
203         use Fcntl;   # For O_RDWR, O_CREAT, etc.
204         use NDBM_File;
205         tie(%last_updated, 'NDBM_File', '/tmp/munin_plugins_last_updated', O_RDWR|O_CREAT, 0666) or ERROR "$!";
206         DEBUG "last_updated{$key}: " . $last_updated{$key};
207         my @last = split(/ /, $last_updated{$key});
208    
209         use Time::HiRes qw(gettimeofday tv_interval);   
210         my $now = [ gettimeofday ];
211
212         my $age = tv_interval(\@last, $now);   
213         DEBUG "last: " . Dumper(\@last) . ", now: " . Dumper($now) . ", age: $age";
214         my $is_fresh_enough = ($age < $update_rate_in_seconds);
215         DEBUG "is_fresh_enough  $is_fresh_enough";
216
217         if (! $is_fresh_enough) {
218                 DEBUG "new value: " . join(" ", @$now);
219                 $last_updated{$key} = join(" ", @$now);
220         }
221
222         untie(%last_updated);
223
224         return $is_fresh_enough;
225 }
226
227 sub parse_update_rate {
228         my ($update_rate_config) = @_;
229
230         my ($is_update_aligned, $update_rate_in_sec);
231         if ($update_rate_config =~ m/(\d+[a-z]?) (aligned)?/) {
232                 $update_rate_in_sec = to_sec($1);
233                 $is_update_aligned = $2;
234         } else {
235                 return (0, 0);
236         }
237
238         return ($update_rate_in_sec, $is_update_aligned);
239 }
240
241 sub round_to_granularity {
242         my ($when, $granularity_in_sec) = @_;
243         $when = time if ($when eq "N"); # N means "now"
244
245         my $rounded_when = $when - ($when % $granularity_in_sec);
246         return $rounded_when;
247 }
248
249 sub handle_dirty_config {
250         my ($self, $service_config) = @_;
251        
252         my %service_data;
253
254         my $services = $service_config->{global}{multigraph};
255         foreach my $service (@$services) {
256                 my $service_data_source = $service_config->{"data_source"}->{$service};
257                 foreach my $field (keys %$service_data_source) {
258                         my $field_value = $service_data_source->{$field}->{"value"};
259                         # If not present, ignore
260                         next if (! defined $field_value);
261
262                         DEBUG "[DEBUG] handle_dirty_config:$service, $field, $field_value";
263                         # Adds the service_data
264                         $service_data{$service}->{$field} = {
265                                 "value" => $field_value,
266                                 "when" => "N",
267                         };
268                 }
269         }
270
271         return %service_data;
272 }
273
274
275 sub uw_fetch_service_config {
276     my ($self, $plugin) = @_;
277
278     # Note, this can die for several reasons.  Caller must eval us.
279     my %service_config = $self->{node}->fetch_service_config($plugin);
280
281     if ($self->{host}{service_config} &&
282         $self->{host}{service_config}{$plugin}) {
283
284         %service_config
285             = (%service_config, %{$self->{host}{service_config}{$plugin}});
286
287     }
288
289     return %service_config;
290 }
291
292
293 sub _compare_and_act_on_config_changes {
294     my ($self, $nested_service_config) = @_;
295
296     # Kjellm: Why do we need to tune RRD files after upgrade?
297     # Shouldn't we create a upgrade script or something instead?
298     #
299     # janl: Upgrade script sucks.  This way it's inline in munin and
300     #  no need to remember anything or anything.
301
302     my $just_upgraded = 0;
303
304     my $old_config = Munin::Master::Config->instance()->{oldconfig};
305
306     if (not defined $old_config->{version}
307         or ($old_config->{version}
308             ne $Munin::Common::Defaults::MUNIN_VERSION)) {
309         $just_upgraded = 1;
310     }
311
312     for my $service (keys %{$nested_service_config->{data_source}}) {
313
314         my $service_config = $nested_service_config->{data_source}{$service};
315
316         for my $data_source (keys %{$service_config}) {
317             my $old_data_source = $data_source;
318             my $ds_config = $service_config->{$data_source};
319             $self->_set_rrd_data_source_defaults($ds_config);
320
321             my $group = $self->{host}{group}{group_name};
322             my $host = $self->{host}{host_name};
323
324             my $old_host_config = $old_config->{groups}{$group}{hosts}{$host};
325             my $old_ds_config = undef;
326
327             if ($old_host_config) {
328                 $old_ds_config =
329                     $old_host_config->get_canned_ds_config($service,
330                                                            $data_source);
331             }
332
333             if (defined($old_ds_config)
334                 and %$old_ds_config
335                 and defined($ds_config->{oldname})
336                 and $ds_config->{oldname}) {
337
338                 $old_data_source = $ds_config->{oldname};
339                 $old_ds_config =
340                     $old_host_config->get_canned_ds_config($service,
341                                                            $old_data_source);
342             }
343
344             if (defined($old_ds_config)
345                 and %$old_ds_config
346                 and not $self->_ds_config_eq($old_ds_config, $ds_config)) {
347                 $self->_ensure_filename($service,
348                                         $old_data_source, $data_source,
349                                         $old_ds_config, $ds_config)
350                     and $self->_ensure_tuning($service, $data_source,
351                                               $ds_config);
352                 # _ensure_filename prints helpfull warnings in the log
353             } elsif ($just_upgraded) {
354                 $self->_ensure_tuning($service, $data_source,
355                                       $ds_config);
356             }
357         }
358     }
359 }
360
361
362 sub _ds_config_eq {
363     my ($self, $old_ds_config, $ds_config) = @_;
364
365     if (%$old_ds_config ne %$ds_config) {
366         # Config keys differ:
367         return '';
368     }
369
370     for my $key (%$old_ds_config) {
371         if ((not defined($old_ds_config->{$key}))
372             and not defined($ds_config->{$key})) {
373             # Both keys undefined, look further:
374             next;
375         }
376
377         if ((not defined($old_ds_config->{$key}))
378             or not defined($ds_config->{$key})) {
379             # One key undefined, but not both:
380             return '';
381         }
382
383         if ($old_ds_config->{$key} ne $ds_config->{$key}) {
384             # Config content differs:
385             return '';
386         }
387     }
388
389     return 1;
390 }
391
392
393 sub _ensure_filename {
394     my ($self, $service, $old_data_source, $data_source,
395         $old_ds_config, $ds_config) = @_;
396
397     my $rrd_file = $self->_get_rrd_file_name($service, $data_source,
398                                              $ds_config);
399     my $old_rrd_file = $self->_get_rrd_file_name($service, $old_data_source,
400                                                  $old_ds_config);
401
402     my $hostspec = $self->{node}{host}.'/'.$self->{node}{address}.':'.
403         $self->{node}{port};
404
405     if ($rrd_file ne $old_rrd_file) {
406         if (-f $old_rrd_file and -f $rrd_file) {
407             my $host = $self->{host}{host_name};
408             WARN "[WARNING]: $hostspec $service $data_source config change "
409                 . "suggests moving '$old_rrd_file' to '$rrd_file' "
410                 . "but both exist; manually merge the data "
411                 . "or remove whichever file you care less about.\n";
412             return '';
413         } elsif (-f $old_rrd_file) {
414             INFO "[INFO]: Config update, changing name of '$old_rrd_file'"
415                    . " to '$rrd_file' on $hostspec ";
416             unless (rename ($old_rrd_file, $rrd_file)) {
417                 ERROR "[ERROR]: Could not rename '$old_rrd_file' to"
418                     . " '$rrd_file' for $hostspec: $!\n";
419                 return '';
420             }
421         }
422     }
423
424     return 1;
425 }
426
427
428 sub _ensure_tuning {
429     my ($self, $service, $data_source, $ds_config) = @_;
430     my $success = 1;
431
432     my $rrd_file =
433         $self->_get_rrd_file_name($service, $data_source,
434                                   $ds_config);
435
436     my %tune_flags = (type => '--data-source-type',
437                       max => '--maximum',
438                       min => '--minimum');
439
440     for my $rrd_prop (qw(type max min)) {
441         INFO "[INFO]: Config update, ensuring $rrd_prop of"
442             . " '$rrd_file' is '$ds_config->{$rrd_prop}'.\n";
443         RRDs::tune($rrd_file, $tune_flags{$rrd_prop},
444                    "42:$ds_config->{$rrd_prop}");
445         if (my $tune_error = RRDs::error()) {
446             ERROR "[ERROR] Tuning $rrd_prop of '$rrd_file' to"
447                 . " '$ds_config->{$rrd_prop}' failed.\n";
448             $success = '';
449         }
450     }
451
452     return $success;
453 }
454
455
456 sub _update_rrd_files {
457     my ($self, $nested_service_config, $nested_service_data) = @_;
458
459     my $nodedesignation = $self->{host}{host_name}."/".
460         $self->{host}{address}.":".$self->{host}{port};
461
462     for my $service (keys %{$nested_service_config->{data_source}}) {
463
464         my $service_config = $nested_service_config->{data_source}{$service};
465         my $service_data   = $nested_service_data->{$service};
466
467         for my $ds_name (keys %{$service_config}) {
468             $self->_set_rrd_data_source_defaults($service_config->{$ds_name});
469             my $ds_config = $service_config->{$ds_name};
470
471             unless (defined($ds_config->{label})) {
472                 ERROR "[ERROR] Unable to update $service on $nodedesignation -> $ds_name: Missing data source configuration attribute: label";
473                 next;
474             }
475            
476             # Sets the DS resolution, searching in that order :
477             # - per field
478             # - per plugin
479             # - globally
480             my $configref = $self->{node}{configref};
481             $ds_config->{graph_data_size} ||= $configref->{"$service.$ds_name.graph_data_size"};
482             $ds_config->{graph_data_size} ||= $configref->{"$service.graph_data_size"};
483             $ds_config->{graph_data_size} ||= $config->{graph_data_size};
484
485             DEBUG "[DEBUG] asking for a rrd of size : " . $ds_config->{graph_data_size};
486             my $rrd_file = $self->_create_rrd_file_if_needed($service, $ds_name, $ds_config);
487
488             if (defined($service_data) and defined($service_data->{$ds_name})) {
489                 $self->_update_rrd_file($rrd_file, $ds_name, $service_data->{$ds_name});
490             }
491             else {
492                 WARN "[WARNING] Service $service on $nodedesignation returned no data for label $ds_name";
493             }
494         }
495     }
496 }
497
498
499 sub _set_rrd_data_source_defaults {
500     my ($self, $data_source) = @_;
501
502     # Test for definedness, anything defined should not be overridden
503     # by defaults:
504     $data_source->{type} = 'GAUGE' unless defined($data_source->{type});
505     $data_source->{min}  = 'U'     unless defined($data_source->{min});
506     $data_source->{max}  = 'U'     unless defined($data_source->{max});
507 }
508
509
510 sub _create_rrd_file_if_needed {
511     my ($self, $service, $ds_name, $ds_config) = @_;
512
513     my $rrd_file = $self->_get_rrd_file_name($service, $ds_name, $ds_config);
514     unless (-f $rrd_file) {
515         $self->_create_rrd_file($rrd_file, $service, $ds_name, $ds_config);
516     }
517
518     return $rrd_file;
519 }
520
521
522 sub _get_rrd_file_name {
523     my ($self, $service, $ds_name, $ds_config) = @_;
524    
525     my $type_id = lc(substr(($ds_config->{type}), 0, 1));
526
527     my $path = $self->{host}->get_full_path;
528     $path =~ s{[;:]}{/}g;
529
530     # Multigraph/nested services will have . in the service name in this function.
531     $service =~ s{\.}{-}g;
532
533     # The following is rigged to match the corresponding function in
534     # munin-graph/munin-html where it's less clear what are groups and
535     # what are hosts and what are services, and they simply pop
536     # elements off the end and so on.
537
538     my $file = sprintf("%s-%s-%s-%s.rrd",
539                        $path,
540                        $service,
541                        $ds_name,
542                        $type_id);
543
544     $file = File::Spec->catfile($config->{dbdir},
545                                 $file);
546        
547     DEBUG "[DEBUG] rrd filename: $file\n";
548
549     return $file;
550 }
551
552
553 sub _create_rrd_file {
554     my ($self, $rrd_file, $service, $ds_name, $ds_config) = @_;
555
556     INFO "[INFO] creating rrd-file for $service->$ds_name: '$rrd_file'";
557     mkpath(dirname($rrd_file), {mode => oct(777)});
558     my @args = (
559         $rrd_file,
560         sprintf('DS:42:%s:600:%s:%s',
561                 $ds_config->{type}, $ds_config->{min}, $ds_config->{max}),
562     );
563
564     my $resolution = $ds_config->{graph_data_size};
565     my $update_rate = $ds_config->{update_rate} || 300; # 5 min per default
566     if ($resolution eq 'normal') {
567         push (@args,
568               "RRA:AVERAGE:0.5:1:576",   # resolution 5 minutes
569               "RRA:MIN:0.5:1:576",
570               "RRA:MAX:0.5:1:576",
571               "RRA:AVERAGE:0.5:6:432",   # 9 days, resolution 30 minutes
572               "RRA:MIN:0.5:6:432",
573               "RRA:MAX:0.5:6:432",
574               "RRA:AVERAGE:0.5:24:540"# 45 days, resolution 2 hours
575               "RRA:MIN:0.5:24:540",
576               "RRA:MAX:0.5:24:540",
577               "RRA:AVERAGE:0.5:288:450", # 450 days, resolution 1 day
578               "RRA:MIN:0.5:288:450",
579               "RRA:MAX:0.5:288:450");
580     }
581     elsif ($resolution eq 'huge') {
582         push (@args,
583               "RRA:AVERAGE:0.5:1:115200"# resolution 5 minutes, for 400 days
584               "RRA:MIN:0.5:1:115200",
585               "RRA:MAX:0.5:1:115200");
586     } elsif ($resolution =~ /^custom (.+)/) {
587         # Parsing resolution to achieve computer format as defined on the RFC :
588         # FULL_NB, MULTIPLIER_1 MULTIPLIER_1_NB, ... MULTIPLIER_NMULTIPLIER_N_NB
589         my @resolutions_computer = parse_custom_resolution($1, $update_rate);
590         foreach my $resolution_computer(@resolutions_computer) {
591             my ($multiplier, $multiplier_nb) = @{$resolution_computer};
592             # Always add 10% to the RRA size, as specified in
593             # http://munin.projects.linpro.no/wiki/format-graph_data_size
594             $multiplier_nb += int ($multiplier_nb / 10) || 1;
595             push (@args,
596                 "RRA:AVERAGE:0.5:$multiplier:$multiplier_nb",
597                 "RRA:MIN:0.5:$multiplier:$multiplier_nb",
598                 "RRA:MAX:0.5:$multiplier:$multiplier_nb"
599             );
600         }
601     }
602     DEBUG "[DEBUG] RRDs::create @args";
603     RRDs::create @args;
604     if (my $ERROR = RRDs::error) {
605         ERROR "[ERROR] Unable to create '$rrd_file': $ERROR";
606     }
607 }
608
609 sub parse_custom_resolution {
610         my @elems = split(',\s*', shift);
611         my $update_rate = shift;
612
613         DEBUG "[DEBUG] update_rate: $update_rate";
614
615         my @computer_format;
616         foreach my $elem (@elems) {
617                 if ($elem =~ m/(\d+) (\d+)/) {
618                         # nothing to do, already in computer format
619                         push @computer_format, [$1, $2];
620                 } elsif ($elem =~ m/(\w+) for (\w+)/) {
621                         my $nb_sec = to_sec($1);
622                         my $for_sec = to_sec($2);
623                        
624                         my $multiplier = int ($nb_sec / $update_rate);
625                         my $multiplier_nb = int ($for_sec / $nb_sec);
626
627                         DEBUG "[DEBUG] $elem"
628                                 . " -> nb_sec:$nb_sec, for_sec:$for_sec"
629                                 . " -> multiplier:$multiplier, multiplier_nb:$multiplier_nb"
630                         ;
631                         push @computer_format, [$multiplier, $multiplier_nb];
632                 }
633         }
634
635         return @computer_format;
636 }
637
638 # return the number of seconds
639 # for the human readable format
640 # s : second,  m : minute, h : hour
641 # d : day, w : week, t : month, y : year
642 sub to_sec {
643         my $secs_table = {
644                 "s" => 1,
645                 "m" => 60,
646                 "h" => 60 * 60,
647                 "d" => 60 * 60 * 24,
648                 "w" => 60 * 60 * 24 * 7,
649                 "t" => 60 * 60 * 24 * 31, # a month always has 31 days
650                 "y" => 60 * 60 * 24 * 365, # a year always has 365 days
651         };
652
653         my ($target) = @_;
654         if ($target =~ m/(\d+)([smhdwty])/i) {
655                 return $1 * $secs_table->{$2}; 
656         } else {
657                 # no recognised unit, return the int value as seconds
658                 return int $target;
659         }
660 }
661
662 sub to_mul {
663         my ($base, $target) = @_;
664         my $target_sec = to_sec($target);
665         if ($target %% $base != 0) {
666                 return 0;
667         }
668
669         return round($target / $base);
670 }
671
672 sub to_mul_nb {
673         my ($base, $target) = @_;
674         my $target_sec = to_sec($target);
675         if ($target %% $base != 0) {
676                 return 0;
677         }
678 }
679
680 sub _update_rrd_file {
681     my ($self, $rrd_file, $ds_name, $ds_values) = @_;
682
683     my $value = $ds_values->{value};
684
685     # Some kind of mismatch between fetch and config can cause this.
686     return if !defined($value); 
687
688     if ($value =~ /\d[Ee]([+-]?\d+)$/) {
689         # Looks like scientific format.  RRDtool does not
690         # like it so we convert it.
691         my $magnitude = $1;
692         if ($magnitude < 0) {
693             # Preserve at least 4 significant digits
694             $magnitude = abs($magnitude) + 4;
695             $value = sprintf("%.*f", $magnitude, $value);
696         } else {
697             $value = sprintf("%.4f", $value);
698         }
699     }
700
701     DEBUG "[DEBUG] Updating $rrd_file with ".$ds_values->{when}.":$value";
702     RRDs::update($rrd_file, "$ds_values->{when}:$value");
703     if (my $ERROR = RRDs::error) {
704         #confess Dumper @_;
705         ERROR "[ERROR] In RRD: Error updating $rrd_file: $ERROR";
706     }
707 }
708
709 1;
710
711
712 __END__
713
714 =head1 NAME
715
716 Munin::Master::UpdateWorker - FIX
717
718 =head1 SYNOPSIS
719
720 FIX
721
722 =head1 METHODS
723
724 =over
725
726 =item B<new>
727
728 FIX
729
730 =item B<do_work>
731
732 FIX
733
734 =back
735
736 =head1 COPYING
737
738 Copyright (C) 2002-2009  Jimmy Olsen, et al.
739
740   This program is free software; you can redistribute it and/or modify
741   it under the terms of the GNU General Public License as published by
742   the Free Software Foundation; version 2 dated June, 1991.
743
744   This program is distributed in the hope that it will be useful,
745   but WITHOUT ANY WARRANTY; without even the implied warranty of
746   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
747   GNU General Public License for more details.
748
749   You should have received a copy of the GNU General Public License
750   along with this program; if not, write to the Free Software
751   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
752
753
Note: See TracBrowser for help on using the browser.