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.
@@ -60,8 +60,7 @@ module Astrails
60
60
  end
61
61
  end
62
62
  end
63
-
64
63
  end
65
64
  end
66
65
  end
67
- end
66
+ end
@@ -2,35 +2,38 @@ module Astrails
2
2
  module Safe
3
3
  class Gpg < Pipe
4
4
 
5
- def compressed?
6
- active? || @parent.compressed?
7
- end
8
-
9
5
  protected
10
6
 
7
+ def post_process
8
+ @backup.compressed = true
9
+ end
10
+
11
11
  def pipe
12
12
  if key
13
- rise RuntimeError, "can't use both gpg password and pubkey" if password
14
- "|gpg -e -r #{key}"
13
+ "|gpg #{@config[:options]} -e -r #{key}"
15
14
  elsif password
16
- "|gpg -c --passphrase-file #{gpg_password_file(password)}"
15
+ "|gpg #{@config[:options]} -c --passphrase-file #{gpg_password_file(password)}"
17
16
  end
18
17
  end
19
18
 
20
19
  def extension
21
- ".gpg" if active?
20
+ ".gpg"
22
21
  end
23
22
 
24
23
  def active?
24
+ raise RuntimeError, "can't use both gpg password and pubkey" if key && password
25
+
25
26
  password || key
26
27
  end
27
28
 
29
+ private
30
+
28
31
  def password
29
- @password ||= config[:gpg, :password]
32
+ @password ||= @config[:gpg, :password]
30
33
  end
31
34
 
32
35
  def key
33
- @key ||= config[:gpg, :key]
36
+ @key ||= @config[:gpg, :key]
34
37
  end
35
38
 
36
39
  def gpg_password_file(pass)
@@ -39,4 +42,4 @@ module Astrails
39
42
  end
40
43
  end
41
44
  end
42
- end
45
+ end
@@ -2,24 +2,24 @@ module Astrails
2
2
  module Safe
3
3
  class Gzip < Pipe
4
4
 
5
- def compressed?
6
- true
7
- end
8
-
9
5
  protected
10
6
 
7
+ def post_process
8
+ @backup.compressed = true
9
+ end
10
+
11
11
  def pipe
12
- "|gzip" if active?
12
+ "|gzip"
13
13
  end
14
14
 
15
15
  def extension
16
- ".gz" if active?
16
+ ".gz"
17
17
  end
18
18
 
19
19
  def active?
20
- !@parent.compressed?
20
+ !@backup.compressed
21
21
  end
22
22
 
23
23
  end
24
24
  end
25
- end
25
+ end
@@ -2,45 +2,37 @@ module Astrails
2
2
  module Safe
3
3
  class Local < Sink
4
4
 
5
- def open(&block)
6
- return @parent.open(&block) unless active?
7
- run
8
- File.open(path, &block) unless $DRY_RUN
9
- end
10
-
11
5
  protected
12
6
 
13
7
  def active?
14
8
  # S3 can't upload from pipe. it needs to know file size, so we must pass through :local
15
- # will change once we add SSH sink
9
+ # will change once we add SSH/FTP sink
16
10
  true
17
11
  end
18
12
 
19
13
  def prefix
20
- @prefix ||= File.expand_path(expand(@config[:local, :path] || raise(RuntimeError, "missing :local/:path in configuration")))
21
- end
22
-
23
- def command
24
- "#{@parent.command} > #{path}"
14
+ @prefix ||= File.expand_path(expand(@config[:local, :path] || raise(RuntimeError, "missing :local/:path")))
25
15
  end
26
16
 
27
17
  def save
28
- puts "command: #{command}" if $_VERBOSE
18
+ puts "command: #{@backup.command}" if $_VERBOSE
19
+
29
20
  unless $DRY_RUN
30
21
  FileUtils.mkdir_p(prefix) unless File.directory?(prefix)
31
- system command
22
+ system "#{@backup.command}>#{@backup.path = path}"
32
23
  end
24
+
33
25
  end
34
26
 
35
27
  def cleanup
36
28
  return unless keep = @config[:keep, :local]
37
29
 
38
- base = File.basename(filename).split(".").first
30
+ base = File.basename(@backup.filename).split(".").first
39
31
 
40
32
  pattern = File.join(prefix, "#{base}*")
41
33
  puts "listing files #{pattern.inspect}" if $_VERBOSE
42
34
  files = Dir[pattern] .
