backup 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -28,33 +28,16 @@ module Backup
28
28
  # Additional "pg_dump" options
29
29
  attr_accessor :additional_options
30
30
 
31
- ##
32
- # Path to pg_dump utility (optional)
33
- attr_accessor :pg_dump_utility
34
-
35
- attr_deprecate :utility_path, :version => '3.0.21',
36
- :message => 'Use PostgreSQL#pg_dump_utility instead.',
37
- :action => lambda {|klass, val| klass.pg_dump_utility = val }
38
-
39
- ##
40
- # Creates a new instance of the PostgreSQL adapter object
41
- # Sets the PGPASSWORD environment variable to the password
42
- # so it doesn't prompt and hang in the process
43
- def initialize(model, &block)
44
- super(model)
45
-
46
- @skip_tables ||= Array.new
47
- @only_tables ||= Array.new
48
- @additional_options ||= Array.new
49
-
31
+ def initialize(model, database_id = nil, &block)
32
+ super
50
33
  instance_eval(&block) if block_given?
51
-
52
- @pg_dump_utility ||= utility(:pg_dump)
53
34
  end
54
35
 
55
36
  ##
56
- # Performs the pgdump command and outputs the
57
- # data to the specified path based on the 'trigger'
37
+ # Performs the mysqldump command and outputs the dump file
38
+ # in the +dump_path+ using +dump_filename+.
39
+ #
40
+ # <trigger>/databases/PostgreSQL[-<database_id>].sql[.gz]
58
41
  def perform!
59
42
  super
60
43
 
@@ -62,84 +45,75 @@ module Backup
62
45
  dump_ext = 'sql'
63
46
 
64
47
  pipeline << pgdump
65
- if @model.compressor
66
- @model.compressor.compress_with do |command, ext|
67
- pipeline << command
68
- dump_ext << ext
69
- end
70
- end
48
+
49
+ model.compressor.compress_with do |command, ext|
50
+ pipeline << command
51
+ dump_ext << ext
52
+ end if model.compressor
71
53
 
72
54
  pipeline << "#{ utility(:cat) } > " +
73
- "'#{ File.join(@dump_path, name) }.#{ dump_ext }'"
55
+ "'#{ File.join(dump_path, dump_filename) }.#{ dump_ext }'"
56
+
74
57
  pipeline.run
75
58
  if pipeline.success?
76
- Logger.info "#{ database_name } Complete!"
59
+ log!(:finished)
77
60
  else
78
61
  raise Errors::Database::PipelineError,
79
- "#{ database_name } Dump Failed!\n" +
80
- pipeline.error_messages
62
+ "#{ database_name } Dump Failed!\n" + pipeline.error_messages
81
63
  end
82
64
  end
83
65
 
84
- ##
85
- # Builds the full pgdump string based on all attributes
86
66
  def pgdump
87
- "#{password_options}" +
88
- "#{ pg_dump_utility } #{ username_options } #{ connectivity_options } " +
67
+ "#{ password_option }" +
68
+ "#{ utility(:pg_dump) } #{ username_option } #{ connectivity_options } " +
89
69
  "#{ user_options } #{ tables_to_dump } #{ tables_to_skip } #{ name }"
90
70
  end
91
71
 
92
- ##
93
- # Builds the password syntax PostgreSQL uses to authenticate the user
94
- # to perform database dumping
95
- def password_options
96
- password.to_s.empty? ? '' : "PGPASSWORD='#{password}' "
72
+ def password_option
73
+ "PGPASSWORD='#{ password }' " if password
97
74
  end
98
75
 
99
- ##
100
- # Builds the credentials PostgreSQL syntax to authenticate the user
101
- # to perform the database dumping process
102
- def username_options
103
- username.to_s.empty? ? '' : "--username='#{username}'"
76
+ def username_option
77
+ "--username='#{ username }'" if username
104
78
  end
105
79
 
