6a51bae400
(ref http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_disabling_write_access_to_take_backups) code from David Bremner via email
151 lines
3.8 KiB
Perl
151 lines
3.8 KiB
Perl
#!/usr/bin/perl
|
|
# Copyright 2011, David Bremner <bremner@debian.org>
|
|
#
|
|
# This add-on to gitolite is licensed under the same terms as gitolite
|
|
# At the time of this writing this is GPL-2, but I also grant
|
|
# Sitaram Chamarty the right to re-license as he chooses.
|
|
|
|
=pod
|
|
|
|
S3BACKUP - Backup the whole gitolite home directory to amazon s3.
|
|
|
|
RUNNING
|
|
|
|
To run it (assuming you call this "s3backup")
|
|
As an ADC, only by a user with read access to gitolite-admin :
|
|
|
|
ssh git@server s3backup [-v error|warning|notice|info|debug] [subcommands]
|
|
|
|
You must pass the AWS_SECRET_ACCESS_KEY on stdin.
|
|
|
|
SUBCOMMANDS
|
|
|
|
You may optionally pass one of the following sub commands
|
|
|
|
=over
|
|
|
|
=item incr|full
|
|
|
|
Run incremental or full backup. By default, leave it to duplicity to
|
|
guess.
|
|
|
|
=item prune
|
|
|
|
remove all but $S3_KEEP_FULL (see Configuration below)
|
|
|
|
=back
|
|
|
|
OPTIONS
|
|
|
|
-v specifies a log level, passed straight to duplicity.
|
|
incr or full specify backup level
|
|
|
|
CONFIGURATION
|
|
|
|
Make a file ~git/.s3backup.rc that looks like
|
|
|
|
$S3_EUROPE=0; # 1 to store in europe
|
|
# (only matters at creation)
|
|
$S3_KEEP_FULL=3; # keep 3 full backups
|
|
$S3_BUCKET="my_bucket"; # s3 bucket name, will be created
|
|
# if it doesn't exist.
|
|
$S3_AWS_KEY_ID="ABADABA57DOO"; # this is the _non_ secret one
|
|
$S3_ENCRYPT_KEY="DEADBEEF AA232332"; # gpg keys, space delimited.
|
|
# note that duplicity will abort if
|
|
# these keys are not trusted
|
|
=cut
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
|
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
|
|
|
unshift @INC, $ENV{GL_BINDIR};
|
|
require gitolite or die "parse gitolite.pm failed\n";
|
|
gitolite->import;
|
|
|
|
my ($perm, $creator) = check_access("gitolite-admin");
|
|
die "no read access to gitolite-admin\n" unless $perm =~ /R/;
|
|
|
|
our ($S3_EUROPE, $S3_BUCKET, $S3_AWS_KEY_ID, $S3_ENCRYPT_KEYS, $S3_KEEP_FULL);
|
|
|
|
chdir($ENV{HOME}) or die "chdir $ENV{HOME} : $!\n";
|
|
|
|
my $configfile = $ENV{HOME} . "/.s3backup.rc";
|
|
|
|
do $configfile or die "error parsing $configfile\n";
|
|
|
|
# ANCHOR ALL PATTERNS
|
|
die 'bad value for $S3_EUROPE'
|
|
unless (defined($S3_EUROPE) && $S3_EUROPE =~ m/^0|1$/);
|
|
|
|
die 'bad value for $S3_KEEP_FULL'
|
|
unless (defined($S3_KEEP_FULL) && $S3_KEEP_FULL =~ m/^[0-9]+$/);
|
|
|
|
die 'bad value for $S3_BACKUP'
|
|
unless (defined($S3_BUCKET) && $S3_BUCKET =~ m/^[a-z\-_0-9\.]+$/);
|
|
|
|
die 'bad value for $S3_AWS_KEY_ID'
|
|
unless (defined($S3_AWS_KEY_ID) && $S3_AWS_KEY_ID =~ m/^[A-Z0-9]+$/);
|
|
|
|
die 'bad value for $S3_ENCRYPT_KEYS'
|
|
unless (defined($S3_ENCRYPT_KEYS) &&
|
|
$S3_ENCRYPT_KEYS =~ m/^[a-fA-F0-9]+(\s+[a-fA-F0-9]+)*/);
|
|
|
|
my $verbosity='notice';
|
|
if (scalar(@ARGV)>0 and $ARGV[0] eq '-v'){
|
|
shift;
|
|
$verbosity = shift;
|
|
}
|
|
|
|
die "bad verbosity" unless ($verbosity =~ m/^(error|warning|notice|info|debug)$/);
|
|
|
|
my $subcommand=shift || 'default';
|
|
|
|
die "bad subcommand" if (defined($subcommand) &&
|
|
$subcommand !~ m/^(incr|full|prune|default)$/);
|
|
|
|
$ENV{AWS_ACCESS_KEY_ID}=$S3_AWS_KEY_ID;
|
|
|
|
chomp($ENV{AWS_SECRET_ACCESS_KEY}=<>) or
|
|
die "must pass SECRET_ACCESS_KEY on stdin";
|
|
|
|
my @args=();
|
|
|
|
if ($subcommand ne 'default' ){
|
|
if ($subcommand eq 'prune') {
|
|
push(@args, 'remove-all-but-n-full', $S3_KEEP_FULL, '--force');
|
|
} else {
|
|
push(@args, $subcommand);
|
|
}
|
|
}
|
|
|
|
push(@args, '--verb', $verbosity);
|
|
push(@args, '--s3-use-new-style');
|
|
foreach my $key (split(' ',$S3_ENCRYPT_KEYS)){
|
|
push(@args, '--encrypt-key', $key);
|
|
}
|
|
|
|
push(@args, '--s3-european-buckets') if ($S3_EUROPE);
|
|
|
|
push(@args, $ENV{HOME}) unless ($subcommand eq 'prune');
|
|
|
|
push(@args, 's3+http://'.$S3_BUCKET);
|
|
|
|
my $semaphore=$ENV{HOME}."/.gitolite.down";
|
|
|
|
die "$semaphore already exists" if (-f $semaphore);
|
|
|
|
eval {
|
|
open (SEMFD,'>',$semaphore) or die ("failed to open $semaphore");
|
|
my $now = gmtime();
|
|
print SEMFD "Repo unavailable due to $subcommand backup started at $now GMT\n";
|
|
close SEMFD;
|
|
|
|
system '/usr/bin/duplicity', @args;
|
|
|
|
};
|
|
|
|
unlink $semaphore;
|