43
- select{|f| File.file?(f)} .
35
+ select{|f| File.file?(f) && File.size(f) > 0} .
44
36
  sort
45
37
 
46
38
  cleanup_with_limit(files, keep) do |f|
@@ -48,7 +40,6 @@ module Astrails
48
40
  File.unlink(f) unless $DRY_RUN
49
41
  end
50
42
  end
51
-
52
43
  end
53
44
  end
54
45
  end
@@ -3,7 +3,7 @@ module Astrails
3
3
  class Mysqldump < Source
4
4
 
5
5
  def command
6
- @commanbd ||= "mysqldump --defaults-extra-file=#{mysql_password_file} #{@config[:options]} #{mysql_skip_tables} #{@id}"
6
+ "mysqldump --defaults-extra-file=#{mysql_password_file} #{@config[:options]} #{mysql_skip_tables} #{@id}"
7
7
  end
8
8
 
9
9
  def extension; '.sql'; end
@@ -28,4 +28,4 @@ module Astrails
28
28
 
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -0,0 +1,36 @@
1
+ module Astrails
2
+ module Safe
3
+ class Pgdump < Source
4
+
5
+ def command
6
+ if @config["password"]
7
+ ENV['PGPASSWORD'] = @config["password"]
8
+ else
9
+ ENV['PGPASSWORD'] = nil
10
+ end
11
+ "pg_dump #{postgres_options} #{postgres_username} #{postgres_host} #{postgres_port} #{@id}"
12
+ end
13
+
14
+ def extension; '.sql'; end
15
+
16
+ protected
17
+
18
+ def postgres_options
19
+ @config[:options]
20
+ end
21
+
22
+ def postgres_host
23
+ @config["host"] && "--host='#{@config["host"]}'"
24
+ end
25
+
26
+ def postgres_port
27
+ @config["port"] && "--port='#{@config["port"]}'"
28
+ end
29
+
30
+ def postgres_username
31
+ @config["user"] && "--username='#{@config["user"]}'"
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -1,15 +1,13 @@
1
1
  module Astrails
2
2
  module Safe
3
3
  class Pipe < Stream
4
+ def process
5
+ return unless active?
4
6
 
5
- def command
6
- "#{@parent.command}#{pipe}"
7
+ @backup.command << pipe
8
+ @backup.extension << extension
9
+ post_process
7
10
  end
8
-
9
- def filename
10
- "#{@parent.filename}#{extension}"
11
- end
12
-
13
11
  end
14
12
  end
15
13
  end
@@ -9,32 +9,30 @@ module Astrails
9
9
  end
10
10
 
11
11
  def prefix
12
- @prefix ||= expand(config[:s3, :path] || expand(config[:local, :path] || ":kind/:id"))
12
+ @prefix ||= expand(config[:s3, :path] || config[:local, :path] || ":kind/:id")
13
13
  end
14
14
 
15
15
  def save
16
+ raise RuntimeError, "pipe-streaming not supported for S3." unless @backup.path
17
+
16
18
  # needed in cleanup even on dry run
17
19
  AWS::S3::Base.establish_connection!(:access_key_id => key, :secret_access_key => secret, :use_ssl => true) unless $LOCAL
18
20
 
19
- file = @parent.open
20
21
  puts "Uploading #{bucket}:#{path}" if $_VERBOSE || $DRY_RUN
21
22
  unless $DRY_RUN || $LOCAL
22
23
  AWS::S3::Bucket.create(bucket)
23
- AWS::S3::S3Object.store(path, file, bucket)
24
+ File.open(@backup.path) do |file|
25
+ AWS::S3::S3Object.store(path, file, bucket)
26
+ end
24
27
  puts "...done" if $_VERBOSE
25
28
  end
26
- file.close if file
27
-
28
29
  end
29
30
 
30
31
  def cleanup
31
-
32
32
  return if $LOCAL
33
33
 
34
34
  return unless keep = @config[:keep, :s3]
35
35
 
36
- bucket = @config[:s3, :bucket]
37
-
38
36
  base = File.basename(filename).split(".").first
39
37
 
40
38
  puts "listing files in #{bucket}:#{prefix}/#{base}"
@@ -52,15 +50,15 @@ module Astrails
52
50
  end
53
51
 
54
52
  def bucket
55
- config[:s3, :bucket]
53
+ @config[:s3, :bucket]
56
54
  end
57
55
 
58
56
  def key
59
- config[:s3, :key]
57
+ @config[:s3, :key]
60
58
  end
61
59
 
