astrails-safe 0.1.6 → 0.1.7

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.
@@ -0,0 +1,64 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ describe Astrails::Safe::Gzip do
4
+
5
+ def def_backup
6
+ {
7
+ :compressed => false,
8
+ :command => "command",
9
+ :extension => ".foo",
10
+ :filename => "qweqwe"
11
+ }
12
+ end
13
+
14
+ after(:each) { Astrails::Safe::TmpFile.cleanup }
15
+
16
+ def gzip(config = {}, backup = def_backup)
17
+ Astrails::Safe::Gzip.new(
18
+ @config = Astrails::Safe::Config::Node.new(nil, config),
19
+ @backup = Astrails::Safe::Backup.new(backup)
20
+ )
21
+ end
22
+
23
+ describe :preocess do
24
+
25
+ describe "when not yet compressed" do
26
+ before(:each) { @gzip = gzip }
27
+
28
+ it "should add .gz extension" do
29
+ mock(@backup.extension) << '.gz'
30
+ @gzip.process
31
+ end
32
+
33
+ it "should add |gzip pipe" do
34
+ mock(@backup.command) << '|gzip'
35
+ @gzip.process
36
+ end
37
+
38
+ it "should set compressed" do
39
+ mock(@backup).compressed = true
40
+ @gzip.process
41
+ end
42
+ end
43
+
44
+ describe "when already compressed" do
45
+
46
+ before(:each) { @gzip = gzip({}, :compressed => true) }
47
+
48
+ it "should not touch extension" do
49
+ dont_allow(@backup.extension).<< anything
50
+ @gzip.process
51
+ end
52
+
53
+ it "should not touch command" do
54
+ dont_allow(@backup.command).<< anything
55
+ @gzip.process
56
+ end
57
+
58
+ it "should not touch compressed" do
59
+ dont_allow(@backup).compressed = anything
60
+ @gzip.process
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ describe Astrails::Safe::Local do
4
+ def def_config
5
+ {
6
+ :local => {
7
+ :path => "/:kind~:id~:timestamp"
8
+ }
9
+ }
10
+ end
11
+
12
+ def def_backup
13
+ {
14
+ :kind => "mysqldump",
15
+ :id => "blog",
16
+ :timestamp => "NoW",
17
+ :compressed => true,
18
+ :command => "command",
19
+ :extension => ".foo.gz",
20
+ :filename => "qweqwe"
21
+ }
22
+ end
23
+
24
+ def local(config = def_config, backup = def_backup)
25
+ Astrails::Safe::Local.new(
26
+ @config = Astrails::Safe::Config::Node.new(nil, config),
27
+ @backup = Astrails::Safe::Backup.new(backup)
28
+ )
29
+ end
30
+
31
+ describe :active? do
32
+ it "should be true" do
33
+ local.should be_active
34
+ end
35
+ end
36
+
37
+ describe :prefix do
38
+ it "should raise RuntimeError when no path" do
39
+ lambda {
40
+ local({}).send :prefix
41
+ }.should raise_error(RuntimeError, "missing :local/:path")
42
+ end
43
+
44
+ it "should use local/path" do
45
+ local.send(:prefix).should == "/mysqldump~blog~NoW"
46
+ end
47
+ end
48
+
49
+ describe :save do
50
+ before(:each) do
51
+ @local = local
52
+ stub(@local).system
53
+ stub(@local).path {"file-path"}
54
+ stub(FileUtils).mkdir_p
55
+ end
56
+
57
+ it "should call system to save the file" do
58
+ mock(@local).system("command>file-path")
59
+ @local.send(:save)
60
+ end
61
+
62
+ it "should create directory" do
63
+ mock(FileUtils).mkdir_p("/mysqldump~blog~NoW")
64
+ @local.send(:save)
65
+ end
66
+
67
+ it "should set backup.path" do
68
+ mock(@backup).path = "file-path"
69
+ @local.send(:save)
70
+ end
71
+
72
+ describe "dry run" do
73
+ it "should not create directory"
74
+ it "should not call system"
75
+ it "should set backup.path"
76
+ end
77
+ end
78
+
79
+ describe :cleanup do
80
+ it "should have test"
81
+ end
82
+ end
@@ -0,0 +1,83 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ describe Astrails::Safe::Mysqldump do
4
+
5
+ def def_config
6
+ {
7
+ :options => "OPTS",
8
+ :user => "User",
9
+ :password => "pwd",
10
+ :host => "localhost",
11
+ :port => 7777,
12
+ :socket => "socket",
13
+ :skip_tables => [:bar, :baz]
14
+ }
15
+ end
16
+
17
+ def mysqldump(id = :foo, config = def_config)
18
+ Astrails::Safe::Mysqldump.new(id, Astrails::Safe::Config::Node.new(nil, config))
19
+ end
20
+
21
+ before(:each) do
22
+ stub(Time).now.stub!.strftime {"NOW"}
23
+ end
24
+
25
+ after(:each) { Astrails::Safe::TmpFile.cleanup }
26
+
27
+ describe :backup do
28
+ before(:each) do
29
+ @mysql = mysqldump
30
+ stub(@mysql).mysql_password_file {"/tmp/pwd"}
31
+ end
32
+
33
+ {
34
+ :id => "foo",
35
+ :kind => "mysqldump",
36
+ :extension => ".sql",
37
+ :filename => "mysqldump-foo.NOW",
38
+ :command => "mysqldump --defaults-extra-file=/tmp/pwd OPTS --ignore-table=foo.bar --ignore-table=foo.baz foo",
39
+ }.each do |k, v|
40
+ it "should set #{k} to #{v}" do
41
+ @mysql.backup.send(k).should == v
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ describe :mysql_skip_tables do
48
+ it "should return nil if no skip_tables" do
49
+ config = def_config.dup
50
+ config.delete(:skip_tables)
51
+ m = mysqldump(:foo, Astrails::Safe::Config::Node.new(nil, config))
52
+ stub(m).timestamp {"NOW"}
53
+ m.send(:mysql_skip_tables).should be_nil
54
+ m.backup.command.should_not match(/ignore-table/)
55
+ end
56
+
57
+ it "should return '' if skip_tables empty" do
58
+ config = def_config.dup
59
+ config[:skip_tables] = []
60
+ m = mysqldump(:foo, Astrails::Safe::Config::Node.new(nil, config))
61
+ stub(m).timestamp {"NOW"}
62
+ m.send(:mysql_skip_tables).should == ""
63
+ m.backup.command.should_not match(/ignore-table/)
64
+ end
65
+
66
+ end
67
+
68
+ describe :mysql_password_file do
69
+ it "should create passwords file" do
70
+ m = mysqldump
71
+ file = m.send(:mysql_password_file)
72
+ File.exists?(file).should == true
73
+ File.read(file).should == <<-PWD
74
+ [mysqldump]
75
+ user = User
76
+ password = pwd
77
+ socket = socket
78
+ host = localhost
79
+ port = 7777
80
+ PWD
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ describe Astrails::Safe::Pgdump do
4
+
5
+ def def_config
6
+ {
7
+ :options => "OPTS",
8
+ :user => "User",
9
+ :password => "pwd",
10
+ :host => "localhost",
11
+ :port => 7777,
12
+ :skip_tables => [:bar, :baz]
13
+ }
14
+ end
15
+
16
+ def pgdump(id = :foo, config = def_config)
17
+ Astrails::Safe::Pgdump.new(id, Astrails::Safe::Config::Node.new(nil, config))
18
+ end
19
+
20
+ before(:each) do
21
+ stub(Time).now.stub!.strftime {"NOW"}
22
+ end
23
+
24
+ after(:each) { Astrails::Safe::TmpFile.cleanup }
25
+
26
+ describe :backup do
27
+ before(:each) do
28
+ @pg = pgdump
29
+ end
30
+
31
+ {
32
+ :id => "foo",
33
+ :kind => "pgdump",
34
+ :extension => ".sql",
35
+ :filename => "pgdump-foo.NOW",
36
+ :command => "pg_dump OPTS --username='User' --host='localhost' --port='7777' foo",
37
+ }.each do |k, v|
38
+ it "should set #{k} to #{v}" do
39
+ @pg.backup.send(k).should == v
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ describe Astrails::Safe::S3 do
4
+
5
+ describe :active do
6
+ it "should be true when all params are set"
7
+ it "should be false if bucket is missing"
8
+ it "should be false if key is missing"
9
+ it "should be false if secret is missing"
10
+ end
11
+
12
+ describe :prefix do
13
+ it "should use s3/path 1st"
14
+ it "should use local/path 2nd"
15
+ it "should use constant 3rd"
16
+ end
17
+
18
+ describe :save do
19
+ it "should establish s3 connection"
20
+ it "should RuntimeError if no local file (i.e. :local didn't run)"
21
+ it "should open local file"
22
+ it "should upload file"
23
+ end
24
+
25
+ describe :cleanup do
26
+ it "should have some tests"
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../example_helper')
2
+
3
+ describe Astrails::Safe::Svndump do
4
+ def def_config
5
+ {
6
+ :options => "OPTS",
7
+ :repo_path => "bar/baz"
8
+ }
9
+ end
10
+
11
+ def svndump(id = :foo, config = def_config)
12
+ Astrails::Safe::Svndump.new(id, Astrails::Safe::Config::Node.new(nil, config))
13
+ end
14
+
15
+ before(:each) do
16
+ stub(Time).now.stub!.strftime {"NOW"}
17
+ end
18
+
19
+ after(:each) { Astrails::Safe::TmpFile.cleanup }
20
+
21
+ describe :backup do
22
+ before(:each) do
23
+ @svn = svndump
24
+ end
25
+
26
+ {
27
+ :id => "foo",
28
+ :kind => "svndump",
29
+ :extension => ".svn",
30
+ :filename => "svndump-foo.NOW",
31
+ :command => "svnadmin dump OPTS bar/baz",
32
+ }.each do |k, v|
33
+ it "should set #{k} to #{v}" do
34
+ @svn.backup.send(k).should == v
35
+ end
36
+ end
37
+
38
+ end
39
+ end
data/lib/astrails/safe.rb CHANGED
@@ -1,4 +1,9 @@
1
+ require "aws/s3"
2
+ require 'fileutils'
3
+
4
+ require 'tempfile'
1
5
  require 'extensions/mktmpdir'
