knife-ec-backup 2.0.0.beta.2 → 2.0.0.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|