chef 11.14.6-x86-mingw32 → 11.16.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/exceptions.rb +4 -0
- data/lib/chef/mixin/windows_architecture_helper.rb +16 -0
- data/lib/chef/platform/query_helpers.rb +5 -1
- data/lib/chef/provider/dsc_script.rb +148 -0
- data/lib/chef/provider/user/dscl.rb +32 -28
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource/dsc_script.rb +140 -0
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/util/dsc/configuration_generator.rb +115 -0
- data/lib/chef/util/dsc/lcm_output_parser.rb +133 -0
- data/lib/chef/util/dsc/local_configuration_manager.rb +137 -0
- data/lib/chef/util/dsc/resource_info.rb +26 -0
- data/lib/chef/util/path_helper.rb +2 -2
- data/lib/chef/util/powershell/cmdlet.rb +136 -0
- data/lib/chef/util/powershell/cmdlet_result.rb +46 -0
- data/lib/chef/version.rb +1 -1
- data/spec/functional/resource/dsc_script_spec.rb +337 -0
- data/spec/functional/resource/group_spec.rb +5 -1
- data/spec/functional/util/powershell/cmdlet_spec.rb +114 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/platform_helpers.rb +24 -0
- data/spec/unit/platform/query_helpers_spec.rb +23 -0
- data/spec/unit/provider/dsc_script_spec.rb +145 -0
- data/spec/unit/provider/user/dscl_spec.rb +2 -1
- data/spec/unit/resource/dsc_script_spec.rb +127 -0
- data/spec/unit/util/dsc/configuration_generator_spec.rb +171 -0
- data/spec/unit/util/dsc/lcm_output_parser_spec.rb +169 -0
- data/spec/unit/util/dsc/local_configuration_manager_spec.rb +134 -0
- data/spec/unit/util/powershell/cmdlet_spec.rb +106 -0
- metadata +20 -4
data/spec/spec_helper.rb
CHANGED
@@ -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")
|
@@ -30,3 +30,26 @@ describe "Chef::Platform#windows_server_2003?" do
|
|
30
30
|
expect { Thread.fork { Chef::Platform.windows_server_2003? }.join }.not_to raise_error
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
describe 'Chef::Platform#supports_dsc?' do
|
35
|
+
it 'returns false if powershell is not present' do
|
36
|
+
node = Chef::Node.new
|
37
|
+
Chef::Platform.supports_dsc?(node).should be_false
|
38
|
+
end
|
39
|
+
|
40
|
+
['1.0', '2.0', '3.0'].each do |version|
|
41
|
+
it "returns false for Powershell #{version}" do
|
42
|
+
node = Chef::Node.new
|
43
|
+
node.automatic[:languages][:powershell][:version] = version
|
44
|
+
Chef::Platform.supports_dsc?(node).should be_false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
['4.0', '5.0'].each do |version|
|
49
|
+
it "returns true for Powershell #{version}" do
|
50
|
+
node = Chef::Node.new
|
51
|
+
node.automatic[:languages][:powershell][:version] = version
|
52
|
+
Chef::Platform.supports_dsc?(node).should be_true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,145 @@
|
|
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) {
|
26
|
+
node = Chef::Node.new
|
27
|
+
node.automatic[:languages][:powershell][:version] = '4.0'
|
28
|
+
node
|
29
|
+
}
|
30
|
+
let (:events) { Chef::EventDispatch::Dispatcher.new }
|
31
|
+
let (:run_context) { Chef::RunContext.new(node, {}, events) }
|
32
|
+
let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
|
33
|
+
let (:provider) do
|
34
|
+
Chef::Provider::DscScript.new(resource, run_context)
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#load_current_resource' do
|
38
|
+
it "describes the resource as converged if there were 0 DSC resources" do
|
39
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([])
|
40
|
+
provider.load_current_resource
|
41
|
+
provider.instance_variable_get('@resource_converged').should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "describes the resource as not converged if there is 1 DSC resources that is converged" do
|
45
|
+
dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
|
46
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
|
47
|
+
provider.load_current_resource
|
48
|
+
provider.instance_variable_get('@resource_converged').should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
|
52
|
+
dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
|
53
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
|
54
|
+
provider.load_current_resource
|
55
|
+
provider.instance_variable_get('@resource_converged').should be_false
|
56
|
+
end
|
57
|
+
|
58
|
+
it "describes the resource as not converged if there are any DSC resources that are not converged" do
|
59
|
+
dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
|
60
|
+
dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
|
61
|
+
|
62
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
|
63
|
+
provider.load_current_resource
|
64
|
+
provider.instance_variable_get('@resource_converged').should be_false
|
65
|
+
end
|
66
|
+
|
67
|
+
it "describes the resource as converged if all DSC resources that are converged" do
|
68
|
+
dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
|
69
|
+
dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
|
70
|
+
|
71
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
|
72
|
+
provider.load_current_resource
|
73
|
+
provider.instance_variable_get('@resource_converged').should be_true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#generate_configuration_document' do
|
78
|
+
# I think integration tests should cover these cases
|
79
|
+
|
80
|
+
it 'uses configuration_document_from_script_path when a dsc script file is given' do
|
81
|
+
allow(provider).to receive(:load_current_resource)
|
82
|
+
resource.command("path_to_script")
|
83
|
+
generator = double('Chef::Util::DSC::ConfigurationGenerator')
|
84
|
+
generator.should_receive(:configuration_document_from_script_path)
|
85
|
+
allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
|
86
|
+
provider.send(:generate_configuration_document, 'tmp', nil)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'uses configuration_document_from_script_code when a the dsc resource is given' do
|
90
|
+
allow(provider).to receive(:load_current_resource)
|
91
|
+
resource.code("ImADSCResource{}")
|
92
|
+
generator = double('Chef::Util::DSC::ConfigurationGenerator')
|
93
|
+
generator.should_receive(:configuration_document_from_script_code)
|
94
|
+
allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
|
95
|
+
provider.send(:generate_configuration_document, 'tmp', nil)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should noop if neither code or command are provided' do
|
99
|
+
allow(provider).to receive(:load_current_resource)
|
100
|
+
generator = double('Chef::Util::DSC::ConfigurationGenerator')
|
101
|
+
generator.should_receive(:configuration_document_from_script_code).with('', anything(), anything())
|
102
|
+
allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
|
103
|
+
provider.send(:generate_configuration_document, 'tmp', nil)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'action_run' do
|
108
|
+
it 'should converge the script if it is not converged' do
|
109
|
+
dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
|
110
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
|
111
|
+
allow(provider).to receive(:run_configuration).with(:set)
|
112
|
+
|
113
|
+
provider.run_action(:run)
|
114
|
+
resource.should be_updated
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should not converge if the script is already converged' do
|
118
|
+
allow(provider).to receive(:run_configuration).with(:test).and_return([])
|
119
|
+
|
120
|
+
provider.run_action(:run)
|
121
|
+
resource.should_not be_updated
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#generate_description' do
|
126
|
+
it 'removes the resource name from the beginning of any log line from the LCM' do
|
127
|
+
dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
|
128
|
+
provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
|
129
|
+
provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing something/)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'ignores the last line' do
|
133
|
+
dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
|
134
|
+
provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
|
135
|
+
provider.send(:generate_description)[1].should_not match(/lastline/)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
|
139
|
+
dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
|
140
|
+
provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
|
141
|
+
provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing nothing/)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
@@ -376,6 +376,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
|
|
376
376
|
let(:user_plist_file) { nil }
|
377
377
|
|
378
378
|
before do
|
379
|
+
provider.should_receive(:shell_out).with("dscacheutil '-flushcache'")
|
379
380
|
provider.should_receive(:shell_out).with("plutil -convert xml1 -o - /var/db/dslocal/nodes/Default/users/toor.plist") do
|
380
381
|
if user_plist_file.nil?
|
381
382
|
ShellCmdResult.new('Can not find the file', 'Sorry!!', 1)
|
@@ -715,7 +716,6 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
|
|
715
716
|
provider.should_receive(:read_user_info)
|
716
717
|
provider.should_receive(:dscl_set)
|
717
718
|
provider.should_receive(:sleep).with(3)
|
718
|
-
provider.should_receive(:shell_out).with("dscacheutil '-flushcache'")
|
719
719
|
provider.should_receive(:save_user_info)
|
720
720
|
provider.set_password
|
721
721
|
end
|
@@ -822,6 +822,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
|
|
822
822
|
|
823
823
|
describe "when the user exists" do
|
824
824
|
before do
|
825
|
+
provider.should_receive(:shell_out).with("dscacheutil '-flushcache'")
|
825
826
|
provider.should_receive(:shell_out).with("plutil -convert xml1 -o - /var/db/dslocal/nodes/Default/users/toor.plist") do
|
826
827
|
ShellCmdResult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/10.9.plist.xml")), "", 0)
|
827
828
|
end
|
@@ -0,0 +1,127 @@
|
|
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_resource_name) { 'DSCTest' }
|
23
|
+
|
24
|
+
context 'when Powershell supports Dsc' do
|
25
|
+
let(:dsc_test_run_context) {
|
26
|
+
node = Chef::Node.new
|
27
|
+
node.automatic[:languages][:powershell][:version] = '4.0'
|
28
|
+
empty_events = Chef::EventDispatch::Dispatcher.new
|
29
|
+
Chef::RunContext.new(node, {}, empty_events)
|
30
|
+
}
|
31
|
+
let(:dsc_test_resource) {
|
32
|
+
Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
|
33
|
+
}
|
34
|
+
let(:configuration_code) {'echo "This is supposed to create a configuration document."'}
|
35
|
+
let(:configuration_path) {'c:/myconfigs/formatc.ps1'}
|
36
|
+
let(:configuration_name) { 'formatme' }
|
37
|
+
let(:configuration_data) { '@{AllNodes = @( @{ NodeName = "localhost"; PSDscAllowPlainTextPassword = $true })}' }
|
38
|
+
let(:configuration_data_script) { 'c:/myconfigs/data/safedata.psd1' }
|
39
|
+
|
40
|
+
it "has a default action of `:run`" do
|
41
|
+
expect(dsc_test_resource.action).to eq(:run)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
|
45
|
+
expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "allows the code attribute to be set" do
|
49
|
+
dsc_test_resource.code(configuration_code)
|
50
|
+
expect(dsc_test_resource.code).to eq(configuration_code)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows the command attribute to be set" do
|
54
|
+
dsc_test_resource.command(configuration_path)
|
55
|
+
expect(dsc_test_resource.command).to eq(configuration_path)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "allows the configuration_name attribute to be set" do
|
59
|
+
dsc_test_resource.configuration_name(configuration_name)
|
60
|
+
expect(dsc_test_resource.configuration_name).to eq(configuration_name)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "allows the configuration_data attribute to be set" do
|
64
|
+
dsc_test_resource.configuration_data(configuration_data)
|
65
|
+
expect(dsc_test_resource.configuration_data).to eq(configuration_data)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "allows the configuration_data_script attribute to be set" do
|
69
|
+
dsc_test_resource.configuration_data_script(configuration_data_script)
|
70
|
+
expect(dsc_test_resource.configuration_data_script).to eq(configuration_data_script)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "raises an ArgumentError exception if an attempt is made to set the code attribute when the command attribute is already set" do
|
74
|
+
dsc_test_resource.command(configuration_path)
|
75
|
+
expect { dsc_test_resource.code(configuration_code) }.to raise_error(ArgumentError)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "raises an ArgumentError exception if an attempt is made to set the command attribute when the code attribute is already set" do
|
79
|
+
dsc_test_resource.code(configuration_code)
|
80
|
+
expect { dsc_test_resource.command(configuration_path) }.to raise_error(ArgumentError)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "raises an ArgumentError exception if an attempt is made to set the configuration_name attribute when the code attribute is already set" do
|
84
|
+
dsc_test_resource.code(configuration_code)
|
85
|
+
expect { dsc_test_resource.configuration_name(configuration_name) }.to raise_error(ArgumentError)
|
86
|
+
end
|
87
|
+
|
88
|
+
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
|
89
|
+
dsc_test_resource.configuration_data_script(configuration_data_script)
|
90
|
+
expect { dsc_test_resource.configuration_data(configuration_data) }.to raise_error(ArgumentError)
|
91
|
+
end
|
92
|
+
|
93
|
+
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
|
94
|
+
dsc_test_resource.configuration_data(configuration_data)
|
95
|
+
expect { dsc_test_resource.configuration_data_script(configuration_data_script) }.to raise_error(ArgumentError)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when Powershell does not supported Dsc' do
|
100
|
+
['1.0', '2.0', '3.0'].each do |version|
|
101
|
+
it "raises an exception for powershell version '#{version}'" do
|
102
|
+
node = Chef::Node.new
|
103
|
+
node.automatic[:languages][:powershell][:version] = version
|
104
|
+
empty_events = Chef::EventDispatch::Dispatcher.new
|
105
|
+
dsc_test_run_context = Chef::RunContext.new(node, {}, empty_events)
|
106
|
+
|
107
|
+
expect {
|
108
|
+
Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
|
109
|
+
}.to raise_error(Chef::Exceptions::NoProviderAvailable)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when Powershell is not present' do
|
115
|
+
let (:dsc_test_run_context) {
|
116
|
+
node = Chef::Node.new
|
117
|
+
empty_events = Chef::EventDispatch::Dispatcher.new
|
118
|
+
dsc_test_run_context = Chef::RunContext.new(node, {}, empty_events)
|
119
|
+
}
|
120
|
+
|
121
|
+
it 'raises an exception if powershell is not present' do
|
122
|
+
expect {
|
123
|
+
Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
|
124
|
+
}.to raise_error(Chef::Exceptions::NoProviderAvailable)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,171 @@
|
|
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
|
+
let(:conf_man) do
|
24
|
+
node = Chef::Node.new
|
25
|
+
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
|
+
let(:file_like_object) { double("file like object") }
|
126
|
+
|
127
|
+
it "should write the input to a file" do
|
128
|
+
allow(File).to receive(:open).and_yield(file_like_object)
|
129
|
+
allow(File).to receive(:join) do |a, b|
|
130
|
+
[a,b].join("++")
|
131
|
+
end
|
132
|
+
allow(file_like_object).to receive(:write)
|
133
|
+
conf_man.send(:write_document_generation_script, 'file', 'hello')
|
134
|
+
expect(file_like_object).to have_received(:write)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "#find_configuration_document" do
|
139
|
+
it "should find the mof file" do
|
140
|
+
# These tests seem way too implementation specific. Unfortunatly, File and Dir
|
141
|
+
# need to be mocked because they are OS specific
|
142
|
+
allow(File).to receive(:join) do |a, b|
|
143
|
+
[a,b].join("++")
|
144
|
+
end
|
145
|
+
|
146
|
+
allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'hello.mof', 'f3']}
|
147
|
+
expect(conf_man.send(:find_configuration_document, 'hello')).to eql('tmp++hello++hello.mof')
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should return nil if the mof file is not found" do
|
151
|
+
allow(File).to receive(:join) do |a, b|
|
152
|
+
[a,b].join("++")
|
153
|
+
end
|
154
|
+
allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'f3']}
|
155
|
+
expect(conf_man.send(:find_configuration_document, 'hello')).to be_nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#configuration_code" do
|
160
|
+
it "should build dsc" do
|
161
|
+
dsc = conf_man.send(:configuration_code, 'archive{}', 'hello')
|
162
|
+
found_configuration = false
|
163
|
+
dsc.split(';').each do |command|
|
164
|
+
if command.downcase =~ /\s*configuration\s+'hello'\s*\{\s*node\s+'localhost'\s*\{\s*archive\s*\{\s*\}\s*\}\s*\}\s*/
|
165
|
+
found_configuration = true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
expect(found_configuration).to be_true
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|