knife-backup 0.0.8 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04b6c3af80a1e59f1a86f7d5e28302fe9e1db33a
4
- data.tar.gz: 558fee3f51e25c3df03258627361085e7ecfdcfb
3
+ metadata.gz: e3b74fdf9a67ae00a32a68e1b37201dd7d27e318
4
+ data.tar.gz: 0cfa2a717cc5223e068424beab952813c250805a
5
5
  SHA512:
6
- metadata.gz: e775afdf8af2aa7bdca73c118f864e81c830b54f8a9e20562c6dc670d5fd841e69ef81e88db75f4915d0040a52244f28fa798a265a89997f4b49049526f90988
7
- data.tar.gz: 21e76c6903269dc2a0f8cb5f9269a56df36d4c762f41d4dd680922288d5c81301590a3744ebdef26ad322a200bac865d65b1e67f97c705a5c2bcf1c56ed83aec
6
+ metadata.gz: 766023ac2102bc799dd8eb27af1bf53b3175ecb601007722411ca2ff88609c463ea390adf0f2df22a89e262e88699fc1e7ac9a99824a1e83ccadee8811548ef9
7
+ data.tar.gz: 2bd111ebe9cb9a58526293976d30a33ad92ca915ae69c7adbd164d9bb085fa49e13876945dafbbcbd4f406983263345cfd05a72585d0135396e4a31832dc2ae7
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .chef
3
4
  Gemfile.lock
