knife-essentials 0.9.4 → 0.9.5

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.
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