106
- ##
107
- # Builds the PostgreSQL connectivity options syntax to connect the user
108
- # to perform the database dumping process, socket gets gsub'd to host since
109
- # that's the option PostgreSQL takes for socket connections as well. In case
110
- # both the host and the socket are specified, the socket will take priority over the host
111
80
  def connectivity_options
112
- %w[host port socket].map do |option|
113
- next if send(option).to_s.empty?
114
- "--#{option}='#{send(option)}'".gsub('--socket=', '--host=')
115
- end.compact.join(' ')
81
+ return "--host='#{ socket }'" if socket
82
+
83
+ opts = []
84
+ opts << "--host='#{ host }'" if host
85
+ opts << "--port='#{ port }'" if port
86
+ opts.join(' ')
116
87
  end
117
88
 
118
- ##
119
- # Builds a PostgreSQL compatible string for the additional options
120
- # specified by the user
121
89
  def user_options
122
- additional_options.join(' ')
90
+ Array(additional_options).join(' ')
123
91
  end
124
92
 
125
- ##
126
- # Builds the PostgreSQL syntax for specifying which tables to dump
127
- # during the dumping of the database
128
93
  def tables_to_dump
129
- only_tables.map do |table|
130
- "--table='#{table}'"
94
+ Array(only_tables).map do |table|
95
+ "--table='#{ table }'"
131
96
  end.join(' ')
132
97
  end
133
98
 
134
- ##
135
- # Builds the PostgreSQL syntax for specifying which tables to skip
136
- # during the dumping of the database
137
99
  def tables_to_skip
138
- skip_tables.map do |table|
139
- "--exclude-table='#{table}'"
100
+ Array(skip_tables).map do |table|
101
+ "--exclude-table='#{ table }'"
140
102
  end.join(' ')
141
103
  end
142
104
 
105
+ attr_deprecate :utility_path, :version => '3.0.21',
106
+ :message => 'Use Backup::Utilities.configure instead.',
107
+ :action => lambda {|klass, val|
108
+ Utilities.configure { pg_dump val }
109
+ }
110
+
111
+ attr_deprecate :pg_dump_utility, :version => '3.3.0',
112
+ :message => 'Use Backup::Utilities.configure instead.',
113
+ :action => lambda {|klass, val|
114
+ Utilities.configure { pg_dump val }
115
+ }
116
+
143
117
  end
144
118
  end
145
119
  end
@@ -5,85 +5,76 @@ module Backup
5
5
  class Redis < Base
6
6
 
7
7
  ##
8
- # Name of and path to the database that needs to get dumped
9
- attr_accessor :name, :path
8
+ # Name of the redis dump file.
9
+ #
10
+ # This is set in `redis.conf` as `dbfilename`.
11
+ # This must be set to the name of that file without the `.rdb` extension.
12
+ # Default: 'dump'
13
+ attr_accessor :name
10
14
 
11
15
  ##
12
- # Credentials for the specified database
16
+ # Path to the redis dump file.
17
+ #
18
+ # This is set in `redis.conf` as `dir`.
19
+ attr_accessor :path
20
+
21
+ ##
22
+ # Password for the redis-cli utility to perform the `SAVE` command
23
+ # if +invoke_save+ is set `true`.
13
24
  attr_accessor :password
14
25
 
15
26
  ##
16
- # Connectivity options
27
+ # Connectivity options for the +invoke_save+ option.
17
28
  attr_accessor :host, :port, :socket
18
29
 
19
30
  ##
20
- # Determines whether Backup should invoke the SAVE command through
21
- # the 'redis-cli' utility to persist the most recent data before
22
- # copying over the dump file
31
+ # Determines whether Backup should invoke the `SAVE` command through
32
+ # the `redis-cli` utility to persist the most recent data before
33
+ # copying the dump file specified by +path+ and +name+.
23
34
  attr_accessor :invoke_save
24
35
 
