chef 11.10.4 → 11.12.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +6 -6
- data/README.md +1 -1
- data/lib/chef/api_client.rb +1 -3
- data/lib/chef/application.rb +2 -1
- data/lib/chef/application/client.rb +11 -1
- data/lib/chef/client.rb +24 -9
- data/lib/chef/cookbook/syntax_check.rb +107 -6
- data/lib/chef/dsl/reboot_pending.rb +61 -0
- data/lib/chef/exceptions.rb +12 -1
- data/lib/chef/formatters/error_descriptor.rb +1 -1
- data/lib/chef/http/remote_request_id.rb +46 -0
- data/lib/chef/knife/bootstrap.rb +1 -1
- data/lib/chef/knife/bootstrap/README.md +12 -0
- data/lib/chef/knife/bootstrap/chef-full.erb +3 -0
- data/lib/chef/knife/client_create.rb +6 -0
- data/lib/chef/knife/client_delete.rb +15 -1
- data/lib/chef/knife/raw.rb +1 -0
- data/lib/chef/node.rb +1 -1
- data/lib/chef/node/attribute_collections.rb +8 -1
- data/lib/chef/node/immutable_collections.rb +8 -1
- data/lib/chef/provider/deploy.rb +1 -1
- data/lib/chef/provider/group.rb +1 -1
- data/lib/chef/provider/ifconfig/debian.rb +19 -8
- data/lib/chef/provider/ohai.rb +6 -5
- data/lib/chef/provider/service/macosx.rb +68 -14
- data/lib/chef/recipe.rb +2 -0
- data/lib/chef/request_id.rb +37 -0
- data/lib/chef/resource.rb +2 -0
- data/lib/chef/resource_reporter.rb +7 -4
- data/lib/chef/rest.rb +5 -1
- data/lib/chef/run_status.rb +4 -1
- data/lib/chef/server_api.rb +3 -1
- data/lib/chef/version.rb +2 -2
- data/spec/functional/dsl/reboot_pending_spec.rb +118 -0
- data/spec/functional/resource/base.rb +1 -3
- data/spec/functional/resource/deploy_revision_spec.rb +192 -1
- data/spec/functional/resource/git_spec.rb +1 -1
- data/spec/functional/resource/ohai_spec.rb +65 -0
- data/spec/functional/resource/registry_spec.rb +4 -5
- data/spec/integration/client/client_spec.rb +14 -0
- data/spec/spec_helper.rb +1 -2
- data/spec/support/shared/functional/windows_script.rb +1 -2
- data/spec/unit/api_client_spec.rb +46 -0
- data/spec/unit/client_spec.rb +345 -229
- data/spec/unit/cookbook/syntax_check_spec.rb +0 -1
- data/spec/unit/dsl/reboot_pending_spec.rb +100 -0
- data/spec/unit/knife/client_create_spec.rb +29 -1
- data/spec/unit/knife/client_delete_spec.rb +44 -1
- data/spec/unit/knife_spec.rb +55 -0
- data/spec/unit/node/attribute_spec.rb +7 -0
- data/spec/unit/node/immutable_collections_spec.rb +5 -1
- data/spec/unit/provider/group_spec.rb +5 -0
- data/spec/unit/provider/ifconfig/debian_spec.rb +251 -24
- data/spec/unit/provider/ohai_spec.rb +2 -3
- data/spec/unit/provider/service/macosx_spec.rb +29 -11
- data/spec/unit/resource_reporter_spec.rb +1 -1
- data/spec/unit/rest_spec.rb +38 -13
- metadata +151 -194
@@ -28,7 +28,6 @@ describe Chef::Cookbook::SyntaxCheck do
|
|
28
28
|
Chef::Log.logger = Logger.new(StringIO.new)
|
29
29
|
Chef::Log.level = :warn # suppress "Syntax OK" messages
|
30
30
|
|
31
|
-
|
32
31
|
@attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, 'attributes', f) }
|
33
32
|
@defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, 'definitions', f)}
|
34
33
|
@recipes = %w{default.rb gigantor.rb one.rb}.map { |f| File.join(cookbook_path, 'recipes', f) }
|
@@ -0,0 +1,100 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Bryan McLellan <btm@loftninjas.org>
|
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/dsl/reboot_pending"
|
20
|
+
require "spec_helper"
|
21
|
+
|
22
|
+
describe Chef::DSL::RebootPending do
|
23
|
+
describe "reboot_pending?" do
|
24
|
+
describe "in isoloation" do
|
25
|
+
let(:recipe) { Object.new.extend(Chef::DSL::RebootPending) }
|
26
|
+
|
27
|
+
before do
|
28
|
+
recipe.stub(:platform?).and_return(false)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "platform is windows" do
|
32
|
+
before do
|
33
|
+
recipe.stub(:platform?).with('windows').and_return(true)
|
34
|
+
recipe.stub(:registry_key_exists?).and_return(false)
|
35
|
+
recipe.stub(:registry_value_exists?).and_return(false)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return true if "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations" exists' do
|
39
|
+
recipe.stub(:registry_value_exists?).with('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }).and_return(true)
|
40
|
+
expect(recipe.reboot_pending?).to be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return true if "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" exists' do
|
44
|
+
recipe.stub(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired').and_return(true)
|
45
|
+
expect(recipe.reboot_pending?).to be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should return true if key "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired" exists' do
|
49
|
+
recipe.stub(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired').and_return(true)
|
50
|
+
expect(recipe.reboot_pending?).to be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should return true if value "HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile" contains specific data' do
|
54
|
+
recipe.stub(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(true)
|
55
|
+
recipe.stub(:registry_get_values).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(
|
56
|
+
[{:name => "Flags", :type => :dword, :data => 3}])
|
57
|
+
expect(recipe.reboot_pending?).to be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "platform is ubuntu" do
|
62
|
+
before do
|
63
|
+
recipe.stub(:platform?).with('ubuntu').and_return(true)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should return true if /var/run/reboot-required exists' do
|
67
|
+
File.stub(:exists?).with('/var/run/reboot-required').and_return(true)
|
68
|
+
expect(recipe.reboot_pending?).to be_true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should return false if /var/run/reboot-required does not exist' do
|
72
|
+
File.stub(:exists?).with('/var/run/reboot-required').and_return(false)
|
73
|
+
expect(recipe.reboot_pending?).to be_false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "platform is not supported" do
|
78
|
+
it 'should raise an exception' do
|
79
|
+
recipe.stub_chain(:node, :[]).with(:platform).and_return('msdos')
|
80
|
+
expect { recipe.reboot_pending? }.to raise_error(Chef::Exceptions::UnsupportedPlatform)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end # describe in isolation
|
84
|
+
|
85
|
+
describe "in a recipe" do
|
86
|
+
it "responds to reboot_pending?" do
|
87
|
+
# Chef::Recipe.new(cookbook_name, recipe_name, run_context(node, cookbook_collection, events))
|
88
|
+
recipe = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, nil))
|
89
|
+
expect(recipe).to respond_to(:reboot_pending?)
|
90
|
+
end
|
91
|
+
end # describe in a recipe
|
92
|
+
|
93
|
+
describe "in a resource" do
|
94
|
+
it "responds to reboot_pending?" do
|
95
|
+
resource = Chef::Resource::new("Crackerjack::Timing", nil)
|
96
|
+
expect(resource).to respond_to(:reboot_pending?)
|
97
|
+
end
|
98
|
+
end # describe in a resource
|
99
|
+
end
|
100
|
+
end
|
@@ -25,7 +25,9 @@ describe Chef::Knife::ClientCreate do
|
|
25
25
|
Chef::Config[:node_name] = "webmonkey.example.com"
|
26
26
|
@knife = Chef::Knife::ClientCreate.new
|
27
27
|
@knife.config = {
|
28
|
-
:file => nil
|
28
|
+
:file => nil,
|
29
|
+
:admin => false,
|
30
|
+
:validator => false
|
29
31
|
}
|
30
32
|
@knife.name_args = [ "adam" ]
|
31
33
|
@client = Chef::ApiClient.new
|
@@ -49,6 +51,16 @@ describe Chef::Knife::ClientCreate do
|
|
49
51
|
@knife.run
|
50
52
|
end
|
51
53
|
|
54
|
+
it "by default it is not an admin" do
|
55
|
+
@client.should_receive(:admin).with(false)
|
56
|
+
@knife.run
|
57
|
+
end
|
58
|
+
|
59
|
+
it "by default it is not a validator" do
|
60
|
+
@client.should_receive(:validator).with(false)
|
61
|
+
@knife.run
|
62
|
+
end
|
63
|
+
|
52
64
|
it "should allow you to edit the data" do
|
53
65
|
@knife.should_receive(:edit_data).with(@client)
|
54
66
|
@knife.run
|
@@ -70,5 +82,21 @@ describe Chef::Knife::ClientCreate do
|
|
70
82
|
end
|
71
83
|
end
|
72
84
|
|
85
|
+
describe "with -a or --admin" do
|
86
|
+
it "should create an admin client" do
|
87
|
+
@knife.config[:admin] = true
|
88
|
+
@client.should_receive(:admin).with(true)
|
89
|
+
@knife.run
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "with --validator" do
|
94
|
+
it "should create an validator client" do
|
95
|
+
@knife.config[:validator] = true
|
96
|
+
@client.should_receive(:validator).with(true)
|
97
|
+
@knife.run
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
73
101
|
end
|
74
102
|
end
|
@@ -21,12 +21,16 @@ require 'spec_helper'
|
|
21
21
|
describe Chef::Knife::ClientDelete do
|
22
22
|
before(:each) do
|
23
23
|
@knife = Chef::Knife::ClientDelete.new
|
24
|
+
# defaults
|
25
|
+
@knife.config = {
|
26
|
+
:force => false
|
27
|
+
}
|
24
28
|
@knife.name_args = [ 'adam' ]
|
25
29
|
end
|
26
30
|
|
27
31
|
describe 'run' do
|
28
32
|
it 'should delete the client' do
|
29
|
-
@knife.should_receive(:delete_object).with(Chef::ApiClient, 'adam')
|
33
|
+
@knife.should_receive(:delete_object).with(Chef::ApiClient, 'adam', 'client')
|
30
34
|
@knife.run
|
31
35
|
end
|
32
36
|
|
@@ -37,4 +41,43 @@ describe Chef::Knife::ClientDelete do
|
|
37
41
|
lambda { @knife.run }.should raise_error(SystemExit)
|
38
42
|
end
|
39
43
|
end
|
44
|
+
|
45
|
+
describe 'with a validator' do
|
46
|
+
before(:each) do
|
47
|
+
Chef::Knife::UI.stub(:confirm).and_return(true)
|
48
|
+
@knife.stub(:confirm).and_return(true)
|
49
|
+
@client = Chef::ApiClient.new
|
50
|
+
Chef::ApiClient.should_receive(:load).and_return(@client)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should delete non-validator client if --force is not set' do
|
54
|
+
@knife.config[:force] = false
|
55
|
+
@client.should_receive(:destroy).and_return(@client)
|
56
|
+
@knife.should_receive(:msg)
|
57
|
+
|
58
|
+
@knife.run
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should delete non-validator client if --force is set' do
|
62
|
+
@knife.config[:force] = true
|
63
|
+
@client.should_receive(:destroy).and_return(@client)
|
64
|
+
@knife.should_receive(:msg)
|
65
|
+
|
66
|
+
@knife.run
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should not delete validator client if --force is not set' do
|
70
|
+
@client.validator(true)
|
71
|
+
@knife.ui.should_receive(:fatal)
|
72
|
+
lambda { @knife.run}.should raise_error(SystemExit)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should delete validator client if --force is set' do
|
76
|
+
@knife.config[:force] = true
|
77
|
+
@client.should_receive(:destroy).and_return(@client)
|
78
|
+
@knife.should_receive(:msg)
|
79
|
+
|
80
|
+
@knife.run
|
81
|
+
end
|
82
|
+
end
|
40
83
|
end
|
data/spec/unit/knife_spec.rb
CHANGED
@@ -22,6 +22,7 @@ module KnifeSpecs
|
|
22
22
|
end
|
23
23
|
|
24
24
|
require 'spec_helper'
|
25
|
+
require 'uri'
|
25
26
|
|
26
27
|
describe Chef::Knife do
|
27
28
|
before(:each) do
|
@@ -141,6 +142,60 @@ describe Chef::Knife do
|
|
141
142
|
|
142
143
|
end
|
143
144
|
|
145
|
+
describe "the headers include X-Remote-Request-Id" do
|
146
|
+
|
147
|
+
let(:headers) {{"Accept"=>"application/json",
|
148
|
+
"Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
|
149
|
+
'X-Chef-Version' => Chef::VERSION,
|
150
|
+
"Host"=>"api.opscode.piab:443",
|
151
|
+
"X-REMOTE-REQUEST-ID"=>request_id}}
|
152
|
+
|
153
|
+
let(:request_id) {"1234"}
|
154
|
+
|
155
|
+
let(:request_mock) { {} }
|
156
|
+
|
157
|
+
let(:rest) do
|
158
|
+
Net::HTTP.stub(:new).and_return(http_client)
|
159
|
+
Chef::RequestID.instance.stub(:request_id).and_return(request_id)
|
160
|
+
Chef::Config.stub(:chef_server_url).and_return("https://api.opscode.piab")
|
161
|
+
command = Chef::Knife.run(%w{test yourself})
|
162
|
+
rest = command.noauth_rest
|
163
|
+
rest
|
164
|
+
end
|
165
|
+
|
166
|
+
let!(:http_client) do
|
167
|
+
http_client = Net::HTTP.new(url.host, url.port)
|
168
|
+
http_client.stub(:request).and_yield(http_response).and_return(http_response)
|
169
|
+
http_client
|
170
|
+
end
|
171
|
+
|
172
|
+
let(:url) { URI.parse("https://api.opscode.piab") }
|
173
|
+
|
174
|
+
let(:http_response) do
|
175
|
+
http_response = Net::HTTPSuccess.new("1.1", "200", "successful rest req")
|
176
|
+
http_response.stub(:read_body)
|
177
|
+
http_response.stub(:body).and_return(body)
|
178
|
+
http_response["Content-Length"] = body.bytesize.to_s
|
179
|
+
http_response
|
180
|
+
end
|
181
|
+
|
182
|
+
let(:body) { "ninja" }
|
183
|
+
|
184
|
+
before(:each) do
|
185
|
+
Chef::Config[:chef_server_url] = "https://api.opscode.piab"
|
186
|
+
if KnifeSpecs.const_defined?(:TestYourself)
|
187
|
+
KnifeSpecs.send :remove_const, :TestYourself
|
188
|
+
end
|
189
|
+
Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
|
190
|
+
Chef::Knife.subcommands.each { |name, klass| Chef::Knife.subcommands.delete(name) unless klass.kind_of?(Class) }
|
191
|
+
end
|
192
|
+
|
193
|
+
it "confirms that the headers include X-Remote-Request-Id" do
|
194
|
+
Net::HTTP::Get.should_receive(:new).with("/monkey", headers).and_return(request_mock)
|
195
|
+
rest.get_rest("monkey")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
144
199
|
describe "when running a command" do
|
145
200
|
before(:each) do
|
146
201
|
if KnifeSpecs.const_defined?(:TestYourself)
|
@@ -488,6 +488,13 @@ describe Chef::Node::Attribute do
|
|
488
488
|
end
|
489
489
|
end
|
490
490
|
|
491
|
+
describe "dup" do
|
492
|
+
it "array can be duped even if some elements can't" do
|
493
|
+
@attributes.default[:foo] = %w[foo bar baz] + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ]
|
494
|
+
@attributes.default[:foo].dup
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
491
498
|
describe "has_key?" do
|
492
499
|
it "should return true if an attribute exists" do
|
493
500
|
@attributes.has_key?("music").should == true
|
@@ -86,7 +86,7 @@ end
|
|
86
86
|
describe Chef::Node::ImmutableArray do
|
87
87
|
|
88
88
|
before do
|
89
|
-
@immutable_array = Chef::Node::ImmutableArray.new(%w[foo bar baz])
|
89
|
+
@immutable_array = Chef::Node::ImmutableArray.new(%w[foo bar baz] + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ])
|
90
90
|
end
|
91
91
|
|
92
92
|
##
|
@@ -130,6 +130,10 @@ describe Chef::Node::ImmutableArray do
|
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
|
+
it "can be duped even if some elements can't" do
|
134
|
+
@immutable_array.dup
|
135
|
+
end
|
136
|
+
|
133
137
|
it "returns a mutable version of itself when duped" do
|
134
138
|
mutable = @immutable_array.dup
|
135
139
|
mutable[0] = :value
|
@@ -96,6 +96,11 @@ describe Chef::Provider::User do
|
|
96
96
|
@provider.compare_group.should be_false
|
97
97
|
end
|
98
98
|
|
99
|
+
it "should coerce an integer to a string for comparison" do
|
100
|
+
@current_resource.stub!(:gid).and_return("500")
|
101
|
+
@provider.compare_group.should be_false
|
102
|
+
end
|
103
|
+
|
99
104
|
it "should return false if append is true and the group member(s) already exists" do
|
100
105
|
@current_resource.members << "extra_user"
|
101
106
|
@new_resource.stub(:append).and_return(true)
|
@@ -53,38 +53,264 @@ describe Chef::Provider::Ifconfig::Debian do
|
|
53
53
|
|
54
54
|
let(:config_filename_ifcfg) { "/etc/network/interfaces.d/ifcfg-#{new_resource.device}" }
|
55
55
|
|
56
|
-
describe "generate_config
|
56
|
+
describe "generate_config" do
|
57
57
|
|
58
|
-
|
58
|
+
context "when writing a file" do
|
59
|
+
let(:config_file_ifcfg) { StringIO.new }
|
59
60
|
|
60
|
-
|
61
|
+
let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") }
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
63
|
+
let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") }
|
64
|
+
|
65
|
+
let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" }
|
66
|
+
|
67
|
+
before do
|
68
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
|
69
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
|
70
|
+
expect(File).to receive(:new).with(config_filename_ifcfg, "w").and_return(config_file_ifcfg)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should write a network-script" do
|
74
|
+
provider.run_action(:add)
|
75
|
+
expect(config_file_ifcfg.string).to match(/^iface eth0 inet static\s*$/)
|
76
|
+
expect(config_file_ifcfg.string).to match(/^\s+address 10\.0\.0\.1\s*$/)
|
77
|
+
expect(config_file_ifcfg.string).to match(/^\s+netmask 255\.255\.254\.0\s*$/)
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when the interface_dot_d directory does not exist" do
|
81
|
+
before do
|
82
|
+
FileUtils.rmdir tempdir_path
|
83
|
+
expect(File.exists?(tempdir_path)).to be_false
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should create the /etc/network/interfaces.d directory" do
|
87
|
+
provider.run_action(:add)
|
88
|
+
expect(File.exists?(tempdir_path)).to be_true
|
89
|
+
expect(File.directory?(tempdir_path)).to be_true
|
90
|
+
end
|
69
91
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
92
|
+
it "should mark the resource as updated" do
|
93
|
+
provider.run_action(:add)
|
94
|
+
expect(new_resource.updated_by_last_action?).to be_true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when the interface_dot_d directory exists" do
|
99
|
+
before do
|
100
|
+
expect(File.exists?(tempdir_path)).to be_true
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should still mark the resource as updated (we still write a file to it)" do
|
104
|
+
provider.run_action(:add)
|
105
|
+
expect(new_resource.updated_by_last_action?).to be_true
|
106
|
+
end
|
107
|
+
end
|
74
108
|
end
|
75
109
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
110
|
+
context "when the file is up-to-date" do
|
111
|
+
let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") }
|
112
|
+
|
113
|
+
let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") }
|
114
|
+
|
115
|
+
let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" }
|
116
|
+
|
117
|
+
before do
|
118
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
|
119
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
|
120
|
+
config_file_ifcfg = StringIO.new(<<-EOF
|
121
|
+
iface eth0 inet static
|
122
|
+
address 10.0.0.1
|
123
|
+
netmask 255.255.254.0
|
124
|
+
EOF
|
125
|
+
)
|
126
|
+
expect(File).to receive(:new).with(config_filename_ifcfg, "w").and_return(config_file_ifcfg)
|
127
|
+
expect(File.exists?(tempdir_path)).to be_true # since the file exists, the enclosing dir must also exist
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when the /etc/network/interfaces file has the source line" do
|
131
|
+
let(:expected_string) do
|
132
|
+
<<-EOF
|
133
|
+
a line
|
134
|
+
source #{tempdir_path}/*
|
135
|
+
another line
|
136
|
+
EOF
|
137
|
+
end
|
138
|
+
|
139
|
+
before do
|
140
|
+
tempfile.write(expected_string)
|
141
|
+
tempfile.close
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should preserve all the contents" do
|
145
|
+
provider.run_action(:add)
|
146
|
+
expect(IO.read(tempfile.path)).to eq(expected_string)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not mark the resource as updated" do
|
150
|
+
provider.run_action(:add)
|
151
|
+
pending "superclass ifconfig provider is not idempotent"
|
152
|
+
expect(new_resource.updated_by_last_action?).to be_false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when the /etc/network/interfaces file does not have the source line" do
|
157
|
+
let(:expected_string) do
|
158
|
+
<<-EOF
|
159
|
+
a line
|
160
|
+
another line
|
161
|
+
source #{tempdir_path}/*
|
162
|
+
EOF
|
163
|
+
end
|
164
|
+
|
165
|
+
before do
|
166
|
+
tempfile.write("a line\nanother line\n")
|
167
|
+
tempfile.close
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should preserve the original contents and add the source line" do
|
171
|
+
provider.run_action(:add)
|
172
|
+
expect(IO.read(tempfile.path)).to eq(expected_string)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should mark the resource as updated" do
|
176
|
+
provider.run_action(:add)
|
177
|
+
expect(new_resource.updated_by_last_action?).to be_true
|
178
|
+
end
|
179
|
+
end
|
80
180
|
end
|
81
181
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
182
|
+
describe "when running under why run" do
|
183
|
+
|
184
|
+
before do
|
185
|
+
Chef::Config[:why_run] = true
|
186
|
+
end
|
187
|
+
|
188
|
+
after do
|
189
|
+
Chef::Config[:why_run] = false
|
190
|
+
end
|
191
|
+
|
192
|
+
context "when writing a file" do
|
193
|
+
let(:config_file_ifcfg) { StringIO.new }
|
194
|
+
|
195
|
+
let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") }
|
196
|
+
|
197
|
+
let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") }
|
198
|
+
|
199
|
+
let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" }
|
200
|
+
|
201
|
+
before do
|
202
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
|
203
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
|
204
|
+
expect(File).not_to receive(:new).with(config_filename_ifcfg, "w")
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should write a network-script" do
|
208
|
+
provider.run_action(:add)
|
209
|
+
expect(config_file_ifcfg.string).not_to match(/^iface eth0 inet static\s*$/)
|
210
|
+
expect(config_file_ifcfg.string).not_to match(/^\s+address 10\.0\.0\.1\s*$/)
|
211
|
+
expect(config_file_ifcfg.string).not_to match(/^\s+netmask 255\.255\.254\.0\s*$/)
|
212
|
+
end
|
213
|
+
|
214
|
+
context "when the interface_dot_d directory does not exist" do
|
215
|
+
before do
|
216
|
+
FileUtils.rmdir tempdir_path
|
217
|
+
expect(File.exists?(tempdir_path)).to be_false
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should not create the /etc/network/interfaces.d directory" do
|
221
|
+
provider.run_action(:add)
|
222
|
+
expect(File.exists?(tempdir_path)).not_to be_true
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should mark the resource as updated" do
|
226
|
+
provider.run_action(:add)
|
227
|
+
expect(new_resource.updated_by_last_action?).to be_true
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "when the interface_dot_d directory exists" do
|
232
|
+
before do
|
233
|
+
expect(File.exists?(tempdir_path)).to be_true
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should still mark the resource as updated (we still write a file to it)" do
|
237
|
+
provider.run_action(:add)
|
238
|
+
expect(new_resource.updated_by_last_action?).to be_true
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
context "when the file is up-to-date" do
|
244
|
+
let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") }
|
245
|
+
|
246
|
+
let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") }
|
247
|
+
|
248
|
+
let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" }
|
249
|
+
|
250
|
+
before do
|
251
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
|
252
|
+
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
|
253
|
+
config_file_ifcfg = StringIO.new(<<-EOF
|
254
|
+
iface eth0 inet static
|
255
|
+
address 10.0.0.1
|
256
|
+
netmask 255.255.254.0
|
257
|
+
EOF
|
258
|
+
)
|
259
|
+
expect(File).not_to receive(:new).with(config_filename_ifcfg, "w")
|
260
|
+
expect(File.exists?(tempdir_path)).to be_true # since the file exists, the enclosing dir must also exist
|
261
|
+
end
|
262
|
+
|
263
|
+
context "when the /etc/network/interfaces file has the source line" do
|
264
|
+
let(:expected_string) do
|
265
|
+
<<-EOF
|
266
|
+
a line
|
267
|
+
source #{tempdir_path}/*
|
268
|
+
another line
|
269
|
+
EOF
|
270
|
+
end
|
271
|
+
|
272
|
+
before do
|
273
|
+
tempfile.write(expected_string)
|
274
|
+
tempfile.close
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should preserve all the contents" do
|
278
|
+
provider.run_action(:add)
|
279
|
+
expect(IO.read(tempfile.path)).to eq(expected_string)
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should not mark the resource as updated" do
|
283
|
+
provider.run_action(:add)
|
284
|
+
pending "superclass ifconfig provider is not idempotent"
|
285
|
+
expect(new_resource.updated_by_last_action?).to be_false
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
context "when the /etc/network/interfaces file does not have the source line" do
|
290
|
+
let(:expected_string) do
|
291
|
+
<<-EOF
|
292
|
+
a line
|
293
|
+
another line
|
294
|
+
source #{tempdir_path}/*
|
295
|
+
EOF
|
296
|
+
end
|
297
|
+
|
298
|
+
before do
|
299
|
+
tempfile.write("a line\nanother line\n")
|
300
|
+
tempfile.close
|
301
|
+
end
|
302
|
+
|
303
|
+
it "should preserve the original contents and not add the source line" do
|
304
|
+
provider.run_action(:add)
|
305
|
+
expect(IO.read(tempfile.path)).to eq("a line\nanother line\n")
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should mark the resource as updated" do
|
309
|
+
provider.run_action(:add)
|
310
|
+
expect(new_resource.updated_by_last_action?).to be_true
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
88
314
|
end
|
89
315
|
end
|
90
316
|
|
@@ -98,4 +324,5 @@ describe Chef::Provider::Ifconfig::Debian do
|
|
98
324
|
provider.run_action(:delete)
|
99
325
|
end
|
100
326
|
end
|
327
|
+
|
101
328
|
end
|