astrails-safe 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/astrails/safe.png)](https://travis-ci.org/astrails/safe)
|
9
10
|
[![Code Climate](https://codeclimate.com/github/astrails/safe.png)](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
|