chef 13.3.42-universal-mingw32 → 13.4.19-universal-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/VERSION +1 -1
- data/lib/.DS_Store +0 -0
- data/lib/chef/.DS_Store +0 -0
- data/lib/chef/knife/core/ui.rb +1 -1
- data/lib/chef/mash.rb +6 -0
- data/lib/chef/mixin/deep_merge.rb +1 -1
- data/lib/chef/mixin/user_context.rb +52 -0
- data/lib/chef/node/attribute.rb +80 -14
- data/lib/chef/node/immutable_collections.rb +16 -19
- data/lib/chef/provider/apt_repository.rb +12 -10
- data/lib/chef/provider/git.rb +20 -3
- data/lib/chef/provider/ifconfig/redhat.rb +4 -0
- data/lib/chef/provider/launchd.rb +20 -0
- data/lib/chef/provider/package/dnf.rb +3 -1
- data/lib/chef/provider/remote_file.rb +19 -0
- data/lib/chef/provider/remote_file/fetcher.rb +3 -0
- data/lib/chef/provider/remote_file/network_file.rb +18 -5
- data/lib/chef/provider/service/macosx.rb +4 -3
- data/lib/chef/provider/windows_path.rb +62 -0
- data/lib/chef/provider/zypper_repository.rb +1 -1
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource.rb +5 -1
- data/lib/chef/resource/apt_repository.rb +1 -1
- data/lib/chef/resource/ifconfig.rb +36 -0
- data/lib/chef/resource/remote_file.rb +60 -0
- data/lib/chef/resource/windows_path.rb +41 -0
- data/lib/chef/resource/zypper_repository.rb +1 -0
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/shell.rb +1 -0
- data/lib/chef/shell/shell_session.rb +4 -4
- data/lib/chef/util/windows/logon_session.rb +126 -0
- data/lib/chef/version.rb +4 -3
- data/lib/chef/win32/api/security.rb +2 -0
- data/spec/.DS_Store +0 -0
- data/spec/data/nodes/Timothys-MacBook-Pro.local.json +3 -0
- data/spec/functional/.DS_Store +0 -0
- data/spec/functional/mixin/user_context_spec.rb +117 -0
- data/spec/functional/resource/remote_file_spec.rb +171 -0
- data/spec/functional/resource/windows_path_spec.rb +64 -0
- data/spec/support/.DS_Store +0 -0
- data/spec/unit/.DS_Store +0 -0
- data/spec/unit/knife/client_delete_spec.rb +1 -1
- data/spec/unit/mixin/user_context_spec.rb +109 -0
- data/spec/unit/node/immutable_collections_spec.rb +12 -4
- data/spec/unit/node_spec.rb +7 -0
- data/spec/unit/provider/git_spec.rb +55 -0
- data/spec/unit/provider/ifconfig/redhat_spec.rb +8 -0
- data/spec/unit/provider/remote_file/fetcher_spec.rb +1 -0
- data/spec/unit/provider/remote_file/network_file_spec.rb +7 -2
- data/spec/unit/provider/service/macosx_spec.rb +4 -1
- data/spec/unit/provider/windows_path_spec.rb +65 -0
- data/spec/unit/resource/windows_path_spec.rb +38 -0
- data/spec/unit/resource_spec.rb +8 -0
- data/spec/unit/shell/shell_session_spec.rb +82 -58
- data/spec/unit/util/windows/logon_session_spec.rb +284 -0
- data/tasks/maintainers.rb +3 -3
- metadata +22 -5
data/lib/chef/version.rb
CHANGED
@@ -14,15 +14,16 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
|
16
16
|
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
17
|
-
# NOTE: This file is
|
18
|
-
#
|
17
|
+
# NOTE: This file is generated by running `rake version` in the top level of
|
18
|
+
# this repo. Do not edit this manually. Edit the VERSION file and run the rake
|
19
|
+
# task instead.
|
19
20
|
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
20
21
|
|
21
22
|
require "chef/version_string"
|
22
23
|
|
23
24
|
class Chef
|
24
25
|
CHEF_ROOT = File.expand_path("../..", __FILE__)
|
25
|
-
VERSION = Chef::VersionString.new("13.
|
26
|
+
VERSION = Chef::VersionString.new("13.4.19")
|
26
27
|
end
|
27
28
|
|
28
29
|
#
|
@@ -453,6 +453,8 @@ class Chef
|
|
453
453
|
safe_attach_function :SetSecurityDescriptorSacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL
|
454
454
|
safe_attach_function :GetTokenInformation, [ :HANDLE, :TOKEN_INFORMATION_CLASS, :pointer, :DWORD, :PDWORD ], :BOOL
|
455
455
|
safe_attach_function :LogonUserW, [:LPTSTR, :LPTSTR, :LPTSTR, :DWORD, :DWORD, :PHANDLE], :BOOL
|
456
|
+
safe_attach_function :ImpersonateLoggedOnUser, [:HANDLE], :BOOL
|
457
|
+
safe_attach_function :RevertToSelf, [], :BOOL
|
456
458
|
|
457
459
|
end
|
458
460
|
end
|
data/spec/.DS_Store
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2015 Chef Software, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require "spec_helper"
|
19
|
+
|
20
|
+
require "chef/win32/api" if Chef::Platform.windows?
|
21
|
+
require "chef/win32/api/error" if Chef::Platform.windows?
|
22
|
+
require "chef/mixin/user_context"
|
23
|
+
|
24
|
+
describe Chef::Mixin::UserContext, windows_only: true do
|
25
|
+
include Chef::Mixin::UserContext
|
26
|
+
|
27
|
+
let(:get_user_name_a) do
|
28
|
+
FFI.ffi_lib "advapi32.dll"
|
29
|
+
FFI.attach_function :GetUserNameA, [ :pointer, :pointer ], :bool
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:process_username) do
|
33
|
+
name_size = FFI::Buffer.new(:long).write_long(0)
|
34
|
+
succeeded = get_user_name_a.call(nil, name_size)
|
35
|
+
last_error = FFI::LastError.error
|
36
|
+
if succeeded || last_error != Chef::ReservedNames::Win32::API::Error::ERROR_INSUFFICIENT_BUFFER
|
37
|
+
raise Chef::Exceptions::Win32APIError, "Expected ERROR_INSUFFICIENT_BUFFER from GetUserNameA but it returned the following error: #{last_error}"
|
38
|
+
end
|
39
|
+
user_name = FFI::MemoryPointer.new :char, (name_size.read_long)
|
40
|
+
succeeded = get_user_name_a.call(user_name, name_size)
|
41
|
+
last_error = FFI::LastError.error
|
42
|
+
if succeeded == 0 || last_error != 0
|
43
|
+
raise Chef::Exceptions::Win32APIError, "GetUserNameA failed with #{lasterror}"
|
44
|
+
end
|
45
|
+
user_name.read_string
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:test_user) { "chefuserctx3" }
|
49
|
+
let(:test_domain) { windows_nonadmin_user_domain }
|
50
|
+
let(:test_password) { "j823jfxK3;2Xe1" }
|
51
|
+
|
52
|
+
let(:username_domain_qualification) { nil }
|
53
|
+
let(:username_with_conditional_domain) { username_domain_qualification.nil? ? username_to_impersonate : "#{username_domain_qualification}\\#{username_to_impersonate}" }
|
54
|
+
|
55
|
+
let(:windows_nonadmin_user) { test_user }
|
56
|
+
let(:windows_nonadmin_user_password) { test_password }
|
57
|
+
|
58
|
+
let(:username_while_impersonating) do
|
59
|
+
username = nil
|
60
|
+
with_user_context(username_with_conditional_domain, username_to_impersonate_password, domain_to_impersonate) do
|
61
|
+
username = process_username
|
62
|
+
end
|
63
|
+
username
|
64
|
+
end
|
65
|
+
|
66
|
+
before do
|
67
|
+
allow_any_instance_of(described_class).to receive(:node).and_return({ "platform_family" => "windows" })
|
68
|
+
end
|
69
|
+
|
70
|
+
shared_examples_for "method that executes the block while impersonating the alternate user" do
|
71
|
+
it "uses different credentials for other network connections" do
|
72
|
+
allow_any_instance_of(Chef::Util::Windows::LogonSession).to receive(:validate_session_open!).and_return(true)
|
73
|
+
expect(username_while_impersonating.downcase).not_to eq(username_to_impersonate.downcase)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#with_user_context" do
|
78
|
+
context "when the user and domain are both nil" do
|
79
|
+
let(:username_to_impersonate) { nil }
|
80
|
+
let(:domain_to_impersonate) { nil }
|
81
|
+
let(:username_to_impersonate_password) { nil }
|
82
|
+
|
83
|
+
it "has the same token and username as the process" do
|
84
|
+
expect(username_while_impersonating.downcase).to eq(ENV["username"].downcase)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when a non-nil user is specified" do
|
89
|
+
include_context "a non-admin Windows user"
|
90
|
+
context "when a username different than the process user is specified" do
|
91
|
+
let(:username_to_impersonate) { test_user }
|
92
|
+
let(:username_to_impersonate_password) { test_password }
|
93
|
+
context "when an explicit domain is given with a valid password" do
|
94
|
+
let(:domain_to_impersonate) { test_domain }
|
95
|
+
it "uses different credentials for other network connections" do
|
96
|
+
expect(username_while_impersonating.downcase).not_to eq(username_to_impersonate.downcase)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when a valid password and a non-qualified user is given and no domain is specified" do
|
101
|
+
let(:domain_to_impersonate) { "." }
|
102
|
+
it_behaves_like "method that executes the block while impersonating the alternate user"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "raises an error user if specified with the wrong password" do
|
106
|
+
expect { with_user_context(username_to_impersonate, username_to_impersonate_password + "1", nil) }.to raise_error(ArgumentError)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when invalid arguments are passed" do
|
112
|
+
it "raises an ArgumentError exception if the password is not specified but the user is specified" do
|
113
|
+
expect { with_user_context(test_user, nil, nil) }.to raise_error(ArgumentError)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -123,6 +123,177 @@ describe Chef::Resource::RemoteFile do
|
|
123
123
|
|
124
124
|
end
|
125
125
|
|
126
|
+
context "when running on Windows", :windows_only do
|
127
|
+
describe "when fetching files over SMB" do
|
128
|
+
include Chef::Mixin::ShellOut
|
129
|
+
let(:smb_share_root_directory) { directory = File.join(Dir.tmpdir, make_tmpname("windows_script_test")); Dir.mkdir(directory); directory }
|
130
|
+
let(:smb_file_local_file_name) { "smb_file.txt" }
|
131
|
+
let(:smb_file_local_path) { File.join( smb_share_root_directory, smb_file_local_file_name ) }
|
132
|
+
let(:smb_share_name) { "chef_smb_test" }
|
133
|
+
let(:smb_remote_path) { File.join("//#{ENV['COMPUTERNAME']}", smb_share_name, smb_file_local_file_name).gsub(/\//, "\\") }
|
134
|
+
let(:smb_file_content) { "hellofun" }
|
135
|
+
let(:local_destination_path) { File.join(Dir.tmpdir, make_tmpname("chef_remote_file")) }
|
136
|
+
let(:windows_current_user) { ENV["USERNAME"] }
|
137
|
+
let(:windows_current_user_domain) { ENV["USERDOMAIN"] || ENV["COMPUTERNAME"] }
|
138
|
+
let(:windows_current_user_qualified) { "#{windows_current_user_domain}\\#{windows_current_user}" }
|
139
|
+
|
140
|
+
let(:remote_domain) { nil }
|
141
|
+
let(:remote_user) { nil }
|
142
|
+
let(:remote_password) { nil }
|
143
|
+
|
144
|
+
let(:resource) do
|
145
|
+
node = Chef::Node.new
|
146
|
+
events = Chef::EventDispatch::Dispatcher.new
|
147
|
+
run_context = Chef::RunContext.new(node, {}, events)
|
148
|
+
resource = Chef::Resource::RemoteFile.new(path, run_context)
|
149
|
+
end
|
150
|
+
|
151
|
+
before do
|
152
|
+
shell_out("net.exe share #{smb_share_name} /delete")
|
153
|
+
File.write(smb_file_local_path, smb_file_content )
|
154
|
+
shell_out!("net.exe share #{smb_share_name}=\"#{smb_share_root_directory.gsub(/\//, '\\')}\" /grant:\"authenticated users\",read")
|
155
|
+
end
|
156
|
+
|
157
|
+
after do
|
158
|
+
shell_out("net.exe share #{smb_share_name} /delete")
|
159
|
+
File.delete(smb_file_local_path) if File.exist?(smb_file_local_path)
|
160
|
+
File.delete(local_destination_path) if File.exist?(local_destination_path)
|
161
|
+
Dir.rmdir(smb_share_root_directory)
|
162
|
+
end
|
163
|
+
|
164
|
+
context "when configuring the Windows identity used to access the remote file" do
|
165
|
+
before do
|
166
|
+
resource.path(local_destination_path)
|
167
|
+
resource.source(smb_remote_path)
|
168
|
+
resource.remote_domain(remote_domain)
|
169
|
+
resource.remote_user(remote_user)
|
170
|
+
resource.remote_password(remote_password)
|
171
|
+
resource.node.default["platform_family"] = "windows"
|
172
|
+
allow_any_instance_of(Chef::Provider::RemoteFile::NetworkFile).to receive(:node).and_return({ "platform_family" => "windows" })
|
173
|
+
end
|
174
|
+
|
175
|
+
shared_examples_for "a remote_file resource accessing a remote file to which the specified user has access" do
|
176
|
+
it "has the same content as the original file" do
|
177
|
+
expect { resource.run_action(:create) }.not_to raise_error
|
178
|
+
expect(::File.read(local_destination_path).chomp).to eq smb_file_content
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
shared_examples_for "a remote_file resource accessing a remote file to which the specified user does not have access" do
|
183
|
+
it "causes an error to be raised" do
|
184
|
+
expect { resource.run_action(:create) }.to raise_error(Errno::EACCES)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
shared_examples_for "a remote_file resource accessing a remote file with invalid user" do
|
189
|
+
it "causes an error to be raised" do
|
190
|
+
allow(Chef::Util::Windows::LogonSession).to receive(:validate_session_open!).and_return(true)
|
191
|
+
expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32APIError)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "when the file is accessible to non-admin users only as the current identity" do
|
196
|
+
before do
|
197
|
+
shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /grant \"#{windows_current_user_qualified}:(R)\" /inheritance:r")
|
198
|
+
end
|
199
|
+
|
200
|
+
context "when the resource is accessed using the current user's identity" do
|
201
|
+
let(:remote_user) { nil }
|
202
|
+
let(:remote_domain) { nil }
|
203
|
+
let(:remote_password) { nil }
|
204
|
+
|
205
|
+
it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
|
206
|
+
|
207
|
+
describe "uses the ::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE constant to chunk the file" do
|
208
|
+
let(:invalid_chunk_size) { -1 }
|
209
|
+
before do
|
210
|
+
stub_const("::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE", invalid_chunk_size)
|
211
|
+
end
|
212
|
+
|
213
|
+
it "raises an ArgumentError when the chunk size is negative" do
|
214
|
+
expect(::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE).to eq(invalid_chunk_size)
|
215
|
+
expect { resource.run_action(:create) }.to raise_error(ArgumentError)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
context "when the file must be transferred in more than one chunk" do
|
220
|
+
before do
|
221
|
+
stub_const("::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE", 3)
|
222
|
+
end
|
223
|
+
it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "when the resource is accessed using an alternate user's identity with no access to the file" do
|
228
|
+
let (:windows_nonadmin_user) { "chefremfile1" }
|
229
|
+
let (:windows_nonadmin_user_password) { "j82ajfxK3;2Xe1" }
|
230
|
+
include_context "a non-admin Windows user"
|
231
|
+
|
232
|
+
before do
|
233
|
+
shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /deny \"#{windows_current_user_qualified}:(R)\" /inheritance:r")
|
234
|
+
end
|
235
|
+
|
236
|
+
let(:remote_user) { windows_nonadmin_user }
|
237
|
+
let(:remote_domain) { windows_nonadmin_user_domain }
|
238
|
+
let(:remote_password) { windows_nonadmin_user_password }
|
239
|
+
|
240
|
+
it_behaves_like "a remote_file resource accessing a remote file to which the specified user does not have access"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context "when the the file is only accessible as a specific alternate identity" do
|
245
|
+
let (:windows_nonadmin_user) { "chefremfile2" }
|
246
|
+
let (:windows_nonadmin_user_password) { "j82ajfxK3;2Xe2" }
|
247
|
+
include_context "a non-admin Windows user"
|
248
|
+
|
249
|
+
before do
|
250
|
+
shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /grant \"#{windows_current_user_qualified}:(R)\" /inheritance:r")
|
251
|
+
end
|
252
|
+
|
253
|
+
context "when the resource is accessed using the specific non-qualified alternate user identity with access" do
|
254
|
+
let(:remote_user) { windows_nonadmin_user }
|
255
|
+
let(:remote_domain) { "." }
|
256
|
+
let(:remote_password) { windows_nonadmin_user_password }
|
257
|
+
|
258
|
+
it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
|
259
|
+
end
|
260
|
+
|
261
|
+
context "when the resource is accessed using the specific alternate user identity with access and the domain is specified" do
|
262
|
+
let(:remote_user) { windows_nonadmin_user }
|
263
|
+
let(:remote_domain) { windows_nonadmin_user_domain }
|
264
|
+
let(:remote_password) { windows_nonadmin_user_password }
|
265
|
+
|
266
|
+
it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
|
267
|
+
end
|
268
|
+
|
269
|
+
context "when the resource is accessed using the current user's identity" do
|
270
|
+
before do
|
271
|
+
shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /grant \"#{windows_nonadmin_user_qualified}:(R)\" /deny #{windows_current_user_qualified}:(R) /inheritance:r")
|
272
|
+
end
|
273
|
+
|
274
|
+
it_behaves_like "a remote_file resource accessing a remote file to which the specified user does not have access"
|
275
|
+
end
|
276
|
+
|
277
|
+
context "when the resource is accessed using an alternate user's identity with no access to the file" do
|
278
|
+
let (:windows_nonadmin_user) { "chefremfile3" }
|
279
|
+
let (:windows_nonadmin_user_password) { "j82ajfxK3;2Xe3" }
|
280
|
+
include_context "a non-admin Windows user"
|
281
|
+
|
282
|
+
let(:remote_user) { windows_nonadmin_user_qualified }
|
283
|
+
let(:remote_domain) { nil }
|
284
|
+
let(:remote_password) { windows_nonadmin_user_password }
|
285
|
+
|
286
|
+
before do
|
287
|
+
allow_any_instance_of(Chef::Util::Windows::LogonSession).to receive(:validate_session_open!).and_return(true)
|
288
|
+
end
|
289
|
+
|
290
|
+
it_behaves_like "a remote_file resource accessing a remote file with invalid user"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
126
297
|
context "when dealing with content length checking" do
|
127
298
|
before(:each) do
|
128
299
|
start_tiny_server
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
|
3
|
+
# Copyright:: Copyright (c) 2017 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::WindowsPath, :windows_only do
|
22
|
+
let(:path) { "test_path" }
|
23
|
+
|
24
|
+
before(:all) do
|
25
|
+
@old_path = ENV["PATH"].dup
|
26
|
+
end
|
27
|
+
|
28
|
+
after(:all) do
|
29
|
+
ENV["PATH"] = @old_path
|
30
|
+
end
|
31
|
+
|
32
|
+
subject do
|
33
|
+
new_resource = Chef::Resource::WindowsPath.new(path, run_context)
|
34
|
+
new_resource
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "adding path" do
|
38
|
+
after { remove_path }
|
39
|
+
|
40
|
+
it "appends the user given path in the Environment variable Path" do
|
41
|
+
subject.run_action(:add)
|
42
|
+
expect(ENV["PATH"]).to include(path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "removing path" do
|
47
|
+
before { add_path }
|
48
|
+
|
49
|
+
it "removes the user given path from the Environment variable Path" do
|
50
|
+
subject.run_action(:remove)
|
51
|
+
expect(ENV["PATH"]).not_to include(path)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def remove_path
|
56
|
+
new_resource = Chef::Resource::WindowsPath.new(path, run_context)
|
57
|
+
new_resource.run_action(:remove)
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_path
|
61
|
+
new_resource = Chef::Resource::WindowsPath.new(path, run_context)
|
62
|
+
new_resource.run_action(:add)
|
63
|
+
end
|
64
|
+
end
|
Binary file
|
data/spec/unit/.DS_Store
ADDED
Binary file
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2015 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/user_context"
|
21
|
+
require "chef/util/windows/logon_session"
|
22
|
+
|
23
|
+
describe "a class that mixes in user_context" do
|
24
|
+
let(:instance_with_user_context) do
|
25
|
+
class UserContextConsumer
|
26
|
+
include ::Chef::Mixin::UserContext
|
27
|
+
def with_context(user, domain, password, &block)
|
28
|
+
with_user_context(user, password, domain, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
UserContextConsumer.new
|
32
|
+
end
|
33
|
+
|
34
|
+
shared_examples_for "a method that requires a block" do
|
35
|
+
it "raises an ArgumentError exception if a block is not supplied" do
|
36
|
+
expect { instance_with_user_context.with_context(nil, nil, nil) }.to raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when running on Windows" do
|
41
|
+
before do
|
42
|
+
allow(::Chef::Platform).to receive(:windows?).and_return(true)
|
43
|
+
allow(::Chef::Util::Windows::LogonSession).to receive(:new).and_return(logon_session)
|
44
|
+
allow(instance_with_user_context).to receive(:node).and_return({ "platform_family" => "windows" })
|
45
|
+
end
|
46
|
+
|
47
|
+
let(:logon_session) { instance_double("::Chef::Util::Windows::LogonSession", :set_user_context => nil, :open => nil, :close => nil) }
|
48
|
+
|
49
|
+
it "does not raise an exception when the user and all parameters are nil" do
|
50
|
+
expect { instance_with_user_context.with_context(nil, nil, nil) {} }.not_to raise_error
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when given valid user credentials" do
|
54
|
+
before do
|
55
|
+
expect(::Chef::Util::Windows::LogonSession).to receive(:new).and_return(logon_session)
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:block_object) do
|
59
|
+
class BlockClass
|
60
|
+
def block_method
|
61
|
+
end
|
62
|
+
end
|
63
|
+
BlockClass.new
|
64
|
+
end
|
65
|
+
|
66
|
+
let(:block_parameter) { Proc.new { block_object.block_method } }
|
67
|
+
|
68
|
+
context "when the block doesn't raise an exception" do
|
69
|
+
before do
|
70
|
+
expect( block_object ).to receive(:block_method)
|
71
|
+
end
|
72
|
+
it "calls the supplied block" do
|
73
|
+
expect { instance_with_user_context.with_context("kamilah", nil, "chef4life", &block_parameter) }.not_to raise_error
|
74
|
+
end
|
75
|
+
|
76
|
+
it "does not raise an exception if the user, password, and domain are specified" do
|
77
|
+
expect { instance_with_user_context.with_context("kamilah", "xanadu", "chef4life", &block_parameter) }.not_to raise_error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when the block raises an exception" do
|
82
|
+
class UserContextTestException < RuntimeError
|
83
|
+
end
|
84
|
+
let(:block_parameter) { Proc.new { raise UserContextTextException } }
|
85
|
+
|
86
|
+
it "raises the exception raised by the block" do
|
87
|
+
expect { instance_with_user_context.with_context("kamilah", nil, "chef4life", &block_parameter) }.not_to raise_error(UserContextTestException)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "closes the logon session so resources are not leaked" do
|
91
|
+
expect(logon_session).to receive(:close)
|
92
|
+
expect { instance_with_user_context.with_context("kamilah", nil, "chef4life", &block_parameter) }.not_to raise_error(UserContextTestException)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it_behaves_like "a method that requires a block"
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when not running on Windows" do
|
101
|
+
before do
|
102
|
+
allow(instance_with_user_context).to receive(:node).and_return({ "platform_family" => "ubuntu" })
|
103
|
+
end
|
104
|
+
|
105
|
+
it "raises a ::Chef::Exceptions::UnsupportedPlatform exception" do
|
106
|
+
expect { instance_with_user_context.with_context(nil, nil, nil) {} }.to raise_error(::Chef::Exceptions::UnsupportedPlatform)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|