chef_backup 0.0.1.dev.4 → 0.2.0.pre1

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.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/lib/chef_backup/config.rb +22 -12
  3. data/lib/chef_backup/data_map.rb +18 -12
  4. data/lib/chef_backup/deep_merge.rb +145 -0
  5. data/lib/chef_backup/helpers.rb +154 -28
  6. data/lib/chef_backup/logger.rb +11 -6
  7. data/lib/chef_backup/mash.rb +226 -0
  8. data/lib/chef_backup/runner.rb +24 -21
  9. data/lib/chef_backup/strategy/backup/custom.rb +1 -2
  10. data/lib/chef_backup/strategy/backup/ebs.rb +3 -6
  11. data/lib/chef_backup/strategy/backup/lvm.rb +2 -4
  12. data/lib/chef_backup/strategy/backup/object.rb +2 -4
  13. data/lib/chef_backup/strategy/backup/tar.rb +96 -40
  14. data/lib/chef_backup/strategy/restore/tar.rb +81 -51
  15. data/lib/chef_backup/strategy.rb +10 -10
  16. data/lib/chef_backup/version.rb +1 -1
  17. data/lib/chef_backup.rb +8 -8
  18. metadata +21 -162
  19. data/.gitignore +0 -23
  20. data/.kitchen.yml +0 -30
  21. data/.rubocop.yml +0 -21
  22. data/.travis.yml +0 -6
  23. data/Gemfile +0 -4
  24. data/Guardfile +0 -22
  25. data/README.md +0 -21
  26. data/Rakefile +0 -44
  27. data/chef_backup.gemspec +0 -33
  28. data/spec/fixtures/chef-server-running.json +0 -589
  29. data/spec/spec_helper.rb +0 -103
  30. data/spec/unit/data_map_spec.rb +0 -59
  31. data/spec/unit/helpers_spec.rb +0 -88
  32. data/spec/unit/runner_spec.rb +0 -185
  33. data/spec/unit/shared_examples/helpers.rb +0 -20
  34. data/spec/unit/strategy/backup/lvm_spec.rb +0 -0
  35. data/spec/unit/strategy/backup/shared_examples/backup.rb +0 -92
  36. data/spec/unit/strategy/backup/tar_spec.rb +0 -294
  37. data/spec/unit/strategy/restore/lvm_spec.rb +0 -0
  38. data/spec/unit/strategy/restore/shared_examples/restore.rb +0 -84
  39. data/spec/unit/strategy/restore/tar_spec.rb +0 -238
  40. data/spec/unit/strategy_spec.rb +0 -36