25
36
  ##
26
37
  # Additional "redis-cli" options
27
38
  attr_accessor :additional_options
28
39
 
29
- ##
30
- # Path to the redis-cli utility (optional)
31
- attr_accessor :redis_cli_utility
32
-
33
- attr_deprecate :utility_path, :version => '3.0.21',
34
- :message => 'Use Redis#redis_cli_utility instead.',
35
- :action => lambda {|klass, val| klass.redis_cli_utility = val }
36
-
37
- ##
38
- # Creates a new instance of the Redis database object
39
- def initialize(model, &block)
40
- super(model)
41
-
42
- @additional_options ||= Array.new
43
-
40
+ def initialize(model, database_id = nil, &block)
41
+ super
44
42
  instance_eval(&block) if block_given?
45
43
 
46
44
  @name ||= 'dump'
47
- @redis_cli_utility ||= utility('redis-cli')
48
45
  end
49
46
 
50
47
  ##
51
- # Performs the Redis backup by using the 'cp' unix utility
52
- # to copy the persisted Redis dump file to the Backup archive.
53
- # Additionally, when 'invoke_save' is set to true, it'll tell
54
- # the Redis server to persist the current state to the dump file
55
- # before copying the dump to get the most recent updates in to the backup
48
+ # Copies and optionally compresses the Redis dump file to the
49
+ # +dump_path+ using the +dump_filename+.
50
+ #
51
+ # <trigger>/databases/Redis[-<database_id>].rdb[.gz]
52
+ #
53
+ # If +invoke_save+ is true, `redis-cli SAVE` will be invoked.
56
54
  def perform!
57
55
  super
58
56
 
59
57
  invoke_save! if invoke_save
60
58
  copy!
59
+
60
+ log!(:finished)
61
61
  end
62
62
 
63
63
  private
64
64
 
65
- ##
66
- # Tells Redis to persist the current state of the
67
- # in-memory database to the persisted dump file
68
65
  def invoke_save!
69
- response = run("#{ redis_cli_utility } #{ credential_options } " +
70
- "#{ connectivity_options } #{ user_options } SAVE")
71
- unless response =~ /OK/
66
+ resp = run(redis_save_cmd)
67
+ unless resp =~ /OK$/
72
68
  raise Errors::Database::Redis::CommandError, <<-EOS
73
69
  Could not invoke the Redis SAVE command.
74
- The #{ database } file might not contain the most recent data.
75
- Please check if the server is running, the credentials (if any) are correct,
76
- and the host/port/socket are correct.
77
-
78
- Redis CLI response: #{ response }
70
+ Command was: #{ redis_save_cmd }
71
+ Response was: #{ resp }
79
72
  EOS
80
73
  end
81
74
  end
82
75
 
83
- ##
84
- # Performs the copy command to copy over the Redis dump file to the Backup archive
85
76
  def copy!
86
- src_path = File.join(path, database)
77
+ src_path = File.join(path, name + '.rdb')
87
78
  unless File.exist?(src_path)
88
79
  raise Errors::Database::Redis::NotFoundError, <<-EOS
89
80
  Redis database dump not found
@@ -91,46 +82,50 @@ module Backup
91
82
  EOS
92
83
  end
93
84
 
94
- dst_path = File.join(@dump_path, database)
95
- if @model.compressor
96
- @model.compressor.compress_with do |command, ext|
97
- run("#{ command } -c #{ src_path } > #{ dst_path + ext }")
85
+ dst_path = File.join(dump_path, dump_filename + '.rdb')
86
+ if model.compressor
87
+ model.compressor.compress_with do |command, ext|
88
+ run("#{ command } -c '#{ src_path }' > '#{ dst_path + ext }'")
98
89
  end
99
90
  else
100
91
  FileUtils.cp(src_path, dst_path)
101
92
  end
102
93
  end
103
94
 
