| OLD | NEW |
| 1 package Brackup::Target::Amazon; | 1 package Brackup::Target::Amazon; |
| 2 use strict; | 2 use strict; |
| 3 use warnings; | 3 use warnings; |
| 4 use base 'Brackup::Target'; | 4 use base 'Brackup::Target'; |
| 5 use Net::Amazon::S3 0.41; | 5 use Net::Amazon::S3 0.41; |
| 6 | 6 |
| 7 # fields in object: | 7 # fields in object: |
| 8 # s3 -- Net::Amazon::S3 | 8 # s3 -- Net::Amazon::S3 |
| 9 # access_key_id | 9 # access_key_id |
| 10 # sec_access_key_id | 10 # sec_access_key_id |
| 11 # prefix | 11 # prefix |
| 12 # location | 12 # location |
| 13 # chunk_bucket : $self->{prefix} . "-chunks"; | 13 # chunk_bucket : $self->{prefix} . "-chunks"; |
| 14 # backup_bucket : $self->{prefix} . "-backups"; | 14 # backup_bucket : $self->{prefix} . "-backups"; |
| 15 # backup_prefix : added to the front of backup names when stored | 15 # backup_prefix : added to the front of backup names when stored |
| 16 # | 16 # |
| 17 | 17 |
| 18 sub new { | 18 sub new { |
| 19 my ($class, $confsec) = @_; | 19 my ($class, $confsec) = @_; |
| 20 my $self = $class->SUPER::new($confsec); | 20 my $self = $class->SUPER::new($confsec); |
| 21 | 21 |
| 22 $self->{access_key_id} = $confsec->value("aws_access_key_id") | 22 $self->{access_key_id} = $confsec->value("aws_access_key_id") |
| 23 or die "No 'aws_access_key_id'"; | 23 or die "No 'aws_access_key_id'"; |
| 24 $self->{sec_access_key_id} = $confsec->value("aws_secret_access_key") | 24 $self->{sec_access_key_id} = $confsec->value("aws_secret_access_key") |
| 25 or die "No 'aws_secret_access_key'"; | 25 or die "No 'aws_secret_access_key'"; |
| 26 $self->{prefix} = $confsec->value("aws_prefix") || $self->{access_key_id}; | 26 $self->{prefix} = $confsec->value("aws_prefix") || $self->{access_key_id}; |
| 27 $self->{location} = $confsec->value("aws_location") || undef; | 27 $self->{location} = $confsec->value("aws_location") || undef; |
| 28 $self->{backup_prefix} = $confsec->value("backup_prefix") || undef; | 28 $self->{backup_prefix} = $confsec->value("backup_prefix") || undef; |
| 29 | 29 |
| 30 $self->_common_s3_init; | 30 $self->_common_s3_init; |
| 31 | 31 |
| 32 my $s3 = $self->{s3}; | 32 my $s3 = $self->{s3}; |
| 33 my $buckets = $s3->buckets or die "Failed to get bucket list"; | 33 my $buckets = $s3->buckets or die "Failed to get bucket list"; |
| 34 | 34 |
| 35 unless (grep { $_->{bucket} eq $self->{chunk_bucket} } @{ $buckets->{buckets
} }) { | 35 unless (grep { $_->{bucket} eq $self->{chunk_bucket} } @{ $buckets->{buckets
} }) { |
| 36 $s3->add_bucket({ bucket => $self->{chunk_bucket}, location_constraint =
> $self->{location} }) | 36 $s3->add_bucket({ bucket => $self->{chunk_bucket}, location_constraint =
> $self->{location} }) |
| 37 or die "Chunk bucket creation failed\n"; | 37 or die "Chunk bucket creation failed\n"; |
| 38 } | 38 } |
| 39 | 39 |
| 40 unless (grep { $_->{bucket} eq $self->{backup_bucket} } @{ $buckets->{bucket
s} }) { | 40 unless (grep { $_->{bucket} eq $self->{backup_bucket} } @{ $buckets->{bucket
s} }) { |
| 41 $s3->add_bucket({ bucket => $self->{backup_bucket}, location_constraint
=> $self->{location} }) | 41 $s3->add_bucket({ bucket => $self->{backup_bucket}, location_constraint
=> $self->{location} }) |
| 42 or die "Backup bucket creation failed\n"; | 42 or die "Backup bucket creation failed\n"; |
| 43 } | 43 } |
| 44 | 44 |
| 45 return $self; | 45 return $self; |
| 46 } | 46 } |
| 47 | 47 |
| 48 sub _common_s3_init { | 48 sub _common_s3_init { |
| 49 my $self = shift; | 49 my $self = shift; |
| 50 $self->{chunk_bucket} = $self->{prefix} . "-chunks"; | 50 $self->{chunk_bucket} = $self->{prefix} . "-chunks"; |
| 51 $self->{backup_bucket} = $self->{prefix} . "-backups"; | 51 $self->{backup_bucket} = $self->{prefix} . "-backups"; |
| 52 $self->{s3} = Net::Amazon::S3->new({ | 52 $self->{s3} = Net::Amazon::S3->new({ |
| 53 aws_access_key_id => $self->{access_key_id}, | 53 aws_access_key_id => $self->{access_key_id}, |
| 54 aws_secret_access_key => $self->{sec_access_key_id}, | 54 aws_secret_access_key => $self->{sec_access_key_id}, |
| 55 retry => 1 |
| 55 }); | 56 }); |
| 56 } | 57 } |
| 57 | 58 |
| 58 # ghetto | 59 # ghetto |
| 59 sub _prompt { | 60 sub _prompt { |
| 60 my ($q) = @_; | 61 my ($q) = @_; |
| 61 print "$q"; | 62 print "$q"; |
| 62 my $ans = <STDIN>; | 63 my $ans = <STDIN>; |
| 63 $ans =~ s/^\s+//; | 64 $ans =~ s/^\s+//; |
| 64 $ans =~ s/\s+$//; | 65 $ans =~ s/\s+$//; |
| 65 return $ans; | 66 return $ans; |
| 66 } | 67 } |
| 67 | 68 |
| 68 sub new_from_backup_header { | 69 sub new_from_backup_header { |
| 69 my ($class, $header) = @_; | 70 my ($class, $header) = @_; |
| 70 | 71 |
| 71 my $accesskey = ($ENV{'AWS_KEY'} || _prompt("Your Amazon AWS access key?
")) | 72 my $accesskey = ($ENV{'AWS_KEY'} || _prompt("Your Amazon AWS access key?
")) |
| 72 or die "Need your Amazon access key.\n"; | 73 or die "Need your Amazon access key.\n"; |
| 73 my $sec_accesskey = ($ENV{'AWS_SEC_KEY'} || _prompt("Your Amazon AWS secret
access key? ")) | 74 my $sec_accesskey = ($ENV{'AWS_SEC_KEY'} || _prompt("Your Amazon AWS secret
access key? ")) |
| 74 or die "Need your Amazon secret access key.\n"; | 75 or die "Need your Amazon secret access key.\n"; |
| 75 my $prefix = ($ENV{'AWS_PREFIX'} || _prompt("Your Amazon AWS prefix? (Leave
empty if none) ")); | 76 my $prefix = ($ENV{'AWS_PREFIX'} || _prompt("Your Amazon AWS prefix? (Leave
empty if none) ")); |
| 76 | 77 |
| 77 my $self = bless {}, $class; | 78 my $self = bless {}, $class; |
| 78 $self->{access_key_id} = $accesskey; | 79 $self->{access_key_id} = $accesskey; |
| 79 $self->{sec_access_key_id} = $sec_accesskey; | 80 $self->{sec_access_key_id} = $sec_accesskey; |
| 80 $self->{prefix} = $prefix || $self->{access_key_id}; | 81 $self->{prefix} = $prefix || $self->{access_key_id}; |
| 81 $self->_common_s3_init; | 82 $self->_common_s3_init; |
| 82 return $self; | 83 return $self; |
| 83 } | 84 } |
| 84 | 85 |
| 85 sub has_chunk { | 86 sub has_chunk { |
| 86 my ($self, $chunk) = @_; | 87 my ($self, $chunk) = @_; |
| 87 my $dig = $chunk->backup_digest; # "sha1:sdfsdf" format scalar | 88 my $dig = $chunk->backup_digest; # "sha1:sdfsdf" format scalar |
| 88 | 89 |
| 89 my $res = eval { $self->{s3}->head_key({ bucket => $self->{chunk_bucket}, ke
y => $dig }); }; | 90 my $res = eval { $self->{s3}->head_key({ bucket => $self->{chunk_bucket}, ke
y => $dig }); }; |
| 90 return 0 unless $res; | 91 return 0 unless $res; |
| 91 return 0 if $@ && $@ =~ /key not found/; | 92 return 0 if $@ && $@ =~ /key not found/; |
| 92 return 0 unless $res->{content_type} eq "x-danga/brackup-chunk"; | 93 return 0 unless $res->{content_type} eq "x-danga/brackup-chunk"; |
| 93 return 1; | 94 return 1; |
| 94 } | 95 } |
| 95 | 96 |
| 96 sub load_chunk { | 97 sub load_chunk { |
| 97 my ($self, $dig) = @_; | 98 my ($self, $dig) = @_; |
| 98 my $bucket = $self->{s3}->bucket($self->{chunk_bucket}); | 99 my $bucket = $self->{s3}->bucket($self->{chunk_bucket}); |
| 99 | 100 |
| 100 my $val = $bucket->get_key($dig) | 101 my $val = $bucket->get_key($dig) |
| 101 or return 0; | 102 or return 0; |
| 102 return \ $val->{value}; | 103 return \ $val->{value}; |
| 103 } | 104 } |
| 104 | 105 |
| (...skipping 118 matching lines...) Show 10 above Show 10 below |
| 223 =head1 CONFIG OPTIONS | 224 =head1 CONFIG OPTIONS |
| 224 | 225 |
| 225 All options may be omitted unless specified. | 226 All options may be omitted unless specified. |
| 226 | 227 |
| 227 =over | 228 =over |
| 228 | 229 |
| 229 =item B<type> | 230 =item B<type> |
| 230 | 231 |
| 231 I<(Mandatory.)> Must be "B<Amazon>". | 232 I<(Mandatory.)> Must be "B<Amazon>". |
| 232 | 233 |
| 233 =item B<aws_access_key_id> | 234 =item B<aws_access_key_id> |
| 234 | 235 |
| 235 I<(Mandatory.)> Your Amazon Web Services access key id. | 236 I<(Mandatory.)> Your Amazon Web Services access key id. |
| 236 | 237 |
| 237 =item B<aws_secret_access_key> | 238 =item B<aws_secret_access_key> |
| 238 | 239 |
| 239 I<(Mandatory.)> Your Amazon Web Services secret password for the above access ke
y. (not your Amazon password) | 240 I<(Mandatory.)> Your Amazon Web Services secret password for the above access ke
y. (not your Amazon password) |
| 240 | 241 |
| 241 =item B<aws_prefix> | 242 =item B<aws_prefix> |
| 242 | 243 |
| 243 If you want to setup multiple backup targets on a single Amazon account you can | 244 If you want to setup multiple backup targets on a single Amazon account you can |
| 244 use different prefixes. This string is used to name the S3 buckets created by | 245 use different prefixes. This string is used to name the S3 buckets created by |
| 245 Brackup. If not specified it defaults to the AWS access key id. | 246 Brackup. If not specified it defaults to the AWS access key id. |
| 246 | 247 |
| 247 =item B<aws_location> | 248 =item B<aws_location> |
| 248 | 249 |
| 249 Sets the location constraint of the new buckets. If left unspecified, the | 250 Sets the location constraint of the new buckets. If left unspecified, the |
| 250 default S3 datacenter location will be used. Otherwise, you can set it | 251 default S3 datacenter location will be used. Otherwise, you can set it |
| 251 to 'EU' for an AWS European data center - note that costs are different. | 252 to 'EU' for an AWS European data center - note that costs are different. |
| 252 This has only effect when your backup environment is initialized in S3 (i.e. | 253 This has only effect when your backup environment is initialized in S3 (i.e. |
| 253 when buckets are created). If you want to move an existing backup environment | 254 when buckets are created). If you want to move an existing backup environment |
| 254 to another datacenter location, you have to delete its buckets before or create | 255 to another datacenter location, you have to delete its buckets before or create |
| 255 a new one by specifing a different I<aws_prefix>. | 256 a new one by specifing a different I<aws_prefix>. |
| 256 | 257 |
| 257 =item B<backup_prefix> | 258 =item B<backup_prefix> |
| 258 | 259 |
| 259 When storing the backup metadata to S3, the string specified here will be | 260 When storing the backup metadata to S3, the string specified here will be |
| 260 prefixed onto the backup name. This is useful if you are collecting | 261 prefixed onto the backup name. This is useful if you are collecting |
| 261 backups from several hosts into a single Amazon S3 account but need to | 262 backups from several hosts into a single Amazon S3 account but need to |
| 262 be able to differentiate them; set your prefix to be the hostname | 263 be able to differentiate them; set your prefix to be the hostname |
| 263 of each system, for example. | 264 of each system, for example. |
| 264 | 265 |
| 265 =back | 266 =back |
| 266 | 267 |
| 267 =head1 SEE ALSO | 268 =head1 SEE ALSO |
| 268 | 269 |
| 269 L<Brackup::Target> | 270 L<Brackup::Target> |
| 270 | 271 |
| 271 L<Net::Amazon::S3> -- required module to use Brackup::Target::Amazon | 272 L<Net::Amazon::S3> -- required module to use Brackup::Target::Amazon |
| 272 | 273 |
| OLD | NEW |