@@ -0,0 +1,226 @@
1
+ # Copyright 2009-2016, Dan Kubb
2
+
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # ---
23
+ # ---
24
+
25
+ # Some portions of blank.rb and mash.rb are verbatim copies of software
26
+ # licensed under the MIT license. That license is included below:
27
+
28
+ # Copyright 2005-2016, David Heinemeier Hansson
29
+
30
+ # Permission is hereby granted, free of charge, to any person obtaining
31
+ # a copy of this software and associated documentation files (the
32
+ # "Software"), to deal in the Software without restriction, including
33
+ # without limitation the rights to use, copy, modify, merge, publish,
34
+ # distribute, sublicense, and/or sell copies of the Software, and to
35
+ # permit persons to whom the Software is furnished to do so, subject to
36
+ # the following conditions:
37
+
38
+ # The above copyright notice and this permission notice shall be
39
+ # included in all copies or substantial portions of the Software.
40
+
41
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
44
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
45
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
46
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
47
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
+
49
+ # This class has dubious semantics and we only have it so that people can write
50
+ # params[:key] instead of params['key'].
51
+ class Mash < Hash
52
+
53
+ # @param constructor<Object>
54
+ # The default value for the mash. Defaults to an empty hash.
55
+ #
56
+ # @details [Alternatives]
57
+ # If constructor is a Hash, a new mash will be created based on the keys of
58
+ # the hash and no default value will be set.
59
+ def initialize(constructor = {})
60
+ if constructor.is_a?(Hash)
61
+ super()
62
+ update(constructor)
63
+ else
64
+ super(constructor)
65
+ end
66
+ end
67
+
68
+ # @param orig<Object> Mash being copied
69
+ #
70
+ # @return [Object] A new copied Mash
71
+ def initialize_copy(orig)
72
+ super
73
+ # Handle nested values
74
+ each do |k, v|
75
+ if v.kind_of?(Mash) || v.is_a?(Array)
76
+ self[k] = v.dup
77
+ end
78
+ end
79
+ self
80
+ end
81
+
82
+ # @param key<Object> The default value for the mash. Defaults to nil.
83
+ #
84
+ # @details [Alternatives]
85
+ # If key is a Symbol and it is a key in the mash, then the default value will
86
+ # be set to the value matching the key.
87
+ def default(key = nil)
88
+ if key.is_a?(Symbol) && include?(key = key.to_s)
89
+ self[key]
90
+ else
91
+ super
92
+ end
93
+ end
94
+
95
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
96
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
97
+
98
+ # @param key<Object> The key to set.
99
+ # @param value<Object>
100
+ # The value to set the key to.
101
+ #
102
+ # @see Mash#convert_key
103
+ # @see Mash#convert_value
104
+ def []=(key, value)
105
+ regular_writer(convert_key(key), convert_value(value))
106
+ end
107
+
108
+ # @param other_hash<Hash>
109
+ # A hash to update values in the mash with. The keys and the values will be
110
+ # converted to Mash format.
111
+ #
112
+ # @return [Mash] The updated mash.
113
+ def update(other_hash)
114
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
115
+ self
116
+ end
117
+
118
+ alias_method :merge!, :update
119
+
120
+ # @param key<Object> The key to check for. This will be run through convert_key.
121
+ #
122
+ # @return [Boolean] True if the key exists in the mash.
123
+ def key?(key)
124
+ super(convert_key(key))
125
+ end
126
+
127
+ # def include? def has_key? def member?
128
+ alias_method :include?, :key?
129
+ alias_method :has_key?, :key?
130
+ alias_method :member?, :key?
131
+
132
+ # @param key<Object> The key to fetch. This will be run through convert_key.
133
+ # @param *extras<Array> Default value.
134
+ #
135
+ # @return [Object] The value at key or the default value.
136
+ def fetch(key, *extras)
137
+ super(convert_key(key), *extras)
138
+ end
139
+
140
+ # @param *indices<Array>
141
+ # The keys to retrieve values for. These will be run through +convert_key+.
142
+ #
143
+ # @return [Array] The values at each of the provided keys
144
+ def values_at(*indices)
145
+ indices.collect { |key| self[convert_key(key)] }
146
+ end
147
+
148
+ # @param hash<Hash> The hash to merge with the mash.
149
+ #
150
+ # @return [Mash] A new mash with the hash values merged in.
151
+ def merge(hash)
152
+ self.dup.update(hash)
153
+ end
154
+
155
+ # @param key<Object>
156
+ # The key to delete from the mash.\
157
+ def delete(key)
158
+ super(convert_key(key))
159
+ end
160
+
161
+ # @param *rejected<Array[(String, Symbol)] The mash keys to exclude.
162
+ #
163
+ # @return [Mash] A new mash without the selected keys.
164
+ #
165
+ # @example
166
+ # { :one => 1, :two => 2, :three => 3 }.except(:one)
167
+ # #=> { "two" => 2, "three" => 3 }
168
+ def except(*keys)
169
+ super(*keys.map { |k| convert_key(k) })
170
+ end
171
+
172
+ # Used to provide the same interface as Hash.
173
+ #
174
+ # @return [Mash] This mash unchanged.
175
+ def stringify_keys!; self end
176
+
177
+ # @return [Hash] The mash as a Hash with symbolized keys.
178
+ def symbolize_keys
179
+ h = Hash.new(default)
180
+ each { |key, val| h[key.to_sym] = val }
181
+ h
182
+ end
183
+
184
+ # @return [Hash] The mash as a Hash with string keys.
185
+ def to_hash
186
+ Hash.new(default).merge(self)
187
+ end
188
+
189
+ # @return [Mash] Convert a Hash into a Mash
190
+ # The input Hash's default value is maintained
191
+ def self.from_hash(hash)
192
+ mash = Mash.new(hash)
193
+ mash.default = hash.default
194
+ mash
195
+ end
196
+
197
+ protected
198
+
199
+ # @param key<Object> The key to convert.
200
+ #
201
+ # @param [Object]
202
+ # The converted key. If the key was a symbol, it will be converted to a
203
+ # string.
204
+ #
205
+ # @api private
206
+ def convert_key(key)
207
+ key.kind_of?(Symbol) ? key.to_s : key
208
+ end
209
+
210
+ # @param value<Object> The value to convert.
211
+ #
212
+ # @return [Object]
213
+ # The converted value. A Hash or an Array of hashes, will be converted to
214
+ # their Mash equivalents.
215
+ #
216
+ # @api private
217
+ def convert_value(value)
218
+ if value.class == Hash
219
+ Mash.from_hash(value)
220
+ elsif value.is_a?(Array)
221
+ value.collect { |e| convert_value(e) }
222
+ else
223
+ value
224
+ end
225
+ end
226
+ end
@@ -1,5 +1,5 @@
1
- require 'fileutils'
2
- require 'pathname'
1
+ require "fileutils" unless defined?(FileUtils)
2
+ require "pathname" unless defined?(Pathname)
3
3
 