6
+
2
7
  require 'astrails/safe/tmp_file'
3
8
 
4
9
  require 'astrails/safe/config/node'
@@ -6,9 +11,15 @@ require 'astrails/safe/config/builder'
6
11
 
7
12
  require 'astrails/safe/stream'
8
13
 
14
+ require 'astrails/safe/backup'
15
+
16
+ require 'astrails/safe/backup'
17
+
9
18
  require 'astrails/safe/source'
10
19
  require 'astrails/safe/mysqldump'
20
+ require 'astrails/safe/pgdump'
11
21
  require 'astrails/safe/archive'
22
+ require 'astrails/safe/svndump'
12
23
 
13
24
  require 'astrails/safe/pipe'
14
25
  require 'astrails/safe/gpg'
@@ -23,19 +34,25 @@ module Astrails
23
34
  module Safe
24
35
  ROOT = File.join(File.dirname(__FILE__), "..", "..")
25
36
 
26
- def timestamp
27
- @timestamp ||= Time.now.strftime("%y%m%d-%H%M")
28
- end
29
-
30
37
  def safe(&block)
31
38
  config = Config::Node.new(&block)
32
39
  #config.dump
33
40
 
34
- Astrails::Safe::Mysqldump.run(config[:mysqldump, :databases])
35
- Astrails::Safe::Archive.run(config[:tar, :archives])
41
+
42
+ [[Astrails::Safe::Mysqldump, [:mysqldump, :databases]],
43
+ [Astrails::Safe::Pgdump, [:pgdump, :databases]],
44
+ [Astrails::Safe::Archive, [:tar, :archives]],
45
+ [Astrails::Safe::Svndump, [:svndump, :repos]]
46
+ ].each do |klass, path|
47
+ if collection = config[*path]
48
+ collection.each do |name, config|
49
+ klass.new(name, config).backup.run(config, :gpg, :gzip, :local, :s3)
50
+ end
51
+ end
52
+ end
36
53
 
