darkofabijan-astrails-safe 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +237 -0
  3. data/Rakefile +61 -0
  4. data/bin/astrails-safe +53 -0
  5. data/examples/example_helper.rb +19 -0
  6. data/lib/astrails/safe.rb +61 -0
  7. data/lib/astrails/safe/archive.rb +24 -0
  8. data/lib/astrails/safe/backup.rb +20 -0
  9. data/lib/astrails/safe/cloudfiles.rb +70 -0
  10. data/lib/astrails/safe/config/builder.rb +60 -0
  11. data/lib/astrails/safe/config/node.rb +76 -0
  12. data/lib/astrails/safe/gpg.rb +46 -0
  13. data/lib/astrails/safe/gzip.rb +25 -0
  14. data/lib/astrails/safe/local.rb +70 -0
  15. data/lib/astrails/safe/mysqldump.rb +32 -0
  16. data/lib/astrails/safe/pgdump.rb +36 -0
  17. data/lib/astrails/safe/pipe.rb +17 -0
  18. data/lib/astrails/safe/s3.rb +86 -0
  19. data/lib/astrails/safe/sftp.rb +88 -0
  20. data/lib/astrails/safe/sink.rb +35 -0
  21. data/lib/astrails/safe/source.rb +47 -0
  22. data/lib/astrails/safe/stream.rb +20 -0
  23. data/lib/astrails/safe/svndump.rb +13 -0
  24. data/lib/astrails/safe/tmp_file.rb +48 -0
  25. data/lib/extensions/mktmpdir.rb +45 -0
  26. data/spec/integration/archive_integration_spec.rb +88 -0
  27. data/spec/integration/cleanup_spec.rb +61 -0
  28. data/spec/spec.opts +5 -0
  29. data/spec/spec_helper.rb +16 -0
  30. data/spec/unit/archive_spec.rb +67 -0
  31. data/spec/unit/cloudfiles_spec.rb +170 -0
  32. data/spec/unit/config_spec.rb +213 -0
  33. data/spec/unit/gpg_spec.rb +148 -0
  34. data/spec/unit/gzip_spec.rb +64 -0
  35. data/spec/unit/local_spec.rb +110 -0
  36. data/spec/unit/mysqldump_spec.rb +83 -0
  37. data/spec/unit/pgdump_spec.rb +45 -0
  38. data/spec/unit/s3_spec.rb +160 -0
  39. data/spec/unit/svndump_spec.rb +39 -0
  40. data/templates/script.rb +165 -0
  41. metadata +179 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Astrails Ltd.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,237 @@