4
4
  module ChefBackup
5
5
  # ChefBackup::Runner class initializes the strategy and runs the action
@@ -7,8 +7,6 @@ module ChefBackup
7
7
  include ChefBackup::Helpers
8
8
  include ChefBackup::Exceptions
9
9
 
10
- attr_reader :restore_param
11
-
12
10
  #
13
11
  # @param running_config [Hash] A hash of the private-chef-running.json
14
12
  # or the CLI args for a restore
@@ -17,7 +15,7 @@ module ChefBackup
17
15
  #
18
16
  def initialize(running_config)
19
17
  ChefBackup::Config.config = running_config
20
- ChefBackup::Logger.logger(private_chef['backup']['logfile'] || nil)
18
+ ChefBackup::Logger.logger(service_config["backup"]["logfile"] || nil)
21
19
  end
22
20
 
23
21
  #
@@ -28,6 +26,13 @@ module ChefBackup
28
26
  @backup.backup
29
27
  end
30
28
 
29
+ #
30
+ # @return [ChefBackup::Config]
31
+ #
32
+ def config
33
+ ChefBackup::Config.config
34
+ end
35
+
31
36
  #
32
37
  # @return [TrueClass, FalseClass] Execute Chef Server restore
33
38
  #
@@ -40,7 +45,7 @@ module ChefBackup
40
45
  # @return [String] String name of the configured backup strategy
41
46
  #
42
47
  def backup_strategy
43
- config['private_chef']['backup']['strategy']
48
+ service_config["backup"]["strategy"]
44
49
  end
45
50
 
46
51
  #
@@ -48,23 +53,21 @@ module ChefBackup
48
53
  # or a path to a tarball
49
54
  #
50
55
  def restore_param
51
- config['restore_param']
56
+ config["restore_param"]
52
57
  end
53
58
 
54
59
  #
55
60
  # @return [String] A path to backup tarball or EBS snapshot ID
56
61
  #
57
62
  def restore_strategy
58
- @restore_strategy ||= begin
59
- if tarball?
60
- unpack_tarball
61
- manifest['strategy']
62
- elsif ebs_snapshot?
63
- 'ebs'
64
- else
65
- fail InvalidStrategy, "#{restore_param} is not a valid backup"
66
- end
67
- end
63
+ @restore_strategy ||= if tarball?
64
+ unpack_tarball
65
+ manifest["strategy"]
66
+ elsif ebs_snapshot?
67
+ "ebs"
68
+ else
69
+ raise InvalidStrategy, "#{restore_param} is not a valid backup"
70
+ end
68
71
  end
69
72
 
70
73
  #
@@ -72,7 +75,7 @@ module ChefBackup
72
75
  #
73
76
  def tarball?
74
77
  file = Pathname.new(File.expand_path(restore_param))
75
- file.exist? && file.extname == '.tgz'
78
+ file.exist? && file.extname == ".tgz"
76
79
  end
