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.
@@ -107,8 +107,11 @@ RSpec.configure do |config|
107
107
  config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3?
108
108
  config.filter_run_excluding :not_supported_on_solaris => true if solaris?
109
109
  config.filter_run_excluding :win2k3_only => true unless windows_win2k3?
110
+ config.filter_run_excluding :windows_2008r2_or_later => true unless windows_2008r2_or_later?
110
111
  config.filter_run_excluding :windows64_only => true unless windows64?
111
112
  config.filter_run_excluding :windows32_only => true unless windows32?
113
+ config.filter_run_excluding :windows_powershell_dsc_only => true unless windows_powershell_dsc?
114
+ config.filter_run_excluding :windows_powershell_no_dsc_only => true unless ! windows_powershell_dsc?
112
115
  config.filter_run_excluding :windows_domain_joined_only => true unless windows_domain_joined?
113
116
  config.filter_run_excluding :solaris_only => true unless solaris?
114
117
  config.filter_run_excluding :system_windows_service_gem_only => true unless system_windows_service_gem?
@@ -43,6 +43,30 @@ def windows_win2k3?
43
43
  (host['version'] && host['version'].start_with?("5.2"))
44
44
  end
45
45
 
46
+ def windows_2008r2_or_later?
47
+ return false unless windows?
48
+ wmi = WmiLite::Wmi.new
49
+ host = wmi.first_of('Win32_OperatingSystem')
50
+ version = host['version']
51
+ return false unless version
52
+ components = version.split('.').map do | component |
53
+ component.to_i
54
+ end
55
+ components.length >=2 && components[0] >= 6 && components[1] >= 1
56
+ end
57
+
58
+ def windows_powershell_dsc?
59
+ return false unless windows?
60
+ supports_dsc = false
61
+ begin
62
+ wmi = WmiLite::Wmi.new('root/microsoft/windows/desiredstateconfiguration')
63
+ lcm = wmi.query("SELECT * FROM meta_class WHERE __this ISA 'MSFT_DSCLocalConfigurationManager'")
64
+ supports_dsc = !! lcm
65
+ rescue WmiLite::WmiException
66
+ end
67
+ supports_dsc
68
+ end
69
+
46
70
  def mac_osx_106?
47
71
  if File.exists? "/usr/bin/sw_vers"
48
72
  result = shell_out("/usr/bin/sw_vers")
