chef 10.28.2 → 10.30.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/lib/chef.rb +1 -0
  2. data/lib/chef/application/knife.rb +2 -0
  3. data/lib/chef/client.rb +1 -1
  4. data/lib/chef/config.rb +5 -1
  5. data/lib/chef/cookbook_uploader.rb +7 -14
  6. data/lib/chef/data_bag.rb +2 -3
  7. data/lib/chef/exceptions.rb +9 -1
  8. data/lib/chef/formatters/error_inspectors/registration_error_inspector.rb +4 -0
  9. data/lib/chef/knife.rb +3 -0
  10. data/lib/chef/mixin/deep_merge.rb +53 -21
  11. data/lib/chef/monkey_patches/net_http.rb +34 -0
  12. data/lib/chef/monkey_patches/uri.rb +70 -0
  13. data/lib/chef/node.rb +5 -5
  14. data/lib/chef/platform.rb +1 -0
  15. data/lib/chef/provider/cookbook_file.rb +14 -6
  16. data/lib/chef/provider/directory.rb +16 -10
  17. data/lib/chef/provider/file.rb +23 -17
  18. data/lib/chef/provider/group.rb +50 -31
  19. data/lib/chef/provider/group/dscl.rb +26 -4
  20. data/lib/chef/provider/group/gpasswd.rb +14 -19
  21. data/lib/chef/provider/group/groupadd.rb +41 -1
  22. data/lib/chef/provider/group/groupmod.rb +46 -36
  23. data/lib/chef/provider/group/pw.rb +59 -16
  24. data/lib/chef/provider/group/suse.rb +16 -13
  25. data/lib/chef/provider/group/usermod.rb +40 -18
  26. data/lib/chef/provider/group/windows.rb +13 -6
  27. data/lib/chef/provider/package/yum.rb +1 -0
  28. data/lib/chef/provider/remote_file.rb +8 -2
  29. data/lib/chef/provider/ruby_block.rb +1 -1
  30. data/lib/chef/provider/template.rb +11 -5
  31. data/lib/chef/provider/user/useradd.rb +9 -1
  32. data/lib/chef/provider/whyrun_safe_ruby_block.rb +30 -0
  33. data/lib/chef/providers.rb +1 -0
  34. data/lib/chef/resource/group.rb +11 -1
  35. data/lib/chef/resource/whyrun_safe_ruby_block.rb +31 -0
  36. data/lib/chef/resources.rb +1 -0
  37. data/lib/chef/rest.rb +6 -2
  38. data/lib/chef/rest/rest_request.rb +6 -2
  39. data/lib/chef/util/windows/net_group.rb +5 -1
  40. data/lib/chef/version.rb +1 -1
  41. data/spec/functional/resource/base.rb +40 -0
  42. data/spec/functional/resource/group_spec.rb +343 -0
  43. data/spec/spec_helper.rb +4 -0
  44. data/spec/support/platform_helpers.rb +17 -0
  45. data/spec/unit/client_spec.rb +1 -1
  46. data/spec/unit/data_bag_spec.rb +4 -6
  47. data/spec/unit/mixin/deep_merge_spec.rb +416 -190
  48. data/spec/unit/monkey_patches/uri_spec.rb +34 -0
  49. data/spec/unit/node/attribute_spec.rb +49 -14
  50. data/spec/unit/node_spec.rb +31 -0
  51. data/spec/unit/provider/file_spec.rb +27 -27
  52. data/spec/unit/provider/group/dscl_spec.rb +1 -0
  53. data/spec/unit/provider/group/gpasswd_spec.rb +16 -9
  54. data/spec/unit/provider/group/groupadd_spec.rb +3 -4
  55. data/spec/unit/provider/group/groupmod_spec.rb +0 -1
  56. data/spec/unit/provider/group/pw_spec.rb +12 -15
  57. data/spec/unit/provider/group/usermod_spec.rb +21 -6
  58. data/spec/unit/provider/group/windows_spec.rb +0 -8
  59. data/spec/unit/provider/group_spec.rb +26 -4
  60. data/spec/unit/provider/user/useradd_spec.rb +21 -0
  61. data/spec/unit/provider/whyrun_safe_ruby_block_spec.rb +47 -0
  62. data/spec/unit/rest_spec.rb +55 -22
  63. metadata +119 -44
  64. checksums.yaml +0 -7
