astrails-safe 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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