knife-essentials 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/lib/chef/knife/diff_essentials.rb +2 -5
  2. data/lib/chef/knife/raw_essentials.rb +2 -2
  3. data/lib/chef_fs/command_line.rb +98 -79
  4. data/lib/chef_fs/data_handler/acl_data_handler.rb +22 -0
  5. data/lib/chef_fs/data_handler/container_data_handler.rb +20 -0
  6. data/lib/chef_fs/data_handler/group_data_handler.rb +33 -0
  7. data/lib/chef_fs/data_handler/user_data_handler.rb +6 -1
  8. data/lib/chef_fs/file_system/acl_dir.rb +62 -0
  9. data/lib/chef_fs/file_system/acl_entry.rb +54 -0
  10. data/lib/chef_fs/file_system/acls_dir.rb +66 -0
  11. data/lib/chef_fs/file_system/base_fs_object.rb +0 -74
  12. data/lib/chef_fs/file_system/chef_repository_file_system_root_dir.rb +9 -0
  13. data/lib/chef_fs/file_system/chef_server_root_dir.rb +21 -2
  14. data/lib/chef_fs/file_system/cookbook_dir.rb +1 -1
  15. data/lib/chef_fs/file_system/cookbooks_acl_dir.rb +39 -0
  16. data/lib/chef_fs/file_system/cookbooks_dir.rb +3 -2
  17. data/lib/chef_fs/file_system/data_bags_dir.rb +1 -5
  18. data/lib/chef_fs/file_system/nodes_dir.rb +13 -3
  19. data/lib/chef_fs/file_system/rest_list_dir.rb +5 -7
  20. data/lib/chef_fs/file_system/rest_list_entry.rb +18 -18
  21. data/lib/chef_fs/knife.rb +7 -4
  22. data/lib/chef_fs/raw_request.rb +73 -0
  23. data/lib/chef_fs/version.rb +1 -1
  24. data/spec/support/integration_helper.rb +12 -1
  25. metadata +10 -6
  26. data/spec/chef_fs/file_system/chef_server_root_dir_spec.rb +0 -252
  27. data/spec/chef_fs/file_system/cookbook_dir_spec.rb +0 -582
  28. data/spec/chef_fs/file_system/cookbooks_dir_spec.rb +0 -165
  29. data/spec/chef_fs/file_system/data_bags_dir_spec.rb +0 -235
@@ -44,13 +44,10 @@ class Chef
44
44
  error = false
45
45
  begin
46
46
  patterns.each do |pattern|
47
- found_match = ChefFS::CommandLine.diff_print(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode, proc { |entry| format_path(entry) }, config[:diff_filter] ) do |diff|
47
+ found_error = ChefFS::CommandLine.diff_print(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode, proc { |entry| format_path(entry) }, config[:diff_filter], ui ) do |diff|
48
48
  stdout.print diff
49
49
  end
50
- if !found_match
51
- ui.error "#{pattern}: No such file or directory on remote or local"
52
- error = true
53
- end
50
+ error = true if found_error
54
51
  end
55
52
  rescue ChefFS::FileSystem::OperationFailedError => e
56
53
  ui.error "Failed on #{format_path(e.entry)} in #{e.operation}: #{e.message}"
@@ -1,6 +1,6 @@
1
1
  require 'json'
2
2
  require 'chef_fs/data_handler/data_handler_base'
3
- require 'chef_fs/file_system/base_fs_object'
3
+ require 'chef_fs/raw_request'
4
4
 
5
5
  class Chef
6
6
  class Knife
@@ -44,7 +44,7 @@ class Chef
44
44
  end
45
45
  chef_rest = Chef::REST.new(Chef::Config[:chef_server_url])
46
46
  begin
47
- output ::ChefFS::FileSystem::BaseFSObject.api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
47
+ output ChefFS::RawRequest.api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
48
48
  rescue Net::HTTPServerException => e
49
49
  ui.error "Server responded with error #{e.response.code} \"#{e.response.message}\""
50
50
  ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ''
@@ -17,18 +17,20 @@
17
17
  #
18
18
 
19
19
  require 'chef_fs/file_system'
20
+ require 'chef_fs/file_system/operation_failed_error'
21
+ require 'chef_fs/file_system/operation_not_allowed_error'
20
22
 
21
23
  module ChefFS
22
24
  module CommandLine
23
25
 
24
- def self.diff_print(pattern, a_root, b_root, recurse_depth, output_mode, format_path = nil, diff_filter = nil)
26
+ def self.diff_print(pattern, a_root, b_root, recurse_depth, output_mode, format_path = nil, diff_filter = nil, ui = nil)
25
27
  if format_path.nil?
