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 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