webbynode-safe 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +211 -0
  3. data/Rakefile +53 -0
  4. data/VERSION.yml +4 -0
  5. data/bin/astrails-safe +53 -0
  6. data/examples/example_helper.rb +19 -0
  7. data/examples/integration/archive_integration_example.rb +86 -0
  8. data/examples/integration/cleanup_example.rb +62 -0
  9. data/examples/unit/archive_example.rb +67 -0
  10. data/examples/unit/config_example.rb +184 -0
  11. data/examples/unit/gpg_example.rb +138 -0
  12. data/examples/unit/gzip_example.rb +64 -0
  13. data/examples/unit/local_example.rb +110 -0
  14. data/examples/unit/mysqldump_example.rb +83 -0
  15. data/examples/unit/pgdump_example.rb +45 -0
  16. data/examples/unit/s3_example.rb +112 -0
  17. data/examples/unit/svndump_example.rb +39 -0
  18. data/lib/astrails/safe.rb +62 -0
  19. data/lib/astrails/safe/archive.rb +24 -0
  20. data/lib/astrails/safe/backup.rb +20 -0
  21. data/lib/astrails/safe/config/builder.rb +60 -0
  22. data/lib/astrails/safe/config/node.rb +66 -0
  23. data/lib/astrails/safe/gpg.rb +45 -0
  24. data/lib/astrails/safe/gzip.rb +25 -0
  25. data/lib/astrails/safe/local.rb +46 -0
  26. data/lib/astrails/safe/mongodbdump.rb +25 -0
  27. data/lib/astrails/safe/multi.rb +134 -0
  28. data/lib/astrails/safe/mysqldump.rb +31 -0
  29. data/lib/astrails/safe/pgdump.rb +36 -0
  30. data/lib/astrails/safe/pipe.rb +13 -0
  31. data/lib/astrails/safe/s3.rb +68 -0
  32. data/lib/astrails/safe/sftp.rb +79 -0
  33. data/lib/astrails/safe/sink.rb +37 -0
  34. data/lib/astrails/safe/source.rb +46 -0
  35. data/lib/astrails/safe/stream.rb +19 -0
  36. data/lib/astrails/safe/svndump.rb +13 -0
  37. data/lib/astrails/safe/tmp_file.rb +48 -0
  38. data/lib/extensions/mktmpdir.rb +45 -0
  39. data/templates/script.rb +130 -0
  40. metadata +126 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 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.