26
28
  format_path = proc { |entry| entry.path_for_printing }
27
29
  end
28
30
 
29
31
  get_content = (output_mode != :name_only && output_mode != :name_status)
30
32
  found_match = false
31
- diff(pattern, a_root, b_root, recurse_depth, get_content) do |type, old_entry, new_entry, old_value, new_value|
33
+ diff(pattern, a_root, b_root, recurse_depth, get_content) do |type, old_entry, new_entry, old_value, new_value, error|
32
34
  found_match = true unless type == :both_nonexistent
33
35
  old_path = format_path.call(old_entry)
34
36
  new_path = format_path.call(new_entry)
@@ -104,9 +106,22 @@ module ChefFS
104
106
  when :deleted_cannot_download
105
107
  when :same
106
108
  # Skip these silently
109
+ when :error
110
+ if error.is_a?(ChefFS::FileSystem::OperationFailedError)
111
+ ui.error "#{format_path.call(error.entry)} failed to #{error.operation}: #{error.message}" if ui
112
+ error = true
113
+ elsif error.is_a?(ChefFS::FileSystem::OperationNotAllowedError)
114
+ ui.error "#{format_path.call(error.entry)} #{error.reason}." if ui
115
+ else
116
+ raise error
117
+ end
107
118
  end
108
119
  end
109
- found_match
120
+ if !found_match
121
+ ui.error "#{pattern}: No such file or directory on remote or local" if ui
122
+ error = true
123
+ end
124
+ error
110
125
  end
111
126
 
112
127
  def self.diff(pattern, a_root, b_root, recurse_depth, get_content)
@@ -119,98 +134,102 @@ module ChefFS
119
134
 
120
135
  # Diff two known entries (could be files or dirs)
121
136
  def self.diff_entries(old_entry, new_entry, recurse_depth, get_content)
122
- # If both are directories
123
- if old_entry.dir?
124
- if new_entry.dir?
125
- if recurse_depth == 0
126
- yield [ :common_subdirectories, old_entry, new_entry ]
127
- else
128
- ChefFS::FileSystem.child_pairs(old_entry, new_entry).each do |old_child,new_child|
129
- diff_entries(old_child, new_child,
130
- recurse_depth ? recurse_depth - 1 : nil, get_content) do |diff|
131
- yield diff
137
+ begin
138
+ # If both are directories
139
+ if old_entry.dir?
140
+ if new_entry.dir?
141
+ if recurse_depth == 0
142
+ yield [ :common_subdirectories, old_entry, new_entry ]
143
+ else
144
+ ChefFS::FileSystem.child_pairs(old_entry, new_entry).each do |old_child,new_child|
145
+ diff_entries(old_child, new_child,
146
+ recurse_depth ? recurse_depth - 1 : nil, get_content) do |diff|
147
+ yield diff
148
+ end
132
149
  end
133
150
  end
134
- end
135
151
 
136
- # If old is a directory and new is a file
137
- elsif new_entry.exists?
138
- yield [ :directory_to_file, old_entry, new_entry ]
139
-
140
- # If old is a directory and new does not exist
141
- elsif new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
142
- yield [ :deleted, old_entry, new_entry ]
143
- end
152
+ # If old is a directory and new is a file
153
+ elsif new_entry.exists?
154
+ yield [ :directory_to_file, old_entry, new_entry ]
144
155
 
145
- # If new is a directory and old is a file
146
- elsif new_entry.dir?
147
- if old_entry.exists?
148
- yield [ :file_to_directory, old_entry, new_entry ]
156
+ # If old is a directory and new does not exist
157
+ elsif new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
158
+ yield [ :deleted, old_entry, new_entry ]
159
+ end
149
160
 
150
- # If new is a directory and old does not exist
151
- elsif old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
152
- yield [ :added, old_entry, new_entry ]
153
- end
161
+ # If new is a directory and old is a file
162
+ elsif new_entry.dir?
163
+ if old_entry.exists?
164
+ yield [ :file_to_directory, old_entry, new_entry ]
154
165
 
155
- # Neither is a directory, so they are diffable with file diff
156
- else
157
- are_same, old_value, new_value = ChefFS::FileSystem.compare(old_entry, new_entry)
158
- if are_same
159
- if old_value == :none
160
- yield [ :both_nonexistent, old_entry, new_entry ]
161
- else
162
- yield [ :same, old_entry, new_entry ]
163
- end
164
- else
165
- if old_value == :none
166
- old_exists = false
167
- elsif old_value.nil?
168
- old_exists = old_entry.exists?
169
- else
170
- old_exists = true
166
+ # If new is a directory and old does not exist
167
+ elsif old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
168
+ yield [ :added, old_entry, new_entry ]
171
169
  end
