astrails-safe 0.3.0 → 0.3.1
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/CHANGELOG +10 -0
- data/README.markdown +5 -2
- data/TODO +19 -0
- data/astrails-safe.gemspec +1 -1
- data/bin/astrails-safe +1 -3
- data/lib/astrails/safe.rb +5 -1
- data/lib/astrails/safe/config/builder.rb +1 -1
- data/lib/astrails/safe/ftp.rb +85 -0
- data/lib/astrails/safe/mongodump.rb +23 -0
- data/lib/astrails/safe/version.rb +1 -1
- data/spec/integration/cleanup_spec.rb +1 -1
- data/spec/unit/config_spec.rb +15 -0
- data/spec/unit/mongodump_spec.rb +54 -0
- data/templates/script.rb +9 -0
- metadata +9 -5
data/CHANGELOG
CHANGED
data/README.markdown
CHANGED
@@ -4,8 +4,9 @@ Simple database and filesystem backups with S3 and Rackspace Cloud Files support
|
|
4
4
|
|
5
5
|
* Home: [http://astrails.com/opensource/astrails-safe](http://astrails.com/opensource/astrails-safe)
|
6
6
|
* Code: [http://github.com/astrails/safe](http://github.com/astrails/safe)
|
7
|
-
* Blog: [http://
|
7
|
+
* Blog: [http://astrails.com/blog/astrails-safe](http://astrails.com/blog/astrails-safe)
|
8
8
|
|
9
|
+
[](https://travis-ci.org/astrails/safe)
|
9
10
|
[](https://codeclimate.com/github/astrails/safe)
|
10
11
|
|
11
12
|
## Motivation
|
@@ -34,6 +35,8 @@ The following functionality was contributed by astrails-safe users:
|
|
34
35
|
* improved config file parsing (by Fedor Kocherga <fkocherga@gmail.com>)
|
35
36
|
* mysql password file quoting (by Jonathan Sutherland <jonathan.sutherland@gmail.com>)
|
36
37
|
* Rackspace Cloud Files support (by H. Wade Minter <minter@lunenburg.org>)
|
38
|
+
* Plan FTP support (by seroy <seroy@bk.ru>)
|
39
|
+
* mongodump support (by Matt Berther <matt@mattberther.com>)
|
37
40
|
|
38
41
|
Thanks to all :)
|
39
42
|
|
@@ -234,4 +237,4 @@ The procedure to create and transfer the key is as follows:
|
|
234
237
|
|
235
238
|
## Copyright
|
236
239
|
|
237
|
-
Copyright (c) 2010 Astrails Ltd. See LICENSE.txt for details.
|
240
|
+
Copyright (c) 2010-2013 Astrails Ltd. See LICENSE.txt for details.
|
data/TODO
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
- refactor
|
2
|
+
- refactor out global variables. pass a config object around instead
|
3
|
+
- common logging
|
4
|
+
- remove 1.8.6 support
|
5
|
+
- module registry
|
6
|
+
- base => prefix ?
|
7
|
+
- move requires into specific modules
|
8
|
+
|
9
|
+
- features
|
10
|
+
- remote-only s3 support
|
11
|
+
- generic notifier support
|
12
|
+
- email notifier
|
13
|
+
- hipchat
|
14
|
+
- generic error notifier support
|
15
|
+
- email
|
16
|
+
- hipchat
|
17
|
+
|
18
|
+
|
19
|
+
|
1
20
|
- add 'silent'
|
2
21
|
- handle errors from mysqldump
|
3
22
|
- check that gpg is installed
|
data/astrails-safe.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.description = <<-DESC
|
12
12
|
Astrails-Safe is a simple tool to backup databases (MySQL and PostgreSQL), Subversion repositories (with svndump) and just files.
|
13
13
|
Backups can be stored locally or remotely and can be enctypted.
|
14
|
-
Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain SFTP.
|
14
|
+
Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain FTP/SFTP.
|
15
15
|
DESC
|
16
16
|
spec.summary = %Q{Backup filesystem and databases (MySQL and PostgreSQL) locally or to a remote server/service (with encryption)}
|
17
17
|
spec.homepage = "http://astrails.com/astrails-safe"
|
data/bin/astrails-safe
CHANGED
data/lib/astrails/safe.rb
CHANGED
@@ -3,6 +3,7 @@ require "astrails/safe/version"
|
|
3
3
|
require "aws/s3"
|
4
4
|
require "cloudfiles"
|
5
5
|
require 'net/sftp'
|
6
|
+
require 'net/ftp'
|
6
7
|
require 'fileutils'
|
7
8
|
require 'benchmark'
|
8
9
|
|
@@ -23,6 +24,7 @@ require 'astrails/safe/mysqldump'
|
|
23
24
|
require 'astrails/safe/pgdump'
|
24
25
|
require 'astrails/safe/archive'
|
25
26
|
require 'astrails/safe/svndump'
|
27
|
+
require 'astrails/safe/mongodump'
|
26
28
|
|
27
29
|
require 'astrails/safe/pipe'
|
28
30
|
require 'astrails/safe/gpg'
|
@@ -33,6 +35,7 @@ require 'astrails/safe/local'
|
|
33
35
|
require 'astrails/safe/s3'
|
34
36
|
require 'astrails/safe/cloudfiles'
|
35
37
|
require 'astrails/safe/sftp'
|
38
|
+
require 'astrails/safe/ftp'
|
36
39
|
|
37
40
|
module Astrails
|
38
41
|
module Safe
|
@@ -45,12 +48,13 @@ module Astrails
|
|
45
48
|
|
46
49
|
[[Mysqldump, [:mysqldump, :databases]],
|
47
50
|
[Pgdump, [:pgdump, :databases]],
|
51
|
+
[Mongodump, [:mongodump, :databases]],
|
48
52
|
[Archive, [:tar, :archives]],
|
49
53
|
[Svndump, [:svndump, :repos]]
|
50
54
|
].each do |klass, path|
|
51
55
|
if collection = config[*path]
|
52
56
|
collection.each do |name, c|
|
53
|
-
klass.new(name, c).backup.run(c, :gpg, :gzip, :local, :s3, :cloudfiles, :sftp)
|
57
|
+
klass.new(name, c).backup.run(c, :gpg, :gzip, :local, :s3, :cloudfiles, :sftp, :ftp)
|
54
58
|
end
|
55
59
|
end
|
56
60
|
end
|
@@ -4,7 +4,7 @@ module Astrails
|
|
4
4
|
class Builder
|
5
5
|
COLLECTIONS = %w/database archive repo/
|
6
6
|
ITEMS = %w/s3 cloudfiles key secret bucket api_key container service_net path gpg password keep local mysqldump pgdump command options
|
7
|
-
user host port socket skip_tables tar files exclude filename svndump repo_path sftp/
|
7
|
+
user host port socket skip_tables tar files exclude filename svndump repo_path sftp ftp mongodump/
|
8
8
|
NAMES = COLLECTIONS + ITEMS
|
9
9
|
def initialize(node)
|
10
10
|
@node = node
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Astrails
|
2
|
+
module Safe
|
3
|
+
class Ftp < Sink
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
def active?
|
8
|
+
host && user
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
@path ||= expand(config[:ftp, :path] || config[:local, :path] || ":kind/:id")
|
13
|
+
end
|
14
|
+
|
15
|
+
def save
|
16
|
+
raise RuntimeError, "pipe-streaming not supported for FTP." unless @backup.path
|
17
|
+
|
18
|
+
puts "Uploading #{host}:#{full_path} via FTP" if $_VERBOSE || $DRY_RUN
|
19
|
+
|
20
|
+
unless $DRY_RUN || $LOCAL
|
21
|
+
if !port
|
22
|
+
port = 21
|
23
|
+
end
|
24
|
+
Net::FTP.open(host) do |ftp|
|
25
|
+
ftp.connect(host, port)
|
26
|
+
ftp.login(user, password)
|
27
|
+
puts "Sending #{@backup.path} to #{full_path}" if $_VERBOSE
|
28
|
+
begin
|
29
|
+
ftp.put(@backup.path, full_path)
|
30
|
+
rescue Net::FTPPermError
|
31
|
+
puts "Ensuring remote path (#{path}) exists" if $_VERBOSE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
puts "...done" if $_VERBOSE
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def cleanup
|
39
|
+
return if $LOCAL || $DRY_RUN
|
40
|
+
|
41
|
+
return unless keep = @config[:keep, :ftp]
|
42
|
+
|
43
|
+
puts "listing files: #{host}:#{base}*" if $_VERBOSE
|
44
|
+
if !port
|
45
|
+
port = 21
|
46
|
+
end
|
47
|
+
Net::FTP.open(host) do |ftp|
|
48
|
+
ftp.connect(host, port)
|
49
|
+
ftp.login(user, password)
|
50
|
+
files = ftp.nlst(path)
|
51
|
+
pattern = File.basename("#{base}")
|
52
|
+
files = files.reject{ |x| !x.start_with?(pattern)}
|
53
|
+
puts files.collect {|x| x} if $_VERBOSE
|
54
|
+
|
55
|
+
files = files.
|
56
|
+
collect {|x| x }.
|
57
|
+
sort
|
58
|
+
|
59
|
+
cleanup_with_limit(files, keep) do |f|
|
60
|
+
file = File.join(path, f)
|
61
|
+
puts "removing ftp file #{host}:#{file}" if $DRY_RUN || $_VERBOSE
|
62
|
+
ftp.delete(file) unless $DRY_RUN || $LOCAL
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def host
|
68
|
+
@config[:ftp, :host]
|
69
|
+
end
|
70
|
+
|
71
|
+
def user
|
72
|
+
@config[:ftp, :user]
|
73
|
+
end
|
74
|
+
|
75
|
+
def password
|
76
|
+
@config[:ftp, :password]
|
77
|
+
end
|
78
|
+
|
79
|
+
def port
|
80
|
+
@config[:ftp, :port]
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Astrails
|
2
|
+
module Safe
|
3
|
+
class Mongodump < Source
|
4
|
+
|
5
|
+
def command
|
6
|
+
opts = []
|
7
|
+
opts << "--host #{@config[:host]}" if @config[:host]
|
8
|
+
opts << "-u #{@config[:user]}" if @config[:user]
|
9
|
+
opts << "-p #{@config[:password]}" if @config[:password]
|
10
|
+
opts << "--out #{output_directory}"
|
11
|
+
|
12
|
+
"mongodump -q \"{xxxx : { \\$ne : 0 } }\" --db #{@id} #{opts.join(" ")} && cd #{output_directory} && tar cf - ."
|
13
|
+
end
|
14
|
+
|
15
|
+
def extension; '.tar'; end
|
16
|
+
|
17
|
+
protected
|
18
|
+
def output_directory
|
19
|
+
File.join(TmpFile.tmproot, "mongodump")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -55,7 +55,7 @@ describe "tar backup" do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it "should NOT remove backups with base having same prefix" do
|
58
|
-
Dir["#{@dst}/archive/archive-foobar.*"].should == ["#{@dst}/archive/archive-foobar.000001.tar.gz", "#{@dst}/archive/archive-foobar.000002.tar.gz"]
|
58
|
+
Dir["#{@dst}/archive/archive-foobar.*"].sort.should == ["#{@dst}/archive/archive-foobar.000001.tar.gz", "#{@dst}/archive/archive-foobar.000002.tar.gz"]
|
59
59
|
end
|
60
60
|
|
61
61
|
end
|
data/spec/unit/config_spec.rb
CHANGED
@@ -101,6 +101,12 @@ describe Astrails::Safe::Config do
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
+
mongodump do
|
105
|
+
host "host"
|
106
|
+
database "database"
|
107
|
+
user "user"
|
108
|
+
password "password"
|
109
|
+
end
|
104
110
|
end
|
105
111
|
|
106
112
|
expected = {
|
@@ -177,6 +183,15 @@ describe Astrails::Safe::Config do
|
|
177
183
|
"misc" => { "files" => ["/backup/*.rb"] },
|
178
184
|
},
|
179
185
|
},
|
186
|
+
|
187
|
+
"mongodump" => {
|
188
|
+
"host" => "host",
|
189
|
+
"databases" => {
|
190
|
+
"database" => {}
|
191
|
+
},
|
192
|
+
"user" => "user",
|
193
|
+
"password" => "password"
|
194
|
+
}
|
180
195
|
}
|
181
196
|
|
182
197
|
config.to_hash.should == expected
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Astrails::Safe::Mongodump do
|
4
|
+
def def_config
|
5
|
+
{
|
6
|
+
:host => 'prod.example.com',
|
7
|
+
:user => 'testuser',
|
8
|
+
:password => 'p4ssw0rd',
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def mongodump(id = :foo, config = def_config)
|
13
|
+
Astrails::Safe::Mongodump.new(id, Astrails::Safe::Config::Node.new(nil, config))
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
stub(Time).now.stub!.strftime {"NOW"}
|
18
|
+
@output_folder = File.join(Astrails::Safe::TmpFile.tmproot, 'mongodump')
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:each) { Astrails::Safe::TmpFile.cleanup }
|
22
|
+
|
23
|
+
describe :backup do
|
24
|
+
before(:each) do
|
25
|
+
@mongo = mongodump
|
26
|
+
end
|
27
|
+
|
28
|
+
{
|
29
|
+
:id => "foo",
|
30
|
+
:kind => "mongodump",
|
31
|
+
:extension => ".tar",
|
32
|
+
:filename => "mongodump-foo.NOW"
|
33
|
+
}.each do |k, v|
|
34
|
+
it "should set #{k} to #{v}" do
|
35
|
+
@mongo.backup.send(k).should == v
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should set the command" do
|
40
|
+
@mongo.backup.send(:command).should == "mongodump -q \"{xxxx : { \\$ne : 0 } }\" --db foo --host prod.example.com -u testuser -p p4ssw0rd --out #{@output_folder} && cd #{@output_folder} && tar cf - ."
|
41
|
+
end
|
42
|
+
|
43
|
+
{
|
44
|
+
:host => "--host ",
|
45
|
+
:user => "-u ",
|
46
|
+
:password => "-p "
|
47
|
+
}.each do |key, v|
|
48
|
+
it "should not add #{key} to command if it is not present" do
|
49
|
+
@mongo = mongodump(:foo, def_config.reject! {|k,v| k == key})
|
50
|
+
@mongo.backup.send(:command).should_not =~ /#{v}/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/templates/script.rb
CHANGED
@@ -46,6 +46,15 @@ safe do
|
|
46
46
|
# path ":kind/:id" # this is the default
|
47
47
|
# end
|
48
48
|
|
49
|
+
## uncomment to enable uploads via FTP
|
50
|
+
# ftp do
|
51
|
+
# host "YOUR_REMOTE_HOSTNAME"
|
52
|
+
# user "YOUR_REMOTE_USERNAME"
|
53
|
+
# # port "NON STANDARD FTP PORT"
|
54
|
+
# password "YOUR_REMOTE_PASSWORD"
|
55
|
+
# path ":kind/:id" # this is the default
|
56
|
+
# end
|
57
|
+
|
49
58
|
## uncomment to enable GPG encryption.
|
50
59
|
## Note: you can use public 'key' or symmetric password but not both!
|
51
60
|
# gpg do
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: astrails-safe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.3.
|
5
|
+
version: 0.3.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Vitaly Kushner
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-s3
|
@@ -128,7 +128,7 @@ description: ! 'Astrails-Safe is a simple tool to backup databases (MySQL and Po
|
|
128
128
|
|
129
129
|
Backups can be stored locally or remotely and can be enctypted.
|
130
130
|
|
131
|
-
Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain SFTP.
|
131
|
+
Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain FTP/SFTP.
|
132
132
|
|
133
133
|
'
|
134
134
|
email:
|
@@ -155,9 +155,11 @@ files:
|
|
155
155
|
- lib/astrails/safe/cloudfiles.rb
|
156
156
|
- lib/astrails/safe/config/builder.rb
|
157
157
|
- lib/astrails/safe/config/node.rb
|
158
|
+
- lib/astrails/safe/ftp.rb
|
158
159
|
- lib/astrails/safe/gpg.rb
|
159
160
|
- lib/astrails/safe/gzip.rb
|
160
161
|
- lib/astrails/safe/local.rb
|
162
|
+
- lib/astrails/safe/mongodump.rb
|
161
163
|
- lib/astrails/safe/mysqldump.rb
|
162
164
|
- lib/astrails/safe/pgdump.rb
|
163
165
|
- lib/astrails/safe/pipe.rb
|
@@ -179,6 +181,7 @@ files:
|
|
179
181
|
- spec/unit/gpg_spec.rb
|
180
182
|
- spec/unit/gzip_spec.rb
|
181
183
|
- spec/unit/local_spec.rb
|
184
|
+
- spec/unit/mongodump_spec.rb
|
182
185
|
- spec/unit/mysqldump_spec.rb
|
183
186
|
- spec/unit/pgdump_spec.rb
|
184
187
|
- spec/unit/s3_spec.rb
|
@@ -197,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
197
200
|
- !ruby/object:Gem::Version
|
198
201
|
segments:
|
199
202
|
- 0
|
200
|
-
hash:
|
203
|
+
hash: -3388246215765572723
|
201
204
|
version: '0'
|
202
205
|
none: false
|
203
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -206,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
209
|
- !ruby/object:Gem::Version
|
207
210
|
segments:
|
208
211
|
- 0
|
209
|
-
hash:
|
212
|
+
hash: -3388246215765572723
|
210
213
|
version: '0'
|
211
214
|
none: false
|
212
215
|
requirements: []
|
@@ -226,6 +229,7 @@ test_files:
|
|
226
229
|
- spec/unit/gpg_spec.rb
|
227
230
|
- spec/unit/gzip_spec.rb
|
228
231
|
- spec/unit/local_spec.rb
|
232
|
+
- spec/unit/mongodump_spec.rb
|
229
233
|
- spec/unit/mysqldump_spec.rb
|
230
234
|
- spec/unit/pgdump_spec.rb
|
231
235
|
- spec/unit/s3_spec.rb
|