77
80
 
78
81
  #
@@ -97,7 +100,7 @@ module ChefBackup
97
100
  #
98
101
  def backup_name
99
102
  if tarball?
100
- Pathname.new(restore_param).basename.sub_ext('').to_s
103
+ Pathname.new(restore_param).basename.sub_ext("").to_s
101
104
  elsif ebs_snapshot?
102
105
  restore_param
103
106
  end
@@ -110,7 +113,7 @@ module ChefBackup
110
113
  # @return [String] A path to the restore directory
111
114
  #
112
115
  def restore_directory
113
- config['restore_dir'] ||= begin
116
+ config["restore_dir"] ||= begin
114
117
  dir_name = File.join(tmp_dir, backup_name)
115
118
  if File.directory?(dir_name)
116
119
  # clean restore directory if it exists
@@ -128,7 +131,7 @@ module ChefBackup
128
131
  def manifest
129
132
  @manifest ||= begin
130
133
  file = "#{restore_directory}/manifest.json"
131
- ensure_file!(file, InvalidTarball, 'No manifest found in tarball')
134
+ ensure_file!(file, InvalidTarball, "No manifest found in tarball")
132
135
  JSON.parse(File.read(file))
133
136
  end
134
137
  end
@@ -2,6 +2,5 @@
2
2
  # - Verify that backup executable exists and is runnable
3
3
  # - exec script
4
4
  class ChefBackup::Strategy::CustomBackup < ChefBackup::Strategy::TarBackup
5
- def backup
6
- end
5
+ def backup; end
7
6
  end
@@ -17,12 +17,9 @@ class ChefBackup::Strategy::EbsBackup < ChefBackup::Strategy::TarBackup
17
17
  cleanup
18
18
  end
19
19
 
20
- def verify_ebs
21
- end
20
+ def verify_ebs; end
22
21
 
23
- def take_ebs_snapshot
24
- end
22
+ def take_ebs_snapshot; end
25
23
 
26
- def copy_opscode_config
27
- end
24
+ def copy_opscode_config; end
28
25
  end
@@ -34,9 +34,7 @@ class ChefBackup::Strategy::LvmBackup < ChefBackup::Strategy::TarBackup
34
34
  # warn if vg space is low
35
35
  end
36
36
 
37
- def take_lvm_snapshot
38
- end
37
+ def take_lvm_snapshot; end
39
38
 
40
- def mount_lvm_snapshot
41
- end
39
+ def mount_lvm_snapshot; end
42
40
  end
@@ -21,9 +21,7 @@ class ChefBackup::Strategy::ObjectBackup < ChefBackup::Strategy::TarBackup
21
21
  cleanup
22
22
  end
23
23
 
24
- def verify_object
25
- end
24
+ def verify_object; end
26
25
 
27
- def knife_ec_backup
28
- end
26
+ def knife_ec_backup; end
29
27
  end
@@ -1,7 +1,6 @@
1
1
  require 'fileutils'
2
2
  require 'json'
3
3
  require 'time'
4
- require 'highline/import'
5
4
 
6
5
  # rubocop:disable IndentationWidth
7
6
  module ChefBackup
@@ -27,8 +26,8 @@ class TarBackup
27
26
  def export_dir
28
27
  @export_dir ||= begin
29
28
  dir =
30
- if private_chef['backup']['export_dir']
31
- private_chef['backup']['export_dir']
29
+ if service_config['backup']['export_dir']
30
+ service_config['backup']['export_dir']
32
31
  else
33
32
  msg = ["backup['export_dir'] has not been set.",
34
33
  'defaulting to: /var/opt/chef-backups'].join(' ')
@@ -47,39 +46,65 @@ class TarBackup
47
46
  #
48
47
  def dump_db
49
48
  return true unless pg_dump?
50
- pg_user = private_chef['postgresql']['username']
49
+ if external_pg?
50
+ log('Cannot backup external postgresql', :warn)
51
+ return false
52
+ end
53
+ pg_user = service_config['postgresql']['username']
51
54
  sql_file = "#{tmp_dir}/chef_backup-#{backup_time}.sql"