172
170
 
173
- if new_value == :none
174
- new_exists = false
175
- elsif new_value.nil?
176
- new_exists = new_entry.exists?
171
+ # Neither is a directory, so they are diffable with file diff
172
+ else
173
+ are_same, old_value, new_value = ChefFS::FileSystem.compare(old_entry, new_entry)
174
+ if are_same
175
+ if old_value == :none
176
+ yield [ :both_nonexistent, old_entry, new_entry ]
177
+ else
178
+ yield [ :same, old_entry, new_entry ]
179
+ end
177
180
  else
178
- new_exists = true
179
- end
181
+ if old_value == :none
182
+ old_exists = false
183
+ elsif old_value.nil?
184
+ old_exists = old_entry.exists?
185
+ else
186
+ old_exists = true
187
+ end
180
188
 
181
- # If one of the files doesn't exist, we only want to print the diff if the
182
- # other file *could be uploaded/downloaded*.
183
- if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
184
- yield [ :old_cannot_upload, old_entry, new_entry ]
185
- return
186
- end
187
- if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
188
- yield [ :new_cannot_upload, old_entry, new_entry ]
189
- return
190
- end
189
+ if new_value == :none
190
+ new_exists = false
191
+ elsif new_value.nil?
192
+ new_exists = new_entry.exists?
193
+ else
194
+ new_exists = true
195
+ end
191
196
 
192
- if get_content
193
- # If we haven't read the values yet, get them now so that they can be diffed
194
- begin
195
- old_value = old_entry.read if old_value.nil?
196
- rescue ChefFS::FileSystem::NotFoundError
197
- old_value = :none
197
+ # If one of the files doesn't exist, we only want to print the diff if the
198
+ # other file *could be uploaded/downloaded*.
199
+ if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
200
+ yield [ :old_cannot_upload, old_entry, new_entry ]
201
+ return
198
202
  end
199
- begin
200
- new_value = new_entry.read if new_value.nil?
201
- rescue ChefFS::FileSystem::NotFoundError
202
- new_value = :none
203
+ if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
204
+ yield [ :new_cannot_upload, old_entry, new_entry ]
205
+ return
203
206
  end
204
- end
205
207
 
206
- if old_value == :none || (old_value == nil && !old_entry.exists?)
207
- yield [ :added, old_entry, new_entry, old_value, new_value ]
208
- elsif new_value == :none
209
- yield [ :deleted, old_entry, new_entry, old_value, new_value ]
210
- else
211
- yield [ :modified, old_entry, new_entry, old_value, new_value ]
208
+ if get_content
209
+ # If we haven't read the values yet, get them now so that they can be diffed
210
+ begin
211
+ old_value = old_entry.read if old_value.nil?
212
+ rescue ChefFS::FileSystem::NotFoundError
213
+ old_value = :none
214
+ end
215
+ begin
216
+ new_value = new_entry.read if new_value.nil?
217
+ rescue ChefFS::FileSystem::NotFoundError
218
+ new_value = :none
219
+ end
220
+ end
221
+
222
+ if old_value == :none || (old_value == nil && !old_entry.exists?)
223
+ yield [ :added, old_entry, new_entry, old_value, new_value ]
224
+ elsif new_value == :none
225
+ yield [ :deleted, old_entry, new_entry, old_value, new_value ]
226
+ else
227
+ yield [ :modified, old_entry, new_entry, old_value, new_value ]
228
+ end
212
229
  end
213
230
  end
231
+ rescue ChefFS::FileSystem::FileSystemError => e
232
+ yield [ :error, old_entry, new_entry, nil, nil, e ]
214
233
  end
215
234
  end
216
235
 
