knife-ec-backup 2.0.0.beta.2 → 2.0.0.beta.3
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 +127 -16
- data/lib/chef/knife/ec_backup.rb +109 -191
- data/lib/chef/knife/ec_base.rb +148 -0
- data/lib/chef/knife/ec_restore.rb +97 -210
- data/lib/chef/server.rb +38 -0
- data/lib/knife_ec_backup/version.rb +1 -1
- data/spec/chef/knife/ec_backup_spec.rb +158 -0
- data/spec/chef/knife/ec_base_spec.rb +73 -0
- data/spec/chef/knife/ec_key_base_spec.rb +2 -0
- data/spec/chef/knife/ec_key_export_spec.rb +2 -0
- data/spec/chef/knife/ec_key_import_spec.rb +2 -0
- data/spec/chef/knife/ec_restore_spec.rb +138 -0
- data/spec/chef/server_spec.rb +50 -0
- data/spec/chef/tsorter_spec.rb +9 -0
- data/spec/spec_helper.rb +6 -0
- metadata +44 -5
@@ -0,0 +1,148 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Steven Danna (<steve@getchef.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Knife
|
23
|
+
module EcBase
|
24
|
+
class NoAdminFound < Exception; end
|
25
|
+
|
26
|
+
def self.included(includer)
|
27
|
+
includer.class_eval do
|
28
|
+
|
29
|
+
option :concurrency,
|
30
|
+
:long => '--concurrency THREADS',
|
31
|
+
:description => 'Maximum number of simultaneous requests to send (default: 10)'
|
32
|
+
|
33
|
+
option :webui_key,
|
34
|
+
:long => '--webui-key KEYPATH',
|
35
|
+
:description => 'Path to the WebUI Key (default: /etc/opscode/webui_priv.pem)',
|
36
|
+
:default => '/etc/opscode/webui_priv.pem'
|
37
|
+
|
38
|
+
option :skip_useracl,
|
39
|
+
:long => '--skip-useracl',
|
40
|
+
:boolean => true,
|
41
|
+
:default => false,
|
42
|
+
:description => "Skip downloading/restoring User ACLs. This is required for EC 11.0.2 and lower"
|
43
|
+
|
44
|
+
option :skip_version,
|
45
|
+
:long => '--skip-version-check',
|
46
|
+
:boolean => true,
|
47
|
+
:default => false,
|
48
|
+
:description => "Skip Chef Server version check. This will also skip any auto-configured options"
|
49
|
+
|
50
|
+
option :org,
|
51
|
+
:long => "--only-org ORG",
|
52
|
+
:description => "Only download/restore objects in the named organization (default: all orgs)"
|
53
|
+
|
54
|
+
option :sql_host,
|
55
|
+
:long => '--sql-host HOSTNAME',
|
56
|
+
:description => 'Postgresql database hostname (default: localhost)',
|
57
|
+
:default => "localhost"
|
58
|
+
|
59
|
+
option :sql_port,
|
60
|
+
:long => '--sql-port PORT',
|
61
|
+
:description => 'Postgresql database port (default: 5432)',
|
62
|
+
:default => 5432
|
63
|
+
|
64
|
+
option :sql_user,
|
65
|
+
:long => "--sql-user USERNAME",
|
66
|
+
:description => 'User used to connect to the postgresql database.'
|
67
|
+
|
68
|
+
option :sql_password,
|
69
|
+
:long => "--sql-password PASSWORD",
|
70
|
+
:description => 'Password used to connect to the postgresql database'
|
71
|
+
|
72
|
+
option :with_user_sql,
|
73
|
+
:long => '--with-user-sql',
|
74
|
+
:description => 'Try direct data base access for user export/import. Required to properly handle passwords, keys, and USAGs'
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_accessor :dest_dir
|
78
|
+
|
79
|
+
def configure_chef
|
80
|
+
super
|
81
|
+
Chef::Config[:concurrency] = config[:concurrency].to_i if config[:concurrency]
|
82
|
+
Chef::ChefFS::Parallelizer.threads = (Chef::Config[:concurrency] || 10) - 1
|
83
|
+
end
|
84
|
+
|
85
|
+
def org_admin
|
86
|
+
rest = Chef::REST.new(Chef::Config.chef_server_url)
|
87
|
+
admin_users = rest.get_rest('groups/admins')['users']
|
88
|
+
org_members = rest.get_rest('users').map { |user| user['user']['username'] }
|
89
|
+
admin_users.delete_if { |user| !org_members.include?(user) || user == 'pivotal' }
|
90
|
+
if admin_users.empty?
|
91
|
+
raise Chef::Knife::EcBase::NoAdminFound
|
92
|
+
else
|
93
|
+
admin_users[0]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def server
|
99
|
+
@server ||= if Chef::Config.chef_server_root.nil?
|
100
|
+
ui.warn("chef_server_root not found in knife configuration; using chef_server_url")
|
101
|
+
Chef::Server.from_chef_server_url(Chef::Config.chef_server_url)
|
102
|
+
else
|
103
|
+
Chef::Server.new(Chef::Config.chef_server_root)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def rest
|
108
|
+
@rest ||= Chef::REST.new(server.root_url)
|
109
|
+
end
|
110
|
+
|
111
|
+
def user_acl_rest
|
112
|
+
@user_acl_rest ||= if config[:skip_version]
|
113
|
+
rest
|
114
|
+
elsif server.supports_user_acls?
|
115
|
+
rest
|
116
|
+
elsif server.direct_account_access?
|
117
|
+
Chef::REST.new("http://127.0.0.1:9465")
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
def set_skip_user_acl!
|
123
|
+
config[:skip_useracl] ||= !(server.supports_user_acls? || server.direct_account_access?)
|
124
|
+
end
|
125
|
+
|
126
|
+
def set_client_config!
|
127
|
+
Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
|
128
|
+
Chef::Config.node_name = 'pivotal'
|
129
|
+
Chef::Config.client_key = config[:webui_key]
|
130
|
+
end
|
131
|
+
|
132
|
+
def set_dest_dir_from_args!
|
133
|
+
if name_args.length <= 0
|
134
|
+
ui.error("Must specify backup directory as an argument.")
|
135
|
+
exit 1
|
136
|
+
end
|
137
|
+
@dest_dir = name_args[0]
|
138
|
+
end
|
139
|
+
|
140
|
+
def ensure_webui_key_exists!
|
141
|
+
if !File.exist?(config[:webui_key])
|
142
|
+
ui.error("Webui Key (#{config[:webui_key]}) does not exist.")
|
143
|
+
exit 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
require 'chef/knife'
|
2
|
+
require 'chef/knife/ec_base'
|
2
3
|
|
3
4
|
class Chef
|
4
5
|
class Knife
|
5
6
|
class EcRestore < Chef::Knife
|
6
|
-
banner "knife ec restore DIRECTORY"
|
7
7
|
|
8
|
-
|
9
|
-
:long => '--concurrency THREADS',
|
10
|
-
:description => 'Maximum number of simultaneous requests to send (default: 10)'
|
8
|
+
include Knife::EcBase
|
11
9
|
|
12
|
-
|
13
|
-
:long => '--webui-key KEYPATH',
|
14
|
-
:description => 'Used to set the path to the WebUI Key (default: /etc/opscode/webui_priv.pem)'
|
10
|
+
banner "knife ec restore DIRECTORY"
|
15
11
|
|
16
12
|
option :overwrite_pivotal,
|
17
13
|
:long => '--overwrite-pivotal',
|
@@ -19,48 +15,10 @@ class Chef
|
|
19
15
|
:default => false,
|
20
16
|
:description => "Whether to overwrite pivotal's key. Once this is done, future requests will fail until you fix the private key."
|
21
17
|
|
22
|
-
option :skip_useracl,
|
23
|
-
:long => '--skip-useracl',
|
24
|
-
:boolean => true,
|
25
|
-
:default => false,
|
26
|
-
:description => "Whether to skip restoring User ACLs. This is required for EC 11.0.2 and lower"
|
27
|
-
|
28
|
-
option :skip_version,
|
29
|
-
:long => '--skip-version-check',
|
30
|
-
:boolean => true,
|
31
|
-
:default => false,
|
32
|
-
:description => "Whether to skip checking the Chef Server version. This will also skip any auto-configured options"
|
33
|
-
|
34
|
-
option :org,
|
35
|
-
:long => "--only-org ORG",
|
36
|
-
:description => "Only restore objects in the named organization (default: all orgs)"
|
37
|
-
|
38
18
|
option :skip_users,
|
39
19
|
:long => "--skip-users",
|
40
20
|
:description => "Skip restoring users"
|
41
21
|
|
42
|
-
option :with_user_sql,
|
43
|
-
:long => "--with-user-sql",
|
44
|
-
:description => "Restore user id's, passwords, and keys from sql export"
|
45
|
-
|
46
|
-
option :sql_host,
|
47
|
-
:long => '--sql-host HOSTNAME',
|
48
|
-
:description => 'Postgresql database hostname (default: localhost)',
|
49
|
-
:default => "localhost"
|
50
|
-
|
51
|
-
option :sql_port,
|
52
|
-
:long => '--sql-port PORT',
|
53
|
-
:description => 'Postgresql database port (default: 5432)',
|
54
|
-
:default => 5432
|
55
|
-
|
56
|
-
option :sql_user,
|
57
|
-
:long => "--sql-user USERNAME",
|
58
|
-
:description => 'User used to connect to the postgresql database.'
|
59
|
-
|
60
|
-
option :sql_password,
|
61
|
-
:long => "--sql-password PASSWORD",
|
62
|
-
:description => 'Password used to connect to the postgresql database'
|
63
|
-
|
64
22
|
deps do
|
65
23
|
require 'chef/json_compat'
|
66
24
|
require 'chef/chef_fs/config'
|
@@ -73,172 +31,104 @@ class Chef
|
|
73
31
|
require 'securerandom'
|
74
32
|
require 'chef/chef_fs/parallelizer'
|
75
33
|
require 'chef/tsorter'
|
76
|
-
|
77
|
-
|
78
|
-
def configure_chef
|
79
|
-
super
|
80
|
-
Chef::Config[:concurrency] = config[:concurrency].to_i if config[:concurrency]
|
81
|
-
Chef::ChefFS::Parallelizer.threads = (Chef::Config[:concurrency] || 10) - 1
|
34
|
+
require 'chef/server'
|
82
35
|
end
|
83
36
|
|
84
37
|
def run
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
exit 1
|
99
|
-
end
|
100
|
-
Chef::Config.node_name = 'pivotal'
|
101
|
-
Chef::Config.client_key = '/etc/opscode/pivotal.pem'
|
38
|
+
set_dest_dir_from_args!
|
39
|
+
set_client_config!
|
40
|
+
ensure_webui_key_exists!
|
41
|
+
set_skip_user_acl!
|
42
|
+
|
43
|
+
restore_users unless config[:skip_users]
|
44
|
+
restore_user_sql if config[:with_user_sql]
|
45
|
+
|
46
|
+
for_each_organization do |orgname|
|
47
|
+
create_organization(orgname)
|
48
|
+
restore_open_invitations(orgname)
|
49
|
+
add_users_to_org(orgname)
|
50
|
+
upload_org_data(orgname)
|
102
51
|
end
|
103
52
|
|
104
|
-
|
105
|
-
|
106
|
-
if !File.exist?("/etc/opscode/webui_priv.pem")
|
107
|
-
ui.error("WebUI not specified and /etc/opscode/webui_priv.pem does not exist. It is recommended that you run this plugin from your Chef server.")
|
108
|
-
exit 1
|
109
|
-
end
|
110
|
-
ui.warn("WebUI not specified. Using /etc/opscode/webui_priv.pem")
|
111
|
-
webui_key = '/etc/opscode/webui_priv.pem'
|
53
|
+
if config[:skip_useracl]
|
54
|
+
ui.warn("Skipping user ACL update. To update user ACLs, remove --skip-useracl or upgrade your Enterprise Chef Server.")
|
112
55
|
else
|
113
|
-
|
56
|
+
restore_user_acls
|
114
57
|
end
|
58
|
+
end
|
115
59
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
60
|
+
def create_organization(orgname)
|
61
|
+
org = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/org.json"))
|
62
|
+
rest.post_rest('organizations', org)
|
63
|
+
rescue Net::HTTPServerException => e
|
64
|
+
if e.response.code == "409"
|
65
|
+
rest.put_rest("organizations/#{orgname}", org)
|
66
|
+
else
|
67
|
+
raise
|
122
68
|
end
|
69
|
+
end
|
123
70
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
server_version = open(uri, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).each_line.first.split(' ').last
|
133
|
-
server_version_parts = server_version.split('.')
|
134
|
-
|
135
|
-
if server_version_parts.count == 3
|
136
|
-
puts "Detected Enterprise Chef Server version: #{server_version}"
|
137
|
-
|
138
|
-
# All versions of Chef Server below 11.0.X are unable to update user acls
|
139
|
-
if server_version_parts[0].to_i < 11 || (server_version_parts[0].to_i == 11 && server_version_parts[1].to_i == 0)
|
140
|
-
ui.warn("Your version of Enterprise Chef Server does not support the updating of User ACLs. Setting skip-useracl to TRUE")
|
141
|
-
config[:skip_useracl] = true
|
142
|
-
user_acl_rest = nil
|
143
|
-
else
|
144
|
-
user_acl_rest = rest
|
71
|
+
def restore_open_invitations(orgname)
|
72
|
+
invitations = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/invitations.json"))
|
73
|
+
invitations.each do |invitation|
|
74
|
+
begin
|
75
|
+
rest.post_rest("organizations/#{orgname}/association_requests", { 'user' => invitation['username'] })
|
76
|
+
rescue Net::HTTPServerException => e
|
77
|
+
if e.response.code != "409"
|
78
|
+
ui.error("Cannot create invitation #{invitation['id']}")
|
145
79
|
end
|
146
|
-
else
|
147
|
-
ui.warn("Unable to detect Chef Server version.")
|
148
80
|
end
|
149
81
|
end
|
82
|
+
end
|
150
83
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
# Restore organizations
|
157
|
-
Dir.foreach("#{dest_dir}/organizations") do |name|
|
158
|
-
next if name == '..' || name == '.' || !File.directory?("#{dest_dir}/organizations/#{name}")
|
159
|
-
next unless (config[:org].nil? || config[:org] == name)
|
160
|
-
puts "Restoring org #{name} ..."
|
161
|
-
|
162
|
-
# Create organization
|
163
|
-
org = JSONCompat.from_json(IO.read("#{dest_dir}/organizations/#{name}/org.json"))
|
84
|
+
def add_users_to_org(orgname)
|
85
|
+
members = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/members.json"))
|
86
|
+
members.each do |member|
|
87
|
+
username = member['user']['username']
|
164
88
|
begin
|
165
|
-
rest.post_rest(
|
89
|
+
response = rest.post_rest("organizations/#{orgname}/association_requests", { 'user' => username })
|
90
|
+
association_id = response["uri"].split("/").last
|
91
|
+
rest.put_rest("users/#{username}/association_requests/#{association_id}", { 'response' => 'accept' })
|
166
92
|
rescue Net::HTTPServerException => e
|
167
|
-
if e.response.code
|
168
|
-
rest.put_rest("organizations/#{name}", org)
|
169
|
-
else
|
93
|
+
if e.response.code != "409"
|
170
94
|
raise
|
171
95
|
end
|
172
96
|
end
|
97
|
+
end
|
98
|
+
end
|
173
99
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
rescue Net::HTTPServerException => e
|
180
|
-
if e.response.code != "409"
|
181
|
-
ui.error("Cannot create invitation #{invitation['id']}")
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Repopulate org members
|
187
|
-
members = JSONCompat.from_json(IO.read("#{dest_dir}/organizations/#{name}/members.json"))
|
188
|
-
members.each do |member|
|
189
|
-
username = member['user']['username']
|
190
|
-
begin
|
191
|
-
response = rest.post_rest("organizations/#{name}/association_requests", { 'user' => username })
|
192
|
-
association_id = response["uri"].split("/").last
|
193
|
-
rest.put_rest("users/#{username}/association_requests/#{association_id}", { 'response' => 'accept' })
|
194
|
-
rescue Net::HTTPServerException => e
|
195
|
-
if e.response.code != "409"
|
196
|
-
raise
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Upload org data
|
202
|
-
upload_org(dest_dir, webui_key, name)
|
100
|
+
def restore_user_acls
|
101
|
+
ui.msg "Restoring user ACLs ..."
|
102
|
+
for_each_user do |name|
|
103
|
+
user_acl = JSONCompat.from_json(File.read("#{dest_dir}/user_acls/#{name}.json"))
|
104
|
+
put_acl(user_acl_rest, "users/#{name}/_acl", user_acl)
|
203
105
|
end
|
106
|
+
end
|
204
107
|
|
205
|
-
|
206
|
-
puts "Restoring user ACLs ..."
|
108
|
+
def for_each_user
|
207
109
|
Dir.foreach("#{dest_dir}/users") do |filename|
|
208
110
|
next if filename !~ /(.+)\.json/
|
209
111
|
name = $1
|
210
|
-
if config[:skip_useracl]
|
211
|
-
ui.warn("Skipping user ACL update for #{name}. To update this ACL, remove --skip-useracl or upgrade your Enterprise Chef Server.")
|
212
|
-
next
|
213
|
-
end
|
214
112
|
if name == 'pivotal' && !config[:overwrite_pivotal]
|
215
|
-
ui.warn("Skipping pivotal
|
113
|
+
ui.warn("Skipping pivotal user. To overwrite pivotal, pass --overwrite-pivotal.")
|
216
114
|
next
|
217
115
|
end
|
218
|
-
|
219
|
-
# Update user acl
|
220
|
-
user_acl = JSONCompat.from_json(IO.read("#{dest_dir}/user_acls/#{name}.json"))
|
221
|
-
put_acl(rest, "users/#{name}/_acl", user_acl)
|
116
|
+
yield name
|
222
117
|
end
|
118
|
+
end
|
223
119
|
|
224
|
-
|
225
|
-
|
226
|
-
|
120
|
+
def for_each_organization
|
121
|
+
Dir.foreach("#{dest_dir}/organizations") do |name|
|
122
|
+
next if name == '..' || name == '.' || !File.directory?("#{dest_dir}/organizations/#{name}")
|
123
|
+
next unless (config[:org].nil? || config[:org] == name)
|
124
|
+
yield name
|
227
125
|
end
|
228
126
|
end
|
229
127
|
|
230
|
-
def restore_users
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
name = $1
|
235
|
-
if name == 'pivotal' && !config[:overwrite_pivotal]
|
236
|
-
ui.warn("Skipping pivotal update. To overwrite pivotal, pass --overwrite-pivotal.")
|
237
|
-
next
|
238
|
-
end
|
239
|
-
|
240
|
-
# Update user object
|
241
|
-
user = JSONCompat.from_json(IO.read("#{dest_dir}/users/#{name}.json"))
|
128
|
+
def restore_users
|
129
|
+
ui.msg "Restoring users ..."
|
130
|
+
for_each_user do |name|
|
131
|
+
user = JSONCompat.from_json(File.read("#{dest_dir}/users/#{name}.json"))
|
242
132
|
begin
|
243
133
|
# Supply password for new user
|
244
134
|
user_with_password = user.dup
|
@@ -254,7 +144,7 @@ class Chef
|
|
254
144
|
end
|
255
145
|
end
|
256
146
|
|
257
|
-
def restore_user_sql
|
147
|
+
def restore_user_sql
|
258
148
|
require 'chef/knife/ec_key_import'
|
259
149
|
k = Chef::Knife::EcKeyImport.new
|
260
150
|
k.name_args = ["#{dest_dir}/key_dump.json"]
|
@@ -268,7 +158,7 @@ class Chef
|
|
268
158
|
end
|
269
159
|
|
270
160
|
PATHS = %w(chef_repo_path cookbook_path environment_path data_bag_path role_path node_path client_path acl_path group_path container_path)
|
271
|
-
def
|
161
|
+
def upload_org_data(name)
|
272
162
|
old_config = Chef::Config.save
|
273
163
|
|
274
164
|
begin
|
@@ -279,40 +169,42 @@ class Chef
|
|
279
169
|
|
280
170
|
Chef::Config.chef_repo_path = "#{dest_dir}/organizations/#{name}"
|
281
171
|
Chef::Config.versioned_cookbooks = true
|
282
|
-
|
283
|
-
Chef::Config.chef_server_url = "#{Chef::Config.chef_server_root}/organizations/#{name}"
|
172
|
+
Chef::Config.chef_server_url = "#{server.root_url}/organizations/#{name}"
|
284
173
|
|
285
174
|
# Upload the admins group and billing-admins acls
|
286
|
-
|
175
|
+
ui.msg "Restoring the org admin data"
|
287
176
|
chef_fs_config = Chef::ChefFS::Config.new
|
288
177
|
|
289
|
-
#
|
178
|
+
# Handle Admins and Billing Admins seperately
|
179
|
+
#
|
180
|
+
# admins: We need to upload admins first so that we
|
181
|
+
# can upload all of the other objects as a user in the org
|
182
|
+
# rather than as pivotal. Because the clients, and groups, don't
|
183
|
+
# exist yet, we first upload the group with only the users.
|
184
|
+
#
|
185
|
+
# billing-admins: The default permissions on the
|
186
|
+
# billing-admin group only give update permissions to
|
187
|
+
# pivotal and members of the billing-admins group. Since we
|
188
|
+
# can't unsure that the admin we choose for uploading will
|
189
|
+
# be in the billing admins group, we have to upload this
|
190
|
+
# group as pivotal. Thus, we upload its users and ACL here,
|
191
|
+
# and then update it again once all of the clients and
|
192
|
+
# groups are uploaded.
|
193
|
+
#
|
290
194
|
['admins', 'billing-admins'].each do |group|
|
291
195
|
restore_group(chef_fs_config, group, :clients => false)
|
292
196
|
end
|
293
197
|
|
294
198
|
pattern = Chef::ChefFS::FilePattern.new('/acls/groups/billing-admins.json')
|
295
|
-
|
296
|
-
|
297
|
-
|
199
|
+
Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs_config.local_fs,
|
200
|
+
chef_fs_config.chef_fs, nil, config, ui,
|
201
|
+
proc { |entry| chef_fs_config.format_path(entry)})
|
298
202
|
|
299
|
-
|
300
|
-
rest = Chef::REST.new(Chef::Config.chef_server_url)
|
301
|
-
org_admins = rest.get_rest('groups/admins')['users']
|
302
|
-
org_members = rest.get_rest('users').map { |user| user['user']['username'] }
|
303
|
-
org_admins.delete_if { |user| !org_members.include?(user) || user == 'pivotal' }
|
304
|
-
if org_admins[0] != nil
|
305
|
-
# Using an org admin already on the destination server
|
306
|
-
Chef::Config.node_name = org_admins[0]
|
307
|
-
Chef::Config.client_key = webui_key
|
308
|
-
else
|
309
|
-
# No suitable org admins found, defaulting to pivotal
|
310
|
-
ui.warn("No suitable Organizational Admins found. Defaulting to pivotal for org creation")
|
311
|
-
end
|
312
|
-
Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
|
203
|
+
Chef::Config.node_name = org_admin
|
313
204
|
|
314
205
|
# Restore the entire org skipping the admin data and restoring groups and acls last
|
315
|
-
|
206
|
+
ui.msg "Restoring the rest of the org"
|
207
|
+
ui.debug "Using admin user: #{org_admin}"
|
316
208
|
chef_fs_config = Chef::ChefFS::Config.new
|
317
209
|
top_level_paths = chef_fs_config.local_fs.children.select { |entry| entry.name != 'acls' && entry.name != 'groups' }.map { |entry| entry.path }
|
318
210
|
|
@@ -326,10 +218,9 @@ class Chef
|
|
326
218
|
(top_level_paths + group_paths + group_acl_paths + acl_paths).each do |path|
|
327
219
|
Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new(path), chef_fs_config.local_fs, chef_fs_config.chef_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
|
328
220
|
end
|
329
|
-
|
330
|
-
|
331
|
-
Chef::Config[:
|
332
|
-
Chef::Config.custom_http_headers = {}
|
221
|
+
|
222
|
+
# restore clients to groups, using the pivotal user again
|
223
|
+
Chef::Config[:node_name] = 'pivotal'
|
333
224
|
['admins', 'billing-admins'].each do |group|
|
334
225
|
restore_group(Chef::ChefFS::Config.new, group)
|
335
226
|
end
|
@@ -384,10 +275,6 @@ class Chef
|
|
384
275
|
group.write(members.to_json)
|
385
276
|
end
|
386
277
|
|
387
|
-
def parallelize(entries, options = {}, &block)
|
388
|
-
Chef::ChefFS::Parallelizer.parallelize(entries, options, &block)
|
389
|
-
end
|
390
|
-
|
391
278
|
def put_acl(rest, url, acls)
|
392
279
|
old_acls = rest.get_rest(url)
|
393
280
|
old_acls = Chef::ChefFS::DataHandler::AclDataHandler.new.normalize(old_acls, nil)
|