52
- cmd = ['/opt/opscode/embedded/bin/chpst',
55
+ cmd = [chpst,
53
56
  "-u #{pg_user}",
54
- '/opt/opscode/embedded/bin/pg_dumpall',
55
- "> #{sql_file}"
56
- ].join(' ')
57
+ pg_dumpall,
58
+ "> #{sql_file}"].join(' ')
57
59
  log "Dumping Postgresql database to #{sql_file}"
58
- shell_out!(cmd)
60
+ shell_out!(cmd, env: ["PGOPTIONS=#{pg_options}"])
59
61
  data_map.services['postgresql']['pg_dump_success'] = true
60
62
  data_map.services['postgresql']['username'] = pg_user
61
63
  true
62
64
  end
63
65
 
66
+ def chpst
67
+ "#{base_install_dir}/embedded/bin/chpst"
68
+ end
69
+
70
+ def pg_dumpall
71
+ "#{base_install_dir}/embedded/bin/pg_dumpall"
72
+ end
73
+
64
74
  def populate_data_map
65
- stateful_services.each do |service|
66
- next unless private_chef.key?(service)
67
- data_map.add_service(service, private_chef[service]['data_dir'])
75
+ unless config_only?
76
+ stateful_services.each do |service|
77
+ next unless service_config.key?(service)
78
+ data_map.add_service(service, service_config[service]['data_dir'])
79
+ end
68
80
  end
69
81
 
70
82
  config_directories.each do |config|
71
83
  data_map.add_config(config, "/etc/#{config}")
72
84
  end
73
85
 
86
+ populate_versions
87
+
74
88
  # Don't forget the upgrades!
75
- if private_chef.key?('upgrades')
76
- data_map.add_service('upgrades', private_chef['upgrades']['dir'])
89
+ if service_config.key?('upgrades')
90
+ data_map.add_service('upgrades', service_config['upgrades']['dir'])
91
+ end
92
+
93
+ add_ha_services
94
+ end
95
+
96
+ def populate_versions
97
+ project_names.each do |project|
98
+ path = File.join(addon_install_dir(project), '/version-manifest.json')
99
+ data_map.add_version(project, version_from_manifest_file(path))
77
100
  end
101
+ end
78
102
 
79
- if ha?
80
- data_map.add_service('keepalived', private_chef['keepalived']['dir'])
81
- data_map.add_ha_info('provider', private_chef['ha']['provider'])
82
- data_map.add_ha_info('path', private_chef['ha']['path'])
103
+ def add_ha_services
104
+ if ha? && !config_only?
105
+ data_map.add_service('keepalived', service_config['keepalived']['dir'])
106
+ data_map.add_ha_info('provider', service_config['ha']['provider'])
107
+ data_map.add_ha_info('path', service_config['ha']['path'])
83
108
  end
84
109
  end
85
110
 
@@ -94,22 +119,29 @@ class TarBackup
94
119
  end
95
120
  end
96
121
 
122
+ DEFAULT_STATEFUL_SERVICES = %w[rabbitmq
123
+ opscode-solr4
124
+ elasticsearch
125
+ redis_lb
126
+ postgresql
127
+ bookshelf].freeze
128
+
97
129
  def stateful_services
98
- if private_chef.key?('drbd') && private_chef['drbd']['enable'] == true
130
+ if service_config.key?('drbd') && service_config['drbd']['enable'] == true
99
131
  ['drbd']
100
132
  else
101
- %w(
102
- rabbitmq
103
- opscode-solr4
104
- redis_lb
105
- postgresql
106
- bookshelf
107
- )
133
+ DEFAULT_STATEFUL_SERVICES.select do |service|
134
+ service_enabled?(service)
135
+ end
108
136
  end
109
137
  end
110
138
 
111
139
  def config_directories
112
- %w(opscode) + enabled_addons
140
+ [project_name] + enabled_addons.keys
141
+ end
142
+
143
+ def project_names
144
+ ([project_name] + enabled_addons.keys).uniq
113
145
  end
114
146
 
115
147
  # The data_map is a working record of all of the data that is backed up.
@@ -123,30 +155,32 @@ class TarBackup
123
155
 
124
156
  def not_implemented
125
157
  msg = "#{caller[0].split[1]} is not implemented for this strategy"
