Class: Chef::Knife::EcRestore
- Inherits:
-
Chef::Knife
- Object
- Chef::Knife
- Chef::Knife::EcRestore
- Includes:
- EcBase
- Defined in:
- lib/chef/knife/ec_restore.rb
Constant Summary collapse
- PATHS =
%w(chef_repo_path cookbook_path environment_path data_bag_path role_path node_path client_path acl_path group_path container_path)
Instance Method Summary collapse
- #add_users_to_org(orgname) ⇒ Object
- #create_organization(orgname) ⇒ Object
- #ec_key_import ⇒ Object
- #for_each_organization ⇒ Object
- #for_each_user ⇒ Object
- #group_array_to_sortable_hash(groups) ⇒ Object
- #put_acl(rest, url, acls) ⇒ Object
- #restore_group(chef_fs_config, group_name, includes = {:users => true, :clients => true}) ⇒ Object
- #restore_key_sql ⇒ Object
- #restore_open_invitations(orgname) ⇒ Object
- #restore_user_acls ⇒ Object
- #restore_user_sql ⇒ Object
- #restore_users ⇒ Object
- #run ⇒ Object
-
#sort_groups_for_upload(groups) ⇒ Object
Takes an array of group objects and topologically sorts them.
- #upload_org_data(name) ⇒ Object
Methods included from EcBase
#configure_chef, #ensure_webui_key_exists!, included, #org_admin, #rest, #server, #set_client_config!, #set_dest_dir_from_args!, #set_skip_user_acl!, #user_acl_rest
Instance Method Details
#add_users_to_org(orgname) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/chef/knife/ec_restore.rb', line 87 def add_users_to_org(orgname) members = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/members.json")) members.each do |member| username = member['user']['username'] begin response = rest.post_rest("organizations/#{orgname}/association_requests", { 'user' => username }) association_id = response["uri"].split("/").last rest.put_rest("users/#{username}/association_requests/#{association_id}", { 'response' => 'accept' }) rescue Net::HTTPServerException => e if e.response.code != "409" raise end end end end |
#create_organization(orgname) ⇒ Object
63 64 65 66 67 68 69 70 71 72 |
# File 'lib/chef/knife/ec_restore.rb', line 63 def create_organization(orgname) org = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/org.json")) rest.post_rest('organizations', org) rescue Net::HTTPServerException => e if e.response.code == "409" rest.put_rest("organizations/#{orgname}", org) else raise end end |
#ec_key_import ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/chef/knife/ec_restore.rb', line 150 def ec_key_import @ec_key_import ||= begin require 'chef/knife/ec_key_import' k = Chef::Knife::EcKeyImport.new k.name_args = ["#{dest_dir}/key_dump.json", "#{dest_dir}/key_table_dump.json"] k.config[:skip_pivotal] = true k.config[:skip_ids] = false k.config[:sql_host] = config[:sql_host] k.config[:sql_port] = config[:sql_port] k.config[:sql_user] = config[:sql_user] k.config[:sql_password] = config[:sql_password] k end end |
#for_each_organization ⇒ Object
123 124 125 126 127 128 129 |
# File 'lib/chef/knife/ec_restore.rb', line 123 def for_each_organization Dir.foreach("#{dest_dir}/organizations") do |name| next if name == '..' || name == '.' || !File.directory?("#{dest_dir}/organizations/#{name}") next unless (config[:org].nil? || config[:org] == name) yield name end end |
#for_each_user ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/chef/knife/ec_restore.rb', line 111 def for_each_user Dir.foreach("#{dest_dir}/users") do |filename| next if filename !~ /(.+)\.json/ name = $1 if name == 'pivotal' && !config[:overwrite_pivotal] ui.warn("Skipping pivotal user. To overwrite pivotal, pass --overwrite-pivotal.") next end yield name end end |
#group_array_to_sortable_hash(groups) ⇒ Object
266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/chef/knife/ec_restore.rb', line 266 def group_array_to_sortable_hash(groups) ret = {} groups.each do |group| name = group["name"] ret[name] = if group.key?("groups") group["groups"] else [] end end ret end |
#put_acl(rest, url, acls) ⇒ Object
306 307 308 309 310 311 312 313 314 315 |
# File 'lib/chef/knife/ec_restore.rb', line 306 def put_acl(rest, url, acls) old_acls = rest.get_rest(url) old_acls = Chef::ChefFS::DataHandler::AclDataHandler.new.normalize(old_acls, nil) acls = Chef::ChefFS::DataHandler::AclDataHandler.new.normalize(acls, nil) if acls != old_acls Chef::ChefFS::FileSystem::AclEntry::PERMISSIONS.each do || rest.put_rest("#{url}/#{}", { => acls[] }) end end end |
#restore_group(chef_fs_config, group_name, includes = {:users => true, :clients => true}) ⇒ Object
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/chef/knife/ec_restore.rb', line 279 def restore_group(chef_fs_config, group_name, includes = {:users => true, :clients => true}) includes[:users] = true unless includes.key? :users includes[:clients] = true unless includes.key? :clients group = Chef::ChefFS::FileSystem.resolve_path( chef_fs_config.chef_fs, "/groups/#{group_name}.json" ) members_json = Chef::ChefFS::FileSystem.resolve_path( chef_fs_config.local_fs, "/groups/#{group_name}.json" ).read members = JSON.parse(members_json).select do |member| if includes[:users] and includes[:clients] member elsif includes[:users] member == 'users' elsif includes[:clients] member == 'clients' end end group.write(members.to_json) end |
#restore_key_sql ⇒ Object
173 174 175 176 177 178 179 180 |
# File 'lib/chef/knife/ec_restore.rb', line 173 def restore_key_sql k = ec_key_import k.config[:skip_users_table] = true k.config[:skip_keys_table] = false k.config[:users_only] = false k.config[:clients_only] = true k.run end |
#restore_open_invitations(orgname) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/chef/knife/ec_restore.rb', line 74 def restore_open_invitations(orgname) invitations = JSONCompat.from_json(File.read("#{dest_dir}/organizations/#{orgname}/invitations.json")) invitations.each do |invitation| begin rest.post_rest("organizations/#{orgname}/association_requests", { 'user' => invitation['username'] }) rescue Net::HTTPServerException => e if e.response.code != "409" ui.error("Cannot create invitation #{invitation['id']}") end end end end |
#restore_user_acls ⇒ Object
103 104 105 106 107 108 109 |
# File 'lib/chef/knife/ec_restore.rb', line 103 def restore_user_acls ui.msg "Restoring user ACLs" for_each_user do |name| user_acl = JSONCompat.from_json(File.read("#{dest_dir}/user_acls/#{name}.json")) put_acl(user_acl_rest, "users/#{name}/_acl", user_acl) end end |
#restore_user_sql ⇒ Object
165 166 167 168 169 170 171 |
# File 'lib/chef/knife/ec_restore.rb', line 165 def restore_user_sql k = ec_key_import k.config[:skip_users_table] = false k.config[:skip_keys_table] = !config[:with_key_sql] k.config[:users_only] = true k.run end |
#restore_users ⇒ Object
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/chef/knife/ec_restore.rb', line 131 def restore_users ui.msg "Restoring users" for_each_user do |name| user = JSONCompat.from_json(File.read("#{dest_dir}/users/#{name}.json")) begin # Supply password for new user user_with_password = user.dup user_with_password['password'] = SecureRandom.hex rest.post_rest('users', user_with_password) rescue Net::HTTPServerException => e if e.response.code == "409" rest.put_rest("users/#{name}", user) else raise end end end end |
#run ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/chef/knife/ec_restore.rb', line 37 def run set_dest_dir_from_args! set_client_config! ensure_webui_key_exists! set_skip_user_acl! restore_users unless config[:skip_users] restore_user_sql if config[:with_user_sql] for_each_organization do |orgname| ui.msg "Restoring organization[#{orgname}]" create_organization(orgname) restore_open_invitations(orgname) add_users_to_org(orgname) upload_org_data(orgname) end restore_key_sql if config[:with_key_sql] if config[:skip_useracl] ui.warn("Skipping user ACL update. To update user ACLs, remove --skip-useracl or upgrade your Enterprise Chef Server.") else restore_user_acls end end |
#sort_groups_for_upload(groups) ⇒ Object
Takes an array of group objects and topologically sorts them
262 263 264 |
# File 'lib/chef/knife/ec_restore.rb', line 262 def sort_groups_for_upload(groups) Chef::Tsorter.new(group_array_to_sortable_hash(groups)).tsort end |
#upload_org_data(name) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/chef/knife/ec_restore.rb', line 183 def upload_org_data(name) old_config = Chef::Config.save begin # Clear out paths PATHS.each do |path| Chef::Config.delete(path.to_sym) end Chef::Config.chef_repo_path = "#{dest_dir}/organizations/#{name}" Chef::Config.versioned_cookbooks = true Chef::Config.chef_server_url = "#{server.root_url}/organizations/#{name}" # Upload the admins group and billing-admins acls ui.msg "Restoring org admin data" chef_fs_config = Chef::ChefFS::Config.new # Handle Admins and Billing Admins seperately # # admins: We need to upload admins first so that we # can upload all of the other objects as a user in the org # rather than as pivotal. Because the clients, and groups, don't # exist yet, we first upload the group with only the users. # # billing-admins: The default permissions on the # billing-admin group only give update permissions to # pivotal and members of the billing-admins group. Since we # can't unsure that the admin we choose for uploading will # be in the billing admins group, we have to upload this # group as pivotal. Thus, we upload its users and ACL here, # and then update it again once all of the clients and # groups are uploaded. # ['admins', 'billing-admins'].each do |group| restore_group(chef_fs_config, group, :clients => false) end pattern = Chef::ChefFS::FilePattern.new('/acls/groups/billing-admins.json') Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs_config.local_fs, chef_fs_config.chef_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry)}) Chef::Config.node_name = org_admin # Restore the entire org skipping the admin data and restoring groups and acls last ui.msg "Restoring the rest of the org" Chef::Log.debug "Using admin user: #{org_admin}" chef_fs_config = Chef::ChefFS::Config.new top_level_paths = chef_fs_config.local_fs.children.select { |entry| entry.name != 'acls' && entry.name != 'groups' }.map { |entry| entry.path } # Topologically sort groups for upload unsorted_groups = Chef::ChefFS::FileSystem.list(chef_fs_config.local_fs, Chef::ChefFS::FilePattern.new('/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| JSON.parse(entry.read) } group_paths = sort_groups_for_upload(unsorted_groups).map { |group_name| "/groups/#{group_name}.json" } group_acl_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.local_fs, Chef::ChefFS::FilePattern.new('/acls/groups/*')).select { |entry| entry.name != 'billing-admins.json' }.map { |entry| entry.path } acl_paths = Chef::ChefFS::FileSystem.list(chef_fs_config.local_fs, Chef::ChefFS::FilePattern.new('/acls/*')).select { |entry| entry.name != 'groups' }.map { |entry| entry.path } # Store organization data in a particular order: # - clients must be uploaded before groups (in top_level_paths) # - groups must be uploaded before any acl's # - groups must be uploaded twice to account for Chef Server versions that don't # accept group members on POST (top_level_paths + group_paths*2 + group_acl_paths + acl_paths).each do |path| 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) }) end # restore clients to groups, using the pivotal user again Chef::Config[:node_name] = 'pivotal' ['admins', 'billing-admins'].each do |group| restore_group(Chef::ChefFS::Config.new, group) end ensure Chef::Config.restore(old_config) end end |