knife-ec-backup 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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