104
- ##
105
- # Returns the Redis database file name
106
- def database
107
- "#{ name }.rdb"
95
+ def redis_save_cmd
96
+ "#{ utility('redis-cli') } #{ password_option } " +
97
+ "#{ connectivity_options } #{ user_options } SAVE"
108
98
  end
109
99
 
110
- ##
111
- # Builds the Redis credentials syntax to authenticate the user
112
- # to perform the database dumping process
113
- def credential_options
114
- password.to_s.empty? ? '' : "-a '#{password}'"
100
+ def password_option
101
+ "-a '#{ password }'" if password
115
102
  end
116
103
 
117
- ##
118
- # Builds the Redis connectivity options syntax to connect the user
119
- # to perform the database dumping process
120
104
  def connectivity_options
121
- %w[host port socket].map do |option|
122
- next if send(option).to_s.empty?
123
- "-#{option[0,1]} '#{send(option)}'"
124
- end.compact.join(' ')
105
+ return "-s '#{ socket }'" if socket
106
+
107
+ opts = []
108
+ opts << "-h '#{ host }'" if host
109
+ opts << "-p '#{ port }'" if port
110
+ opts.join(' ')
125
111
  end
126
112
 
127
- ##
128
- # Builds a Redis compatible string for the
129
- # additional options specified by the user
130
113
  def user_options
131
- @additional_options.join(' ')
114
+ Array(additional_options).join(' ')
132
115
  end
133
116
 
117
+ attr_deprecate :utility_path, :version => '3.0.21',
118
+ :message => 'Use Backup::Utilities.configure instead.',
119
+ :action => lambda {|klass, val|
120
+ Utilities.configure { redis_cli val }
121
+ }
122
+
123
+ attr_deprecate :redis_cli_utility, :version => '3.3.0',
124
+ :message => 'Use Backup::Utilities.configure instead.',
125
+ :action => lambda {|klass, val|
126
+ Utilities.configure { redis_cli val }
127
+ }
128
+
134
129
  end
135
130
  end
136
131
  end
@@ -4,77 +4,98 @@ module Backup
4
4
  module Database
5
5
  class Riak < Base
6
6
 
7
- ##
8
- # Name is the name of the backup
9
- attr_accessor :name
10
-
11
7
  ##
12
8
  # Node is the node from which to perform the backup.
9
+ # Default: riak@127.0.0.1
13
10
  attr_accessor :node
14
11
 
15
12
  ##
16
13
  # Cookie is the Erlang cookie/shared secret used to connect to the node.
14
+ # Default: riak
17
15
  attr_accessor :cookie
18
16
 
19
17
  ##
20
- # Path to riak-admin utility (optional)
21
- attr_accessor :riak_admin_utility
22
-
23
- ##
24
- # Username for the riak instance (optional)
18
+ # Username for the riak instance
19
+ # Default: riak
25
20
  attr_accessor :user
26
21
 
27
- ##
28
- # Group for the riak instance (optional)
29
- attr_accessor :group
30
-
31
- attr_deprecate :utility_path, :version => '3.0.21',
32
- :message => 'Use Riak#riak_admin_utility instead.',
33
- :action => lambda {|klass, val| klass.riak_admin_utility = val }
34
-
35
- ##
36
- # Creates a new instance of the Riak adapter object
37
- def initialize(model, &block)
38
- super(model)
39
-
22
+ def initialize(model, database_id = nil, &block)
23
+ super
40
24
  instance_eval(&block) if block_given?
41
25
 
42
- @riak_admin_utility ||= utility('riak-admin')
43
- @user ||= 'riak'
44
- @group ||= 'riak'
26
+ @node ||= 'riak@127.0.0.1'
27
+ @cookie ||= 'riak'
28
+ @user ||= 'riak'
45
29
  end
46
30
 
47
31
  ##
48
- # Performs the `riak-admin` command which creates a single dump file in
49
- # @dump_path based on the `name` and `node`.
32
+ # Performs the dump using `riak-admin backup`.
50
33
  #
