knife-ec-backup 0.9.3 → 0.9.4

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: c64485c8411324223a9453e39e68afbd7a834aa2
4
- data.tar.gz: 904be6ea0754370384521c07d90578fa70ca4513
3
+ metadata.gz: 5c285a56c4950610acb55aa11b686076df1a82b2
4
+ data.tar.gz: 5e6b0e50898af2481631db6703072bfd9708621a
5
5
  SHA512:
6
- metadata.gz: 084f0ac8b43a0cd0139dd97c2a41e7840641bbca0589bba38a388845ca98857446c2f147e336a7943966804facf8949f27133b986e13480fbba8b314536a9970
7
- data.tar.gz: 1e8489c6d5da29a0fd2bd6f8697cf78fe198905efbde6dfecd75ae4c586727552bcb2c969af634af376ddd3eac24fd13ba7e52a491fe399e4e91234ca2f92bda
6
+ metadata.gz: a0422cabb085a15ddf31b14a0eb53e169c184844a8ccd11091d2c8678355130d4fd99adde97ed4afb9a880b56652347b0f1b1ab948b5ab3e293234e59a37929b
7
+ data.tar.gz: 4fa91e9ebb1a1b5f5ebe8f1b7e03adb692b8e53cf8f897cc973e811ee9b48c242d046164f7547c7e5981aed050f3f469b9c0b4a3edf7d1dd0ff2f8b7b2fbb26d
@@ -33,10 +33,10 @@ class Chef
33
33
 
34
34
  rest.get_rest('/users').each_pair do |name, url|
35
35
  File.open("#{dest_dir}/users/#{name}.json", 'w') do |file|
36
- file.write(rest.get_rest(url).to_json)
36
+ file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest(url)))
37
37
  end
38
38
  File.open("#{dest_dir}/user_acls/#{name}.json", 'w') do |file|
39
- file.write(user_acl_rest.get_rest("users/#{name}/_acl").to_json)
39
+ file.write(Chef::JSONCompat.to_json_pretty(user_acl_rest.get_rest("users/#{name}/_acl")))
40
40
  end
41
41
  end
42
42
 
@@ -46,10 +46,17 @@ class Chef
46
46
  org = rest.get_rest(url)
47
47
  if org['assigned_at']
48
48
  puts "Grabbing organization #{name} ..."
49
- File.open("#{dest_dir}/organizations/#{name}.json", 'w') do |file|
50
- file.write(org.to_json)
51
- end
49
+ ensure_dir("#{dest_dir}/organizations/#{name}")
52
50
  download_org(dest_dir, webui_key, name)
51
+ File.open("#{dest_dir}/organizations/#{name}/org.json", 'w') do |file|
52
+ file.write(Chef::JSONCompat.to_json_pretty(org))
53
+ end
54
+ File.open("#{dest_dir}/organizations/#{name}/members.json", 'w') do |file|
55
+ file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest("#{url}/users")))
56
+ end
57
+ File.open("#{dest_dir}/organizations/#{name}/invitations.json", 'w') do |file|
58
+ file.write(Chef::JSONCompat.to_json_pretty(rest.get_rest("#{url}/association_requests")))
59
+ end
53
60
  end
54
61
  end
55
62
 
@@ -80,6 +87,17 @@ class Chef
80
87
 
81
88
  Chef::Config.chef_server_url = "#{Chef::Config.chef_server_url}/organizations/#{name}"
82
89
 
90
+ ensure_dir(Chef::Config.chef_repo_path)
91
+
92
+ # Download the billing-admins acls as pivotal
93
+ chef_fs_config = ::ChefFS::Config.new
94
+ %w(/acls/groups/billing-admins.json).each do |name|
95
+ pattern = ::ChefFS::FilePattern.new(name)
96
+ if ::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) })
97
+ @error = true
98
+ end
99
+ end
100
+
83
101
  # Figure out who the admin is so we can spoof him and retrieve his stuff
84
102
  rest = Chef::REST.new(Chef::Config.chef_server_url)
85
103
  admin_users = rest.get_rest('groups/admins')['users']
@@ -90,8 +108,7 @@ class Chef
90
108
  Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
91
109
 
92
110
  # Do the download
