aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--beam.conf26
-rw-r--r--lib/App/Beam.pm40
-rw-r--r--lib/App/Beam/Backend/Tar.pm15
-rw-r--r--lib/App/Beam/Backup.pm9
-rw-r--r--lib/App/Beam/History/Entry.pm10
-rw-r--r--lib/App/Beam/Restore.pm10
6 files changed, 85 insertions, 25 deletions
diff --git a/beam.conf b/beam.conf
index b101841..7f3ef56 100644
--- a/beam.conf
+++ b/beam.conf
@@ -1,11 +1,15 @@
[core]
# Location of the state file
-# statfile = /var/spool/beam/beam.state
- statfile = /tmp/beam.state
+ statfile = /var/spool/beam/beam.state
# Directory for temporary files
tempdir = /tmp
#
archivedir = /var/backups
+ # List of items to back up. Each item is described in
+ # section [item NAME]. It is OK to have such sections
+ # declaring NAMEs not listed in core.items.
+ # If this variable is absent or empty, all itmes from all
+ # such sections will be processed.
items = www
# Configure logging
@@ -47,6 +51,9 @@
retain = 8
[backend tar]
+ # Full pathname of the tar binary
+ binary = /bin/tar
+
# Any additional options to pass to tar. Do not place tar operation
# switches (as -c, -t, etc.) here! These will be added automatically
# by appropriate scripts, depending on the operation being performed.
@@ -66,10 +73,17 @@
# This variable must be set
snapshot-dir = /var/lib/backups
-# [item system]
-# backend = tar
-# directory = /
-# file = etc var/spool/cron
+[item system]
+ # Declare the backend to use for that item.
+ backend = tar
+ # The following settings are specific for tar backend:
+ # Name of the directory to archive.
+ directory = /
+ # Whitespace-separated list of file names within that directory
+ # If emtpy, all files will be archived.
+ file = etc var/spool/cron
+ # Additional tar(1) options. These complement backend.tar.options
+ #options =
[item databases]
backend = mysql
diff --git a/lib/App/Beam.pm b/lib/App/Beam.pm
index 3bee8b9..550bfcf 100644
--- a/lib/App/Beam.pm
+++ b/lib/App/Beam.pm
@@ -9,8 +9,9 @@ use POSIX qw(strftime floor);
require App::Beam::Config;
our @ISA = qw(App::Beam::Config);
-
+
use App::Beam::History;
+use App::Beam::History::Entry qw(:state);
my $default_config_file = '/etc/beam.conf';
@@ -255,8 +256,8 @@ sub format_name {
my ($self, $name, $idx) = @_;
my $rec = $self->{history}->top($idx);
return undef unless defined $rec;
- $name .= '-'
- . $rec->cycle
+ $name .= '-' if $name ne '';
+ $name .= $rec->cycle
. '-'
. $rec->round
. '-'
@@ -301,7 +302,7 @@ sub load_backends {
}
} split(/\s+/, $self->get('core.items'))) {
my $pack = "App::Beam::Backend::" . ucfirst($be);
- $self->debug(1, "loading $pack");
+ $self->debug(2, "loading $pack");
my $obj = eval "use $pack; new $pack(\$self);";
if ($@) {
$self->logger('crit', $@);
@@ -323,14 +324,14 @@ sub begin {
my $options = $self->get('logger.syslog.options') || 'pid';
openlog($tag, $options, $facility)
or do {
- croak "openlog failed";
+ carp "openlog failed";
exit(EX_CONFIG);
}
} elsif (my $filename = $self->get('logger.file.name')) {
my $mode = $self->get('logger.file.append') ? '>>' : '>';
open(STDERR, $mode, $filename)
or do {
- croak "can't open file $filename for logging";
+ carp "can't open file $filename for logging";
exit(EX_CANTCREAT);
};
}
@@ -356,7 +357,22 @@ sub begin {
exit(EX_CANTCREAT);
}
}
-
+
+use constant {
+ EX_SUCCESS => 0, # Successful termination
+ EX_FAILURE => 1, # All operations failed
+ EX_PARTIAL => 2 # Some operations failed
+};
+
+sub update_status {
+ my ($self, $ctr) = @_;
+ unless ($ctr == STATE_SUCCESS || $ctr == STATE_FAILURE) {
+ carp "invalid state counter $ctr; assuming STATE_FAILURE";
+ $ctr = STATE_FAILURE;
+ }
+ $self->{counter}[$ctr]++;
+}
+
sub end {
my $self = shift;
$self->{history}->top->finish;
@@ -365,6 +381,16 @@ sub end {
if ($self->get('logger.channel') eq 'syslog') {
closelog();
}
+
+ if ($self->{counter}[STATE_SUCCESS] > 0) {
+ if ($self->{counter}[STATE_FAILURE] > 0) {
+ exit(EX_PARTIAL);
+ } else {
+ exit(EX_SUCCESS);
+ }
+ } else {
+ exit(EX_FAILURE);
+ }
}
sub run {
diff --git a/lib/App/Beam/Backend/Tar.pm b/lib/App/Beam/Backend/Tar.pm
index bbb4730..f469485 100644
--- a/lib/App/Beam/Backend/Tar.pm
+++ b/lib/App/Beam/Backend/Tar.pm
@@ -106,7 +106,7 @@ sub mksnapshot {
if ($self->record->level != 0) {
my $prev = $self->snapshot_name($item, 1);
if ($prev) {
- $self->debug(1, "cp $prev $snapshot");
+ $self->debug(2, "cp $prev $snapshot");
unless ($self->dry_run) {
use File::Copy;
unless (copy($prev, $snapshot)) {
@@ -151,7 +151,7 @@ sub backup {
$cmd->add('.');
}
- $self->debug(1, "running ".$cmd->command_line);
+ $self->debug(2, "running ".$cmd->command_line);
my $ret = STATE_SUCCESS;
unless ($self->dry_run) {
$cmd->run;
@@ -186,7 +186,6 @@ sub find_full_backup {
sub restore_from {
my ($self, $index, $item) = @_;
- print "restore $item from $index\n";
my $basename = $self->{beam}->format_name($item, $index);
croak "undefined basename" unless defined $basename;
my $archive = $self->get('core', 'archivedir')
@@ -194,6 +193,7 @@ sub restore_from {
. $basename
. '.'
. $self->get('backend', 'tar', 'suffix');
+ $self->debug(1, "restoring \"$item\" from $archive");
my $cmd = new App::Beam::Command($self->get('backend', 'tar', 'binary'));
$cmd->set_logger(CHAN_STDERR, sub { $self->logger('err', $_) });
@@ -208,7 +208,7 @@ sub restore_from {
$cmd->add('-C', $self->get('item', $item, 'directory'));
$cmd->add('--listed', '/dev/null');
- $self->debug(1, "running ".$cmd->command_line);
+ $self->debug(2, "running ".$cmd->command_line);
my $ret = STATE_SUCCESS;
unless ($self->dry_run) {
$cmd->run;
@@ -224,10 +224,15 @@ sub restore {
my $i = $self->find_full_backup($index, $item);
return unless defined $i;
+ my $result = STATE_SUCCESS;
+
while ($i >= $index) {
- $self->restore_from($i, $item);
+ if ($self->restore_from($i, $item) != STATE_SUCCESS) {
+ $result = STATE_FAILURE;
+ }
$i--;
}
+ return $result;
}
1;
diff --git a/lib/App/Beam/Backup.pm b/lib/App/Beam/Backup.pm
index c2da254..68d7360 100644
--- a/lib/App/Beam/Backup.pm
+++ b/lib/App/Beam/Backup.pm
@@ -7,6 +7,7 @@ require App::Beam;
our @ISA = qw(App::Beam);
use Unix::Sysexits;
+use App::Beam::History::Entry qw(state_string);
=head1 NAME
@@ -43,11 +44,15 @@ sub run {
#GetOptionsFromArray(\@_, ...);
my @items = $self->check_items(@_);
-
+ $self->debug(1, "creating backup " . $self->format_name);
foreach my $item (@items) {
+ $self->debug(1, "backing up $item");
my $backend = $self->{backend}{$self->get("item.$item.backend")};
$self->{history}->top->begin_entry($item);
- $self->{history}->top->finish_entry($item, $backend->backup($item));
+ my $ret = $backend->backup($item);
+ $self->{history}->top->finish_entry($item, $ret);
+ $self->update_status($ret);
+ $self->debug(1, "$item: " . state_string($ret));
}
}
diff --git a/lib/App/Beam/History/Entry.pm b/lib/App/Beam/History/Entry.pm
index 8443f3f..e5a8c7e 100644
--- a/lib/App/Beam/History/Entry.pm
+++ b/lib/App/Beam/History/Entry.pm
@@ -5,7 +5,7 @@ use Carp;
require Exporter;
our @ISA = qw(Exporter);
-our @EXPORT_OK = qw(STATE_PENDING STATE_SUCCESS STATE_FAILURE);
+our @EXPORT_OK = qw(STATE_PENDING STATE_SUCCESS STATE_FAILURE state_string);
our %EXPORT_TAGS = (
state => [ qw(STATE_PENDING STATE_SUCCESS STATE_FAILURE) ]
);
@@ -40,9 +40,15 @@ sub state {
return $self->{state};
}
+sub state_string {
+ my ($state) = @_;
+ return $state unless $state <= $#state_str;
+ return $state_str[$state];
+}
+
sub state_name {
my ($self) = @_;
- return $state_str[$self->state];
+ return state_string($self->state);
}
sub start_time {
diff --git a/lib/App/Beam/Restore.pm b/lib/App/Beam/Restore.pm
index 7e3129a..5c2dcf2 100644
--- a/lib/App/Beam/Restore.pm
+++ b/lib/App/Beam/Restore.pm
@@ -8,7 +8,7 @@ our @ISA = qw(App::Beam);
use Unix::Sysexits;
use App::Beam;
-use App::Beam::History::Entry qw(:state);
+use App::Beam::History::Entry qw(state_string :state);
use Getopt::Long qw(GetOptionsFromArray);
=head1 NAME
@@ -69,13 +69,17 @@ sub run {
unless defined $index;
}
- $self->debug(1, "restoring from backup $index");
+ $self->debug(1, "restoring from backup " .
+ $self->format_name(undef, $index));
$self->abend(EX_UNAVAILABLE, "backup $index was not successful")
unless $self->{history}->top($index)->state == STATE_SUCCESS;
foreach my $item (@items) {
+ $self->debug(1, "restoring $item");
my $backend = $self->{backend}{$self->get("item.$item.backend")};
- $backend->restore($index, $item);
+ my $status = $backend->restore($index, $item);
+ $self->update_status($status);
+ $self->debug(1, "$item: " . state_string($status));
}
}

Return to:

Send suggestions and report system problems to the System administrator.