4
5
  pkg/*
6
+ bin/
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in knife-backup.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -4,6 +4,7 @@ Knife-Backup
4
4
  Knife-Backup is a [Knife](http://wiki.opscode.com/display/chef/Knife) plugin that can help you backup and restore a chef server. It is based on the great work of [Steven Danna][stevendanna] and [Joshua Timberman][jtimberman] on the [BackupExport][backup_export] and [BackupRestore][backup_restore] plugins. Currently knife-backup has support for the following objects:
5
5
 
6
6
  * clients
7
+ * users (chef 11 - Open Source)
7
8
  * nodes
8
9
  * roles
9
10
  * environments
@@ -12,7 +13,9 @@ Knife-Backup is a [Knife](http://wiki.opscode.com/display/chef/Knife) plugin tha
12
13
 
13
14
  knife-backup will backup all cookbook versions available on the chef server. Cookbooks are normally available in a repository and should be easy to upload like that, but if you are using various cookbook versions in each environment then it might not be so trivial to find and upload them back to the server; downloading them and having them available to upload like that is simple and clean. If you have too many cookbook [versions](http://www.ducea.com/2013/02/26/knife-cleanup/) then you might want to cleanup them first using something like [knife-cleanup][knifecleanup]
14
15
 
15
- *Known limitation*: currently it is not possible to overwritte a client object already available on the target server and these will be skipped.
16
+ Users are a bit tricky, knife-backup can't gather the crypted passwords via the chef server so it's forced to reset them to a random string on restore. Be sure to copy them from the restore output or reset them.
17
+
18
+ *Known limitation*: currently it is not possible to overwrite a client object already available on the target server and these will be skipped.
16
19
 
17
20
  ## Installation
18
21
 
@@ -24,25 +27,36 @@ gem install knife-backup
24
27
 
25
28
  ## Usage
26
29
 
27
- For a list of commands:
30
+ Currently the available commands are:
28
31
 
29
32
  ```bash
30
- knife backup --help
33
+ knife backup export [component component ...] [-D DIR] [options]
34
+ knife backup restore [component component ...] [-D DIR]
35
+
36
+ #Example:
37
+ knife backup export cookbooks roles environments -D ~/my_chef_backup
31
38
  ```
39
+ #### Optional Switches for export
32
40
 
33
- Currently the available commands are:
41
+ - `-N`, `--latest` only download the latest version of a cookbook
42
+ - `-I`, `--ignore-permissions` ignore any permission errors during export
43
+
44
+ #### Optional Switches for restore
45
+
46
+ - `-I`, `--ignore-metadata-errors` Ignore json metadata errors when restoring cookbooks
47
+
48
+
49
+ For more information on commands:
34
50
 
35
51
  ```bash
36
- knife backup export [-D DIR]
37
- knife backup restore [-D DIR]
52
+ knife backup SUB-COMMAND --help
38
53
  ```
39
54
 
40
55
  Note: you should treat this as beta software; I'm using it with success for my needs and hopefully you will find it useful too.
41
56
 
42
57
  ## Todo/Ideas
43
-
58
+
44
59
  * Timestamp for the backup folder
45
- * Limit the backup to just some objects (for ex, just backup the cookbooks or just the nodes)
46
60
  * Track the failed downloads and report them at the end
47
61
  * Find out if there is a way to overwrite a client object.
48
62
 
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = "https://github.com/mdxp/knife-backup"
11
11
  s.summary = %q{Chef knife plugins to help backup and restore chef servers}
12
12
  s.description = s.summary
13
+ s.license = "Apache 2.0"
13
14
 
14
15
  s.rubyforge_project = "knife-backup"
15
16
 
@@ -19,6 +19,10 @@
19
19
 
20
20
  require 'chef/node'
21
21
  require 'chef/api_client'
22
+
23
+ if Chef::VERSION =~ /^11\./
24
+ require 'chef/user'
25
+ end
22
26
  require 'chef/knife/cookbook_download'
23
27
 
24
28
  module ServerBackup
@@ -32,16 +36,22 @@ module ServerBackup
32
36
  banner "knife backup export [COMPONENT [COMPONENT ...]] [-D DIR] (options)"
33
37
 
34
38
  option :backup_dir,
35
- :short => "-D DIR",
36
- :long => "--backup-directory DIR",
37
- :description => "Store backup data in DIR. DIR will be created if it does not already exist.",
38
- :default => Chef::Config[:knife][:chef_server_backup_dir] ? Chef::Config[:knife][:chef_server_backup_dir] : File.join(".chef", "chef_server_backup")
39
+ :short => "-D DIR",
40
+ :long => "--backup-directory DIR",
41
+ :description => "Store backup data in DIR. DIR will be created if it does not already exist.",
42
+ :default => Chef::Config[:knife][:chef_server_backup_dir] ? Chef::Config[:knife][:chef_server_backup_dir] : File.join(".chef", "chef_server_backup")
39
43
 
40
44
  option :latest,
41
- :short => "-N",
42
- :long => "--latest",
43
- :description => "The version of the cookbook to download",
44
- :boolean => true
45
+ :short => "-N",
46
+ :long => "--latest",
47
+ :description => "The version of the cookbook to download",
48
+ :boolean => true
49
+
50
+ option :ignore_perm,
51
+ :short => "-I",
52
+ :long => "--ignore-permissions",
53
+ :description => "Continue in case a permission problem occurs",
54
+ :boolean => true
45
55
 
46
56
  def run
47
57
  validate!
@@ -50,7 +60,8 @@ module ServerBackup
50
60
  end
51
61
 
52
62
  private
53
- COMPONENTS = %w(clients nodes roles data_bags environments cookbooks)
63
+ COMPONENTS = %w(clients users nodes roles data_bags environments cookbooks)
64
+ LOAD_TRIES = 5
54
65
 
55
66
  def validate!
56
67
  bad_names = name_args - COMPONENTS
@@ -68,6 +79,14 @@ module ServerBackup
68
79
  backup_standard("clients", Chef::ApiClient)
69
80
  end
70
81
 
82
+ def users
83
+ if Chef::VERSION =~ /^1[1]\./
84
+ backup_standard("users", Chef::User)
85
+ else
86
+ ui.warn "users export only supported on chef == 11"
87
+ end
88
+ end
89
+
71
90
  def roles
72
91
  backup_standard("roles", Chef::Role)
73
92
  end
@@ -99,14 +118,34 @@ module ServerBackup
99
118
  klass.list.each do |component_name, url|
100
119
  next if component == "environments" && component_name == "_default"
101
120
  ui.msg "Backing up #{component} #{component_name}"
102
- component_obj = klass.load(component_name)
121
+ component_obj = load_object(klass, component_name).to_hash
122
+ unless component_obj
123
+ ui.error "Could not load #{klass} #{component_name}."
124
+ next
125
+ end
103
126
  File.open(File.join(dir, "#{component_name}.json"), "w") do |component_file|
104
- #component_file.print(component_obj.to_json)
105
127
  component_file.print(JSON.pretty_generate(component_obj))
106
128
  end
107
129
  end
108
130
  end
109
131
 
132
+ def load_object(klass, name, try = 1)
133
+ klass.load(name)
134
+ rescue NoMethodError
135
+ ui.warn "Problem loading #{klass} #{name}. Try #{try}/#{LOAD_TRIES}"
136
+ if try < LOAD_TRIES
137
+ try += 1
138
+ load_object(klass, name, try)
139
+ end
140
+ rescue Net::HTTPServerException => e
141
+ if config[:ignore_perm]
142
+ ui.warn "Problem loading #{name} #{e.message}."
143
+ ui.warn "Possibly an issue with permissions on the chef server... Skipping"
144
+ else
145
+ raise
146
+ end
147
+ end
148
+
110
149
  def cookbooks
111
150
  ui.msg "Backing up cookbooks"
112
151
  dir = File.join(config[:backup_dir], "cookbooks")
@@ -32,27 +32,36 @@ module ServerBackup
32
32
  require 'chef/knife/core/object_loader'
33
33
  require 'chef/cookbook_uploader'
34
34
  require 'chef/api_client'
35
+ require 'securerandom'
36
+ require 'json'
35
37
  end
36
38
 
37
39
  banner "knife backup restore [COMPONENT [COMPONENT ...]] [-D DIR] (options)"
38
40
 
39
41
  option :backup_dir,
40
- :short => "-D DIR",
41
- :long => "--backup-directory DIR",
42
- :description => "Restore backup data from DIR.",
43
- :default => Chef::Config[:knife][:chef_server_backup_dir] ? Chef::Config[:knife][:chef_server_backup_dir] : File.join(".chef", "chef_server_backup")
42
+ :short => "-D DIR",
43
+ :long => "--backup-directory DIR",
44
+ :description => "Restore backup data from DIR.",
45
+ :default => Chef::Config[:knife][:chef_server_backup_dir] ? Chef::Config[:knife][:chef_server_backup_dir] : File.join(".chef", "chef_server_backup")
46
+
47
+ option :ignore_metadata_errors,
48
+ :short => "-I",
49
+ :long => "--ignore-metadata-errors",
50
+ :description => "Ignore json metadata errors when restoring cookbooks",
51
+ :boolean => true,
52
+ :default => Chef::Config[:knife][:ignore_metadata_errors] ? Chef::Config[:knife][:ignore_metadata_errors] : false
44
53
 
45
54
  def run
46
55
  ui.warn "This will overwrite existing data!"
47
56
  ui.warn "Backup is at least 1 day old" if (Time.now - File.atime(config[:backup_dir])) > 86400
48
- ui.confirm "Do you want to restore backup, possibly overwriting exisitng data"
57
+ ui.confirm "Do you want to restore backup, possibly overwriting existing data"
49
58
  validate!
50
59
  components = name_args.empty? ? COMPONENTS : name_args
51
60
  Array(components).each { |component| self.send(component) }
52
61
  end
53
62
 
54
63
  private
55
- COMPONENTS = %w(clients nodes roles data_bags environments cookbooks)
64
+ COMPONENTS = %w(clients users nodes roles data_bags environments cookbooks)
56
65
 
57
66
  def validate!
58
67
  bad_names = name_args - COMPONENTS
@@ -116,12 +125,14 @@ module ServerBackup
116
125
  ui.info "=== Restoring clients ==="
117
126
  clients = Dir.glob(File.join(config[:backup_dir], "clients", "*.json"))
118
127
  clients.each do |file|
128
+ ui.info "Restoring clients from #{file}"
119
129
  client = JSON.parse(IO.read(file))
120
130
  begin
121
131
  rest.post_rest("clients", {
122
132
  :name => client['name'],
123
133
  :public_key => client['public_key'],
124
- :admin => client['admin']
134
+ :admin => client['admin'],
135
+ :validator => client['validator']
125
136
  })
126
137
  rescue Net::HTTPServerException => e
127
138
  handle_error 'client', client['name'], e
@@ -129,32 +140,83 @@ module ServerBackup
129
140
  end
130
141
  end
131
142
 
143
+ def users
144
+ JSON.create_id = "no_thanks"
145
+ ui.info "=== Restoring users ==="
146
+ users = Dir.glob(File.join(config[:backup_dir], "users", "*.json"))
147
+ if !users.empty? and Chef::VERSION !~ /^11\./
148
+ ui.warn "users restore only supported on chef == 11"
149
+ return
150
+ end
151
+ users.each do |file|
152
+ user = JSON.parse(IO.read(file))
153
+ password = SecureRandom.hex[0..7]
154
+ begin
155
+ rest.post_rest("users", {
156
+ :name => user['name'],
157
+ :public_key => user['public_key'],
158
+ :admin => user['admin'],
159
+ :password => password
160
+ })
161
+ ui.info "Set password for #{user['name']} to #{password}, please update"
162
+ rescue Net::HTTPServerException => e
163
+ handle_error 'user', user['name'], e
164
+ end
165
+ end
166
+ end
167
+
132
168
  def cookbooks
169
+ count = 0
133
170
  ui.info "=== Restoring cookbooks ==="
134
171
  cookbooks = Dir.glob(File.join(config[:backup_dir], "cookbooks", '*'))
172
+ #Make tmp dir
173
+ FileUtils.rm_rf(config[:backup_dir] + "/tmp")
174
+ Dir.mkdir config[:backup_dir] + "/tmp"
135
175
  cookbooks.each do |cb|
136
- full_cb = cb.split("/").last
137
- cookbook = full_cb.reverse.split('-',2).last.reverse
138
- full_path = File.join(config[:backup_dir], "cookbooks", cookbook)
139
-
176
+ full_cb = File.expand_path(cb)
177
+ cb_name = File.basename(cb)
178
+ cookbook = cb_name.reverse.split('-',2).last.reverse
179
+ full_path = File.join(config[:backup_dir] + "/tmp", cookbook)
140
180
  begin
141
- File.symlink(full_cb, full_path)
181
+ count += 1
182
+ if Chef::Platform.windows?
183
+ Dir.mkdir config[:backup_dir] + "/tmp/#{cb_name}"
184
+ full_path = File.join(config[:backup_dir] + "/tmp/#{cb_name}", cookbook)
185
+ ui.info "Copy cookbook #{full_cb} to #{full_path}"
186
+ FileUtils.copy_entry(full_cb, full_path)
187
+ else
188
+ full_path = File.join(config[:backup_dir] + "/tmp", cookbook)
189
+ File.symlink(full_cb, full_path)
190
+ end
142
191
  cbu = Chef::Knife::CookbookUpload.new
143
192
  Chef::Knife::CookbookUpload.load_deps
144
193
  cbu.name_args = [ cookbook ]
145
- cbu.config[:cookbook_path] = File.join(config[:backup_dir], "cookbooks")
194
+ cbu.config[:cookbook_path] = File.dirname(full_path)
146
195
  ui.info "Restoring cookbook #{cbu.name_args}"
147
196
  cbu.run
148
197
  rescue Net::HTTPServerException => e
149
- handle_error 'cookbook', full_cb, e
198
+ handle_error 'cookbook', cb_name, e
199
+ rescue Chef::Exceptions::JSON::ParseError => e
200
+ handle_error 'cookbook', cb_name, e
201
+ throw e unless config[:ignore_metadata_errors]
150
202
  ensure
151
- File.unlink(full_path)
203
+ if Chef::Platform.windows?
204
+ rm_path = config[:backup_dir] + "/tmp/#{cb_name}"
205
+ ui.info "remove dir #{rm_path}"
206
+ FileUtils.remove_dir(rm_path, force = true)
207
+ else
208
+ File.unlink(full_path)
209
+ end
152
210
  end
153
211
  end
212
+ ui.info "Uploaded #{count} Cookbooks"
213
+ FileUtils.rm_rf(config[:backup_dir] + "/tmp")
154
214
  end
155
215
 
156
216
  def handle_error(type, name, error)
157
217
  thing = "#{type}[#{name}]"
218
+ return ui.error "Error parsing JSON for: #{thing}" if error.kind_of?(Chef::Exceptions::JSON::ParseError)
219
+
158
220
  case error.response
159
221
  when Net::HTTPConflict # 409
160
222
  ui.warn "#{thing} already exists; skipping"
@@ -1,5 +1,5 @@
1
1
  module Knife
2
2
  module Backup
3
- VERSION = "0.0.8"
3
+ VERSION = "0.0.12"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marius Ducea
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-14 00:00:00.000000000 Z
11
+ date: 2016-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.10.10
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.10.10
27
27
  description: Chef knife plugins to help backup and restore chef servers
@@ -31,7 +31,7 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - .gitignore
34
+ - ".gitignore"
35
35
  - Gemfile
36
36
  - LICENSE
37
37
  - README.md
@@ -42,7 +42,8 @@ files:
42
42
  - lib/knife-backup.rb
43
43
  - lib/knife-backup/version.rb
44
44
  homepage: https://github.com/mdxp/knife-backup
45
- licenses: []
45
+ licenses:
46
+ - Apache 2.0
46
47
  metadata: {}
47
48
  post_install_message:
48
49
  rdoc_options: []
@@ -50,18 +51,19 @@ require_paths:
50
51
  - lib
51
52
  required_ruby_version: !ruby/object:Gem::Requirement
52
53
  requirements:
53
- - - '>='
54
+ - - ">="
54
55
  - !ruby/object:Gem::Version
55
56
  version: '0'
56
57
  required_rubygems_version: !ruby/object:Gem::Requirement
57
58
  requirements:
58
- - - '>='
59
+ - - ">="
59
60
  - !ruby/object:Gem::Version
60
61
  version: '0'
61
62
  requirements: []
62
63
  rubyforge_project: knife-backup
63
- rubygems_version: 2.0.3
64
+ rubygems_version: 2.4.8
64
65
  signing_key:
65
66
  specification_version: 4
66
67
  summary: Chef knife plugins to help backup and restore chef servers
67
68
  test_files: []
69
+ has_rdoc: