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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a427844677521bea76fb22774f405ae3ed97af6
4
- data.tar.gz: ac92e509e8ecee7a4e14852f99c5e43a72305306
3
+ metadata.gz: 2078c6252a1d006cfb49b5f6c3c2a7fc8e47ad30
4
+ data.tar.gz: b67b59762f716a2b66677d56beb86de993020682
5
5
  SHA512:
6
- metadata.gz: 4f27a84674dc02eaee070700efc7f8bf4e898710342d1059b3881deb6c4bd9b75b4aef109708604364a0188cf65a7c67b665460b08c47e019c3abdf77ca0a8a3
7
- data.tar.gz: ad983d25da97492db691b431ac6fef6f60f468d314ea2909f74132eec633053a8a26cd88b03890703d6fa86f8bd133b7f9ca77091fccda2fdb603406682ff817
6
+ metadata.gz: ad00c21eb5460532a51301a12d91c786aca6c8cd77b745024b639a4bcdf082b8fb25e416bc68eee84a4b1bcd942e0d3915dfd0e5dc2fba69a4971c372bb9451f
7
+ data.tar.gz: 091c6bf72543e5d197c361f906d998904d89dcc7e22a5935b88fc170565f5cc303e6cad38b25ef4a512a8889647bc1bfca739cd9772f6853c965cc1c3ecefcf6
data/README.md CHANGED
@@ -2,7 +2,14 @@
2
2
 
3
3
  # Description
4
4
 
5
- This is an UNOFFICIAL and EXPERIMENTAL knife plugin intended to back up and restore an entire Enterprise Chef / Private Chef server, preserving the data in an intermediate, editable text format.
5
+ knife-ec-backup can backup and restore the data in an Enterprise Chef
6
+ Server installation, preserving the data in an intermediate, editable
7
+ text format. It is similar to the `knife download` and `knife upload`
8
+ commands and uses the same underlying libraries, but also includes
9
+ workarounds for objects not yet supported by those tools and various
10
+ Server API deficiencies. The long-run goal is to improve `knife
11
+ donwload`, `knife upload` and the Chef Server API and deprecate this
12
+ tool.
6
13
 
7
14
  # Requirements
8
15
 
@@ -20,6 +27,13 @@ This will install the plugin directly on the Chef Server:
20
27
 
21
28
  /opt/opscode/embedded/bin/gem install knife-ec-backup
22
29
 
30
+ The latest versions of knife-ec-backup require gems with native
31
+ extensions, thus you must install a standard build toolchain. To
32
+ install knife-ec-backup without installing libpq development headers
33
+ on your system, try the following:
34
+
35
+ /opt/opscode/embedded/bin/gem install knife-ec-backup -- --with-pg-config=/opt/opscode/embedded/postgresql/9.2/bin/pg_config
36
+
23
37
  ## Build from source
24
38
  Clone the git repository and run the following from inside:
25
39
 
@@ -29,22 +43,61 @@ Clone the git repository and run the following from inside:
29
43
  # Configuration
30
44
 
31
45
  ## Permissions
46
+
32
47
  Note that most users in an EC installation lack the permissions to pull all of the data from all organizations and other users.
33
48
  This plugin **REQUIRES THE PIVOTAL KEY AND WEBUI KEY** from the Chef Server.
34
49
  It is recommended that you run this from a frontend Enterprise Chef Server, you can use --user and --key to pass the pivotal information along.
35
50
 
36
51
  # Subcommands
37
52
 
53
+ ## Common Option
54
+
55
+ The following options are supported across all subcommands:
56
+
57
+ * `--sql_host`:
58
+ The hostname of the Chef Server's postgresql server. (default: localhost)
59
+
60
+ * `--sql_port`:
61
+ The postgresql listening port on the Chef Server. (default: 5432)
62
+
63
+ * `--sql_user`:
64
+ The username of postgresql user with access to the opscode_chef
65
+ database. (default: autoconfigured from
66
+ /etc/opscode/chef-server-running.json)
67
+
68
+ * `--sql_password`:
69
+ The password for the sql_user. (default: autoconfigured from /etc/opscode/chef-server-running.json)
70
+
38
71
  ## knife ec backup DEST_DIR (options)
39
72
 
40
73
  *Options*
41
74
 
75
+ * `--concurrency THREAD_COUNT`:
76
+ The maximum number of concurrent requests to make to the Chef
77
+ Server. (default: 10)
78
+
42
79
  * `--webui-key`:
43
80
  Used to set the path to the WebUI Key (default: /etc/opscode/webui_priv.pem)
81
+ skip any auto-configured options (default: false)
82
+
83
+ * `--with-user-sql`:
84
+ Whether to backup/restore user data directly from the database. This
85
+ requires access to the listening postgresql port on the Chef
86
+ Server. This is required to correctly handle user passwords and
87
+ to ensure user-specific association groups are not duplicated.
88
+
44
89
  * `--skip-useracl`:
45
- Whether to skip downloading User ACLs. This is required for EC 11.0.0 and lower (default: false)
46
- * `--skip-version-check'`:
47
- Whether to skip checking the Chef Server version. This will also skip any auto-configured options (default: false)
90
+ Skip download/restore of the user ACLs. User ACLs are the
91
+ permissions that actors have *on other global users*. These are
92
+ not the ACLs that control what permissions users have on various
93
+ Chef objects.
94
+
95
+ * `--skip-version-check`:
96
+ Skip Chef Server version check. This will also skip any auto-configured options (default: false)
97
+
98
+ * `--only-org ORG`:
99
+ Only donwload/restore objects in the named organization. Global
100
+ objects such as users will still be downloaded/restored.
48
101
 
49
102
  Creates a repository of an entire Enterprise Chef / Private Chef server.
50
103
 
@@ -100,24 +153,82 @@ This compares very closely with the "knife download /" from an OSC server:
100
153
 
101
154
  ## knife ec restore DEST_DIR (options)
102
155
 
156
+ Restores all data from the specified DEST_DIR to an Enterprise Chef /
157
+ Private Chef server. DEST_DIR should be a backup directory created by
158
+ `knife ec restore`
159
+
103
160
  *Options*
104
161
 
105
162
  * `--webui-key`:
106
163
  Used to set the path to the WebUI Key (default: /etc/opscode/webui_priv.pem)
164
+
107
165
  * `--overwrite-pivotal`:
108
- Whether to overwrite pivotal's key. Once this is done, future requests will fail until you fix the private key (default: false)
166
+ Whether to overwrite pivotal's key. Once this is done, future
167
+ requests will fail until you fix the private key (default: false)
168
+
169
+ * `--skip-users`:
170
+ Skip the restore of global users. This may cause organization
171
+ uploading to fail if the necessary users do not exist on the Chef
172
+ Server.
173
+
174
+ * `--concurrency THREAD_COUNT`:
175
+ The maximum number of concurrent requests to make to the Chef
176
+ Server. (default: 10)
177
+
178
+ * `--skip-version-check`:
179
+ Skip Chef Server version check. This will
180
+ also skip any auto-configured options (default: false)
181
+
182
+ * `--with-user-sql`:
183
+ Whether to backup/restore user data directly from the database. This
184
+ requires access to the listening postgresql port on the Chef
185
+ Server. This is required to correctly handle user passwords and
186
+ to ensure user-specific association groups are not
187
+ duplicated. This option will only work on `restore` if it was also
188
+ used during the `backup`.
189
+
109
190
  * `--skip-useracl`:
110
- Whether to skip downloading User ACLs. This is required for EC 11.0.0 and lower (default: false)
111
- * `--skip-version-check'`:
112
- Whether to skip checking the Chef Server version. This will also skip any auto-configured options (default: false)
191
+ Skip download/restore of the user ACLs. User ACLs are the
192
+ permissions that actors have *on other global users*. These are
193
+ not the ACLs that control what permissions users have on various
194
+ Chef objects.
195
+
196
+ * `--only-org ORG`:
197
+ Only donwload/restore objects in the named organization. Global
198
+ objects such as users will still be downloaded/restored.
199
+
200
+ ## knife ec key export [FILENAME]
201
+
202
+ Create a json representation of the users table from the Chef Server
203
+ database. If no argument is given, the name of the backup is
204
+ `key_dump.json`.
205
+
206
+ Please note, most users should use `knife ec backup` with the
207
+ `--with-user-sql` option rather than this command.
208
+
209
+ ## knife ec key import [FILENAME]
210
+
211
+ Import a json representation of the users table from FILENAME to the
212
+ the Chef Server database. If no argument is given, the filename is
213
+ assumed to be `key_dump.json`.
214
+
215
+ Please note, most user should use `knife ec restore` with the
216
+ `--with-user-sql` option rather than this command.
217
+
218
+ # Known Bugs
219
+
220
+ - `knife ec restore` can fail to restore cookbooks, failing with an
221
+ internal server error. A common cause of this problem is a
222
+ concurrency bug in Chef Server. Setting `--concurrency 1` can often
223
+ work around the issue.
113
224
 
114
- Restores all data from a repository to an Enterprise Chef / Private Chef server.
225
+ - `knife ec restore` can fail if the pool of pre-created organizations
226
+ can not keep up with the newly created organizations. This can
227
+ typically be resolved simply be restarting the restore. To avoid
228
+ this error for backups with large number of organizations, try
229
+ setting (in /etc/opscode/private-chef.rb):
115
230
 
116
- # TODO
231
+ opscode_org_creator['ready_org_depth']
117
232
 
118
- * Ensure easy installation into embedded ruby gemset on Chef Server.
119
- * Remove requirement for Knife Essentials gem to be installed.
120
- * Single org backups.
121
- * This plugin does **NOT** currently backup user passwords. **They will have to be reset after a restore.**
122
- * This plugin does **NOT** currently restore user public keys. **Private keys will have to be reset after a restore.**
123
- * This plugin does **NOT** currently restore custom user ACLs. **It will revert back to default ACLs on a restore.**
233
+ to the number of organizations in your backup and waiting for the
234
+ pool to fill before running `knife ec restore`
@@ -1,214 +1,133 @@
1
1
  require 'chef/knife'
2
+ require 'chef/knife/ec_base'
2
3
 
3
4
  class Chef
4
5
  class Knife
5
6
  class EcBackup < Chef::Knife
6
- banner "knife ec backup DIRECTORY"
7
-
8
- option :concurrency,
9
- :long => '--concurrency THREADS',
10
- :description => 'Maximum number of simultaneous requests to send (default: 10)'
11
-
12
- option :webui_key,
13
- :long => '--webui-key KEYPATH',
14
- :description => 'Used to set the path to the WebUI Key (default: /etc/opscode/webui_priv.pem)'
15
-
16
- option :skip_useracl,
17
- :long => '--skip-useracl',
18
- :boolean => true,
19
- :default => false,
20
- :description => "Whether to skip downloading User ACLs. This is required for EC 11.0.0 and lower"
21
-
22
- option :skip_version,
23
- :long => '--skip-version-check',
24
- :boolean => true,
25
- :default => false,
26
- :description => "Whether to skip checking the Chef Server version. This will also skip any auto-configured options"
27
-
28
- option :with_user_sql,
29
- :long => '--with-user-sql',
30
- :description => 'Whether to try direct data base access for user export. Required to properly handle passwords, keys, and USAGs'
31
-
32
- option :org,
33
- :long => '--only-org ORGNAME',
34
- :description => "Only back up objects in the named organization (default: all orgs)"
35
-
36
- option :sql_host,
37
- :long => '--sql-host HOSTNAME',
38
- :description => 'Postgresql database hostname (default: localhost)',
39
- :default => "localhost"
40
7
 
41
- option :sql_port,
42
- :long => '--sql-port PORT',
43
- :description => 'Postgresql database port (default: 5432)',
44
- :default => 5432
45
-
46
- option :sql_user,
47
- :long => "--sql-user USERNAME",
48
- :description => 'User used to connect to the postgresql database.'
49
-
50
- option :sql_password,
51
- :long => "--sql-password PASSWORD",
52
- :description => 'Password used to connect to the postgresql database'
8
+ include Knife::EcBase
53
9
 
10
+ banner "knife ec backup DIRECTORY"
54
11
 
55
12
  deps do
56
13
  require 'chef/chef_fs/config'
57
14
  require 'chef/chef_fs/file_system'
58
15
  require 'chef/chef_fs/file_pattern'
59
16
  require 'chef/chef_fs/parallelizer'
60
- end
61
-
62
- def configure_chef
63
- super
64
- Chef::Config[:concurrency] = config[:concurrency].to_i if config[:concurrency]
65
- Chef::ChefFS::Parallelizer.threads = (Chef::Config[:concurrency] || 10) - 1
17
+ require 'chef/server'
18
+ require 'fileutils'
66
19
  end
67
20
 
68
21
  def run
69
- #Check for destination directory argument
70
- if name_args.length <= 0
71
- ui.error("Must specify backup directory as an argument.")
72
- exit 1
73
- end
74
- dest_dir = name_args[0]
75
-
22
+ set_dest_dir_from_args!
23
+ set_client_config!
24
+ set_skip_user_acl!
25
+ ensure_webui_key_exists!
76
26
 
77
- #Check for pivotal user and key
78
- node_name = Chef::Config.node_name
79
- client_key = Chef::Config.client_key
80
- if node_name != "pivotal"
81
- if !File.exist?("/etc/opscode/pivotal.pem")
82
- ui.error("Username not configured as pivotal and /etc/opscode/pivotal.pem does not exist. It is recommended that you run this plugin from your Chef server.")
83
- exit 1
27
+ for_each_user do |username, url|
28
+ download_user(username, url)
29
+ if config[:skip_useracl]
30
+ ui.warn("Skipping user ACL download for #{username}. To download this ACL, remove --skip-useracl or upgrade your Enterprise Chef Server.")
31
+ else
32
+ download_user_acl(username)
84
33
  end
85
- Chef::Config.node_name = 'pivotal'
86
- Chef::Config.client_key = '/etc/opscode/pivotal.pem'
87
34
  end
88
35
 
89
- #Check for WebUI Key
90
- if config[:webui_key] == nil
91
- if !File.exist?("/etc/opscode/webui_priv.pem")
92
- 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.")
93
- exit 1
94
- end
95
- ui.warn("WebUI not specified. Using /etc/opscode/webui_priv.pem")
96
- webui_key = '/etc/opscode/webui_priv.pem'
97
- else
98
- webui_key = config[:webui_key]
36
+ if config[:with_user_sql]
37
+ export_users_from_sql
99
38
  end
100
39
 
101
- #Set the server root
102
- server_root = Chef::Config.chef_server_root
103
- if server_root == nil
104
- server_root = Chef::Config.chef_server_url.gsub(/\/organizations\/+[^\/]+\/*$/, '')
105
- ui.warn("chef_server_root not found in knife configuration. Setting root to: #{server_root}")
106
- Chef::Config.chef_server_root = server_root
40
+ ensure_dir("#{dest_dir}/organizations")
41
+ for_each_organization do |org_object|
42
+ name = org_object['name']
43
+ write_org_object_to_disk(org_object)
44
+ download_org_data(name)
45
+ download_org_members(name)
46
+ download_org_invitations(name)
107
47
  end
48
+ end
108
49
 
109
- rest = Chef::REST.new(Chef::Config.chef_server_root)
110
-
111
- if config[:skip_version] && config[:skip_useracl]
112
- ui.warn("Skipping the Chef Server version check. This will also skip any auto-configured options")
113
- user_acl_rest = nil
114
- elsif config[:skip_version] && !config[:skip_useracl]
115
- ui.warn("Skipping the Chef Server version check. This will also skip any auto-configured options")
116
- user_acl_rest = rest
117
- else # Grab Chef Server version number so that we can auto set options
118
- uri = URI.parse("#{Chef::Config.chef_server_root}/version")
119
- server_version = open(uri, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).each_line.first.split(' ').last
120
- server_version_parts = server_version.split('.')
121
-
122
- if server_version_parts.count == 3
123
- puts "Detected Enterprise Chef Server version: #{server_version}"
124
-
125
- # All versions of Chef Server below 11.0.1 are missing the GET User ACL helper in nginx
126
- if server_version_parts[0].to_i < 11 || (server_version_parts[0].to_i == 11 && server_version_parts[1].to_i == 0 && server_version_parts[0].to_i < 1)
127
- #Check to see if Opscode-Account can be directly from the local machine
128
- begin
129
- user_acl_rest.get('users')
130
- ui.warn("Your version of Enterprise Chef Server does not support the downloading of User ACLs. Using local connection to backup")
131
- user_acl_rest = Chef::REST.new("http://127.0.0.1:9465")
132
- rescue
133
- ui.warn("Your version of Enterprise Chef Server does not support the downloading of User ACLs. Setting skip-useracl to TRUE")
134
- config[:skip_useracl] = true
135
- user_acl_rest = nil
136
- end
137
- else
138
- user_acl_rest = rest
139
- end
50
+ def for_each_user
51
+ rest.get_rest('/users').each_pair do |name, url|
52
+ yield name, url
53
+ end
54
+ end
140
55
 
56
+ def for_each_organization
57
+ rest.get_rest('/organizations').each_pair do |name, url|
58
+ next unless (config[:org].nil? || config[:org] == name)
59
+ ui.msg "Downloading organization object for #{name} from #{url}"
60
+ org = rest.get_rest(url)
61
+ # Enterprise Chef 11 and below uses a pool of precreated
62
+ # organizations to account for slow organization creation
63
+ # using CouchDB. Thus, on server versions < 12 we want to
64
+ # skip any of these precreated organizations by checking if
65
+ # they have been assigned or not. The Chef 12 API does not
66
+ # return an assigned_at field.
67
+ if org['assigned_at'] || server.version >= Gem::Version.new("12")
68
+ yield org
141
69
  else
142
- ui.warn("Unable to detect Chef Server version.")
70
+ ui.msg "Skipping pre-created org #{name}"
143
71
  end
144
72
  end
73
+ end
145
74
 
146
- # Grab users
147
- puts "Grabbing users ..."
75
+ def download_user(username, url)
148
76
  ensure_dir("#{dest_dir}/users")
149
- ensure_dir("#{dest_dir}/user_acls")
150
-
151
- rest.get_rest('/users').each_pair do |name, url|
152
- File.open("#{dest_dir}/users/#{name}.json", 'w') do |file|
153
- file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest(url)))
154
- end
155
-
156
- if config[:skip_useracl]
157
- ui.warn("Skipping user ACL download for #{name}. To download this ACL, remove --skip-useracl or upgrade your Enterprise Chef Server.")
158
- next
159
- end
77
+ File.open("#{dest_dir}/users/#{username}.json", 'w') do |file|
78
+ file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest(url)))
79
+ end
80
+ end
160
81
 
161
- File.open("#{dest_dir}/user_acls/#{name}.json", 'w') do |file|
162
- file.write(Chef::JSONCompat.to_json_pretty(user_acl_rest.get_rest("users/#{name}/_acl")))
163
- end
82
+ def download_user_acl(username)
83
+ ensure_dir("#{dest_dir}/user_acls")
84
+ File.open("#{dest_dir}/user_acls/#{username}.json", 'w') do |file|
85
+ file.write(Chef::JSONCompat.to_json_pretty(user_acl_rest.get_rest("users/#{username}/_acl")))
164
86
  end
87
+ end
165
88
 
166
- if config[:with_user_sql]
167
- require 'chef/knife/ec_key_export'
168
- Chef::Knife::EcKeyExport.deps
169
- k = Chef::Knife::EcKeyExport.new
170
- k.name_args = ["#{dest_dir}/key_dump.json"]
171
- k.config[:sql_host] = config[:sql_host]
172
- k.config[:sql_port] = config[:sql_port]
173
- k.config[:sql_user] = config[:sql_user]
174
- k.config[:sql_password] = config[:sql_password]
175
- k.run
89
+ def export_users_from_sql
90
+ require 'chef/knife/ec_key_export'
91
+ Chef::Knife::EcKeyExport.deps
92
+ k = Chef::Knife::EcKeyExport.new
93
+ k.name_args = ["#{dest_dir}/key_dump.json"]
94
+ k.config[:sql_host] = config[:sql_host]
95
+ k.config[:sql_port] = config[:sql_port]
96
+ k.config[:sql_user] = config[:sql_user]
97
+ k.config[:sql_password] = config[:sql_password]
98
+ k.run
99
+ end
100
+
101
+ def write_org_object_to_disk(org_object)
102
+ name = org_object['name']
103
+ ensure_dir("#{dest_dir}/organizations/#{name}")
104
+ File.open("#{dest_dir}/organizations/#{name}/org.json", 'w') do |file|
105
+ file.write(Chef::JSONCompat.to_json_pretty(org_object))
176
106
  end
107
+ end
177
108
 
178
- # Download organizations
179
- ensure_dir("#{dest_dir}/organizations")
180
- rest.get_rest('/organizations').each_pair do |name, url|
181
- do_org = (config[:org].nil? || config[:org] == name)
182
- org = rest.get_rest(url)
183
- if org['assigned_at'] and do_org
184
- puts "Grabbing organization #{name} ..."
185
- ensure_dir("#{dest_dir}/organizations/#{name}")
186
- download_org(dest_dir, webui_key, name)
187
- File.open("#{dest_dir}/organizations/#{name}/org.json", 'w') do |file|
188
- file.write(Chef::JSONCompat.to_json_pretty(org))
189
- end
190
- File.open("#{dest_dir}/organizations/#{name}/members.json", 'w') do |file|
191
- file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest("#{url}/users")))
192
- end
193
- File.open("#{dest_dir}/organizations/#{name}/invitations.json", 'w') do |file|
194
- file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest("#{url}/association_requests")))
195
- end
196
- end
109
+ def download_org_members(name)
110
+ ensure_dir("#{dest_dir}/organizations/#{name}")
111
+ File.open("#{dest_dir}/organizations/#{name}/members.json", 'w') do |file|
112
+ file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest("/organizations/#{name}/users")))
197
113
  end
114
+ end
198
115
 
199
- if @error
200
- exit 1
116
+ def download_org_invitations(name)
117
+ ensure_dir("#{dest_dir}/organizations/#{name}")
118
+ File.open("#{dest_dir}/organizations/#{name}/invitations.json", 'w') do |file|
119
+ file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest("/organizations/#{name}/association_requests")))
201
120
  end
202
121
  end
203
122
 
204
123
  def ensure_dir(dir)
205
124
  if !File.exist?(dir)
206
- Dir.mkdir(dir)
125
+ FileUtils.mkdir_p(dir)
207
126
  end
208
127
  end
209
128
 
210
129
  PATHS = %w(chef_repo_path cookbook_path environment_path data_bag_path role_path node_path client_path acl_path group_path container_path)
211
- def download_org(dest_dir, webui_key, name)
130
+ def download_org_data(name)
212
131
  old_config = Chef::Config.save
213
132
 
214
133
  begin
@@ -219,48 +138,47 @@ class Chef
219
138
  Chef::Config.chef_repo_path = "#{dest_dir}/organizations/#{name}"
220
139
  Chef::Config.versioned_cookbooks = true
221
140
 
222
- Chef::Config.chef_server_url = "#{Chef::Config.chef_server_root}/organizations/#{name}"
141
+ Chef::Config.chef_server_url = "#{server.root_url}/organizations/#{name}"
223
142
 
224
143
  ensure_dir(Chef::Config.chef_repo_path)
225
144
 
226
145
  # Download the billing-admins ACL and group as pivotal
227
146
  chef_fs_config = Chef::ChefFS::Config.new
228
- pattern = Chef::ChefFS::FilePattern.new('/acls/groups/billing-admins.json')
229
- if Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs_config.chef_fs, chef_fs_config.local_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
230
- @error = true
231
- end
232
- pattern = Chef::ChefFS::FilePattern.new('/groups/billing-admins.json')
233
- if Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs_config.chef_fs, chef_fs_config.local_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
234
- @error = true
235
- end
236
- pattern = Chef::ChefFS::FilePattern.new('/groups/admins.json')
237
- if Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs_config.chef_fs, chef_fs_config.local_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
238
- @error = true
239
- end
147
+ chef_fs_copy_pattern('/acls/groups/billing-admins.json', chef_fs_config)
148
+ chef_fs_copy_pattern('/groups/billing-admins.json', chef_fs_config)
149
+ chef_fs_copy_pattern('/groups/admins.json', chef_fs_config)
240
150
 
241
- # Figure out who the admin is so we can spoof him and retrieve his stuff
242
- rest = Chef::REST.new(Chef::Config.chef_server_url)
243
- admin_users = rest.get_rest('groups/admins')['users']
244
- org_members = rest.get_rest('users').map { |user| user['user']['username'] }
245
- admin_users.delete_if { |user| !org_members.include?(user) }
246
- Chef::Config.node_name = admin_users[0]
247
- Chef::Config.client_key = webui_key
248
- Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
151
+ # Set Chef::Config to use an organization administrator
152
+ Chef::Config.node_name = org_admin
249
153
 
250
154
  # Download the entire org skipping the billing admins group ACL and the group itself
251
155
  chef_fs_config = Chef::ChefFS::Config.new
252
156
  top_level_paths = chef_fs_config.chef_fs.children.select { |entry| entry.name != 'acls' && entry.name != 'groups' }.map { |entry| entry.path }
253
- acl_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.chef_fs, Chef::ChefFS::FilePattern.new('/acls/*')).select { |entry| entry.name != 'groups' }.map { |entry| entry.path }
254
- group_acl_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.chef_fs, Chef::ChefFS::FilePattern.new('/acls/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| entry.path }
255
- group_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.chef_fs, Chef::ChefFS::FilePattern.new('/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| entry.path }
157
+ acl_paths = chef_fs_paths('/acls/*', chef_fs_config, 'groups')
158
+ group_acl_paths = chef_fs_paths('/acls/groups/*', chef_fs_config, 'billing-admins.json')
159
+ group_paths = chef_fs_paths('/groups/*', chef_fs_config, 'billing-admins.json')
256
160
  (top_level_paths + group_acl_paths + acl_paths + group_paths).each do |path|
257
- Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new(path), chef_fs_config.chef_fs, chef_fs_config.local_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
161
+ chef_fs_copy_pattern(path, chef_fs_config)
258
162
  end
259
-
260
163
  ensure
261
164
  Chef::Config.restore(old_config)
262
165
  end
263
166
  end
167
+
168
+ def chef_fs_paths(pattern_str, chef_fs_config, exclude=nil)
169
+ pattern = Chef::ChefFS::FilePattern.new(pattern_str)
170
+ list = Chef::ChefFS::FileSystem.list(chef_fs_config.chef_fs, pattern)
171
+ list = list.select { |entry| entry.name != exclude } if ! exclude.nil?
172
+ list.map {|entry| entry.path }
173
+ end
174
+
175
+ def chef_fs_copy_pattern(pattern_str, chef_fs_config)
176
+ pattern = Chef::ChefFS::FilePattern.new(pattern_str)
177
+ Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs_config.chef_fs,
178
+ chef_fs_config.local_fs, nil,
179
+ config, ui,
180
+ proc { |entry| chef_fs_config.format_path(entry) })
181
+ end
264
182
  end
265
183
  end
266
184
  end