@@ -0,0 +1,141 @@
1
+ #
2
+ # Author:: Jay Mundrawala (<jdm@getchef.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2014 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef'
21
+ require 'chef/util/dsc/resource_info'
22
+ require 'spec_helper'
23
+
24
+ describe Chef::Provider::DscScript do
25
+ let (:node) { Chef::Node.new }
26
+ let (:events) { Chef::EventDispatch::Dispatcher.new }
27
+ let (:run_context) { Chef::RunContext.new(node, {}, events) }
28
+ let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
29
+ let (:provider) do
30
+ Chef::Provider::DscScript.new(resource, run_context)
31
+ end
32
+
33
+ describe '#load_current_resource' do
34
+ it "describes the resource as converged if there were 0 DSC resources" do
35
+ allow(provider).to receive(:run_configuration).with(:test).and_return([])
36
+ provider.load_current_resource
37
+ provider.instance_variable_get('@resource_converged').should be_true
38
+ end
39
+
40
+ it "describes the resource as not converged if there is 1 DSC resources that is converged" do
41
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
42
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
43
+ provider.load_current_resource
44
+ provider.instance_variable_get('@resource_converged').should be_true
45
+ end
46
+
47
+ it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
48
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
49
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
50
+ provider.load_current_resource
51
+ provider.instance_variable_get('@resource_converged').should be_false
52
+ end
53
+
54
+ it "describes the resource as not converged if there are any DSC resources that are not converged" do
55
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
56
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
57
+
58
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
59
+ provider.load_current_resource
60
+ provider.instance_variable_get('@resource_converged').should be_false
61
+ end
62
+
63
+ it "describes the resource as converged if all DSC resources that are converged" do
64
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
65
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
66
+
67
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
68
+ provider.load_current_resource
69
+ provider.instance_variable_get('@resource_converged').should be_true
70
+ end
71
+ end
72
+
73
+ describe '#generate_configuration_document' do
74
+ # I think integration tests should cover these cases
75
+
76
+ it 'uses configuration_document_from_script_path when a dsc script file is given' do
77
+ allow(provider).to receive(:load_current_resource)
78
+ resource.command("path_to_script")
79
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
80
+ generator.should_receive(:configuration_document_from_script_path)
81
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
82
+ provider.send(:generate_configuration_document, 'tmp', nil)
83
+ end
84
+
85
+ it 'uses configuration_document_from_script_code when a the dsc resource is given' do
86
+ allow(provider).to receive(:load_current_resource)
87
+ resource.code("ImADSCResource{}")
88
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
89
+ generator.should_receive(:configuration_document_from_script_code)
90
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
91
+ provider.send(:generate_configuration_document, 'tmp', nil)
92
+ end
93
+
94
+ it 'should noop if neither code or command are provided' do
95
+ allow(provider).to receive(:load_current_resource)
96
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
97
+ generator.should_receive(:configuration_document_from_script_code).with('', anything(), anything())
98
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
99
+ provider.send(:generate_configuration_document, 'tmp', nil)
100
+ end
101
+ end
102
+
103
+ describe 'action_run' do
104
+ it 'should converge the script if it is not converged' do
105
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
106
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
107
+ allow(provider).to receive(:run_configuration).with(:set)
108
+
109
+ provider.run_action(:run)
110
+ resource.should be_updated
111
+ end
112
+
113
+ it 'should not converge if the script is already converged' do
114
+ allow(provider).to receive(:run_configuration).with(:test).and_return([])
115
+
116
+ provider.run_action(:run)
117
+ resource.should_not be_updated
118
+ end
119
+ end
120
+
121
+ describe '#generate_description' do
122
+ it 'removes the resource name from the beginning of any log line from the LCM' do
123
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
124
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
125
+ provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing something/)
126
+ end
127
+
128
+ it 'ignores the last line' do
129
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
130
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
131
+ provider.send(:generate_description)[1].should_not match(/lastline/)
132
+ end
133
+
134
+ it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
135
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
136
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
137
+ provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing nothing/)
138
+ end
139
+ end
140
+ end
141
+
@@ -0,0 +1,94 @@
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
+
21
+ describe Chef::Resource::DscScript do
22
+ let(:dsc_test_run_context) {
23
+ node = Chef::Node.new
24
+ empty_events = Chef::EventDispatch::Dispatcher.new
25
+ Chef::RunContext.new(node, {}, empty_events)
26
+ }
27
+ let(:dsc_test_resource_name) { 'DSCTest' }
28
+ let(:dsc_test_resource) {
29
+ Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
30
+ }
31
+ let(:configuration_code) {'echo "This is supposed to create a configuration document."'}
32
+ let(:configuration_path) {'c:/myconfigs/formatc.ps1'}
33
+ let(:configuration_name) { 'formatme' }
34
+ let(:configuration_data) { '@{AllNodes = @( @{ NodeName = "localhost"; PSDscAllowPlainTextPassword = $true })}' }
35
+ let(:configuration_data_script) { 'c:/myconfigs/data/safedata.psd1' }
36
+
37
+ it "has a default action of `:run`" do
38
+ expect(dsc_test_resource.action).to eq(:run)
39
+ end
40
+
41
+ it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
42
+ expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
43
+ end
44
+
45
+ it "allows the code attribute to be set" do
46
+ dsc_test_resource.code(configuration_code)
47
+ expect(dsc_test_resource.code).to eq(configuration_code)
48
+ end
49
+
50
+ it "allows the command attribute to be set" do
51
+ dsc_test_resource.command(configuration_path)
52
+ expect(dsc_test_resource.command).to eq(configuration_path)
53
+ end
54
+
55
+ it "allows the configuration_name attribute to be set" do
56
+ dsc_test_resource.configuration_name(configuration_name)
57
+ expect(dsc_test_resource.configuration_name).to eq(configuration_name)
58
+ end
59
+
60
+ it "allows the configuration_data attribute to be set" do
61
+ dsc_test_resource.configuration_data(configuration_data)
62
+ expect(dsc_test_resource.configuration_data).to eq(configuration_data)
63
+ end
64
+
65
+ it "allows the configuration_data_script attribute to be set" do
66
+ dsc_test_resource.configuration_data_script(configuration_data_script)
67
+ expect(dsc_test_resource.configuration_data_script).to eq(configuration_data_script)
68
+ end
69
+
70
+ it "raises an ArgumentError exception if an attempt is made to set the code attribute when the command attribute is already set" do
71
+ dsc_test_resource.command(configuration_path)
72
+ expect { dsc_test_resource.code(configuration_code) }.to raise_error(ArgumentError)
73
+ end
74
+
75
+ it "raises an ArgumentError exception if an attempt is made to set the command attribute when the code attribute is already set" do
76
+ dsc_test_resource.code(configuration_code)
77
+ expect { dsc_test_resource.command(configuration_path) }.to raise_error(ArgumentError)
78
+ end
79
+
80
+ it "raises an ArgumentError exception if an attempt is made to set the configuration_name attribute when the code attribute is already set" do
81
+ dsc_test_resource.code(configuration_code)
82
+ expect { dsc_test_resource.configuration_name(configuration_name) }.to raise_error(ArgumentError)
83
+ end
84
+
85
+ it "raises an ArgumentError exception if an attempt is made to set the configuration_data attribute when the configuration_data_script attribute is already set" do
86
+ dsc_test_resource.configuration_data_script(configuration_data_script)
87
+ expect { dsc_test_resource.configuration_data(configuration_data) }.to raise_error(ArgumentError)
88
+ end
89
+
90
+ it "raises an ArgumentError exception if an attempt is made to set the configuration_data_script attribute when the configuration_data attribute is already set" do
91
+ dsc_test_resource.configuration_data(configuration_data)
92
+ expect { dsc_test_resource.configuration_data_script(configuration_data_script) }.to raise_error(ArgumentError)
93
+ end
94
+ end
@@ -0,0 +1,173 @@
1
+ #
2
+ # Author:: Jay Mundrawala <jmundrawala@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 'chef'
20
+ require 'chef/util/dsc/configuration_generator'
21
+
22
+ describe Chef::Util::DSC::ConfigurationGenerator do
23
+ before (:all) do
24
+ @node = Chef::Node.new
25
+ @conf_man = Chef::Util::DSC::ConfigurationGenerator.new(@node, 'tmp')
26
+ end
27
+
28
+ describe '#validate_configuration_name!' do
29
+ it 'should not raise an error if a name contains all upper case letters' do
30
+ @conf_man.send(:validate_configuration_name!, "HELLO")
31
+ end
32
+
33
+ it 'should not raise an error if the name contains all lower case letters' do
34
+ @conf_man.send(:validate_configuration_name!, "hello")
35
+ end
36
+
37
+ it 'should not raise an error if no special characters are used except _' do
38
+ @conf_man.send(:validate_configuration_name!, "hello_world")
39
+ end
40
+
41
+ %w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym|
42
+ it "raises an Argument error if it configuration name contains #{sym}" do
43
+ expect {
44
+ @conf_man.send(:validate_configuration_name!, "Hello#{sym}")
45
+ }.to raise_error(ArgumentError)
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "#get_merged_configuration_flags" do
51
+ context 'when strings are used as switches' do
52
+ it 'should merge the hash if there are no restricted switches' do
53
+ merged = @conf_man.send(:get_merged_configuration_flags!, {'flag' => 'a'}, 'hello')
54
+ merged.should include(:flag)
55
+ merged[:flag].should eql('a')
56
+ merged.should include(:outputpath)
57
+ end
58
+
59
+ it 'should raise an ArgumentError if you try to override outputpath' do
60
+ expect {
61
+ @conf_man.send(:get_merged_configuration_flags!, {'outputpath' => 'a'}, 'hello')
62
+ }.to raise_error(ArgumentError)
63
+ end
64
+
65
+ it 'should be case insensitive for switches that are not allowed' do
66
+ expect {
67
+ @conf_man.send(:get_merged_configuration_flags!, {'OutputPath' => 'a'}, 'hello')
68
+ }.to raise_error(ArgumentError)
69
+ end
70
+
71
+ it 'should be case insensitive to switches that are allowed' do
72
+ merged = @conf_man.send(:get_merged_configuration_flags!, {'FLAG' => 'a'}, 'hello')
73
+ merged.should include(:flag)
74
+ end
75
+ end
76
+
77
+ context 'when symbols are used as switches' do
78
+ it 'should merge the hash if there are no restricted switches' do
79
+ merged = @conf_man.send(:get_merged_configuration_flags!, {:flag => 'a'}, 'hello')
80
+ merged.should include(:flag)
81
+ merged[:flag].should eql('a')
82
+ merged.should include(:outputpath)
83
+ end
84
+
85
+ it 'should raise an ArgumentError if you try to override outputpath' do
86
+ expect {
87
+ @conf_man.send(:get_merged_configuration_flags!, {:outputpath => 'a'}, 'hello')
88
+ }.to raise_error(ArgumentError)
89
+ end
90
+
91
+ it 'should be case insensitive for switches that are not allowed' do
92
+ expect {
93
+ @conf_man.send(:get_merged_configuration_flags!, {:OutputPath => 'a'}, 'hello')
94
+ }.to raise_error(ArgumentError)
95
+ end
96
+
97
+ it 'should be case insensitive to switches that are allowed' do
98
+ merged = @conf_man.send(:get_merged_configuration_flags!, {:FLAG => 'a'}, 'hello')
99
+ merged.should include(:flag)
100
+ end
101
+ end
102
+
103
+ context 'when there are no flags' do
104
+ it 'should supply an output path if configuration_flags is an empty hash' do
105
+ merged = @conf_man.send(:get_merged_configuration_flags!, {}, 'hello')
106
+ merged.should include(:outputpath)
107
+ merged.length.should eql(1)
108
+ end
109
+
110
+ it 'should supply an output path if configuration_flags is an empty hash' do
111
+ merged = @conf_man.send(:get_merged_configuration_flags!, nil, 'hello')
112
+ merged.should include(:outputpath)
113
+ merged.length.should eql(1)
114
+ end
115
+ end
116
+
117
+ # What should happen if configuration flags contains duplicates?
118
+ # flagA => 'a', flaga => 'a'
119
+ # or
120
+ # flagA => 'a', flaga => 'b'
121
+ #
122
+ end
123
+
124
+ describe '#write_document_generation_script' do
125
+ before (:each) do
126
+ @file_like_object = double("file like object")
127
+ end
128
+
129
+ it "should write the input to a file" do
130
+ File.stub(:open).and_yield(@file_like_object)
131
+ @file_like_object.stub(:write).with(anything())
132
+ File.stub(:join) do |a, b|
133
+ [a,b].join("++")
134
+ end
135
+ @conf_man.send(:write_document_generation_script, 'file', 'hello')
136
+ expect(@file_like_object).to have_received(:write)
137
+ end
138
+ end
139
+
140
+ describe "#find_configuration_document" do
141
+ it "should find the mof file" do
142
+ # These tests seem way too implementation specific. Unfortunatly, File and Dir
143
+ # need to be mocked because they are OS specific
144
+
145
+ File.stub(:join) do |a, b|
146
+ [a,b].join("++")
147
+ end
148
+ Dir.stub(:entries).with("tmp++hello") {['f1', 'f2', 'hello.mof', 'f3']}
149
+ expect(@conf_man.send(:find_configuration_document, 'hello')).to eql('tmp++hello++hello.mof')
150
+ end
151
+
152
+ it "should return nil if the mof file is not found" do
153
+ File.stub(:join) do |a, b|
154
+ [a,b].join("++")
155
+ end
156
+ Dir.stub(:entries).with("tmp++hello") {['f1', 'f2', 'f3']}
157
+ expect(@conf_man.send(:find_configuration_document, 'hello')).to be_nil
158
+ end
159
+ end
160
+
161
+ describe "#configuration_code" do
162
+ it "should build dsc" do
163
+ dsc = @conf_man.send(:configuration_code, 'archive{}', 'hello')
164
+ found_configuration = false
165
+ dsc.split(';').each do |command|
166
+ if command.downcase =~ /\s*configuration\s+'hello'\s*\{\s*node\s+'localhost'\s*\{\s*archive\s*\{\s*\}\s*\}\s*\}\s*/
167
+ found_configuration = true
168
+ end
169
+ end
170
+ expect(found_configuration).to be_true
171
+ end
172
+ end
173
+ end