@@ -59,8 +59,8 @@ class Chef
59
59
  # find the lowest-level directory in @new_resource.path that already exists
60
60
  # make sure we have write permissions to that directory
61
61
  is_parent_writable = lambda do |base_dir|
62
- base_dir = ::File.dirname(base_dir)
63
- if ::File.exist?(base_dir)
62
+ base_dir = ::File.dirname(base_dir)
63
+ if ::File.exist?(base_dir)
64
64
  ::File.writable?(base_dir)
65
65
  else
66
66
  is_parent_writable.call(base_dir)
@@ -70,27 +70,27 @@ class Chef
70
70
  else
71
71
  # in why run mode & parent directory does not exist no permissions check is required
72
72
  # If not in why run, permissions must be valid and we rely on prior assertion that dir exists
73
- if !whyrun_mode? || ::File.exist?(parent_directory)
73
+ if !whyrun_mode? || ::File.exist?(parent_directory)
74
74
  ::File.writable?(parent_directory)
75
75
  else
76
76
  true
77
77
  end
78
78
  end
79
79
  end
80
- a.failure_message(Chef::Exceptions::InsufficientPermissions,
80
+ a.failure_message(Chef::Exceptions::InsufficientPermissions,
81
81
  "Cannot create #{@new_resource} at #{@new_resource.path} due to insufficient permissions")
82
82
  end
83
83
 
84
- requirements.assert(:delete) do |a|
85
- a.assertion do
84
+ requirements.assert(:delete) do |a|
85
+ a.assertion do
86
86
  if ::File.exist?(@new_resource.path)
87
- ::File.directory?(@new_resource.path) && ::File.writable?(@new_resource.path)
87
+ ::File.directory?(@new_resource.path) && ::File.writable?(@new_resource.path)
88
88
  else
89
89
  true
90
90
  end
91
91
  end
92
92
  a.failure_message(RuntimeError, "Cannot delete #{@new_resource} at #{@new_resource.path}!")
93
- # No why-run handling here:
93
+ # No why-run handling here:
94
94
  # * if we don't have permissions, this is unlikely to be changed earlier in the run
95
95
  # * if the target is a file (not a dir), there's no reasonable path by which this would have been changed
96
96
  end
@@ -98,14 +98,14 @@ class Chef
98
98
 
99
99
  def action_create
100
100
  unless ::File.exist?(@new_resource.path)
101
- converge_by("create new directory #{@new_resource.path}") do
101
+ converge_by("create new directory #{@new_resource.path}") do
102
102
  if @new_resource.recursive == true
103
103
  ::FileUtils.mkdir_p(@new_resource.path)
104
104
  else
105
105
  ::Dir.mkdir(@new_resource.path)
106
106
  end
107
107
  Chef::Log.info("#{@new_resource} created directory #{@new_resource.path}")
108
- end
108
+ end
109
109
  end
110
110
  set_all_access_controls
111
111
  end
@@ -123,6 +123,12 @@ class Chef
123
123
  end
124
124
  end
125
125
  end
126
+
127
+ private
128
+
129
+ def managing_content?
130
+ false
131
+ end
126
132
  end
127
133
  end
128
134
  end
@@ -48,9 +48,9 @@ class Chef
48
48
 
49
49
  def diff_current_from_content(new_content)
50
50
  result = nil
51
- Tempfile.open("chef-diff") do |file|
51
+ Tempfile.open("chef-diff") do |file|
52
52
  file.write new_content
53
- file.close
53
+ file.close
54
54
  result = diff_current file.path
55
55
  end
56
56
  result
@@ -96,12 +96,12 @@ class Chef
96
96
  # -u: Unified diff format
97
97
  result = shell_out("diff -u #{target_path} #{temp_path}" )
98
98
  rescue Exception => e
99
- # Should *not* receive this, but in some circumstances it seems that
99
+ # Should *not* receive this, but in some circumstances it seems that
100
100
  # an exception can be thrown even using shell_out instead of shell_out!
101
101
  return [ "Could not determine diff. Error: #{e.message}" ]
102
102
  end
103
103
 
104
- # diff will set a non-zero return code even when there's
104
+ # diff will set a non-zero return code even when there's
105
105
  # valid stdout results, if it encounters something unexpected
106
106
  # So as long as we have output, we'll show it.
107
107
  if not result.stdout.empty?
@@ -118,7 +118,7 @@ class Chef
118
118
  else
119
119
  [ "(no diff)" ]
120
120
  end
121
- end
121
+ end
122
122
 
123
123
  def whyrun_supported?
124
124
  true
@@ -132,14 +132,14 @@ class Chef
132
132
  @current_resource.path(@new_resource.path)
133
133
  if !::File.directory?(@new_resource.path)
134
134
  if ::File.exist?(@new_resource.path)
135
- if @action != :create_if_missing
135
+ if managing_content?
136
136
  @current_resource.checksum(checksum(@new_resource.path))
137
137
  end
138
138
  end
139
139
  end
140
140
  load_current_resource_attrs
141
141
  setup_acl
142
-
142
+
143
143
  @current_resource
144
144
  end
145
145
 
@@ -159,7 +159,7 @@ class Chef
159
159
 
160
160
  if @new_resource.group.nil?
161
161
  @new_resource.group(@current_resource.group)
162
- end
162
+ end
163
163
  if @new_resource.owner.nil?
164
164
  @new_resource.owner(@current_resource.owner)
165
165
  end
@@ -168,7 +168,7 @@ class Chef
168
168
  end
169
169
  end
170
170
  end
171
-
171
+
172
172
  def setup_acl
173
173
  @acl_scanner = ScanAccessControl.new(@new_resource, @current_resource)
174
174
  @acl_scanner.set_all!
@@ -191,7 +191,7 @@ class Chef
191
191
  # Make sure the file is deletable if it exists. Otherwise, fail.
192
192
  requirements.assert(:delete) do |a|
193
193
  a.assertion do
194
- if ::File.exists?(@new_resource.path)
194
+ if ::File.exists?(@new_resource.path)
195
195
  ::File.writable?(@new_resource.path)
196
196
  else
197
197
  true
@@ -211,7 +211,7 @@ class Chef
211
211
  unless compare_content
212
212
  description = []
213
213
  description << "update content in file #{@new_resource.path} from #{short_cksum(@current_resource.checksum)} to #{short_cksum(new_resource_content_checksum)}"
214
- description << diff_current_from_content(@new_resource.content)
214
+ description << diff_current_from_content(@new_resource.content)
215
215
  converge_by(description) do
216
216
  backup @new_resource.path if ::File.exists?(@new_resource.path)
217
217
  ::File.open(@new_resource.path, "w") {|f| f.write @new_resource.content }
@@ -221,10 +221,10 @@ class Chef
221
221
  end
222
222
 
223
223
  # if you are using a tempfile before creating, you must
224
- # override the default with the tempfile, since the
224
+ # override the default with the tempfile, since the
225
225
  # file at @new_resource.path will not be updated on converge
226
226
  def update_new_file_state(path=@new_resource.path)
227
- if !::File.directory?(path)
227
+ if !::File.directory?(path)
228
228
  @new_resource.checksum(checksum(path))
229
229
  end
230
230
 
@@ -247,8 +247,8 @@ class Chef
247
247
  desc = "create new file #{@new_resource.path}"
248
248
  desc << " with content checksum #{short_cksum(new_resource_content_checksum)}" if new_resource.content
249
249
  description << desc
250
- description << diff_current_from_content(@new_resource.content)
251
-
250
+ description << diff_current_from_content(@new_resource.content)
251
+
252
252
  converge_by(description) do
253
253
  Chef::Log.info("entered create")
254
254
  ::File.open(@new_resource.path, "w+") {|f| f.write @new_resource.content }
@@ -264,7 +264,7 @@ class Chef
264
264
 
265
265
  def set_all_access_controls
266
266
  if access_controls.requires_changes?
267
- converge_by(access_controls.describe_changes) do
267
+ converge_by(access_controls.describe_changes) do
268
268
  access_controls.set_all
269
269
  #Update file state with new access values
270
270
  update_new_file_state
@@ -282,7 +282,7 @@ class Chef
282
282
 
283
283
  def action_delete
284
284
  if ::File.exists?(@new_resource.path)
285
- converge_by("delete file #{@new_resource.path}") do
285
+ converge_by("delete file #{@new_resource.path}") do
286
286
  backup unless ::File.symlink?(@new_resource.path)
287
287
  ::File.delete(@new_resource.path)
288
288
  Chef::Log.info("#{@new_resource} deleted file at #{@new_resource.path}")
@@ -342,6 +342,12 @@ class Chef
342
342
 
343
343
  private
344
344
 
345
+ def managing_content?
346
+ return true if @new_resource.checksum
347
+ return true if !@new_resource.content.nil? && @action != :create_if_missing
348
+ false
349
+ end
350
+
345
351
  def short_cksum(checksum)
346
352
  return "none" if checksum.nil?
347
353
  checksum.slice(0,6)
@@ -6,9 +6,9 @@
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
8
8
  # You may obtain a copy of the License at
9
- #
9
+ #
10
10
  # http://www.apache.org/licenses/LICENSE-2.0
11
- #
11
+ #
12
12
  # Unless required by applicable law or agreed to in writing, software
13
13
  # distributed under the License is distributed on an "AS IS" BASIS,
14
14
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -36,11 +36,11 @@ class Chef
36
36
  super
37
37
  @group_exists = true
38
38
  end
39
-
39
+
40
40
  def load_current_resource
41
41
  @current_resource = Chef::Resource::Group.new(@new_resource.name)
42
42
  @current_resource.group_name(@new_resource.group_name)
43
-
43
+
44
44
  group_info = nil
45
45
  begin
46
46
  group_info = Etc.getgrnam(@new_resource.group_name)
@@ -48,37 +48,47 @@ class Chef
48
48
  @group_exists = false
49
49
  Chef::Log.debug("#{@new_resource} group does not exist")
50
50
  end
51
-
51
+
52
52
  if group_info
53
53
  @new_resource.gid(group_info.gid) unless @new_resource.gid
54
54
  @current_resource.gid(group_info.gid)
55
55
  @current_resource.members(group_info.mem)
56
56
  end
57
-
57
+
58
58
  @current_resource
59
59
  end
60
60
 
61
61
  def define_resource_requirements
62
- requirements.assert(:modify) do |a|
63
- a.assertion { @group_exists }
62
+ requirements.assert(:modify) do |a|
63
+ a.assertion { @group_exists }
64
64
  a.failure_message(Chef::Exceptions::Group, "Cannot modify #{@new_resource} - group does not exist!")
65
65
  a.whyrun("Group #{@new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.")
66
66
  end
67
+
68
+ requirements.assert(:all_actions) do |a|
69
+ # Make sure that the resource doesn't contain any common
70
+ # user names in the members and exclude_members properties.
71
+ if !@new_resource.members.nil? && !@new_resource.excluded_members.nil?
72
+ common_members = @new_resource.members & @new_resource.excluded_members
73
+ a.assertion { common_members.empty? }
74
+ a.failure_message(Chef::Exceptions::ConflictingMembersInGroup, "Attempting to both add and remove users from a group: '#{common_members.join(', ')}'")
75
+ # No why-run alternative
76
+ end
77
+ end
67
78
  end
68
-
69
- # Check to see if a group needs any changes. Populate
70
- # @change_desc with a description of why a change must occur
79
+
80
+ # Check to see if a group needs any changes. Populate
81
+ # @change_desc with a description of why a change must occur
71
82
  #
72
83
  # ==== Returns
73
84
  # <true>:: If a change is required
74
85
  # <false>:: If a change is not required
75
86
  def compare_group
76
- @change_desc = nil
87
+ @change_desc = [ ]
77
88
  if @new_resource.gid != @current_resource.gid
78
- @change_desc = "change gid #{@current_resource.gid} to #{@new_resource.gid}"
79
- return true
89
+ @change_desc << "change gid #{@current_resource.gid} to #{@new_resource.gid}"
80
90
  end
81
-
91
+
82
92
  if(@new_resource.append)
83
93
  missing_members = []
84
94
  @new_resource.members.each do |member|
@@ -86,35 +96,44 @@ class Chef
86
96
  missing_members << member
87
97
  end
88
98
  if missing_members.length > 0
89
- @change_desc = "add missing member(s): #{missing_members.join(", ")}"
90
- return true
99
+ @change_desc << "add missing member(s): #{missing_members.join(", ")}"
100
+ end
101
+
102
+ members_to_be_removed = []
103
+ @new_resource.excluded_members.each do |member|
104
+ if @current_resource.members.include?(member)
105
+ members_to_be_removed << member
106
+ end
107
+ end
108
+ if members_to_be_removed.length > 0
109
+ @change_desc << "remove existing member(s): #{members_to_be_removed.join(", ")}"
91
110
  end
92
111
  else
93
112
  if @new_resource.members != @current_resource.members
94
- @change_desc = "replace group members with new list of members"
95
- return true
113
+ @change_desc << "replace group members with new list of members"
96
114
  end
97
115
  end
98
- return false
116
+
117
+ !@change_desc.empty?
99
118
  end
100
-
119
+
101
120
  def action_create
102
121
  case @group_exists
103
122
  when false
104
- converge_by("create #{@new_resource}") do
123
+ converge_by("create #{@new_resource}") do
105
124
  create_group
106
125
  Chef::Log.info("#{@new_resource} created")
107
126
  end
108
- else
127
+ else
109
128
  if compare_group
110
- converge_by(["alter group #{@new_resource}", @change_desc ]) do
129
+ converge_by(["alter group #{@new_resource}"] + change_desc) do
111
130
  manage_group
112
131
  Chef::Log.info("#{@new_resource} altered")
113
132
  end
114
133
  end
115
134
  end
116
135
  end
117
-
136
+
118
137
  def action_remove
119
138
  if @group_exists
120
139
  converge_by("remove group #{@new_resource}") do
@@ -123,25 +142,25 @@ class Chef
123
142
  end
124
143
  end
125
144
  end
126
-
145
+
127
146
  def action_manage
128
147
  if @group_exists && compare_group
129
- converge_by(["manage group #{@new_resource}", @change_desc]) do
130
- manage_group
148
+ converge_by(["manage group #{@new_resource}"] + change_desc) do
149
+ manage_group
131
150
  Chef::Log.info("#{@new_resource} managed")
132
151
  end
133
152
  end
134
153
  end
135
-
154
+
136
155
  def action_modify
137
156
  if compare_group
138
- converge_by(["modify group #{@new_resource}", @change_desc]) do
157
+ converge_by(["modify group #{@new_resource}"] + change_desc) do
139
158
  manage_group
140
159
  Chef::Log.info("#{@new_resource} modified")
141
160
  end
142
161
  end
143
162
  end
144
-
163
+
145
164
  def create_group
146
165
  raise NotImplementedError, "subclasses of Chef::Provider::Group should define #create_group"
147
166
  end
@@ -73,14 +73,36 @@ class Chef
73
73
  end
74
74
 
75
75
  def set_members
76
+ # First reset the memberships if the append is not set
76
77
  unless @new_resource.append
77
78
  Chef::Log.debug("#{@new_resource} removing group members #{@current_resource.members.join(' ')}") unless @current_resource.members.empty?
78
79
  safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembers ''") # clear guid list
79
80
  safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembership ''") # clear user list
81
+ @current_resource.members([ ])
80
82
  end
81
- unless @new_resource.members.empty?
82
- Chef::Log.debug("#{@new_resource} setting group members #{@new_resource.members.join(', ')}")
83
- safe_dscl("append /Groups/#{@new_resource.group_name} GroupMembership #{@new_resource.members.join(' ')}")
83
+
84
+ # Add any members that need to be added
85
+ if @new_resource.members && !@new_resource.members.empty?
86
+ members_to_be_added = [ ]
87
+ @new_resource.members.each do |member|
88
+ members_to_be_added << member if !@current_resource.members.include?(member)
89
+ end
90
+ unless members_to_be_added.empty?
91
+ Chef::Log.debug("#{@new_resource} setting group members #{members_to_be_added.join(', ')}")
92
+ safe_dscl("append /Groups/#{@new_resource.group_name} GroupMembership #{members_to_be_added.join(' ')}")
93
+ end
94
+ end
95
+
96
+ # Remove any members that need to be removed
97
+ if @new_resource.excluded_members && !@new_resource.excluded_members.empty?
98
+ members_to_be_removed = [ ]
99
+ @new_resource.excluded_members.each do |member|
100
+ members_to_be_removed << member if @current_resource.members.include?(member)
101
+ end
102
+ unless members_to_be_removed.empty?
103
+ Chef::Log.debug("#{@new_resource} removing group members #{members_to_be_removed.join(', ')}")
104
+ safe_dscl("delete /Groups/#{@new_resource.group_name} GroupMembership #{members_to_be_removed.join(' ')}")
105
+ end
84
106
  end
85
107
  end
86
108
 
@@ -110,7 +132,7 @@ class Chef
110
132
  if @new_resource.gid && (@current_resource.gid != @new_resource.gid)
111
133
  set_gid
112
134
  end
113
- if @new_resource.members && (@current_resource.members != @new_resource.members)
135
+ if @new_resource.members || @new_resource.excluded_members
114
136
  set_members
115
137
  end
116
138
  end
@@ -39,25 +39,20 @@ class Chef
39
39
  end
40
40
  end
41
41
 
42
- def modify_group_members
43
- if(@new_resource.append)
44
- unless @new_resource.members.empty?
45
- @new_resource.members.each do |member|
46
- Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}")
47
- shell_out!("gpasswd -a #{member} #{@new_resource.group_name}")
48
- end
49
- else
50
- Chef::Log.debug("#{@new_resource} not changing group members, the group has no members to add")
51
- end
52
- else
53
- unless @new_resource.members.empty?
54
- Chef::Log.debug("#{@new_resource} setting group members to #{@new_resource.members.join(', ')}")
55
- shell_out!("gpasswd -M #{@new_resource.members.join(',')} #{@new_resource.group_name}")
56
- else
57
- Chef::Log.debug("#{@new_resource} setting group members to: none")
58
- shell_out!("gpasswd -M \"\" #{@new_resource.group_name}")
59
- end
60
- end
42
+ def set_members(members)
43
+ unless members.empty?
44
+ shell_out!("gpasswd -M #{members.join(',')} #{@new_resource.group_name}")
45
+ else
46
+ shell_out!("gpasswd -M \"\" #{@new_resource.group_name}")
47
+ end
48
+ end
49
+
50
+ def add_member(member)
51
+ shell_out!("gpasswd -a #{member} #{@new_resource.group_name}")
52
+ end
53
+
54
+ def remove_member(member)
55
+ shell_out!("gpasswd -d #{member} #{@new_resource.group_name}")
61
56
  end
62
57
  end
63
58
  end