@@ -0,0 +1,211 @@
1
+ astrails-safe
2
+ =============
3
+
4
+ Simple database and filesystem backups with S3 support (with optional encryption)
5
+
6
+ Home: http://blog.astrails.com/astrails-safe
7
+
8
+ Motivation
9
+ ----------
10
+
11
+ We needed a backup solution that will satisfy the following requirements:
12
+
13
+ * opensource
14
+ * simple to install and configure
15
+ * support for simple ‘tar’ backups of directories (with includes/excludes)
16
+ * support for simple mysqldump of mysql databases
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
20
+
21
+ And since we didn't find any, we wrote our own :)
22
+
23
+ Contributions
24
+ -------------
25
+
26
+ The following functionality was contributed by astrails-safe users:
27
+
28
+ * PostgreSQL dump using pg_dump (by Mark Mansour <mark@stateofflux.com>)
29
+ * Subversion dump using svndump (by Richard Luther <richard.luther@gmail.com>)
30
+ * SFTP remote storage (by Adam <adam@mediadrive.ca>)
31
+ * benchmarking output (By Neer)
32
+
33
+ Thanks to all :)
34
+
35
+ Installation
36
+ ------------
37
+
38
+ sudo gem install astrails-safe --source http://gemcutter.org
39
+
40
+ Reporting problems
41
+ ------------------
42
+
43
+ Please report problems at the [Issues tracker](http://github.com/astrails/safe/issues)
44
+
45
+ Usage
46
+ -----
47
+
48
+ Usage:
49
+ astrails-safe [OPTIONS] CONFIG_FILE
50
+ Options:
51
+ -h, --help This help screen
52
+ -v, --verbose be verbose, duh!
53
+ -n, --dry-run just pretend, don't do anything.
54
+ -L, --local skip S3
55
+
56
+ Note: CONFIG_FILE will be created from template if missing
57
+
58
+ Encryption
59
+ ----------
60
+
61
+ If you want to encrypt your backups you have 2 options:
62
+ * use simple password encryption
63
+ * use GPG public key encryption
64
+
65
+ For simple password, just add password entry in gpg section.
66
+ For public key encryption you will need to create a public/secret keypair.
67
+
68
+ We recommend to create your GPG keys only on your local machine and then
69
+ transfer your public key to the server that will do the backups.
70
+
71
+ This way the server will only know how to encrypt the backups but only you
72
+ will be able to decrypt them using the secret key you have locally. Of course
73
+ you MUST backup your backup encryption key :)
74
+ We recommend also pringing the hard paper copy of your GPG key 'just in case'.
75
+
76
+ The procedure to create and transfer the key is as follows:
77
+
78
+ 1. run 'gpg --gen-key' on your local machine and follow onscreen instructions to create the key
79
+ (you can accept all the defaults).
80
+
81
+ 2. extract your public key into a file (assuming you used test@example.com as your key email):
82
+ gpg -a --export test@example.com > test@example.com.pub
83
+
84
+ 3. transfer public key to the server
85
+ scp test@example.com.pub root@example.com:
86
+
87
+ 4. import public key on the remote system:
88
+ <pre>
89
+ $ gpg --import test@example.com.pub
90
+ gpg: key 45CA9403: public key "Test Backup <test@example.com>" imported
91
+ gpg: Total number processed: 1
92
+ gpg: imported: 1
93
+ </pre>
94
+
95
+ 5. since we don't keep the secret part of the key on the remote server, gpg has
96
+ no way to know its yours and can be trusted.
97
+ To fix that we can sign it with other trusted key, or just directly modify its
98
+ trust level in gpg (use level 5):
99
+ <pre>
100
+ $ gpg --edit-key test@example.com
101
+ ...
102
+ Command> trust
103
+ ...
104
+ 1 = I don't know or won't say
105
+ 2 = I do NOT trust
106
+ 3 = I trust marginally
107
+ 4 = I trust fully
108
+ 5 = I trust ultimately
109
+ m = back to the main menu
110
+
111
+ Your decision? 5
112
+ ...
113
+ Command> quit
114
+ </pre>
115
+
116
+ 6. export your secret key for backup
117
+ (we recommend to print it on paper and burn to a CD/DVD and store in a safe place):
118
+ <pre>
119
+ $ gpg -a --export-secret-key test@example.com > test@example.com.key
120
+ </pre>
121
+
122
+
123
+ Example configuration
124
+ ---------------------
125
+ <pre>
126
+ safe do
127
+ local :path => "/backup/:kind/:id"
128
+
129
+ s3 do
130
+ key "...................."
131
+ secret "........................................"
132
+ bucket "backup.astrails.com"
133
+ path "servers/alpha/:kind/:id"
134
+ end
135
+
136
+ sftp do
137
+ host "sftp.astrails.com"
138
+ user "astrails"
139
+ password "ssh password for sftp"
140
+ end
141
+
142
+ gpg do
143
+ # symmetric encryption key
144
+ # password "qwe"
145
+
146
+ # public GPG key (must be known to GPG, i.e. be on the keyring)
147
+ key "backup@astrails.com"
148
+ end
149
+
150
+ keep do
151
+ local 2
152
+ s3 2
153
+ end
154
+
155
+ mysqldump do
156
+ options "-ceKq --single-transaction --create-options"
157
+
158
+ user "root"
159
+ password "............"
160
+ socket "/var/run/mysqld/mysqld.sock"
161
+
162
+ database :blog
163
+ database :servershape
164
+ database :astrails_com
165
+ database :secret_project_com
166
+
167
+ end
168
+
169
+ svndump do
170
+ repo :my_repo do
171
+ repo_path "/home/svn/my_repo"
172
+ end
173
+ end
174
+
175
+ pgdump do
176
+ options "-i -x -O" # -i => ignore version, -x => do not dump privileges (grant/revoke), -O => skip restoration of object ownership in plain text format
177
+
178
+ user "username"
179
+ password "............" # shouldn't be used, instead setup ident. Current functionality exports a password env to the shell which pg_dump uses - untested!
180
+
181
+ database :blog
182
+ database :stateofflux_com
183
+ end
184
+
185
+ tar do
186
+ archive "git-repositories", :files => "/home/git/repositories"
187
+ archive "dot-configs", :files => "/home/*/.[^.]*"
188
+ archive "etc", :files => "/etc", :exclude => "/etc/puppet/other"
189
+
190
+ archive "blog-astrails-com" do
191
+ files "/var/www/blog.astrails.com/"
192
+ exclude ["/var/www/blog.astrails.com/log", "/var/www/blog.astrails.com/tmp"]
193
+ end
194
+
195
+ archive "astrails-com" do
196
+ files "/var/www/astrails.com/"
197
+ exclude ["/var/www/astrails.com/log", "/var/www/astrails.com/tmp"]
198
+ end
199
+ end
200
+ end
201
+ </pre>
202
+
203
+ Reporting problems
204
+ ------------------
205
+
206
+ http://github.com/astrails/safe/issues
207
+
208
+ Copyright
209
+ ---------
210
+
211
+ Copyright (c) 2009 Astrails Ltd. See LICENSE for details.
@@ -0,0 +1,53 @@
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) 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)"
10
+ gem.email = "we@astrails.com"
11
+ gem.homepage = "http://blog.astrails.com/astrails-safe"
12
+ gem.authors = ["Astrails Ltd.", "Mark Mansour"]
13
+ gem.files = FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test,templates}/**/*", 'Rakefile', 'LICENSE*']
14
+
15
+ gem.add_dependency("aws-s3")
16
+ gem.add_dependency("net-sftp")
17
+
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ rescue LoadError
21
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
22
+ end
23
+
24
+ require 'micronaut/rake_task'
25
+ Micronaut::RakeTask.new(:examples) do |examples|
26
+ examples.pattern = 'examples/**/*_example.rb'
27
+ examples.ruby_opts << '-Ilib -Iexamples'
28
+ end
29
+
30
+ Micronaut::RakeTask.new(:rcov) do |examples|
31
+ examples.pattern = 'examples/**/*_example.rb'
32
+ examples.rcov_opts = '-Ilib -Iexamples -iastrails -x\/gems\/'
33
+ examples.rcov = true
34
+ end
35
+
36
+
37
+ task :default => :examples
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ if File.exist?('VERSION.yml')
42
+ config = YAML.load(File.read('VERSION.yml'))
43
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
44
+ else
45
+ version = ""
46
+ end
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "safe #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
53
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 2
4
+ :patch: 4
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ #require 'ruby-debug'
6
+ #$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
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
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,86 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ require "fileutils"
4
+ include FileUtils
5
+
6
+ describe "tar backup" do
7
+ before(:all) do
8
+ # need both local and instance vars
9
+ # instance variables are used in tests
10
+ # local variables are used in the backup definition (instance vars can't be seen)
11
+ @root = root = "tmp/archive_backup_example"
12
+
13
+ # clean state
14
+ rm_rf @root
15
+ mkdir_p @root
16
+
17
+ # create source tree
18
+ @src = src = "#{@root}/src"
19
+ mkdir_p "#{@src}/q/w/e"
20
+ mkdir_p "#{@src}/a/s/d"
21
+
22
+ File.open("#{@src}/qwe1", "w") {|f| f.write("qwe") }
23
+ File.open("#{@src}/q/qwe2", "w") {|f| f.write("qwe"*2) }
24
+ File.open("#{@src}/q/w/qwe3", "w") {|f| f.write("qwe"*3) }
25
+ File.open("#{@src}/q/w/e/qwe4", "w") {|f| f.write("qwe"*4) }
26
+
27
+ File.open("#{@src}/asd1", "w") {|f| f.write("asd") }
28
+ File.open("#{@src}/a/asd2", "w") {|f| f.write("asd" * 2) }
29
+ File.open("#{@src}/a/s/asd3", "w") {|f| f.write("asd" * 3) }
30
+
31
+ @dst = dst = "#{@root}/backup"
32
+ mkdir_p @dst
33
+
34
+ @now = Time.now
35
+ @timestamp = @now.strftime("%y%m%d-%H%M")
36
+
37
+ stub(Time).now {@now} # Freeze
38
+
39
+ Astrails::Safe.safe do
40
+ local :path => "#{dst}/:kind"
41
+ tar do
42
+ archive :test1 do
43
+ files src
44
+ exclude "#{src}/q/w"
45
+ end
46
+ end
47
+ end
48
+
49
+ @backup = "#{dst}/archive/archive-test1.#{@timestamp}.tar.gz"
50
+ end
51
+
52
+ it "should create backup file" do
53
+ puts "Expecting: #{@backup}"
54
+ File.exists?(@backup).should be_true
55
+ end
56
+
57
+ describe "after extracting" do
58
+ before(:all) do
59
+ # prepare target dir
60
+ @target = "#{@root}/test"
61
+ mkdir_p @target
62
+ system "tar -zxvf #{@backup} -C #{@target}"
63
+
64
+ @test = "#{@target}/#{@root}/src"
65
+ puts @test
66
+ end
67
+
68
+ it "should include asd1/2/3" do
69
+ File.exists?("#{@test}/asd1").should be_true
70
+ File.exists?("#{@test}/a/asd2").should be_true
71
+ File.exists?("#{@test}/a/s/asd3").should be_true
72
+ end
73
+
74
+ it "should only include qwe 1 and 2 (no 3)" do
75
+ File.exists?("#{@test}/qwe1").should be_true
76
+ File.exists?("#{@test}/q/qwe2").should be_true
77
+ end
78
+
79
+ it "should preserve file content" do
80
+ File.read("#{@test}/qwe1").should == "qwe"
81
+ File.read("#{@test}/q/qwe2").should == "qweqwe"
82
+ File.read("#{@test}/a/s/asd3").should == "asdasdasd"
83
+ end
84
+ end
85
+
86
+ end