93
- ensure_dir(Chef::Config.chef_repo_path)
94
- chef_fs_config ||= ::ChefFS::Config.new
111
+ chef_fs_config = ::ChefFS::Config.new
95
112
  root_pattern = ::ChefFS::FilePattern.new('/')
96
113
  if ::ChefFS::FileSystem.copy_to(root_pattern, chef_fs_config.chef_fs, chef_fs_config.local_fs, nil, config, ui, proc { |entry| chef_fs_config.format_path(entry) })
97
114
  @error = true
@@ -0,0 +1,186 @@
1
+ require 'chef/knife'
2
+
3
+ class Chef
4
+ class Knife
5
+ class EcRestore < Chef::Knife
6
+ banner "knife ec restore"
7
+
8
+ deps do
9
+ require 'chef/json_compat'
10
+ require 'chef_fs/config'
11
+ require 'chef_fs/file_system'
12
+ require 'chef_fs/file_pattern'
13
+ require 'chef_fs/file_system/acl_entry'
14
+ require 'chef_fs/data_handler/acl_data_handler'
15
+ require 'securerandom'
16
+ require 'chef_fs/parallelizer'
17
+ end
18
+
19
+ def run
20
+ if name_args.length == 0
21
+ ui.error("Must specify backup directory as argument.")
22
+ exit 1
23
+ end
24
+
25
+ dest_dir = name_args[0]
26
+ webui_key = name_args[1]
27
+ rest = Chef::REST.new(Chef::Config.chef_server_url)
28
+ if name_args.length >= 3
29
+ user_acl_rest = Chef::REST.new(name_args[2])
30
+ else
31
+ user_acl_rest = rest
32
+ end
33
+
34
+ # Restore users
35
+ puts "Restoring users ..."
36
+ Dir.foreach("#{dest_dir}/users") do |filename|
37
+ next if filename !~ /(.+)\.json/
38
+ name = $1
39
+ user = JSONCompat.from_json(IO.read("#{dest_dir}/users/#{name}.json"))
40
+ begin
41
+ user_with_password = user.dup
42
+ user_with_password['password'] = SecureRandom.hex
43
+ rest.post_rest('users', user_with_password)
44
+ rescue Net::HTTPServerException => e
45
+ if e.response.code == "409"
46
+ rest.put_rest("users/#{name}", user)
47
+ else
48
+ raise
49
+ end
50
+ end
51
+ # Doesn't work at present
52
+ #user_acl = JSONCompat.from_json(IO.read("#{dest_dir}/user_acls/#{name}.json"))
53
+ #put_acl(user_acl_rest, "users/#{name}/_acl", user_acl)
54
+ end
55
+
56
+ # Restore organizations
57
+ Dir.foreach("#{dest_dir}/organizations") do |name|
58
+ next if name == '..' || name == '.' || !File.directory?("#{dest_dir}/organizations/#{name}")
59
+ puts "Restoring org #{name} ..."
60
+
61
+ # Create organization
62
+ org = JSONCompat.from_json(IO.read("#{dest_dir}/organizations/#{name}/org.json"))
63
+ begin
64
+ rest.post_rest('organizations', org)
65
+ rescue Net::HTTPServerException => e
66
+ if e.response.code == "409"
67
+ rest.put_rest("organizations/#{name}", org)
68
+ else
69
+ raise
70
+ end
71
+ end
72
+
73
+ # Restore open invitations
74
+ invitations = JSONCompat.from_json(IO.read("#{dest_dir}/organizations/#{name}/invitations.json"))
75
+ parallelize(invitations) do |invitation|
76
+ begin
77
+ rest.post_rest("organizations/#{name}/association_requests", { 'user' => invitation['username'] })
78
+ rescue Net::HTTPServerException => e
79
+ if e.response.code != "409"
80
+ raise
81
+ end
82
+ end
83
+ end
84
+
85
+ # Repopulate org members
86
+ members = JSONCompat.from_json(IO.read("#{dest_dir}/organizations/#{name}/members.json"))
87
+ parallelize(members) do |member|
88
+ username = member['user']['username']
89
+ begin
90
+ response = rest.post_rest("organizations/#{name}/association_requests", { 'user' => username })
91
+ association_id = response["uri"].split("/").last
92
+ rest.put_rest("users/#{username}/association_requests/#{association_id}", { 'response' => 'accept' })
93
+ rescue Net::HTTPServerException => e
94
+ if e.response.code != "409"
95
+ raise
96
+ end
97
+ end
98
+ end
99
+
100
+ # Upload org data
101
+ upload_org(dest_dir, webui_key, name)
102
+ end
103
+
104
+ if @error
105
+ exit 1
106
+ end
107
+ end
108
+
109
+ PATHS = %w(chef_repo_path cookbook_path environment_path data_bag_path role_path node_path client_path acl_path group_path container_path)
110
+ CONFIG_VARS = %w(chef_server_url custom_http_headers node_name client_key) + PATHS
111
+ def upload_org(dest_dir, webui_key, name)
112
+ old_config = {}
113
+ CONFIG_VARS.each do |key|
114
+ old_config[key] = Chef::Config[key]
115
+ end
116
+ begin
117
+ # Clear out paths
118
+ PATHS.each do |path_var|
119
+ Chef::Config[path_var] = nil
120
+ end
121
+ Chef::Config.chef_repo_path = "#{dest_dir}/organizations/#{name}"
122
+
123
+ Chef::Config.chef_server_url = "#{Chef::Config.chef_server_url}/organizations/#{name}"
124
+
125
+ # Upload the admins group and billing-admins acls
126
+ chef_fs_config = ::ChefFS::Config.new
127
+ %w(/groups/admins.json /groups/billing-admins.json /acls/groups/billing-admins.json).each do |name|
128
+ pattern = ::ChefFS::FilePattern.new(name)
129
+ if ::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) })
130
+ @error = true
131
+ end
132
+ end
133
+
134
+ # Figure out who the admin is so we can spoof him and retrieve his stuff
135
+ rest = Chef::REST.new(Chef::Config.chef_server_url)
136
+ admin_users = rest.get_rest('groups/admins')['users']
137
+ org_members = rest.get_rest('users').map { |user| user['user']['username'] }
138
+ admin_users.delete_if { |user| !org_members.include?(user) }
139
+ Chef::Config.node_name = admin_users[0]
140
+ Chef::Config.client_key = webui_key
141
+ Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
142
+
143
+ # Do the upload.
144
+ chef_fs_config = ::ChefFS::Config.new
145
+ # groups and acls come last.
146
+ children = chef_fs_config.chef_fs.children.map { |child| child.name }
147
+ children.delete('acls')
148
+ children.delete('groups')
149
+ parallelize(children) do |child_name|
150
+ pattern = ::ChefFS::FilePattern.new("/#{child_name}")
151
+ if ::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) })
152
+ @error = true
153
+ end
154
+ end
155
+ pattern = ::ChefFS::FilePattern.new("/groups")
156
+ if ::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) })
157
+ @error = true
158
+ end
159
+ pattern = ::ChefFS::FilePattern.new("/acls")
160
+ if ::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) })
161
+ @error = true
162
+ end
163
+ ensure
164
+ CONFIG_VARS.each do |key|
165
+ Chef::Config[key] = old_config[key]
166
+ end
167
+ end
168
+ end
169
+
170
+ def parallelize(entries, options = {}, &block)
171
+ ::ChefFS::Parallelizer.parallelize(entries, options, &block)
172
+ end
173
+
174
+ def put_acl(rest, url, acls)
175
+ old_acls = rest.get_rest(url)
176
+ old_acls = ::ChefFS::DataHandler::AclDataHandler.new.normalize(old_acls, nil)
177
+ acls = ::ChefFS::DataHandler::AclDataHandler.new.normalize(acls, nil)
178
+ if acls != old_acls
179
+ ::ChefFS::FileSystem::AclEntry::PERMISSIONS.each do |permission|
180
+ rest.put_rest("#{url}/#{permission}", { permission => acls[permission] })
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -1,3 +1,3 @@
1
1
  module KnifeECBackup
