chef 11.14.6 → 11.16.0.rc.0

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.
@@ -0,0 +1,46 @@
1
+ #
2
+ # Author:: Adam Edwards (<adamed@getchef.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2014 Chef Software, Inc.
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 'json'
20
+
21
+ class Chef::Util::Powershell
22
+ class CmdletResult
23
+ attr_reader :output_format
24
+
25
+ def initialize(status, output_format)
26
+ @status = status
27
+ @output_format = output_format
28
+ end
29
+
30
+ def stderr
31
+ @status.stderr
32
+ end
33
+
34
+ def return_value
35
+ if output_format == :object
36
+ JSON.parse(@status.stdout)
37
+ else
38
+ @status.stdout
39
+ end
40
+ end
41
+
42
+ def succeeded?
43
+ @succeeded = @status.status.exitstatus == 0
44
+ end
45
+ end
46
+ end
@@ -17,7 +17,7 @@
17
17
 
18
18
  class Chef
19
19
  CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
20
- VERSION = '11.14.6'
20
+ VERSION = '11.16.0.rc.0'
21
21
  end
22
22
 
23
23
  # NOTE: the Chef::Version class is defined in version_class.rb
@@ -0,0 +1,336 @@
1
+ #
2
+ # Author:: Adam Edwards (<adamed@getchef.com>)
3
+ # Copyright:: Copyright (c) 2014 Chef Software, 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 'spec_helper'
20
+ require 'chef/mixin/shell_out'
21
+ require 'chef/mixin/windows_architecture_helper'
22
+
23
+ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
24
+ include Chef::Mixin::WindowsArchitectureHelper
25
+ before(:all) do
26
+ @temp_dir = ::Dir.mktmpdir("dsc-functional-test")
27
+ end
28
+
29
+ after(:all) do
30
+ ::FileUtils.rm_rf(@temp_dir) if ::Dir.exist?(@temp_dir)
31
+ end
32
+
33
+ include Chef::Mixin::ShellOut
34
+
35
+ def create_config_script_from_code(code, configuration_name, data = false)
36
+ script_code = data ? code : "Configuration '#{configuration_name}'\n{\n\t#{code}\n}\n"
37
+ data_suffix = data ? '_config_data' : ''
38
+ extension = data ? 'psd1' : 'ps1'
39
+ script_path = "#{@temp_dir}/dsc_functional_test#{data_suffix}.#{extension}"
40
+ ::File.open(script_path, 'wt') do | script |
41
+ script.write(script_code)
42
+ end
43
+ script_path
44
+ end
45
+
46
+ def user_exists?(target_user)
47
+ result = false
48
+ begin
49
+ shell_out!("net user #{target_user}")
50
+ result = true
51
+ rescue Mixlib::ShellOut::ShellCommandFailed
52
+ end
53
+ result
54
+ end
55
+
56
+ def delete_user(target_user)
57
+ begin
58
+ shell_out!("net user #{target_user} /delete")
59
+ rescue Mixlib::ShellOut::ShellCommandFailed
60
+ end
61
+ end
62
+
63
+ let(:dsc_env_variable) { 'chefenvtest' }
64
+ let(:dsc_env_value1) { 'value1' }
65
+ let(:env_value2) { 'value2' }
66
+ let(:dsc_test_run_context) {
67
+ node = Chef::Node.new
68
+ node.default['platform'] = 'windows'
69
+ node.default['platform_version'] = '6.1'
70
+ node.default['kernel'][:machine] =
71
+ is_i386_process_on_x86_64_windows? ? :x86_64 : :i386
72
+ empty_events = Chef::EventDispatch::Dispatcher.new
73
+ Chef::RunContext.new(node, {}, empty_events)
74
+ }
75
+ let(:dsc_test_resource_name) { 'DSCTest' }
76
+ let(:dsc_test_resource_base) {
77
+ Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
78
+ }
79
+ let(:test_registry_key) { 'HKEY_LOCAL_MACHINE\Software\Chef\Spec\Functional\Resource\dsc_script_spec' }
80
+ let(:test_registry_value) { 'Registration' }
81
+ let(:test_registry_data1) { 'LL927' }
82
+ let(:test_registry_data2) { 'LL928' }
83
+ let(:dsc_code) { <<-EOH
84
+ Registry "ChefRegKey"
85
+ {
86
+ Key = '#{test_registry_key}'
87
+ ValueName = '#{test_registry_value}'
88
+ ValueData = '#{test_registry_data}'
89
+ Ensure = 'Present'
90
+ }
91
+ EOH
92
+ }
93
+
94
+ let(:dsc_user_prefix) { 'dsc' }
95
+ let(:dsc_user_suffix) { 'chefx' }
96
+ let(:dsc_user) {"#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
97
+ let(:dsc_user_prefix_env_var_name) { 'dsc_user_env_prefix' }
98
+ let(:dsc_user_suffix_env_var_name) { 'dsc_user_env_suffix' }
99
+ let(:dsc_user_prefix_env_code) { "$env:#{dsc_user_prefix_env_var_name}"}
100
+ let(:dsc_user_suffix_env_code) { "$env:#{dsc_user_suffix_env_var_name}"}
101
+ let(:dsc_user_prefix_param_name) { 'dsc_user_prefix_param' }
102
+ let(:dsc_user_suffix_param_name) { 'dsc_user_suffix_param' }
103
+ let(:dsc_user_prefix_param_code) { "$#{dsc_user_prefix_param_name}"}
104
+ let(:dsc_user_suffix_param_code) { "$#{dsc_user_suffix_param_name}"}
105
+ let(:dsc_user_env_code) { "\"$(#{dsc_user_prefix_env_code})_usr_$(#{dsc_user_suffix_env_code})\""}
106
+ let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\""}
107
+
108
+ let(:config_flags) { nil }
109
+ let(:config_params) { <<-EOH
110
+
111
+ [CmdletBinding()]
112
+ param
113
+ (
114
+ $#{dsc_user_prefix_param_name},
115
+ $#{dsc_user_suffix_param_name}
116
+ )
117
+ EOH
118
+ }
119
+
120
+ let(:config_param_section) { '' }
121
+ let(:dsc_user_code) { "'#{dsc_user}'" }
122
+ let(:dsc_user_prefix_code) { dsc_user_prefix }
123
+ let(:dsc_user_suffix_code) { dsc_user_suffix }
124
+ let(:dsc_script_environment_attribute) { nil }
125
+ let(:dsc_user_resources_code) { <<-EOH
126
+ #{config_param_section}
127
+ node localhost
128
+ {
129
+ $testuser = #{dsc_user_code}
130
+ $testpassword = ConvertTo-SecureString -String "jf9a8m49jrajf4#" -AsPlainText -Force
131
+ $testcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testuser, $testpassword
132
+
133
+ User dsctestusercreate
134
+ {
135
+ UserName = $testuser
136
+ Password = $testcred
137
+ Description = "DSC test user"
138
+ Ensure = "Present"
139
+ Disabled = $false
140
+ PasswordNeverExpires = $true
141
+ PasswordChangeRequired = $false
142
+ }
143
+ }
144
+ EOH
145
+ }
146
+
147
+ let(:dsc_user_config_data) {
148
+ <<-EOH
149
+ @{
150
+ AllNodes = @(
151
+ @{
152
+ NodeName = "localhost";
153
+ PSDscAllowPlainTextPassword = $true
154
+ }
155
+ )
156
+ }
157
+
158
+ EOH
159
+ }
160
+
161
+ let(:dsc_environment_env_var_name) { 'dsc_test_cwd' }
162
+ let(:dsc_environment_no_fail_not_etc_directory) { "#{ENV['systemroot']}\\system32" }
163
+ let(:dsc_environment_fail_etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
164
+ let(:exception_message_signature) { 'LL927-LL928' }
165
+ let(:dsc_environment_config) {<<-EOH
166
+ if (($pwd.path -eq '#{dsc_environment_fail_etc_directory}') -and (test-path('#{dsc_environment_fail_etc_directory}')))
167
+ {
168
+ throw 'Signature #{exception_message_signature}: Purposefully failing because cwd == #{dsc_environment_fail_etc_directory}'
169
+ }
170
+ environment "whatsmydir"
171
+ {
172
+ Name = '#{dsc_environment_env_var_name}'
173
+ Value = $pwd.path
174
+ Ensure = 'Present'
175
+ }
176
+ EOH
177
+ }
178
+
179
+ let(:dsc_config_name) {
180
+ dsc_test_resource_base.name
181
+ }
182
+ let(:dsc_resource_from_code) {
183
+ dsc_test_resource_base.code(dsc_code)
184
+ dsc_test_resource_base
185
+ }
186
+ let(:config_name_value) { dsc_test_resource_base.name }
187
+
188
+ let(:dsc_resource_from_path) {
189
+ dsc_test_resource_base.command(create_config_script_from_code(dsc_code, config_name_value))
190
+ dsc_test_resource_base
191
+ }
192
+
193
+ before(:each) do
194
+ test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
195
+ test_key_resource.recursive(true)
196
+ test_key_resource.run_action(:delete_key)
197
+ end
198
+
199
+ after(:each) do
200
+ test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
201
+ test_key_resource.recursive(true)
202
+ test_key_resource.run_action(:delete_key)
203
+ end
204
+
205
+ shared_examples_for 'a dsc_script resource with specified PowerShell configuration code' do
206
+ let(:test_registry_data) { test_registry_data1 }
207
+ it 'should create a registry key with a specific registry value and data' do
208
+ expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
209
+ dsc_test_resource.run_action(:run)
210
+ expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
211
+ expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
212
+ end
213
+
214
+ it_should_behave_like 'a dsc_script resource with configuration affected by cwd'
215
+ end
216
+
217
+ shared_examples_for 'a dsc_script resource with configuration affected by cwd' do
218
+ after(:each) do
219
+ removal_resource = Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
220
+ removal_resource.code <<-EOH
221
+ environment 'removethis'
222
+ {
223
+ Name = '#{dsc_environment_env_var_name}'
224
+ Ensure = 'Absent'
225
+ }
226
+ EOH
227
+ removal_resource.run_action(:run)
228
+ end
229
+ let(:dsc_code) { dsc_environment_config }
230
+ it 'should not raise an exception if the cwd is not etc' do
231
+ dsc_test_resource.cwd(dsc_environment_no_fail_not_etc_directory)
232
+ expect {dsc_test_resource.run_action(:run)}.not_to raise_error
233
+ end
234
+
235
+ it 'should raise an exception if the cwd is etc' do
236
+ dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
237
+ expect {dsc_test_resource.run_action(:run)}.to raise_error(Chef::Exceptions::PowershellCmdletException)
238
+ begin
239
+ dsc_test_resource.run_action(:run)
240
+ rescue Chef::Exceptions::PowershellCmdletException => e
241
+ expect(e.message).to match(exception_message_signature)
242
+ end
243
+ end
244
+ end
245
+
246
+ shared_examples_for 'a parameterized DSC configuration script' do
247
+ context 'when specifying environment variables in the environment attribute' do
248
+ let(:dsc_user_prefix_code) { dsc_user_prefix_env_code }
249
+ let(:dsc_user_suffix_code) { dsc_user_suffix_env_code }
250
+ it_behaves_like 'a dsc_script with configuration that uses environment variables'
251
+ end
252
+ end
253
+
254
+ shared_examples_for 'a dsc_script with configuration data' do
255
+ context 'when using the configuration_data attribute' do
256
+ let(:configuration_data_attribute) { 'configuration_data' }
257
+ it_behaves_like 'a dsc_script with configuration data set via an attribute'
258
+ end
259
+
260
+ context 'when using the configuration_data_script attribute' do
261
+ let(:configuration_data_attribute) { 'configuration_data_script' }
262
+ it_behaves_like 'a dsc_script with configuration data set via an attribute'
263
+ end
264
+ end
265
+
266
+ shared_examples_for 'a dsc_script with configuration data set via an attribute' do
267
+ it 'should run a configuration script that creates a user' do
268
+ config_data_value = dsc_user_config_data
269
+ dsc_test_resource.configuration_name(config_name_value)
270
+ if configuration_data_attribute == 'configuration_data_script'
271
+ config_data_value = create_config_script_from_code(dsc_user_config_data, '', true)
272
+ end
273
+ dsc_test_resource.environment({dsc_user_prefix_env_var_name => dsc_user_prefix,
274
+ dsc_user_suffix_env_var_name => dsc_user_suffix})
275
+ dsc_test_resource.send(configuration_data_attribute, config_data_value)
276
+ dsc_test_resource.flags(config_flags)
277
+ expect(user_exists?(dsc_user)).to eq(false)
278
+ expect {dsc_test_resource.run_action(:run)}.not_to raise_error
279
+ expect(user_exists?(dsc_user)).to eq(true)
280
+ end
281
+ end
282
+
283
+ shared_examples_for 'a dsc_script with configuration data that takes parameters' do
284
+ context 'when script code takes parameters for configuration' do
285
+ let(:dsc_user_code) { dsc_user_param_code }
286
+ let(:config_param_section) { config_params }
287
+ let(:config_flags) {{:"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}"}}
288
+ it 'does not directly contain the user name' do
289
+ configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
290
+ file.read
291
+ end
292
+ expect(configuration_script_content.include?(dsc_user)).to be(false)
293
+ end
294
+ it_behaves_like 'a dsc_script with configuration data'
295
+ end
296
+
297
+ end
298
+
299
+ shared_examples_for 'a dsc_script with configuration data that uses environment variables' do
300
+ context 'when script code uses environment variables' do
301
+ let(:dsc_user_code) { dsc_user_env_code }
302
+
303
+ it 'does not directly contain the user name' do
304
+ configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
305
+ file.read
306
+ end
307
+ expect(configuration_script_content.include?(dsc_user)).to be(false)
308
+ end
309
+ it_behaves_like 'a dsc_script with configuration data'
310
+ end
311
+ end
312
+
313
+ context 'when supplying configuration through the configuration attribute' do
314
+ let(:dsc_test_resource) { dsc_resource_from_code }
315
+ it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
316
+ end
317
+
318
+ context 'when supplying configuration using the path attribute' do
319
+ let(:dsc_test_resource) { dsc_resource_from_path }
320
+ it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
321
+ end
322
+
323
+ context 'when running a configuration that manages users' do
324
+ before(:each) do
325
+ delete_user(dsc_user)
326
+ end
327
+
328
+ let(:dsc_code) { dsc_user_resources_code }
329
+ let(:config_name_value) { 'DSCTestConfig' }
330
+ let(:dsc_test_resource) { dsc_resource_from_path }
331
+
332
+ it_behaves_like 'a dsc_script with configuration data'
333
+ it_behaves_like 'a dsc_script with configuration data that uses environment variables'
334
+ it_behaves_like 'a dsc_script with configuration data that takes parameters'
335
+ end
336
+ end
@@ -40,6 +40,11 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
40
40
  when "windows"
41
41
  user_sid = sid_string_from_user(user)
42
42
  user_sid.nil? ? false : Chef::Util::Windows::NetGroup.new(group_name).local_get_members.include?(user_sid)
43
+ when "mac_os_x"
44
+ membership_info = shell_out("dscl . -read /Groups/#{group_name}").stdout
45
+ members = membership_info.split(" ")
46
+ members.shift # Get rid of GroupMembership: string
47
+ members.include?(user)
43
48
  else
44
49
  Etc::getgrnam(group_name).mem.include?(user)
45
50
  end
@@ -420,4 +425,3 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
420
425
  end
421
426
  end
422
427
  end
423
-
@@ -0,0 +1,114 @@
1
+ #
2
+ # Author:: Adam Edwards (<adamed@getchef.com>)
3
+ #
4
+ # Copyright:: 2014, Chef Software, Inc.
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 'json'
20
+ require File.expand_path('../../../../spec_helper', __FILE__)
21
+
22
+ describe Chef::Util::Powershell::Cmdlet, :windows_only do
23
+ before(:all) do
24
+ ohai = Ohai::System.new
25
+ ohai.load_plugins
26
+ ohai.run_plugins(true, ['platform', 'kernel'])
27
+ @node = Chef::Node.new
28
+ @node.consume_external_attrs(ohai.data, {})
29
+ end
30
+ let(:cmd_output_format) { :text }
31
+ let(:simple_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-childitem', cmd_output_format, {:depth => 2}) }
32
+ let(:invalid_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-idontexist', cmd_output_format) }
33
+ let(:cmdlet_get_item_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-item', cmd_output_format, {:depth => 2}) }
34
+ let(:cmdlet_alias_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'alias', cmd_output_format, {:depth => 2}) }
35
+ let(:etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
36
+ let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE")}
37
+
38
+ it "executes a simple process" do
39
+ result = simple_cmdlet.run
40
+ expect(result.succeeded?).to eq(true)
41
+ end
42
+
43
+ it "#run does not raise a PowershellCmdletException exception if the command cannot be executed" do
44
+ expect {invalid_cmdlet.run}.not_to raise_error
45
+ end
46
+
47
+ it "#run! raises a PowershellCmdletException exception if the command cannot be executed" do
48
+ expect {invalid_cmdlet.run!}.to raise_error(Chef::Exceptions::PowershellCmdletException)
49
+ end
50
+
51
+ it "executes a 64-bit command on a 64-bit OS, 32-bit otherwise" do
52
+ os_arch = ENV['PROCESSOR_ARCHITEW6432']
53
+ if os_arch.nil?
54
+ os_arch = ENV['PROCESSOR_ARCHITECTURE']
55
+ end
56
+
57
+ result = architecture_cmdlet.run
58
+ execution_arch = result.return_value
59
+ execution_arch.strip!
60
+ expect(execution_arch).to eq(os_arch)
61
+ end
62
+
63
+ it "passes command line switches to the command" do
64
+ result = cmdlet_alias_requires_switch_or_argument.run({:name => 'ls'})
65
+ expect(result.succeeded?).to eq(true)
66
+ end
67
+
68
+ it "passes command line arguments to the command" do
69
+ result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
70
+ expect(result.succeeded?).to eq(true)
71
+ end
72
+
73
+ it "passes command line arguments and switches to the command" do
74
+ result = cmdlet_get_item_requires_switch_or_argument.run({:path => etc_directory},{},' | select-object -property fullname | format-table -hidetableheaders')
75
+ expect(result.succeeded?).to eq(true)
76
+ returned_directory = result.return_value
77
+ returned_directory.strip!
78
+ expect(returned_directory).to eq(etc_directory)
79
+ end
80
+
81
+ it "passes execution options to the command" do
82
+ result = cmdlet_get_item_requires_switch_or_argument.run({},{:cwd => etc_directory},'. | select-object -property fullname | format-table -hidetableheaders')
83
+ expect(result.succeeded?).to eq(true)
84
+ returned_directory = result.return_value
85
+ returned_directory.strip!
86
+ expect(returned_directory).to eq(etc_directory)
87
+ end
88
+
89
+ context "when returning json" do
90
+ let(:cmd_output_format) { :json }
91
+ it "returns json format data", :windows_powershell_dsc_only do
92
+ result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
93
+ expect(result.succeeded?).to eq(true)
94
+ expect(lambda{JSON.parse(result.return_value)}).not_to raise_error
95
+ end
96
+ end
97
+
98
+ context "when returning Ruby objects" do
99
+ let(:cmd_output_format) { :object }
100
+ it "returns object format data", :windows_powershell_dsc_only do
101
+ result = simple_cmdlet.run({},{:cwd => etc_directory}, 'hosts')
102
+ expect(result.succeeded?).to eq(true)
103
+ data = result.return_value
104
+ expect(data['Name']).to eq('hosts')
105
+ end
106
+ end
107
+
108
+ context "when constructor is given invalid arguments" do
109
+ let(:cmd_output_format) { :invalid }
110
+ it "throws an exception if an invalid format is passed to the constructor" do
111
+ expect(lambda{simple_cmdlet}).to raise_error
112
+ end
113
+ end
114
+ end