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.
@@ -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 and Amazon S3 for storage
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 S3
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 30
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 Amazon S3 (with encryption)}
9
- gem.description = "Simple tool to backup databases (MySQL and PostgreSQL) and filesystem locally or to Amazon S3 (with optional encryption)"
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.", "Mark Mansour"]
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
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 2
4
- :patch: 6
4
+ :patch: 7
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'rubygems'
4
4
 
5
- #require 'ruby-debug'
6
- #$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
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
- before(:each) do
106
- @gpg = gpg(:gpg => {:key => "foo", :options => "GPG-OPT"}, :options => "OPT")
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
- dont_allow(@gpg).gpg_password_file(anything)
111
- @gpg.send(:pipe)
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
- @gpg.send(:pipe).should == "|gpg GPG-OPT -e -r foo"
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
- before(:each) do
121
- @gpg = gpg(:gpg => {:password => "bar", :options => "GPG-OPT"}, :options => "OPT")
122
- stub(@gpg).gpg_password_file(anything) {"pass-file"}
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
- @gpg.send(:pipe).should == "|gpg GPG-OPT -c --passphrase-file pass-file"
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 = pwd
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
@@ -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)
@@ -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
- "|gpg #{@config[:gpg, :options]} -e -r #{key}"
14
+ "|#{command} #{@config[:gpg, :options]} -e -r #{key}"
14
15
  elsif password
15
- "|gpg #{@config[:gpg,:options]} -c --passphrase-file #{gpg_password_file(password)}"
16
+ "|#{command} #{@config[:gpg, :options]} -c --passphrase-file #{gpg_password_file(password)}"
16
17
  end
17
18
  end
18
19
 
@@ -15,7 +15,8 @@ module Astrails
15
15
  file.puts "[mysqldump]"
16
16
  %w/user password socket host port/.each do |k|
17
17
  v = @config[k]
18
- file.puts "#{k} = #{v}" if v
18
+ # values are quoted if needed
19
+ file.puts "#{k} = #{v.inspect}" if v
19
20
  end
20
21
  end
21
22
  end
@@ -41,7 +41,6 @@ module Astrails
41
41
 
42
42
  return unless keep = @config[:keep, :s3]
43
43
 
44
-
45
44
  puts "listing files: #{bucket}:#{base}*" if $_VERBOSE
46
45
  files = AWS::S3::Bucket.objects(bucket, :prefix => base, :max_keys => keep * 2)
47
46
  puts files.collect {|x| x.key} if $_VERBOSE
@@ -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.6
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: 2009-12-21 00:00:00 +02:00
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: Simple tool to backup databases (MySQL and PostgreSQL) and filesystem locally or to Amazon S3 (with optional encryption)
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 Amazon S3 (with encryption)
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