chef 11.14.6 → 11.16.0.rc.0

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