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 CHANGED
@@ -1,3 +1,13 @@
1
+ 0.3.1
2
+
3
+ * plain ftp support from seroy
4
+ * mongodump support from Matt Berther
5
+
6
+ 0.3.0
7
+
8
+ * switch to bundler
9
+ * fixed the rspec
10
+
1
11
  0.2.8
2
12
 
3
13
  * ruby 1.9.2 compatibility (tests mostly)
@@ -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://blog.astrails.com/astrails-safe](http://blog.astrails.com/astrails-safe)
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
@@ -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"
@@ -2,10 +2,8 @@
2
2
 
3
3
  require 'rubygems'
4
4
 
5
- # require 'ruby-debug'
6
- $:.unshift File.expand_path("../../lib", __FILE__)
7
-
8
5
  require 'astrails/safe'
6
+
9
7
  include Astrails::Safe
10
8
 
11
9
  def die(msg)
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Astrails
2
2
  module Safe
3
- VERSION = "0.3.0"
3
+ VERSION = "0.3.1"
4
4
  end
5
5
  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
@@ -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
@@ -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.0
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-01 00:00:00.000000000 Z
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: 1115506129816519000
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: 1115506129816519000
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