diff options
Diffstat (limited to 'lib/App/Beam.pm')
-rw-r--r-- | lib/App/Beam.pm | 166 |
1 files changed, 39 insertions, 127 deletions
diff --git a/lib/App/Beam.pm b/lib/App/Beam.pm index b7e004e..3bee8b9 100644 --- a/lib/App/Beam.pm +++ b/lib/App/Beam.pm @@ -5,16 +5,12 @@ use Carp; use File::Basename; use Sys::Syslog; use Unix::Sysexits; -use Fcntl qw(:flock SEEK_SET); -use Storable qw(fd_retrieve nstore_fd); use POSIX qw(strftime floor); require App::Beam::Config; our @ISA = qw(App::Beam::Config); -our @EXPORT_OK = qw(RESULT_PENDING RESULT_SUCCESS RESULT_FAILURE); -our %EXPORT_TAGS = ( - result => [ qw(RESULT_PENDING RESULT_SUCCESS RESULT_FAILURE) ] -); + +use App::Beam::History; my $default_config_file = '/etc/beam.conf'; @@ -255,130 +251,16 @@ sub abend { exit($code); } -use constant { - RESULT_PENDING => 0, - RESULT_SUCCESS => 1, - RESULT_FAILURE => 2 -}; - -# Locks the statfile and retrieves data from it into {status} -sub lock { - my $self = shift; - my $file = $self->get('core.statfile'); - unless (open($self->{statfd}, '+>>', $file)) { - $self->abend(EX_CANTCREAT, "can't open file $file: $!"); - } - unless (flock($self->{statfd}, LOCK_EX | LOCK_NB)) { - $self->abend(EX_TEMPFAIL, "can't lock file $file: $!"); - } - seek($self->{statfd}, 0, SEEK_SET); - if ((stat($self->{statfd}))[7] == 0) { - $self->{status} = []; - } else { - $self->{status} = fd_retrieve($self->{statfd}) - or $self->abend(EX_UNAVAILABLE, "can't retrieve status from $file: $!"); - if (ref($self->{status}) ne 'ARRAY') { - $self->abend(EX_DATAERR, "$file: malformed status file"); - } - } - my ($cycle, $round, $level) = $self->compute_triplet(1); - unshift @{$self->{status}}, { timestamp => time(), - result => RESULT_PENDING, - cycle => $cycle, - round => $round, - level => $level }; -} - -# Saves the current status and unlocks the status file. -sub unlock { - my ($self) = @_; - croak "unlock without lock" unless defined $self->{statfd}; - $self->debug(1, "saving state: ".$self->status('result')); - if (!$self->{dry_run} && $self->status('result') != RESULT_PENDING) { - seek($self->{statfd}, 0, SEEK_SET); - truncate($self->{statfd}, 0); - nstore_fd($self->{status}, $self->{statfd}); - } - flock($self->{statfd}, LOCK_UN); - close($self->{statfd}); -} - -sub compute_triplet { - my ($self, $off, $base) = @_; - - $base = 0 unless defined $base; - if ($#{$self->{status}} == -1) { - return (0, 0, 0); - } - croak "invalid base" unless $base <= $#{$self->{status}}; - - my ($cycle, $round, $level) = - (${$self->{status}}[$base]{cycle}, - ${$self->{status}}[$base]{round}, - ${$self->{status}}[$base]{level}); - - my ($maxround, $maxlevel) = - ($self->get('schedule', 'rounds'), - $self->get('schedule', 'levels')); - if ($off == 1) { - $level++; - if ($level > $maxlevel) { - $round++; - $level = 0; - if ($round > $maxround) { - $cycle++; - $round = 0; - } - } - } elsif ($off == -1) { - $level--; - if ($level < 0) { - $level += $maxlevel + 1; - $round--; - } - if ($round < 0) { - $round += $maxround + 1; - $cycle--; - if ($cycle == 0) { - $round = $level = 0; - last; - } - } - } elsif ($off) { - croak "invalid offset"; - } - return ($cycle, $round, $level); -} - -sub status { - my ($self,$item,$base) = @_; - $base = 0 unless defined $base; - return undef unless $base <= $#{$self->{status}}; - return $self->{status}[$base]{$item}; -} - -sub result { - my ($self) = @_; - return $self->{status}[0]{result}; -} - -sub set_result { - my ($self, $item, $result) = @_; - $self->{status}[0]{detail}{$item} = $result; - $self->{status}[0]{result} = $result - unless $self->{status}[0]{result} == RESULT_FAILURE; -} - sub format_name { - my ($self, $name, $base) = @_; - $base = 0 unless defined $base; - return undef unless $base <= $#{$self->{status}}; + my ($self, $name, $idx) = @_; + my $rec = $self->{history}->top($idx); + return undef unless defined $rec; $name .= '-' - . $self->status('cycle', $base) + . $rec->cycle . '-' - . $self->status('round', $base) + . $rec->round . '-' - . $self->status('level', $base); + . $rec->level; return $name; } @@ -458,11 +340,27 @@ sub begin { } $self->logger('info', 'startup'); - $self->load_backends; + $self->load_backends; + + eval { + my %args; + $args{dry_run} = $self->{dry_run}; + $self->{history} = + new App::Beam::History($self->get('core.statfile'), + $self->get('schedule', 'rounds'), + $self->get('schedule', 'levels'), + %args); + }; + if ($@) { + $self->logger('crit', $@); + exit(EX_CANTCREAT); + } } sub end { my $self = shift; + $self->{history}->top->finish; + $self->{history}->save; $self->logger('info', 'shutdown'); if ($self->get('logger.channel') eq 'syslog') { closelog(); @@ -474,4 +372,18 @@ sub run { $self->abend(EX_SOFTWARE, "unsupported command $_[0]"); } +sub check_items { + my $self = shift; + my @items = split /\s+/, $self->get('core.items'); + if (@_) { + push @items, $self->names_of('item'); + foreach my $item (@_) { + $self->abend(EX_USAGE, "$item: no such item defined") + unless grep { $item eq $_ } @items; + } + @items = @_; + } + return @items; +} + 1; |