2
- VERSION = '0.9.3'
2
+ VERSION = '0.9.4'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-ec-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Keiser
@@ -50,7 +50,7 @@ files:
50
50
  - README.md
51
51
  - Rakefile
52
52
  - lib/chef/knife/ec_backup.rb
53
- - lib/chef/knife/opc_restore.rb
53
+ - lib/chef/knife/ec_restore.rb
54
54
  - lib/knife_ec_backup/version.rb
55
55
  homepage: http://www.opscode.com
56
56
  licenses:
@@ -1,96 +0,0 @@
1
- require 'chef/knife'
2
-
3
- class Chef
4
- class Knife
5
- class EcRestore < Chef::Knife
6
- banner "knife ec restore"
7
-
8
- deps do
9
- require 'chef_fs/config'
10
- require 'chef_fs/file_system'
11
- require 'chef_fs/file_pattern'
12
- end
13
-
14
- def run
15
- if name_args.length == 0
16
- ui.error("Must specify backup directory as argument.")
17
- exit 1
18
- end
19
-
20
- dest_dir = name_args[0]
21
- webui_key = name_args[1]
22
- rest = Chef::REST.new(Chef::Config.chef_server_url)
23
-
24
- # Restore users
25
- puts "Restoring users ..."
26
- Dir.foreach("#{dest_dir}/users") do |user_file|
27
- next if user_file !~ /(.+)\.json$/
28
- name = $1
29
- rest.post("#{dest_dir}/users", JSONCompat.to_json(IO.read("#{dest_dir}/users/#{user_file}")))
30
- end
31
-
32
- # Download organizations
33
- Dir.foreach("#{dest_dir}/organizations") do |org_file|
34
- next if org_file !~ /(.+)\.json/
35
- name = $1
36
- rest.post("#{dest_dir}/organizations", JSONCompat.to_json(IO.read("#{dest_dir}/users/#{user_file}")))
37
- end
38
- rest.get('/organizations').each_pair do |name, url|
39
- org = rest.get(url)
40
- if org['assigned_at']
41
- puts "Restoring organization #{name} ..."
42
- File.open("#{dest_dir}/organizations/#{name}.json", 'w') do |file|
43
- file.write(org.to_json)
44
- end
45
- download_org(dest_dir, webui_key, name)
46
- end
47
- end
48
-
49
- if @error
50
- exit 1
51
- end
52
- end
53
-
54
- def ensure_dir(dir)
55
- if !File.exist?(dir)
56
- Dir.mkdir(dir)
57
- end
58
- end
59
-
60
- def download_org(dest_dir, webui_key, name)
61
- @old_chef_server_url = Chef::Config.chef_server_url
62
- @old_chef_repo_path = Chef::Config.chef_repo_path
63
- @old_node_name = Chef::Config.node_name
64
- @old_custom_http_headers = Chef::Config.custom_http_headers
65
- @old_client_key = Chef::Config.client_key
66
- begin
67
- Chef::Config.chef_server_url = "#{Chef::Config.chef_server_url}/organizations/#{name}"
68
- Chef::Config.chef_repo_path = "#{dest_dir}/organizations/#{name}"
69
-
70
- # Figure out who the admin is so we can spoof him and retrieve his stuff
71
- admin_users = rest.get('groups/admins')['users']
72
- org_members = rest.get('users').map { |user| user['user']['username'] }
73
- admin_users.delete_if { |user| !org_members.include?(user) }
74
- admin = admin_users[0]
75
- Chef::Config.node_name = admin_users[0]
76
- Chef::Config.client_key = webui_key
77
- Chef::Config.custom_http_headers = (Chef::Config.custom_http_headers || {}).merge({'x-ops-request-source' => 'web'})
78
-
79
- # Do the download
80
- ensure_dir(Chef::Config.chef_repo_path)
81
- @chef_fs_config ||= ::ChefFS::Config.new
82
- root_pattern = ::ChefFS::FilePattern.new('/')
83
- if ::ChefFS::FileSystem.copy_to(root_pattern, @chef_fs_config.chef_fs, @chef_fs_config.local_fs, nil, config, ui, proc { |entry| @chef_fs_config.format_path(entry) })
84
- @error = true
85
- end
86
- ensure
87
- Chef::Config.chef_server_url = @old_chef_server_url
88
- Chef::Config.chef_repo_path = @old_chef_repo_path
89
- Chef::Config.node_name = @old_node_name
90
- Chef::Config.custom_http_headers = @old_custom_http_headers
91
- Chef::Config.client_key = @old_client_key
92
- end
93
- end
94
- end
95
- end
96
- end