126
- fail NotImplementedError, msg
158
+ raise NotImplementedError, msg
127
159
  end
128
160
 
129
161
  def backup
130
- log 'Starting Chef Server backup'
162
+ log "Starting Chef Server backup #{config_only? ? '(config only)' : ''}"
131
163
  populate_data_map
132
- if backend?
164
+ stopped = false
165
+ if backend? && !config_only?
133
166
  if !online?
134
167
  ask_to_go_offline unless offline_permission_granted?
135
- stop_chef_server(except: [:keepalived, :postgresql])
168
+ stop_chef_server(except: %i[keepalived postgresql])
136
169
  dump_db
137
170
  stop_service(:postgresql)
171
+ stopped = true
138
172
  else
139
173
  dump_db
140
174
  end
141
175
  end
142
176
  write_manifest
143
177
  create_tarball
144
- start_chef_server if backend? && !online?
178
+ start_chef_server if stopped
145
179
  export_tarball
146
180
  cleanup
147
181
  log 'Backup Complete!'
148
182
  rescue => e
149
- log "Something wen't terribly wrong, aborting backup", :error
183
+ log "Something went terribly wrong, aborting backup", :error
150
184
  log e.message, :error
151
185
  cleanup
152
186
  start_chef_server
@@ -156,31 +190,52 @@ class TarBackup
156
190
  def create_tarball
157
191
  log 'Creating backup tarball'
158
192
  cmd = [
159
- "tar -czf #{tmp_dir}/chef-backup-#{backup_time}.tgz",
193
+ "tar -czf #{tmp_dir}/#{export_filename}",
160
194
  data_map.services.map { |_, v| v['data_dir'] }.compact.join(' '),
161
195
  data_map.configs.map { |_, v| v['data_dir'] }.compact.join(' '),
162
196
  Dir["#{tmp_dir}/*"].map { |f| File.basename(f) }.join(' ')
163
197
  ].join(' ').strip
164
198
 
165
- res = shell_out(cmd, cwd: tmp_dir)
199
+ res = shell_out!(cmd, cwd: tmp_dir)
166
200
  res
167
201
  end
168
202
 
169
203
  def export_tarball
170
204
  log "Exporting tarball to #{export_dir}"
171
- cmd = "rsync -chaz #{tmp_dir}/chef-backup-#{backup_time}.tgz #{export_dir}/"
205
+ cmd = "rsync -chaz #{tmp_dir}/#{export_filename} #{export_dir}/"
172
206
 
173
- res = shell_out(cmd)
207
+ res = shell_out!(cmd)
174
208
  res
175
209
  end
176
210
 
211
+ def export_filename
212
+ postfix = if config_only?
213
+ '-config'
214
+ else
215
+ ''
216
+ end
217
+ "chef-backup#{postfix}-#{backup_time}.tgz"
218
+ end
219
+
220
+ def service_enabled?(service)
221
+ service_config[service] && service_config[service]['enable'] && !service_config[service]['external']
222
+ end
223
+
224
+ def external_pg?
225
+ service_config['postgresql']['external']
226
+ end
227
+
177
228
  def pg_dump?
178
229
  # defaults to true
179
- private_chef['backup']['always_dump_db']
230
+ service_config['backup']['always_dump_db']
180
231
  end
181
232
 
182
233
  def offline_permission_granted?
183
- private_chef['backup']['agree_to_go_offline']
234
+ service_config['backup']['agree_to_go_offline']
235
+ end
236
+
237
+ def config_only?
238
+ service_config['backup']['config_only']
184
239
  end
185
240
 
186
241
  def ask_to_go_offline
@@ -188,7 +243,8 @@ class TarBackup
188
243
  msg << 'continuing. You can skip this message by passing a "--yes" '
189
244
  msg << 'argument. Do you wish to proceed? (y/N):'
190
245
 
191
- exit(1) unless ask(msg) =~ /^y/i
246
+ require "tty-prompt" unless defined?(TTY::Prompt)
247
+ exit(1) unless TTY::Prompt.new(interrupt: :exit).ask(msg) =~ /^y/i
192
248
  end
193
249
  end
194
250
  end