1
+ astrails-safe
2
+ =============
3
+
4
+ Simple database and filesystem backups with S3 and Rackspace Cloud Files support (with optional encryption)
5
+
6
+ * Home: [http://astrails.com/opensource/astrails-safe](http://astrails.com/opensource/astrails-safe)
7
+ * Code: [http://github.com/astrails/safe](http://github.com/astrails/safe)
8
+ * Blog: [http://blog.astrails.com/astrails-safe](http://blog.astrails.com/astrails-safe)
9
+
10
+
11
+ Motivation
12
+ ----------
13
+
14
+ We needed a backup solution that will satisfy the following requirements:
15
+
16
+ * opensource
17
+ * simple to install and configure
18
+ * support for simple ‘tar’ backups of directories (with includes/excludes)
19
+ * support for simple mysqldump of mysql databases
20
+ * support for symmetric or public key encryption
21
+ * support for local filesystem, Amazon S3, and Rackspace Cloud Files for storage
22
+ * support for backup rotation. we don’t want backups filling all the diskspace or cost a fortune on S3 or Cloud Files
23
+
24
+ And since we didn't find any, we wrote our own :)
25
+
26
+ Contributions
27
+ -------------
28
+
29
+ The following functionality was contributed by astrails-safe users:
30
+
31
+ * PostgreSQL dump using `pg_dump` (by Mark Mansour <mark@stateofflux.com>)
32
+ * Subversion dump using svndump (by Richard Luther <richard.luther@gmail.com>)
33
+ * SFTP remote storage (by Adam <adam@mediadrive.ca>)
34
+ * benchmarking output (By Neer)
35
+ * README fixes (by Bobby Wilson)
36
+ * improved config file parsing (by Fedor Kocherga <fkocherga@gmail.com>)
37
+ * mysql password file quoting (by Jonathan Sutherland <jonathan.sutherland@gmail.com>)
38
+ * Rackspace Cloud Files support (by H. Wade Minter <minter@lunenburg.org>)
39
+
40
+ Thanks to all :)
41
+
42
+ Installation
43
+ ------------
44
+
45
+ sudo gem install astrails-safe --source http://gemcutter.org
46
+
47
+ Reporting problems
48
+ ------------------
49
+
50
+ Please report problems at the [Issues tracker](http://github.com/astrails/safe/issues)
51
+
52
+ Usage
53
+ -----
54
+
55
+ Usage:
56
+ astrails-safe [OPTIONS] CONFIG_FILE
57
+ Options:
58
+ -h, --help This help screen
59
+ -v, --verbose be verbose, duh!
60
+ -n, --dry-run just pretend, don't do anything.
61
+ -L, --local skip remote storage, only do local backups
62
+
63
+ Note: CONFIG\_FILE will be created from template if missing
64
+
65
+ Encryption
66
+ ----------
67
+
68
+ If you want to encrypt your backups you have 2 options:
69
+ * use simple password encryption
70
+ * use GPG public key encryption
71
+
72
+ > IMPORTANT: some gpg installations automatically set 'use-agent' option in the default
73
+ > configuration file that is created when you run gpg for the first time. This will cause
74
+ > gpg to fail on the 2nd run if you don't have the agent running. The result is that
75
+ > 'astrails-safe' will work ONCE when you manually test it and then fail on any subsequent run.
76
+ > The solution is to remove the 'use-agent' from the config file (usually /root/.gnupg/gpg.conf)
77
+ > To mitigate this problem for the gpg 1.x series '--no-use-agent' option is added by defaults
78
+ > to the autogenerated config file, but for gpg2 is doesn't work. as the manpage says it:
79
+ > "This is dummy option. gpg2 always requires the agent." :(
80
+
81
+ For simple password, just add password entry in gpg section.
82
+ For public key encryption you will need to create a public/secret keypair.
83
+
84
+ We recommend to create your GPG keys only on your local machine and then
85
+ transfer your public key to the server that will do the backups.
86
+
87
+ This way the server will only know how to encrypt the backups but only you
88
+ will be able to decrypt them using the secret key you have locally. Of course
89
+ you MUST backup your backup encryption key :)
90
+ We recommend also pringing the hard paper copy of your GPG key 'just in case'.
91
+
92
+ The procedure to create and transfer the key is as follows:
93
+
94
+ 1. run 'gpg --gen-key' on your local machine and follow onscreen instructions to create the key
95
+ (you can accept all the defaults).
96
+
97
+ 2. extract your public key into a file (assuming you used test@example.com as your key email):
98
+ `gpg -a --export test@example.com > test@example.com.pub`
99
+
100
+ 3. transfer public key to the server
101
+ `scp test@example.com.pub root@example.com:`
102
+
103
+ 4. import public key on the remote system:
104
+
105
+ $ gpg --import test@example.com.pub
106
+ gpg: key 45CA9403: public key "Test Backup <test@example.com>" imported
107
+ gpg: Total number processed: 1
108
+ gpg: imported: 1
109
+
110
+ 5. since we don't keep the secret part of the key on the remote server, gpg has
111
+ no way to know its yours and can be trusted.
112
+ To fix that we can sign it with other trusted key, or just directly modify its
113
+ trust level in gpg (use level 5):
114
+
115
+ $ gpg --edit-key test@example.com
116
+ ...
117
+ Command> trust
118
+ ...
119
+ 1 = I don't know or won't say
120
+ 2 = I do NOT trust
121
+ 3 = I trust marginally
122
+ 4 = I trust fully
123
+ 5 = I trust ultimately
124
+ m = back to the main menu
125
+
126
+ Your decision? 5
127
+ ...
128
+ Command> quit
129
+
130
+ 6. export your secret key for backup
131
+ (we recommend to print it on paper and burn to a CD/DVD and store in a safe place):
132
+
133
+ $ gpg -a --export-secret-key test@example.com > test@example.com.key
134
+
135
+
136
+
137
+ Example configuration
138
+ ---------------------
139
+
140
+ safe do
141
+ local :path => "/backup/:kind/:id"
142
+
143
+ s3 do
144
+ key "...................."
145
+ secret "........................................"
146
+ bucket "backup.astrails.com"
147
+ path "servers/alpha/:kind/:id"
148
+ end
149
+
150
+ cloudfiles do
151
+ user "..........."
152
+ api_key "................................."
153
+ container "safe_backup"
154
+ path ":kind/" # this is default
155
+ service_net false
156
+ end
157
+
158
+ sftp do
159
+ host "sftp.astrails.com"
160
+ user "astrails"
161
+ # port 8023
162
+ password "ssh password for sftp"
163
+ end
164
+
165
+ gpg do
166
+ command "/usr/local/bin/gpg"
167
+ options "--no-use-agent"
168
+ # symmetric encryption key
169
+ # password "qwe"
170
+
171
+ # public GPG key (must be known to GPG, i.e. be on the keyring)
172
+ key "backup@astrails.com"
173
+ end
174
+
175
+ keep do
176
+ local 20
177
+ s3 100
178
+ cloudfiles 100
179
+ sftp 100
180
+ end
181
+
182
+ mysqldump do
183
+ options "-ceKq --single-transaction --create-options"
184
+
185
+ user "root"
186
+ password "............"
187
+ socket "/var/run/mysqld/mysqld.sock"
188
+
189
+ database :blog
190
+ database :servershape
191
+ database :astrails_com
192
+ database :secret_project_com do
193
+ skip_tables "foo"
194
+ skip_tables ["bar", "baz"]
195
+ end
196
+
197
+ end
198
+
199
+ svndump do
200
+ repo :my_repo do
201
+ repo_path "/home/svn/my_repo"
202
+ end
203
+ end
204
+
205
+ pgdump do
206
+ options "-i -x -O" # -i => ignore version, -x => do not dump privileges (grant/revoke), -O => skip restoration of object ownership in plain text format
207
+
208
+ user "username"
209
+ password "............" # shouldn't be used, instead setup ident. Current functionality exports a password env to the shell which pg_dump uses - untested!
210
+
211
+ database :blog
212
+ database :stateofflux_com
213
+ end
214
+
215
+ tar do
216
+ options "-h" # dereference symlinks
217
+ archive "git-repositories", :files => "/home/git/repositories"
218
+ archive "dot-configs", :files => "/home/*/.[^.]*"
219
+ archive "etc", :files => "/etc", :exclude => "/etc/puppet/other"
220
+
221
+ archive "blog-astrails-com" do
222
+ files "/var/www/blog.astrails.com/"
223
+ exclude "/var/www/blog.astrails.com/log"
224
+ exclude "/var/www/blog.astrails.com/tmp"
225
+ end
226
+
227
+ archive "astrails-com" do
228
+ files "/var/www/astrails.com/"
229
+ exclude ["/var/www/astrails.com/log", "/var/www/astrails.com/tmp"]
230
+ end
231
+ end
232
+ end
233
+
234
+ Copyright
235
+ ---------
236
+
237
+ Copyright (c) 2010 Astrails Ltd. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "astrails-safe"
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
14
+ gem.email = "we@astrails.com"
15
+ gem.homepage = "http://blog.astrails.com/astrails-safe"
16
+ gem.authors = ["Astrails Ltd."]
17
+ gem.files = FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test,templates}/**/*", 'Rakefile', 'LICENSE*']
18
+
19
+ gem.add_dependency("aws-s3")
20
+ gem.add_dependency("cloudfiles")
21
+ gem.add_dependency("net-sftp")
22
+
23
+ gem.add_development_dependency "rspec"
24
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
25
+ end
26
+ rescue LoadError
27
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
28
+ end
29
+
30
+
31
+ require 'spec/rake/spectask'
32
+ Spec::Rake::SpecTask.new(:spec) do |spec|
33
+ spec.libs << 'lib' << 'spec'
34
+ spec.spec_opts = ['--options', "\"spec/spec.opts\""]
35
+ spec.spec_files = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
39
+ spec.libs << 'lib' << 'spec'
40
+ spec.pattern = 'spec/**/*_spec.rb'
41
+ spec.rcov = true
42
+ end
43
+
44
+ task :spec => :check_dependencies
45
+
46
+ task :default => :spec
47
+
48
+ require 'rake/rdoctask'
49
+ Rake::RDocTask.new do |rdoc|
50
+ if File.exist?('VERSION')
51
+ version = File.read('VERSION')
52
+ else
53
+ version = ""
54
+ end
55
+
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "safe #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
61
+
data/bin/astrails-safe ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ require 'ruby-debug'
6
+ $:.unshift File.expand_path("../../lib", __FILE__)
7
+
8
+ require 'astrails/safe'
9
+ include Astrails::Safe
10
+
11
+ def die(msg)
12
+ puts "ERROR: #{msg}"
13
+ exit 1
14
+ end
15
+
16
+ def usage
17
+ puts <<-END
18
+ Usage: astrails-safe [OPTIONS] CONFIG_FILE
19
+ Options:
20
+ -h, --help This help screen
21
+ -v, --verbose be verbose, duh!
22
+ -n, --dry-run just pretend, don't do anything.
23
+ -L, --local skip S3 and Cloud Files
24
+
25
+ Note: config file will be created from template if missing
26
+ END
27
+ exit 1
28
+ end
29
+
30
+ def process_options
31
+ usage if ARGV.delete("-h") || ARGV.delete("--help")
32
+ $_VERBOSE = ARGV.delete("-v") || ARGV.delete("--verbose")
33
+ $DRY_RUN = ARGV.delete("-n") || ARGV.delete("--dry-run")
34
+ $LOCAL = ARGV.delete("-L") || ARGV.delete("--local")
35
+ usage unless ARGV.first
36
+ $CONFIG_FILE_NAME = File.expand_path(ARGV.first)
37
+ end
38
+
39
+ def main
40
+ process_options
41
+
42
+ unless File.exists?($CONFIG_FILE_NAME)
43
+ die "Missing configuration file. NOT CREATED! Rerun w/o the -n argument to create a template configuration file." if $DRY_RUN
44
+
45
+ FileUtils.cp File.join(Astrails::Safe::ROOT, "templates", "script.rb"), $CONFIG_FILE_NAME
46
+
47
+ die "Created default #{$CONFIG_FILE_NAME}. Please edit and run again."
48
+ end
49
+
50
+ load($CONFIG_FILE_NAME)
51
+ end
52
+
53
+ main
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'micronaut'
3
+ require 'ruby-debug'
4
+
5
+ SAFE_ROOT = File.dirname(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift(File.join(SAFE_ROOT, 'lib'))
8
+
9
+ require 'astrails/safe'
10
+
11
+ def not_in_editor?
12
+ !(ENV.has_key?('TM_MODE') || ENV.has_key?('EMACS') || ENV.has_key?('VIM'))
13
+ end
14
+
15
+ Micronaut.configure do |c|
16
+ c.color_enabled = not_in_editor?
17
+ c.filter_run :focused => true
18
+ c.mock_with :rr
19
+ end
@@ -0,0 +1,61 @@
1
+ require "aws/s3"
2
+ require "cloudfiles"
3
+ require 'net/sftp'
4
+ require 'fileutils'
5
+ require 'benchmark'
6
+
7
+ require 'tempfile'
8
+ require 'extensions/mktmpdir'
9
+
10
+ require 'astrails/safe/tmp_file'
11
+
12
+ require 'astrails/safe/config/node'
13
+ require 'astrails/safe/config/builder'
14
+
15
+ require 'astrails/safe/stream'
16
+
17
+ require 'astrails/safe/backup'
18
+
19
+ require 'astrails/safe/source'
20
+ require 'astrails/safe/mysqldump'
21
+ require 'astrails/safe/pgdump'
22
+ require 'astrails/safe/archive'
23
+ require 'astrails/safe/svndump'
24
+
25
+ require 'astrails/safe/pipe'
26
+ require 'astrails/safe/gpg'
27
+ require 'astrails/safe/gzip'
28
+ require 'astrails/safe/page'
29
+
30
+ require 'astrails/safe/sink'
31
+ require 'astrails/safe/local'
32
+ require 'astrails/safe/s3'
33
+ require 'astrails/safe/cloudfiles'
34
+ require 'astrails/safe/sftp'
35
+
36
+ module Astrails
37
+ module Safe
38
+ ROOT = File.join(File.dirname(__FILE__), "..", "..")
39
+
40
+ def safe(&block)
41
+ config = Config::Node.new(&block)
42
+ #config.dump
43
+
44
+
45
+ [[Mysqldump, [:mysqldump, :databases]],
46
+ [Pgdump, [:pgdump, :databases]],
47
+ [Archive, [:tar, :archives]],
48
+ [Svndump, [:svndump, :repos]]
49
+ ].each do |klass, path|
50
+ if collection = config[*path]
51
+ collection.each do |name, config|
52
+ klass.new(name, config).backup.run(config, :gpg, :page, :gzip, :local, :s3, :cloudfiles, :sftp)
53
+ end
54
+ end
55
+ end
56
+
57
+ Astrails::Safe::TmpFile.cleanup
58
+ end
59
+ module_function :safe
60
+ end
61
+ end