62
60
  def secret
63
- config[:s3, :secret]
61
+ @config[:s3, :secret]
64
62
  end
65
63
 
66
64
  end
@@ -2,20 +2,18 @@ module Astrails
2
2
  module Safe
3
3
  class Sink < Stream
4
4
 
5
- def run
6
- if active?
7
- save
8
- cleanup
9
- else
10
- @parent.run
11
- end
5
+ def process
6
+ return unless active?
7
+
8
+ save
9
+ cleanup
12
10
  end
13
11
 
14
12
  protected
15
13
 
16
14
  # prefix is defined in subclass
17
15
  def path
18
- @path ||= File.join(prefix, filename)
16
+ @path ||= File.join(prefix, @backup.filename) + @backup.extension
19
17
  end
20
18
 
21
19
  # call block on files to be removed (all except for the LAST 'limit' files
@@ -26,8 +24,6 @@ module Astrails
26
24
  # TODO: validate here
27
25
  to_remove.each(&block)
28
26
  end
29
-
30
27
  end
31
28
  end
32
- end
33
-
29
+ end
@@ -2,27 +2,42 @@ module Astrails
2
2
  module Safe
3
3
  class Source < Stream
4
4
 
5
+ attr_accessor :id
5
6
  def initialize(id, config)
6
- @id, @config = id, config
7
+ @id, @config = id.to_s, config
8
+ end
9
+
10
+ def timestamp
11
+ Time.now.strftime("%y%m%d-%H%M")
12
+ end
13
+
14
+ def kind
15
+ self.class.human_name
7
16
  end
8
17
 
9
18
  def filename
10
- @filename ||= expand(":kind-:id.:timestamp#{extension}")
19
+ @filename ||= expand(":kind-:id.:timestamp")
11
20
  end
12
21
 
13
- # process each config key as source (with full pipe)
14
- def self.run(config)
15
- unless config
16
- puts "No configuration found for #{human_name}"
17
- return
18
- end
19
-
20
- config.each do |key, value|
21
- stream = [Gpg, Gzip, Local, S3].inject(new(key, value)) do |res, klass|
22
- klass.new(res)
23
- end
24
- stream.run
25
- end
22
+ def backup
23
+ return @backup if @backup
24
+ @backup = Backup.new(
25
+ :id => @id,
26
+ :kind => kind,
27
+ :extension => extension,
28
+ :command => command,
29
+ :timestamp => timestamp
30
+ )
31
+ # can't do this in the initializer hash above since
32
+ # filename() calls expand() which requires @backup
33
+ @backup.filename = filename
34
+ @backup
35
+ end
36
+
37
+ protected
38
+
39
+ def self.human_name
40
+ name.split('::').last.downcase
26
41
  end
27
42
 
28
43
  end
@@ -2,44 +2,18 @@ module Astrails
2
2
  module Safe
3
3
  class Stream
4
4
 
5
- def initialize(parent)
6
- @parent = parent
7
- end
8
-
9
- def id
10
- @id ||= @parent.id
11
- end
12
-
13
- def config
14
- @config ||= @parent.config
15
- end
16
-
17
- def filename
18
- @parent.filename
19
- end
20
-
21
- def compressed?
22
- @parent && @parent.compressed?
23
- end
24
-
25
- protected
26
-
27
- def self.human_name
28
- name.split('::').last.downcase
29
- end
30
-
31
- def kind
32
- @parent ? @parent.kind : self.class.human_name
5
+ attr_accessor :config, :backup
6
+ def initialize(config, backup)
7
+ @config, @backup = config, backup
33
8
  end
34
9
 
35
10
  def expand(path)
36
11
  path .
37
- gsub(/:kind\b/, kind) .
38
- gsub(/:id\b/, id) .
39
- gsub(/:timestamp\b/, timestamp)
12
+ gsub(/:kind\b/, @backup.kind.to_s) .
13
+ gsub(/:id\b/, @backup.id.to_s) .
14
+ gsub(/:timestamp\b/, @backup.timestamp)
40
15
  end
41
16
 
42
17
  end
43
18
  end
44
- end
45
-
19
+ end
@@ -0,0 +1,13 @@
1
+ module Astrails
2
+ module Safe
3
+ class Svndump < Source
4
+
5
+ def command
6
+ "svnadmin dump #{@config[:options]} #{@config[:repo_path]}"
7
+ end
8
+
9
+ def extension; '.svn'; end
10
+
11
+ end
12
+ end
13
+ end