51
- # `riak-admin` will append the `node` to the filename.
52
- # i.e. <tmp_path>/<trigger>/databases/Riak/<name>-<node>
34
+ # This will be stored in the final backup package as
35
+ # <trigger>/databases/<dump_filename>-<node>[.gz]
53
36
  def perform!
54
37
  super
55
- # ensure riak-admin user has permissions to write backup file
56
- FileUtils.chown_R(@user, @group, @dump_path)
57
-
58
- backup_file = File.join(@dump_path, name)
59
- run("#{ riakadmin } #{ backup_file } node")
60
-
61
- if @model.compressor
62
- @model.compressor.compress_with do |command, ext|
63
- backup_file << "-#{ node }"
64
- run("#{ command } -c #{ backup_file } > #{ backup_file + ext }")
65
- FileUtils.rm_f(backup_file)
66
- end
38
+
39
+ dump_file = File.join(dump_path, dump_filename)
40
+ with_riak_owned_dump_path do
41
+ run("#{ riakadmin } backup #{ node } #{ cookie } '#{ dump_file }' node")
67
42
  end
43
+
44
+ model.compressor.compress_with do |command, ext|
45
+ dump_file << "-#{ node }" # `riak-admin` appends `node` to the filename.
46
+ run("#{ command } -c '#{ dump_file }' > '#{ dump_file + ext }'")
47
+ FileUtils.rm_f(dump_file)
48
+ end if model.compressor
49
+
50
+ log!(:finished)
68
51
  end
69
52
 
70
53
  private
71
54
 
72
55
  ##
73
- # Builds the full riak-admin string based on all attributes
56
+ # The `riak-admin backup` command is run as the riak +user+,
57
+ # so +user+ must have write priviledges to the +dump_path+.
58
+ #
59
+ # Note that the riak +user+ must also have access to +dump_path+.
60
+ # This means Backup's +tmp_path+ can not be under the home directory of
61
+ # the user running Backup, since the absence of the execute bit on their
62
+ # home directory would deny +user+ access.
63
+ def with_riak_owned_dump_path
64
+ run("#{ utility(:sudo) } -n #{ utility(:chown) } " +
65
+ "#{ user } '#{ dump_path }'")
66
+ yield
67
+ ensure
68
+ # reclaim ownership
69
+ run("#{ utility(:sudo) } -n #{ utility(:chown) } -R " +
70
+ "#{ Config.user } '#{ dump_path }'")
71
+ end
72
+
73
+ ##
74
+ # `riak-admin` must be run as the riak +user+.
75
+ # It will do this itself, but without `-n` and emits a message on STDERR.
74
76
  def riakadmin
75
- "#{ riak_admin_utility } backup #{ node } #{ cookie }"
77
+ "#{ utility(:sudo) } -n -u #{ user } #{ utility('riak-admin') }"
76
78
  end
77
79
 
80
+ attr_deprecate :utility_path, :version => '3.0.21',
81
+ :message => 'Use Backup::Utilities.configure instead.',
82
+ :action => lambda {|klass, val|
83
+ Utilities.configure { riak_admin val }
84
+ }
85
+
86
+ attr_deprecate :riak_admin_utility, :version => '3.3.0',
87
+ :message => 'Use Backup::Utilities.configure instead.',
88
+ :action => lambda {|klass, val|
89
+ Utilities.configure { riak_admin val }
90
+ }
91
+
92
+ attr_deprecate :name, :version => '3.3.0',
93
+ :message => "If you wish to add an identifier to the dump filename,\n" +
94
+ "use a +database_id+ when defining the database in your Model.\n" +
95
+ "e.g. database Riak, :my_id do |db|"
96
+
97
+ attr_deprecate :group, :version => '3.3.0'
98
+
78
99
  end
79
100
  end
80
101
  end