37
54
  Astrails::Safe::TmpFile.cleanup
38
55
  end
56
+ module_function :safe
39
57
  end
40
58
  end
41
-
@@ -16,9 +16,9 @@ module Astrails
16
16
 
17
17
  def tar_files
18
18
  raise RuntimeError, "missing files for tar" unless @config[:files]
19
- [*@config[:files]] * " "
19
+ [*@config[:files]].map {|s| s.strip} * " "
20
20
  end
21
21
 
22
22
  end
23
23
  end
24
- end
24
+ end
@@ -0,0 +1,20 @@
1
+ module Astrails
2
+ module Safe
3
+ class Backup
4
+ attr_accessor :id, :kind, :filename, :extension, :command, :compressed, :timestamp, :path
5
+ def initialize(opts = {})
6
+ opts.each do |k, v|
7
+ self.send("#{k}=", v)
8
+ end
9
+ end
10
+
11
+ def run(config, *mods)
12
+ mods.each do |mod|
13
+ mod = mod.to_s
14
+ mod[0] = mod[0..0].upcase
15
+ Astrails::Safe.const_get(mod).new(config, self).process
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,9 +2,9 @@ module Astrails
2
2
  module Safe
3
3
  module Config
4
4
  class Builder
5
- COLLECTIONS = %w/database archive/
6
- ITEMS = %w/s3 key secret bucket path gpg password keep local mysqldump options
7
- user host port socket skip_tables tar files exclude filename/
5
+ COLLECTIONS = %w/database archive repo/
6
+ ITEMS = %w/s3 key secret bucket path gpg password keep local mysqldump pgdump options
7
+ user host port socket skip_tables tar files exclude filename svndump repo_path/
8
8
  NAMES = COLLECTIONS + ITEMS
9
9
  def initialize(node)
10
10
  @node = node
@@ -27,13 +27,13 @@ module Astrails
27
27
 
28
28
  # do we have data hash?
29
29
  if data = args.shift
30
- die "#{sym}: hash expected: #{data.inspect}" unless data.is_a?(Hash)
30
+ raise "#{sym}: hash expected: #{data.inspect}" unless data.is_a?(Hash)
31
31
  end
32
32
 
33
33
  #puts "#{sym}: args=#{args.inspect}, id_or_value=#{id_or_value}, data=#{data.inspect}, block=#{block.inspect}"
34
34
 
35
- die "#{sym}: unexpected: #{args.inspect}" unless args.empty?
36
- die "#{sym}: missing arguments" unless id_or_value || data || block
35
+ raise "#{sym}: unexpected: #{args.inspect}" unless args.empty?
36
+ raise "#{sym}: missing arguments" unless id_or_value || data || block
37
37
 
38
38
  if COLLECTIONS.include?(sym.to_s) && id_or_value
39
39
  data ||= {}