astrails-safe 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +30 -5
- data/Rakefile +8 -3
- data/VERSION.yml +1 -1
- data/bin/astrails-safe +3 -3
- data/examples/unit/gpg_example.rb +19 -9
- data/examples/unit/mysqldump_example.rb +8 -8
- data/lib/astrails/safe.rb +3 -1
- data/lib/astrails/safe/cloudfiles.rb +64 -0
- data/lib/astrails/safe/config/builder.rb +1 -1
- data/lib/astrails/safe/gpg.rb +3 -2
- data/lib/astrails/safe/mysqldump.rb +2 -1
- data/lib/astrails/safe/s3.rb +0 -1
- data/templates/script.rb +20 -1
- metadata +19 -5
data/README.markdown
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
astrails-safe
|
2
2
|
=============
|
3
3
|
|
4
|
-
Simple database and filesystem backups with S3 support (with optional encryption)
|
4
|
+
Simple database and filesystem backups with S3 and Rackspace Cloud Files support (with optional encryption)
|
5
5
|
|
6
6
|
Home: http://blog.astrails.com/astrails-safe
|
7
7
|
|
@@ -15,8 +15,8 @@ We needed a backup solution that will satisfy the following requirements:
|
|
15
15
|
* support for simple ‘tar’ backups of directories (with includes/excludes)
|
16
16
|
* support for simple mysqldump of mysql databases
|
17
17
|
* support for symmetric or public key encryption
|
18
|
-
* support for local filesystem
|
19
|
-
* support for backup rotation. we don’t want backups filling all the diskspace or cost a fortune on S3
|
18
|
+
* support for local filesystem, Amazon S3, and Rackspace Cloud Files for storage
|
19
|
+
* support for backup rotation. we don’t want backups filling all the diskspace or cost a fortune on S3 or Cloud Files
|
20
20
|
|
21
21
|
And since we didn't find any, we wrote our own :)
|
22
22
|
|
@@ -29,6 +29,10 @@ The following functionality was contributed by astrails-safe users:
|
|
29
29
|
* Subversion dump using svndump (by Richard Luther <richard.luther@gmail.com>)
|
30
30
|
* SFTP remote storage (by Adam <adam@mediadrive.ca>)
|
31
31
|
* benchmarking output (By Neer)
|
32
|
+
* README fixes (by Bobby Wilson)
|
33
|
+
* improved config file parsing (by Fedor Kocherga <fkocherga@gmail.com>)
|
34
|
+
* mysql password file quoting (by Jonathan Sutherland <jonathan.sutherland@gmail.com>)
|
35
|
+
* Rackspace Cloud Files support (by H. Wade Minter <minter@lunenburg.org>)
|
32
36
|
|
33
37
|
Thanks to all :)
|
34
38
|
|
@@ -51,7 +55,7 @@ Usage
|
|
51
55
|
-h, --help This help screen
|
52
56
|
-v, --verbose be verbose, duh!
|
53
57
|
-n, --dry-run just pretend, don't do anything.
|
54
|
-
-L, --local skip
|
58
|
+
-L, --local skip remote storage, only do local backups
|
55
59
|
|
56
60
|
Note: CONFIG_FILE will be created from template if missing
|
57
61
|
|
@@ -62,6 +66,15 @@ If you want to encrypt your backups you have 2 options:
|
|
62
66
|
* use simple password encryption
|
63
67
|
* use GPG public key encryption
|
64
68
|
|
69
|
+
> IMPORTANT: some gpg installations automatically set 'use-agent' option in the default
|
70
|
+
> configuration file that is created when you run gpg for the first time. This will cause
|
71
|
+
> gpg to fail on the 2nd run if you don't have the agent running. The result is that
|
72
|
+
> 'astrails-safe' will work ONCE when you manually test it and then fail on any subsequent run.
|
73
|
+
> The solution is to remove the 'use-agent' from the config file (usually /root/.gnupg/gpg.conf)
|
74
|
+
> To mitigate this problem for the gpg 1.x series '--no-use-agent' option is added by defaults
|
75
|
+
> to the autogenerated config file, but for gpg2 is doesn't work. as the manpage says it:
|
76
|
+
> "This is dummy option. gpg2 always requires the agent." :(
|
77
|
+
|
65
78
|
For simple password, just add password entry in gpg section.
|
66
79
|
For public key encryption you will need to create a public/secret keypair.
|
67
80
|
|
@@ -133,6 +146,14 @@ Example configuration
|
|
133
146
|
path "servers/alpha/:kind/:id"
|
134
147
|
end
|
135
148
|
|
149
|
+
cloudfiles do
|
150
|
+
username "..........."
|
151
|
+
api_key "................................."
|
152
|
+
container "safe_backup"
|
153
|
+
path ":kind/" # this is default
|
154
|
+
service_net false
|
155
|
+
end
|
156
|
+
|
136
157
|
sftp do
|
137
158
|
host "sftp.astrails.com"
|
138
159
|
user "astrails"
|
@@ -141,6 +162,8 @@ Example configuration
|
|
141
162
|
end
|
142
163
|
|
143
164
|
gpg do
|
165
|
+
command "/usr/local/bin/gpg"
|
166
|
+
options "--no-use-agent"
|
144
167
|
# symmetric encryption key
|
145
168
|
# password "qwe"
|
146
169
|
|
@@ -150,7 +173,9 @@ Example configuration
|
|
150
173
|
|
151
174
|
keep do
|
152
175
|
local 20
|
153
|
-
s3
|
176
|
+
s3 100
|
177
|
+
cloudfiles 100
|
178
|
+
sftp 100
|
154
179
|
end
|
155
180
|
|
156
181
|
mysqldump do
|
data/Rakefile
CHANGED
@@ -5,14 +5,19 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "astrails-safe"
|
8
|
-
gem.summary = %Q{Backup filesystem and databases (MySQL and PostgreSQL) to
|
9
|
-
gem.description =
|
8
|
+
gem.summary = %Q{Backup filesystem and databases (MySQL and PostgreSQL) locally or to a remote server/service (with encryption)}
|
9
|
+
gem.description = <<-DESC
|
10
|
+
Astrails-Safe is a simple tool to backup databases (MySQL and PostgreSQL), Subversion repositories (with svndump) and just files.
|
11
|
+
Backups can be stored locally or remotely and can be enctypted.
|
12
|
+
Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain SFTP.
|
13
|
+
DESC
|
10
14
|
gem.email = "we@astrails.com"
|
11
15
|
gem.homepage = "http://blog.astrails.com/astrails-safe"
|
12
|
-
gem.authors = ["Astrails Ltd."
|
16
|
+
gem.authors = ["Astrails Ltd."]
|
13
17
|
gem.files = FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test,templates}/**/*", 'Rakefile', 'LICENSE*']
|
14
18
|
|
15
19
|
gem.add_dependency("aws-s3")
|
20
|
+
gem.add_dependency("cloudfiles")
|
16
21
|
gem.add_dependency("net-sftp")
|
17
22
|
|
18
23
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
data/VERSION.yml
CHANGED
data/bin/astrails-safe
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
|
5
|
-
#require 'ruby-debug'
|
6
|
-
|
5
|
+
# require 'ruby-debug'
|
6
|
+
$:.unshift File.expand_path("../../lib", __FILE__)
|
7
7
|
|
8
8
|
require 'astrails/safe'
|
9
9
|
include Astrails::Safe
|
@@ -20,7 +20,7 @@ Options:
|
|
20
20
|
-h, --help This help screen
|
21
21
|
-v, --verbose be verbose, duh!
|
22
22
|
-n, --dry-run just pretend, don't do anything.
|
23
|
-
-L, --local skip S3
|
23
|
+
-L, --local skip S3 and Cloud Files
|
24
24
|
|
25
25
|
Note: config file will be created from template if missing
|
26
26
|
END
|
@@ -102,28 +102,38 @@ describe Astrails::Safe::Gpg do
|
|
102
102
|
describe :pipe do
|
103
103
|
|
104
104
|
describe "with key" do
|
105
|
-
|
106
|
-
|
105
|
+
def kgpg(extra={})
|
106
|
+
gpg({:gpg => {:key => "foo", :options => "GPG-OPT"}.merge(extra), :options => "OPT"})
|
107
107
|
end
|
108
108
|
|
109
109
|
it "should not call gpg_password_file" do
|
110
|
-
|
111
|
-
|
110
|
+
g = kgpg
|
111
|
+
dont_allow(g).gpg_password_file(anything)
|
112
|
+
g.send(:pipe)
|
112
113
|
end
|
113
114
|
|
114
115
|
it "should use '-r' and :options" do
|
115
|
-
|
116
|
+
kgpg.send(:pipe).should == "|gpg GPG-OPT -e -r foo"
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should use the 'command' options" do
|
120
|
+
kgpg(:command => 'other-gpg').send(:pipe).should == "|other-gpg GPG-OPT -e -r foo"
|
116
121
|
end
|
117
122
|
end
|
118
123
|
|
119
124
|
describe "with password" do
|
120
|
-
|
121
|
-
|
122
|
-
|
125
|
+
def pgpg(extra = {})
|
126
|
+
returning(gpg({:gpg => {:password => "bar", :options => "GPG-OPT"}.merge(extra), :options => "OPT"})) do |g|
|
127
|
+
stub(g).gpg_password_file(anything) {"pass-file"}
|
128
|
+
end
|
123
129
|
end
|
124
130
|
|
125
131
|
it "should use '--passphrase-file' and :options" do
|
126
|
-
|
132
|
+
pgpg.send(:pipe).should == "|gpg GPG-OPT -c --passphrase-file pass-file"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should use the 'command' options" do
|
136
|
+
pgpg(:command => 'other-gpg').send(:pipe).should == "|other-gpg GPG-OPT -c --passphrase-file pass-file"
|
127
137
|
end
|
128
138
|
end
|
129
139
|
end
|
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
|
|
2
2
|
|
3
3
|
describe Astrails::Safe::Mysqldump do
|
4
4
|
|
5
|
-
def def_config
|
5
|
+
def def_config(extra = {})
|
6
6
|
{
|
7
7
|
:options => "OPTS",
|
8
8
|
:user => "User",
|
@@ -11,7 +11,7 @@ describe Astrails::Safe::Mysqldump do
|
|
11
11
|
:port => 7777,
|
12
12
|
:socket => "socket",
|
13
13
|
:skip_tables => [:bar, :baz]
|
14
|
-
}
|
14
|
+
}.merge(extra)
|
15
15
|
end
|
16
16
|
|
17
17
|
def mysqldump(id = :foo, config = def_config)
|
@@ -66,16 +66,16 @@ describe Astrails::Safe::Mysqldump do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
describe :mysql_password_file do
|
69
|
-
it "should create passwords file" do
|
70
|
-
m = mysqldump
|
69
|
+
it "should create passwords file with quoted values" do
|
70
|
+
m = mysqldump(:foo, def_config(:password => '#qwe"asd\'zxc'))
|
71
71
|
file = m.send(:mysql_password_file)
|
72
72
|
File.exists?(file).should == true
|
73
73
|
File.read(file).should == <<-PWD
|
74
74
|
[mysqldump]
|
75
|
-
user = User
|
76
|
-
password =
|
77
|
-
socket = socket
|
78
|
-
host = localhost
|
75
|
+
user = "User"
|
76
|
+
password = "#qwe\\"asd'zxc"
|
77
|
+
socket = "socket"
|
78
|
+
host = "localhost"
|
79
79
|
port = 7777
|
80
80
|
PWD
|
81
81
|
end
|
data/lib/astrails/safe.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "aws/s3"
|
2
|
+
require "cloudfiles"
|
2
3
|
require 'net/sftp'
|
3
4
|
require 'fileutils'
|
4
5
|
require 'benchmark'
|
@@ -30,6 +31,7 @@ require 'astrails/safe/gzip'
|
|
30
31
|
require 'astrails/safe/sink'
|
31
32
|
require 'astrails/safe/local'
|
32
33
|
require 'astrails/safe/s3'
|
34
|
+
require 'astrails/safe/cloudfiles'
|
33
35
|
require 'astrails/safe/sftp'
|
34
36
|
|
35
37
|
module Astrails
|
@@ -48,7 +50,7 @@ module Astrails
|
|
48
50
|
].each do |klass, path|
|
49
51
|
if collection = config[*path]
|
50
52
|
collection.each do |name, config|
|
51
|
-
klass.new(name, config).backup.run(config, :gpg, :gzip, :local, :s3, :sftp)
|
53
|
+
klass.new(name, config).backup.run(config, :gpg, :gzip, :local, :s3, :cloudfiles, :sftp)
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Astrails
|
2
|
+
module Safe
|
3
|
+
class Cloudfiles < Sink
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
def active?
|
8
|
+
container && user && api_key
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
@path ||= expand(config[:cloudfiles, :path] || config[:local, :path] || ":kind/:id")
|
13
|
+
end
|
14
|
+
|
15
|
+
def save
|
16
|
+
raise RuntimeError, "pipe-streaming not supported for S3." unless @backup.path
|
17
|
+
|
18
|
+
# needed in cleanup even on dry run
|
19
|
+
cf = CloudFiles::Connection.new(user, api_key, true, service_net) unless $LOCAL
|
20
|
+
puts "Uploading #{container}:#{full_path} from #{@backup.path}" if $_VERBOSE || $DRY_RUN
|
21
|
+
unless $DRY_RUN || $LOCAL
|
22
|
+
benchmark = Benchmark.realtime do
|
23
|
+
cf_container = cf.create_container(container)
|
24
|
+
o = cf_container.create_object(full_path,true)
|
25
|
+
o.write(open(@backup.path))
|
26
|
+
end
|
27
|
+
puts "...done" if $_VERBOSE
|
28
|
+
puts("Upload took " + sprintf("%.2f", benchmark) + " second(s).") if $_VERBOSE
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def cleanup
|
33
|
+
return if $LOCAL
|
34
|
+
|
35
|
+
return unless keep = @config[:keep, :cloudfiles]
|
36
|
+
|
37
|
+
puts "listing files: #{container}:#{base}*" if $_VERBOSE
|
38
|
+
cf = CloudFiles::Connection.new(user, api_key, true, service_net) unless $LOCAL
|
39
|
+
files = cf.container(container).objects(:prefix => base)
|
40
|
+
|
41
|
+
cleanup_with_limit(files, keep) do |f|
|
42
|
+
puts "removing Cloud File #{container}:#{f}" if $DRY_RUN || $_VERBOSE
|
43
|
+
cf.container(container).delete_object(f) unless $DRY_RUN || $LOCAL
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def container
|
48
|
+
@config[:cloudfiles, :container]
|
49
|
+
end
|
50
|
+
|
51
|
+
def user
|
52
|
+
@config[:cloudfiles, :user]
|
53
|
+
end
|
54
|
+
|
55
|
+
def api_key
|
56
|
+
@config[:cloudfiles, :api_key]
|
57
|
+
end
|
58
|
+
|
59
|
+
def service_net
|
60
|
+
@config[:cloudfiles, :service_net] || false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -3,7 +3,7 @@ module Astrails
|
|
3
3
|
module Config
|
4
4
|
class Builder
|
5
5
|
COLLECTIONS = %w/database archive repo/
|
6
|
-
ITEMS = %w/s3 key secret bucket path gpg password keep local mysqldump pgdump options
|
6
|
+
ITEMS = %w/s3 cloudfiles key secret bucket api_key container service_net path gpg password keep local mysqldump pgdump command options
|
7
7
|
user host port socket skip_tables tar files exclude filename svndump repo_path sftp/
|
8
8
|
NAMES = COLLECTIONS + ITEMS
|
9
9
|
def initialize(node)
|
data/lib/astrails/safe/gpg.rb
CHANGED
@@ -9,10 +9,11 @@ module Astrails
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def pipe
|
12
|
+
command = @config[:gpg, :command] || 'gpg'
|
12
13
|
if key
|
13
|
-
"
|
14
|
+
"|#{command} #{@config[:gpg, :options]} -e -r #{key}"
|
14
15
|
elsif password
|
15
|
-
"
|
16
|
+
"|#{command} #{@config[:gpg, :options]} -c --passphrase-file #{gpg_password_file(password)}"
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
data/lib/astrails/safe/s3.rb
CHANGED
data/templates/script.rb
CHANGED
@@ -12,7 +12,6 @@ safe do
|
|
12
12
|
|
13
13
|
## uncomment to enable uploads to Amazon S3
|
14
14
|
## Amazon S3 auth (optional)
|
15
|
-
## don't forget to add :s3 to the 'store' list
|
16
15
|
# s3 do
|
17
16
|
# key YOUR_S3_KEY
|
18
17
|
# secret YOUR_S3_SECRET
|
@@ -24,6 +23,20 @@ safe do
|
|
24
23
|
## alternative style:
|
25
24
|
# s3 :key => YOUR_S3_KEY, :secret => YOUR_S3_SECRET, :bucket => S3_BUCKET, :path => ":kind/"
|
26
25
|
|
26
|
+
## uncomment to enable uploads to Rackspace Cloud Files
|
27
|
+
## http://www.rackspacecloud.com/cloud_hosting_products/files
|
28
|
+
## Rackspace auth (optional)
|
29
|
+
# cloudfiles do
|
30
|
+
# user "YOUR_RACKSPACE_CLOUD_USERNAME"
|
31
|
+
# api_key "YOUR_RACKSPACE_API_KEY"
|
32
|
+
# container "YOUR_CONTAINER_NAME"
|
33
|
+
# # path for uploads to Cloud Files, supports same substitution like :local/:path
|
34
|
+
# path ":kind/" # this is default
|
35
|
+
# # If you are running the backup from a system within the Rackspace/Slicehost network and would like
|
36
|
+
# # to back up over the private (unbilled) service net, set this value to true.
|
37
|
+
# # service_net true
|
38
|
+
# end
|
39
|
+
|
27
40
|
## uncomment to enable uploads via SFTP
|
28
41
|
# sftp do
|
29
42
|
# host "YOUR_REMOTE_HOSTNAME"
|
@@ -36,6 +49,12 @@ safe do
|
|
36
49
|
## uncomment to enable GPG encryption.
|
37
50
|
## Note: you can use public 'key' or symmetric password but not both!
|
38
51
|
# gpg do
|
52
|
+
# # you can specify your own gpg executable with the 'command' options
|
53
|
+
# # this can be useful for example to choose b/w gpg and gpg2 if both are installed
|
54
|
+
# # some gpg installations will automatically set 'use-agent' option in the
|
55
|
+
# # config file on the 1st run. see README for more details
|
56
|
+
# options "--no-use-agent"
|
57
|
+
# # command "/usr/local/bin/gpg"
|
39
58
|
# # key "backup@astrails.com"
|
40
59
|
# password "astrails"
|
41
60
|
# end
|
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: astrails-safe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Astrails Ltd.
|
8
|
-
- Mark Mansour
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
11
|
|
13
|
-
date:
|
12
|
+
date: 2010-01-21 00:00:00 +02:00
|
14
13
|
default_executable: astrails-safe
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
@@ -23,6 +22,16 @@ dependencies:
|
|
23
22
|
- !ruby/object:Gem::Version
|
24
23
|
version: "0"
|
25
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cloudfiles
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
26
35
|
- !ruby/object:Gem::Dependency
|
27
36
|
name: net-sftp
|
28
37
|
type: :runtime
|
@@ -33,7 +42,11 @@ dependencies:
|
|
33
42
|
- !ruby/object:Gem::Version
|
34
43
|
version: "0"
|
35
44
|
version:
|
36
|
-
description:
|
45
|
+
description: |
|
46
|
+
Astrails-Safe is a simple tool to backup databases (MySQL and PostgreSQL), Subversion repositories (with svndump) and just files.
|
47
|
+
Backups can be stored locally or remotely and can be enctypted.
|
48
|
+
Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain SFTP.
|
49
|
+
|
37
50
|
email: we@astrails.com
|
38
51
|
executables:
|
39
52
|
- astrails-safe
|
@@ -63,6 +76,7 @@ files:
|
|
63
76
|
- lib/astrails/safe.rb
|
64
77
|
- lib/astrails/safe/archive.rb
|
65
78
|
- lib/astrails/safe/backup.rb
|
79
|
+
- lib/astrails/safe/cloudfiles.rb
|
66
80
|
- lib/astrails/safe/config/builder.rb
|
67
81
|
- lib/astrails/safe/config/node.rb
|
68
82
|
- lib/astrails/safe/gpg.rb
|
@@ -107,7 +121,7 @@ rubyforge_project:
|
|
107
121
|
rubygems_version: 1.3.5
|
108
122
|
signing_key:
|
109
123
|
specification_version: 3
|
110
|
-
summary: Backup filesystem and databases (MySQL and PostgreSQL) to
|
124
|
+
summary: Backup filesystem and databases (MySQL and PostgreSQL) locally or to a remote server/service (with encryption)
|
111
125
|
test_files:
|
112
126
|
- examples/example_helper.rb
|
113
127
|
- examples/integration/archive_integration_example.rb
|