@@ -0,0 +1,22 @@
1
+ require 'chef_fs/data_handler/data_handler_base'
2
+
3
+ module ChefFS
4
+ module DataHandler
5
+ class AclDataHandler < DataHandlerBase
6
+ def normalize(node, entry)
7
+ # Normalize the order of the keys for easier reading
8
+ result = super(node, {
9
+ 'create' => {},
10
+ 'read' => {},
11
+ 'update' => {},
12
+ 'delete' => {},
13
+ 'grant' => {}
14
+ })
15
+ result.keys.each do |key|
16
+ result[key] = super(result[key], { 'actors' => [], 'groups' => [] })
17
+ end
18
+ result
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ require 'chef_fs/data_handler/data_handler_base'
2
+
3
+ module ChefFS
4
+ module DataHandler
5
+ class ContainerDataHandler < DataHandlerBase
6
+ def normalize(user, entry)
7
+ super(user, {
8
+ 'containername' => remove_dot_json(entry.name),
9
+ 'containerpath' => remove_dot_json(entry.name)
10
+ })
11
+ end
12
+
13
+ def preserve_key(key)
14
+ return key == 'containername'
15
+ end
16
+
17
+ # There is no chef_class for users, nor does to_ruby work.
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ require 'chef_fs/data_handler/data_handler_base'
2
+ require 'chef/api_client'
3
+
4
+ module ChefFS
5
+ module DataHandler
6
+ class GroupDataHandler < DataHandlerBase
7
+ def normalize(group, entry)
8
+ defaults = {
9
+ 'name' => remove_dot_json(entry.name),
10
+ 'groupname' => remove_dot_json(entry.name),
11
+ 'users' => [],
12
+ 'actors' => [],
13
+ 'clients' => [],
14
+ 'groups' => [],
15
+ }
16
+ if entry.org
17
+ defaults['orgname'] = entry.org
18
+ end
19
+ super(group, defaults)
20
+ end
21
+
22
+ def preserve_key(key)
23
+ return key == 'name'
24
+ end
25
+
26
+ def chef_class
27
+ Chef::ApiClient
28
+ end
29
+
30
+ # There is no Ruby API for Chef::ApiClient
31
+ end
32
+ end
33
+ end
@@ -6,7 +6,12 @@ module ChefFS
6
6
  def normalize(user, entry)
7
7
  super(user, {
8
8
  'name' => remove_dot_json(entry.name),
9
- 'admin' => false
9
+ 'admin' => false,
10
+ 'json_class' => 'Chef::WebUIUser',
11
+ 'chef_type' => 'webui_user',
12
+ 'salt' => nil,
13
+ 'password' => nil,
14
+ 'openid' => nil
10
15
  })
11
16
  end
12
17
 
@@ -0,0 +1,62 @@
1
+ #
2
+ # Author:: John Keiser (<jkeiser@opscode.com>)
3
+ # Copyright:: Copyright (c) 2013 Opscode, 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_fs/file_system/base_fs_dir'
20
+ require 'chef_fs/file_system/acl_entry'
21
+ require 'chef_fs/file_system/operation_not_allowed_error'
22
+
23
+ module ChefFS
24
+ module FileSystem
25
+ class AclDir < BaseFSDir
26
+ def api_path
27
+ parent.parent.child(name).api_path
28
+ end
29
+
30
+ def child(name)
31
+ result = @children.select { |child| child.name == name }.first if @children
32
+ result ||= can_have_child?(name, false) ?
33
+ AclEntry.new(name, self) : NonexistentFSObject.new(name, self)
34
+ end
35
+
36
+ def can_have_child?(name, is_dir)
37
+ name =~ /\.json$/ && !is_dir
38
+ end
39
+
40
+ def children
41
+ if @children.nil?
42
+ # Grab the ACTUAL children (/nodes, /containers, etc.) and get their names
43
+ names = parent.parent.child(name).children.map { |child| child.dir? ? "#{child.name}.json" : child.name }
44
+ @children = names.map { |name| AclEntry.new(name, self, true) }
45
+ end
46
+ @children
47
+ end
48
+
49
+ def create_child(name, file_contents)
50
+ raise OperationNotAllowedError.new(:create_child, self)
51
+ end
52
+
53
+ def data_handler
54
+ parent.data_handler
55
+ end
56
+
57
+ def rest
58
+ parent.rest
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
1
+ #
2
+ # Author:: John Keiser (<jkeiser@opscode.com>)
3
+ # Copyright:: Copyright (c) 2013 Opscode, 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_fs/file_system/rest_list_entry'
20
+ require 'chef_fs/file_system/not_found_error'
21
+ require 'chef_fs/file_system/operation_not_allowed_error'
22
+ require 'chef_fs/file_system/operation_failed_error'
23
+
24
+ module ChefFS
25
+ module FileSystem
26
+ class AclEntry < RestListEntry
27
+ PERMISSIONS = %w(create read update delete grant)
28
+
29
+ def api_path
30
+ "#{super}/_acl"
31
+ end
32
+
33
+ def delete(recurse)
34
+ raise ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self, e), "ACLs cannot be deleted."
35
+ end
36
+
37
+ def write(file_contents)
38
+ # ACL writes are fun.
39
+ acls = data_handler.normalize(JSON.parse(file_contents, :create_additions => false), self)
40
+ PERMISSIONS.each do |permission|
41
+ begin
42
+ rest.put_rest("#{api_path}/#{permission}", { permission => acls[permission] })
43
+ rescue Net::HTTPServerException => e
44
+ if e.response.code == "404"
45
+ raise ChefFS::FileSystem::NotFoundError.new(self, e)
46
+ else
47
+ raise ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end