knife-ec-backup 2.0.7 → 2.1.0
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.
- checksums.yaml +4 -4
- data/README.md +12 -6
- data/lib/chef/knife/ec_backup.rb +48 -10
- data/lib/chef/knife/ec_base.rb +69 -4
- data/lib/chef/knife/ec_key_base.rb +25 -1
- data/lib/chef/knife/ec_restore.rb +27 -2
- data/lib/chef/server.rb +4 -0
- data/lib/knife_ec_backup/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c0eaeaca5c1a8707e66a26cafe08186a77ea6fa
|
4
|
+
data.tar.gz: 2b4675644bc5a526f3a26ad436dfd73a30ed1307
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba31ebcf31a0aca8b4df975c9687436822c5fabdc81095b23e30c4e60e35f7ff88516334949ad53fa86c4d8fe4c6787c1ed5764fa9ddd0057e132ee73f78eab1
|
7
|
+
data.tar.gz: e751b01f0094618a3fb5a6249ef083a42d20e911135d69d07b9bba77a4438b4118fb1f7f80201ec86ec7cd392865f1d8241775c8b4f9e83305ad9fbf3d6871e8
|
data/README.md
CHANGED
@@ -84,23 +84,29 @@ It is recommended that you run this from a frontend Enterprise Chef Server, you
|
|
84
84
|
|
85
85
|
# Subcommands
|
86
86
|
|
87
|
-
## Common
|
87
|
+
## Common Options
|
88
88
|
|
89
89
|
The following options are supported across all subcommands:
|
90
90
|
|
91
|
-
* `--
|
91
|
+
* `--sql-host`:
|
92
92
|
The hostname of the Chef Server's postgresql server. (default: localhost)
|
93
93
|
|
94
|
-
* `--
|
94
|
+
* `--sql-port`:
|
95
95
|
The postgresql listening port on the Chef Server. (default: 5432)
|
96
96
|
|
97
|
-
* `--
|
97
|
+
* `--sql-user`:
|
98
98
|
The username of postgresql user with access to the opscode_chef
|
99
99
|
database. (default: autoconfigured from
|
100
100
|
/etc/opscode/chef-server-running.json)
|
101
101
|
|
102
|
-
* `--
|
103
|
-
The password for the
|
102
|
+
* `--sql-password`:
|
103
|
+
The password for the sql-user. (default: autoconfigured from /etc/opscode/chef-server-running.json)
|
104
|
+
|
105
|
+
* `--purge`:
|
106
|
+
Whether to sync deletions from backup source to restore destination. (default: false)
|
107
|
+
|
108
|
+
* `--dry-run`:
|
109
|
+
Report what actions would be taken without performing any. (default: false)
|
104
110
|
|
105
111
|
## knife ec backup DEST_DIR (options)
|
106
112
|
|
data/lib/chef/knife/ec_backup.rb
CHANGED
@@ -24,6 +24,9 @@ class Chef
|
|
24
24
|
set_skip_user_acl!
|
25
25
|
ensure_webui_key_exists!
|
26
26
|
|
27
|
+
ensure_dir("#{dest_dir}/users")
|
28
|
+
ensure_dir("#{dest_dir}/user_acls") unless config[:skip_useracl]
|
29
|
+
ui.msg 'Downloading Users'
|
27
30
|
for_each_user do |username, url|
|
28
31
|
download_user(username, url)
|
29
32
|
if config[:skip_useracl]
|
@@ -32,6 +35,7 @@ class Chef
|
|
32
35
|
download_user_acl(username)
|
33
36
|
end
|
34
37
|
end
|
38
|
+
purge_users_on_backup
|
35
39
|
|
36
40
|
if config[:with_user_sql] || config[:with_key_sql]
|
37
41
|
export_from_sql
|
@@ -47,8 +51,30 @@ class Chef
|
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
54
|
+
def users_for_purge
|
55
|
+
purge_list = local_user_list - remote_user_list
|
56
|
+
# failsafe - don't delete pivotal
|
57
|
+
purge_list -= ['pivotal']
|
58
|
+
purge_list.each do |user|
|
59
|
+
yield user
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def purge_users_on_backup
|
64
|
+
return unless config[:purge]
|
65
|
+
users_for_purge do |user|
|
66
|
+
ui.msg "Deleting user #{user} from local backup (purge is on)"
|
67
|
+
begin
|
68
|
+
::File.delete("#{dest_dir}/users/#{user}.json")
|
69
|
+
::File.delete("#{dest_dir}/user_acls/#{user}.json")
|
70
|
+
rescue Errno::ENOENT => e
|
71
|
+
ui.warn "Failed to find local #{user} data #{e}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
50
76
|
def for_each_user
|
51
|
-
|
77
|
+
remote_users.each_pair do |name, url|
|
52
78
|
yield name, url
|
53
79
|
end
|
54
80
|
end
|
@@ -73,14 +99,12 @@ class Chef
|
|
73
99
|
end
|
74
100
|
|
75
101
|
def download_user(username, url)
|
76
|
-
ensure_dir("#{dest_dir}/users")
|
77
102
|
File.open("#{dest_dir}/users/#{username}.json", 'w') do |file|
|
78
103
|
file.write(Chef::JSONCompat.to_json_pretty(rest.get(url)))
|
79
104
|
end
|
80
105
|
end
|
81
106
|
|
82
107
|
def download_user_acl(username)
|
83
|
-
ensure_dir("#{dest_dir}/user_acls")
|
84
108
|
File.open("#{dest_dir}/user_acls/#{username}.json", 'w') do |file|
|
85
109
|
file.write(Chef::JSONCompat.to_json_pretty(user_acl_rest.get("users/#{username}/_acl")))
|
86
110
|
end
|
@@ -152,16 +176,30 @@ class Chef
|
|
152
176
|
chef_fs_copy_pattern('/groups/public_key_read_access.json', chef_fs_config)
|
153
177
|
chef_fs_copy_pattern('/groups/admins.json', chef_fs_config)
|
154
178
|
|
155
|
-
|
156
|
-
|
179
|
+
Chef::Config.node_name = if config[:skip_version]
|
180
|
+
org_admin
|
181
|
+
else
|
182
|
+
server.supports_defaulting_to_pivotal? ? 'pivotal' : org_admin
|
183
|
+
end
|
157
184
|
|
158
|
-
# Download the entire org skipping the billing-admins, public_key_read_access group ACLs and the groups themselves
|
159
185
|
chef_fs_config = Chef::ChefFS::Config.new
|
160
186
|
top_level_paths = chef_fs_config.chef_fs.children.select { |entry| entry.name != 'acls' && entry.name != 'groups' }.map { |entry| entry.path }
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
187
|
+
|
188
|
+
# The top level acl object names end with .json extension
|
189
|
+
# Therefore we can use Chef::ChefFS::FilePattern matching for items
|
190
|
+
# such as /acls/organizations.json
|
191
|
+
#
|
192
|
+
# 2nd level leaf /acl/*/* objects as well as /groups/* objects do not end with .json
|
193
|
+
# therefore we use normalize_path_name to add the .json extension
|
194
|
+
# for example: /acls/environments/_default
|
195
|
+
|
196
|
+
# Skip the billing-admins, public_key_read_access group ACLs and the groups since they've already been copied
|
197
|
+
exclude_list = ['billing-admins','public_key_read_access']
|
198
|
+
|
199
|
+
top_level_acls = chef_fs_paths('/acls/*.json', chef_fs_config, [])
|
200
|
+
acl_paths = chef_fs_paths('/acls/*/*', chef_fs_config, exclude_list)
|
201
|
+
group_paths = chef_fs_paths('/groups/*', chef_fs_config, exclude_list)
|
202
|
+
(top_level_paths + top_level_acls + acl_paths + group_paths).each do |path|
|
165
203
|
chef_fs_copy_pattern(path, chef_fs_config)
|
166
204
|
end
|
167
205
|
ensure
|
data/lib/chef/knife/ec_base.rb
CHANGED
@@ -18,11 +18,13 @@
|
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
20
|
require 'chef/server_api'
|
21
|
+
require 'veil'
|
21
22
|
|
22
23
|
class Chef
|
23
24
|
class Knife
|
24
25
|
module EcBase
|
25
26
|
class NoAdminFound < Exception; end
|
27
|
+
class UnImplemented < Exception; end
|
26
28
|
|
27
29
|
def self.included(includer)
|
28
30
|
includer.class_eval do
|
@@ -33,8 +35,12 @@ class Chef
|
|
33
35
|
|
34
36
|
option :webui_key,
|
35
37
|
:long => '--webui-key KEYPATH',
|
36
|
-
:description => 'Path to the WebUI Key (default: /etc/opscode/webui_priv.pem)'
|
37
|
-
|
38
|
+
:description => 'Path to the WebUI Key (default: Read from secrets store or /etc/opscode/webui_priv.pem)'
|
39
|
+
|
40
|
+
option :secrets_file_path,
|
41
|
+
:long => '--secrets-file PATH',
|
42
|
+
:description => 'Path to a valid private-chef-secrets.json file (default: /etc/opscode/private-chef-secrets.json)',
|
43
|
+
:default => '/etc/opscode/private-chef-secrets.json'
|
38
44
|
|
39
45
|
option :skip_useracl,
|
40
46
|
:long => '--skip-useracl',
|
@@ -78,6 +84,17 @@ class Chef
|
|
78
84
|
:long => '--with-key-sql',
|
79
85
|
:description => 'Try direct data base access for key table export/import. Required to properly handle rotated keys.'
|
80
86
|
|
87
|
+
option :purge,
|
88
|
+
:long => '--purge',
|
89
|
+
:boolean => true | false,
|
90
|
+
:default => false,
|
91
|
+
:description => 'Syncs deletions from backup source to restore destination.'
|
92
|
+
|
93
|
+
option :dry_run,
|
94
|
+
:long => '--dry-run',
|
95
|
+
:boolean => true | false,
|
96
|
+
:default => false,
|
97
|
+
:description => 'Report what actions would be taken without performing any.'
|
81
98
|
end
|
82
99
|
|
83
100
|
attr_accessor :dest_dir
|
@@ -116,6 +133,23 @@ class Chef
|
|
116
133
|
@rest ||= Chef::ServerAPI.new(server.root_url, {:api_version => "0"})
|
117
134
|
end
|
118
135
|
|
136
|
+
def remote_users
|
137
|
+
@remote_users ||= rest.get('/users')
|
138
|
+
end
|
139
|
+
|
140
|
+
def remote_user_list
|
141
|
+
@remote_user_list ||= remote_users.keys
|
142
|
+
end
|
143
|
+
|
144
|
+
def local_user_list
|
145
|
+
@local_user_list ||= Dir.glob("#{dest_dir}/users/*\.json").map { |u| File.basename(u, '.json') }
|
146
|
+
end
|
147
|
+
|
148
|
+
def users_for_purge
|
149
|
+
# not itended to be called from ec_base
|
150
|
+
raise Chef::Knife::EcBase::UnImplemented
|
151
|
+
end
|
152
|
+
|
119
153
|
def user_acl_rest
|
120
154
|
@user_acl_rest ||= if config[:skip_version]
|
121
155
|
rest
|
@@ -134,7 +168,7 @@ class Chef
|
|
134
168
|
def set_client_config!
|
135
169
|
Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
|
136
170
|
Chef::Config.node_name = 'pivotal'
|
137
|
-
Chef::Config.client_key =
|
171
|
+
Chef::Config.client_key = webui_key
|
138
172
|
end
|
139
173
|
|
140
174
|
def set_dest_dir_from_args!
|
@@ -145,8 +179,39 @@ class Chef
|
|
145
179
|
@dest_dir = name_args[0]
|
146
180
|
end
|
147
181
|
|
182
|
+
def webui_key
|
183
|
+
if config[:webui_key]
|
184
|
+
config[:webui_key]
|
185
|
+
elsif veil.exist?("chef-server", "webui_key")
|
186
|
+
temporary_webui_key
|
187
|
+
else
|
188
|
+
'/etc/opscode/webui_priv.pem'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def veil_config
|
193
|
+
{ provider: 'chef-secrets-file',
|
194
|
+
path: config[:secrets_file_path] }
|
195
|
+
end
|
196
|
+
|
197
|
+
def veil
|
198
|
+
Veil::CredentialCollection.from_config(veil_config)
|
199
|
+
end
|
200
|
+
|
201
|
+
def temporary_webui_key
|
202
|
+
@temp_webui_key ||= begin
|
203
|
+
key_data = veil.get("chef-server", "webui_key")
|
204
|
+
f = Tempfile.new("knife-ec-backup")
|
205
|
+
f.write(key_data)
|
206
|
+
f.flush
|
207
|
+
f.close
|
208
|
+
f
|
209
|
+
end
|
210
|
+
@temp_webui_key.path
|
211
|
+
end
|
212
|
+
|
148
213
|
def ensure_webui_key_exists!
|
149
|
-
if !File.exist?(
|
214
|
+
if !File.exist?(webui_key)
|
150
215
|
ui.error("Webui Key (#{config[:webui_key]}) does not exist.")
|
151
216
|
exit 1
|
152
217
|
end
|
@@ -48,6 +48,11 @@ class Chef
|
|
48
48
|
:long => "--sql-password PASSWORD",
|
49
49
|
:description => 'Password used to connect to the postgresql database'
|
50
50
|
|
51
|
+
option :secrets_file_path,
|
52
|
+
:long => '--secrets-file PATH',
|
53
|
+
:description => 'Path to a valid private-chef-secrets.json file (default: /etc/opscode/private-chef-secrets.json)',
|
54
|
+
:default => '/etc/opscode/private-chef-secrets.json'
|
55
|
+
|
51
56
|
option :skip_keys_table,
|
52
57
|
:long => "--skip-keys-table",
|
53
58
|
:description => "Skip Chef 12-only keys table",
|
@@ -83,7 +88,26 @@ class Chef
|
|
83
88
|
'postgresql'
|
84
89
|
end
|
85
90
|
config[:sql_user] ||= running_config['private_chef'][hash_key]['sql_user']
|
86
|
-
config[:sql_password] ||=
|
91
|
+
config[:sql_password] ||= sql_password
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def veil_config
|
96
|
+
{ provider: 'chef-secrets-file',
|
97
|
+
path: config[:secrets_file_path] }
|
98
|
+
end
|
99
|
+
|
100
|
+
def veil
|
101
|
+
Veil::CredentialCollection.from_config(veil_config)
|
102
|
+
end
|
103
|
+
|
104
|
+
def sql_password
|
105
|
+
if config[:sql_password]
|
106
|
+
config[:sql_password]
|
107
|
+
elsif veil.exist?("opscode_erchef", "sql_password")
|
108
|
+
veil.get("opscode_erchef", "sql_password")
|
109
|
+
else veil.exist?("postgresql", "sql_password")
|
110
|
+
veil.get("postgresql", "sql_password")
|
87
111
|
end
|
88
112
|
end
|
89
113
|
end
|
@@ -145,6 +145,28 @@ class Chef
|
|
145
145
|
end
|
146
146
|
end
|
147
147
|
end
|
148
|
+
purge_users_on_restore
|
149
|
+
end
|
150
|
+
|
151
|
+
def users_for_purge
|
152
|
+
purge_list = remote_user_list - local_user_list
|
153
|
+
# failsafe - don't delete pivotal
|
154
|
+
purge_list -= ['pivotal']
|
155
|
+
purge_list.each do |user|
|
156
|
+
yield user
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def purge_users_on_restore
|
161
|
+
return unless config[:purge]
|
162
|
+
users_for_purge do |user|
|
163
|
+
ui.msg "Deleting user #{user} from remote (purge is on)"
|
164
|
+
begin
|
165
|
+
rest.delete("/users/#{user}")
|
166
|
+
rescue Net::HTTPServerException => e
|
167
|
+
ui.warn "Failed deleting user #{user} from remote #{e}"
|
168
|
+
end
|
169
|
+
end
|
148
170
|
end
|
149
171
|
|
150
172
|
def ec_key_import
|
@@ -229,11 +251,14 @@ class Chef
|
|
229
251
|
proc { |entry| chef_fs_config.format_path(entry)})
|
230
252
|
end
|
231
253
|
|
232
|
-
Chef::Config.node_name =
|
254
|
+
Chef::Config.node_name = if config[:skip_version]
|
255
|
+
org_admin
|
256
|
+
else
|
257
|
+
server.supports_defaulting_to_pivotal? ? 'pivotal' : org_admin
|
258
|
+
end
|
233
259
|
|
234
260
|
# Restore the entire org skipping the admin data and restoring groups and acls last
|
235
261
|
ui.msg "Restoring the rest of the org"
|
236
|
-
Chef::Log.debug "Using admin user: #{org_admin}"
|
237
262
|
chef_fs_config = Chef::ChefFS::Config.new
|
238
263
|
top_level_paths = chef_fs_config.local_fs.children.select { |entry| entry.name != 'acls' && entry.name != 'groups' }.map { |entry| entry.path }
|
239
264
|
|
data/lib/chef/server.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-ec-backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Keiser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '11.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: veil
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: Backup and Restore of Enterprise Chef
|
56
70
|
email: jkeiser@opscode.com
|
57
71
|
executables: []
|
@@ -102,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
116
|
version: '0'
|
103
117
|
requirements: []
|
104
118
|
rubyforge_project:
|
105
|
-
rubygems_version: 2.6.
|
119
|
+
rubygems_version: 2.6.8
|
106
120
|
signing_key:
|
107
121
|
specification_version: 4
|
108
122
|
summary: Backup and Restore of Enterprise Chef
|