chef_backup 0.0.1.dev.1

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.kitchen.yml +30 -0
  4. data/.rubocop.yml +17 -0
  5. data/.travis.yml +6 -0
  6. data/Gemfile +4 -0
  7. data/Guardfile +22 -0
  8. data/LICENSE +13 -0
  9. data/README.md +33 -0
  10. data/Rakefile +44 -0
  11. data/chef_backup.gemspec +33 -0
  12. data/lib/chef_backup.rb +12 -0
  13. data/lib/chef_backup/config.rb +57 -0
  14. data/lib/chef_backup/data_map.rb +44 -0
  15. data/lib/chef_backup/exceptions.rb +12 -0
  16. data/lib/chef_backup/helpers.rb +159 -0
  17. data/lib/chef_backup/logger.rb +39 -0
  18. data/lib/chef_backup/runner.rb +136 -0
  19. data/lib/chef_backup/strategy.rb +29 -0
  20. data/lib/chef_backup/strategy/backup/custom.rb +7 -0
  21. data/lib/chef_backup/strategy/backup/ebs.rb +28 -0
  22. data/lib/chef_backup/strategy/backup/lvm.rb +42 -0
  23. data/lib/chef_backup/strategy/backup/object.rb +29 -0
  24. data/lib/chef_backup/strategy/backup/tar.rb +165 -0
  25. data/lib/chef_backup/strategy/restore/custom.rb +0 -0
  26. data/lib/chef_backup/strategy/restore/ebs.rb +0 -0
  27. data/lib/chef_backup/strategy/restore/lvm.rb +0 -0
  28. data/lib/chef_backup/strategy/restore/object.rb +0 -0
  29. data/lib/chef_backup/strategy/restore/tar.rb +125 -0
  30. data/lib/chef_backup/version.rb +4 -0
  31. data/spec/fixtures/chef-server-running.json +584 -0
  32. data/spec/spec_helper.rb +103 -0
  33. data/spec/unit/data_map_spec.rb +59 -0
  34. data/spec/unit/helpers_spec.rb +88 -0
  35. data/spec/unit/runner_spec.rb +185 -0
  36. data/spec/unit/shared_examples/helpers.rb +20 -0
  37. data/spec/unit/strategy/backup/lvm_spec.rb +0 -0
  38. data/spec/unit/strategy/backup/shared_examples/backup.rb +74 -0
  39. data/spec/unit/strategy/backup/tar_spec.rb +280 -0
  40. data/spec/unit/strategy/restore/lvm_spec.rb +0 -0
  41. data/spec/unit/strategy/restore/shared_examples/restore.rb +84 -0
  42. data/spec/unit/strategy/restore/tar_spec.rb +238 -0
  43. data/spec/unit/strategy_spec.rb +36 -0
  44. metadata +253 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1bec5855a4a67f6d47efbf80b1b13be09338de3d
4
+ data.tar.gz: c02131b03380815d3a79c281da26fb8fe51f7f7f
5
+ SHA512:
6
+ metadata.gz: 34616288ba8212f0e86fb3e5b26ad75bd6a912c9de52123ea954179c1a52ced09ed5f4f00368bf2c17b4ddb32642ba0f78e76a0da0071510bf8851bc0af93a1f
7
+ data.tar.gz: 02e5d4f0bc8868228c9f329702adfe8099c7f866e7f2e82760a65cd153a487c861e950184eddc938e578db894eb41ac6fcb6a84e7498641a7cbc7a0bb0e26f32
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ *.sw*
@@ -0,0 +1,30 @@
1
+ driver:
2
+ name: vagrant
3
+ forward_agent: true
4
+ customize:
5
+ cpus: 2
6
+ memory: 2048
7
+ synced_folders:
8
+ - ['.', '/home/vagrant/chef_backup']
9
+ - ['../../opscode/chef_packages/', '/home/vagrant/chef_packages']
10
+
11
+ provisioner:
12
+ name: chef_zero
13
+ require_chef_omnibus: 11.16.4
14
+
15
+ platforms:
16
+ - name: ubuntu-14.04
17
+ run_list: apt::default
18
+ - name: ubuntu-12.04
19
+ run_list: apt::default
20
+ - name: ubuntu-11.04
21
+ run_list: apt::default
22
+ - name: ubuntu-10.04
23
+ run_list: apt::default
24
+ - name: centos-5.10
25
+ - name: centos-6.5
26
+
27
+ suites:
28
+ - name: default
29
+ attributes:
30
+ run_list:
@@ -0,0 +1,17 @@
1
+ Style/ClassAndModuleChildren:
2
+ Enabled: false
3
+ Style/GuardClause:
4
+ Enabled: false
5
+ Metrics/ClassLength:
6
+ Max: 200
7
+ Metrics/CyclomaticComplexity:
8
+ Max: 10
9
+ Metrics/PerceivedComplexity:
10
+ Max: 10
11
+ Metrics/MethodLength:
12
+ Max: 40
13
+ Metrics/AbcSize:
14
+ Max: 25
15
+ AllCops:
16
+ Exclude:
17
+ - 'Guardfile'
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.1.5"
4
+ - "2.2.0"
5
+ notifications:
6
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ec_backup.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ # Note: The cmd option is now required due to the increasing number of ways
5
+ # rspec may be run, below are examples of the most common uses.
6
+ # * bundler: 'bundle exec rspec'
7
+ # * bundler binstubs: 'bin/rspec'
8
+ # * spring: 'bin/rsspec' (This will use spring if running and you have
9
+ # installed the spring binstubs per the docs)
10
+ # * zeus: 'zeus rspec' (requires the server to be started separetly)
11
+ # * 'just' rspec: 'rspec'
12
+ guard :rspec, cmd: 'bundle exec rspec -f doc --color', all_after_pass: true do
13
+ watch(%r{^spec/.+/.+_spec\.rb$})
14
+ watch(%r{^spec/.+/.+/.+_spec\.rb$})
15
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
16
+ watch(%r{^lib/chef_backup/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
17
+ watch(%r{^lib/chef_backup/(.+)/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}/#{m[2]}_spec.rb" }
18
+ watch(%r{^lib/chef_backup/(.+)/(.+)/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}/#{m[2]}/#{m[3]}_spec.rb" }
19
+ watch('spec/spec_helper.rb') { "spec" }
20
+ end
21
+
22
+ notification :tmux
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2014 Chef Software, Inc
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,33 @@
1
+ # ChefBackup
2
+ [![Build Status](https://travis-ci.org/ryancragun/chef_backup.svg?branch=master)](https://travis-ci.org/ryancragun/chef_backup)
3
+
4
+ A gem that backs up and restores Chef servers.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'chef_backup'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install chef_backup
19
+
20
+ ## Usage
21
+
22
+ ```shell
23
+ chef-server-ctl backup
24
+ chef-server-ctl restore some_backup.tgz
25
+ ```
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it ( https://github.com/ryancragun/chef_backup/fork )
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create a new Pull Request
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rake'
4
+ require 'rspec'
5
+ require 'rspec/core'
6
+ require 'rspec/core/rake_task'
7
+ require 'bundler'
8
+ require 'bundler/gem_tasks'
9
+ require 'rubocop/rake_task'
10
+
11
+ desc 'Default task to run spec suite'
12
+ task default: %w(spec rubocop)
13
+
14
+ desc 'Run spec suite'
15
+ RSpec::Core::RakeTask.new(:spec) do |task|
16
+ task.pattern = FileList['spec/**/*_spec.rb']
17
+ end
18
+
19
+ desc 'Run RSpec with code coverage'
20
+ task :coverage do
21
+ ENV['COVERAGE'] = 'true'
22
+ Rake::Task['spec'].execute
23
+ end
24
+
25
+ desc 'Run Rubocop style checks'
26
+ RuboCop::RakeTask.new do |cop|
27
+ cop.fail_on_error = true
28
+ end
29
+
30
+ desc 'console'
31
+ task :console do
32
+ require 'pry'
33
+ require 'chef_backup'
34
+ require 'json'
35
+ f = File.expand_path('../spec/fixtures/chef-server-running.json', __FILE__)
36
+ running_config = JSON.parse(File.read(f))
37
+ @runner = ChefBackup::Runner.new(
38
+ running_config.merge('restore_param' => '/tmp/backup.tgz')
39
+ )
40
+ ARGV.clear
41
+ Pry.config.history.should_save = true
42
+ Pry.config.history.should_load = true
43
+ Pry.start
44
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'chef_backup/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'chef_backup'
8
+ spec.version = ChefBackup::VERSION
9
+ spec.authors = ['Ryan Cragun']
10
+ spec.email = ['me@ryan.ec']
11
+ spec.summary = 'A library to backup an Enterprise Chef server'
12
+ spec.description = spec.summary
13
+ spec.homepage = 'https://github.com/ryancragun/chef_backup'
14
+ spec.license = 'Apachev2'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(/^(test|spec|features)/)
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'di-ruby-lvm'
22
+ spec.add_dependency 'mixlib-shellout'
23
+ spec.add_dependency 'highline'
24
+ spec.add_dependency 'chef'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.6'
27
+ spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'guard-rspec'
30
+ spec.add_development_dependency 'pry-rescue'
31
+ spec.add_development_dependency 'rubocop', '0.28'
32
+ spec.add_development_dependency 'simplecov'
33
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright:: Copyright (c) 2014 Chef, Inc.
2
+ #
3
+ # All Rights Reserved
4
+
5
+ require 'chef_backup/version'
6
+ require 'chef_backup/exceptions'
7
+ require 'chef_backup/config'
8
+ require 'chef_backup/logger'
9
+ require 'chef_backup/data_map'
10
+ require 'chef_backup/helpers'
11
+ require 'chef_backup/runner'
12
+ require 'chef_backup/strategy'
@@ -0,0 +1,57 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'forwardable'
4
+
5
+ module ChefBackup
6
+ # ChefBackup Global Config
7
+ class Config
8
+ extend Forwardable
9
+
10
+ DEFAULT_CONFIG = {
11
+ 'backup' => {
12
+ 'always_dump_db' => true,
13
+ 'strategy' => 'none',
14
+ 'export_dir' => '/var/opt/chef-backup'
15
+ }
16
+ }.freeze
17
+
18
+ class << self
19
+ def config
20
+ @config ||= new
21
+ end
22
+
23
+ def config=(hash)
24
+ @config = new(hash)
25
+ end
26
+
27
+ def [](key)
28
+ config[key]
29
+ end
30
+
31
+ def []=(key, value)
32
+ config[key] = value
33
+ end
34
+
35
+ #
36
+ # @param file [String] path to a JSON configration file
37
+ #
38
+ def from_json_file(file)
39
+ path = File.expand_path(file)
40
+ @config = new(JSON.parse(File.read(path))) if File.exist?(path)
41
+ end
42
+ end
43
+
44
+ #
45
+ # @param config [Hash] a Hash of the private-chef-running.json
46
+ #
47
+ def initialize(config = {})
48
+ config['private_chef'] ||= {}
49
+ config['private_chef']['backup'] ||= {}
50
+ config['private_chef']['backup'] =
51
+ DEFAULT_CONFIG['backup'].merge(config['private_chef']['backup'])
52
+ @config = config
53
+ end
54
+
55
+ def_delegators :@config, :[], :[]=
56
+ end
57
+ end
@@ -0,0 +1,44 @@
1
+ require 'time'
2
+
3
+ module ChefBackup
4
+ # DataMap class to store data about the data we're backing up
5
+ class DataMap
6
+ class << self
7
+ def data_map
8
+ @data_map ||= new
9
+ end
10
+
11
+ attr_writer :data_map
12
+ end
13
+
14
+ attr_accessor :strategy, :backup_time, :configs, :services
15
+
16
+ def initialize
17
+ @services = {}
18
+ @configs = {}
19
+ yield self if block_given?
20
+
21
+ @backup_time ||= Time.now.iso8601
22
+ @strategy ||= 'none'
23
+ end
24
+
25
+ def add_service(service, data_dir)
26
+ @services[service] ||= {}
27
+ @services[service]['data_dir'] = data_dir
28
+ end
29
+
30
+ def add_config(config, path)
31
+ @configs[config] ||= {}
32
+ @configs[config]['data_dir'] = path
33
+ end
34
+
35
+ def manifest
36
+ {
37
+ 'strategy' => strategy,
38
+ 'backup_time' => backup_time,
39
+ 'services' => services,
40
+ 'configs' => configs
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ module ChefBackup
2
+ module Exceptions
3
+ # ChefBackup Exceptions
4
+ class ChefBackupException < StandardError; end
5
+ class InvalidTarball < ChefBackupException; end
6
+ class InvalidSnapshot < ChefBackupException; end
7
+ class InvalidDatabaseDump < ChefBackupException; end
8
+ class InvalidManifest < ChefBackupException; end
9
+ class InvalidStrategy < ChefBackupException; end
10
+ class NotImplementedError < ChefBackupException; end
11
+ end
12
+ end
@@ -0,0 +1,159 @@
1
+ require 'fileutils'
2
+ require 'mixlib/shellout'
3
+ require 'chef_backup/config'
4
+ require 'chef_backup/logger'
5
+
6
+ # rubocop:disable IndentationWidth
7
+ module ChefBackup
8
+ # Common helper methods that are usefull in many classes
9
+ module Helpers
10
+ # rubocop:enable IndentationWidth
11
+
12
+ SERVER_ADD_ONS = %w(
13
+ opscode-manage
14
+ opscode-reporting
15
+ opscode-push-jobs-server
16
+ opscode-analytics
17
+ chef-ha
18
+ chef-sync
19
+ ).freeze
20
+
21
+ def private_chef
22
+ config['private_chef']
23
+ end
24
+
25
+ def config
26
+ ChefBackup::Config
27
+ end
28
+
29
+ def log(message, level = :info)
30
+ ChefBackup::Logger.logger.log(message, level)
31
+ end
32
+
33
+ #
34
+ # @param file [String] A path to a file on disk
35
+ # @param exception [Exception] An exception to raise if file is not present
36
+ # @param message [String] Exception message to raise
37
+ #
38
+ # @return [TrueClass, FalseClass]
39
+ #
40
+ def ensure_file!(file, exception, message)
41
+ File.exist?(file) ? true : fail(exception, message)
42
+ end
43
+
44
+ def shell_out(*command)
45
+ cmd = Mixlib::ShellOut.new(*command)
46
+ cmd.live_stream ||= $stdout.tty? ? $stdout : nil
47
+ cmd.run_command
48
+ cmd
49
+ end
50
+
51
+ def shell_out!(*command)
52
+ cmd = shell_out(*command)
53
+ cmd.error!
54
+ cmd
55
+ end
56
+
57
+ def all_services
58
+ Dir['/opt/opscode/sv/*'].map { |f| File.basename(f) }.sort
59
+ end
60
+
61
+ def enabled_services
62
+ all_services.select { |sv| service_enabled?(sv) }
63
+ end
64
+
65
+ def disabled_services
66
+ all_services.select { |sv| !service_enabled?(sv) }
67
+ end
68
+
69
+ def service_enabled?(service)
70
+ File.symlink?("/opt/opscode/service/#{service}")
71
+ end
72
+
73
+ def stop_service(service)
74
+ res = shell_out("chef-server-ctl stop #{service}")
75
+ res
76
+ end
77
+
78
+ def start_service(service)
79
+ res = shell_out("chef-server-ctl start #{service}")
80
+ res
81
+ end
82
+
83
+ def stop_chef_server(params = {})
84
+ log 'Bringing down the Chef Server'
85
+ services = enabled_services
86
+ services -= params[:except].map(&:to_s) if params.key?(:except)
87
+ services.each { |sv| stop_service(sv) }
88
+ end
89
+
90
+ def start_chef_server
91
+ log 'Bringing up the Chef Server'
92
+ enabled_services.each { |sv| start_service(sv) }
93
+ end
94
+
95
+ def enabled_addons
96
+ SERVER_ADD_ONS.select { |service| addon?(service) }
97
+ end
98
+
99
+ def addon?(service)
100
+ File.directory?("/etc/#{service}")
101
+ end
102
+
103
+ def pg_dump?
104
+ if frontend? # don't dump postgres on frontends
105
+ false
106
+ elsif private_chef['backup']['always_dump_db'] == true # defaults to true
107
+ true
108
+ elsif strategy !~ /lvm|ebs/ && backend? # backup non-block device backends
109
+ true
110
+ else
111
+ false # if we made it here then we're on lvm/ebs and overrode defaults
112
+ end
113
+ end
114
+
115
+ def strategy
116
+ private_chef['backup']['strategy']
117
+ end
118
+
119
+ def frontend?
120
+ private_chef['role'] == 'frontend'
121
+ end
122
+
123
+ def backend?
124
+ private_chef['role'] =~ /backend|standalone/
125
+ end
126
+
127
+ def online?
128
+ private_chef['backup']['mode'] == 'online'
129
+ end
130
+
131
+ def tmp_dir
132
+ @tmp_dir ||= begin
133
+ dir = safe_key { config['tmp_dir'] } ||
134
+ safe_key { private_chef['backup']['tmp_dir'] }
135
+ if dir
136
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
137
+ dir
138
+ else
139
+ Dir.mktmpdir('chef_backup')
140
+ end
141
+ end
142
+ end
143
+
144
+ def cleanup
145
+ log "Cleaning up #{tmp_dir}"
146
+ FileUtils.rm_r(tmp_dir)
147
+ rescue Errno::ENOENT
148
+ true
149
+ end
150
+
151
+ private
152
+
153
+ def safe_key
154
+ yield
155
+ rescue NameError
156
+ nil
157
+ end
158
+ end
159
+ end