chef 10.16.4 → 10.16.6.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/chef/monkey_patches/fileutils.rb +65 -0
- data/lib/chef/provider/deploy.rb +2 -1
- data/lib/chef/provider/template.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/spec/data/git_bundles/sinatra-test-app-with-symlinks.gitbundle +0 -0
- data/spec/functional/knife/cookbook_delete_spec.rb +0 -2
- data/spec/functional/knife/exec_spec.rb +2 -4
- data/spec/functional/knife/ssh_spec.rb +0 -1
- data/spec/functional/resource/cookbook_file_spec.rb +7 -1
- data/spec/functional/resource/deploy_revision_spec.rb +17 -1
- data/spec/functional/resource/link_spec.rb +1 -1
- data/spec/functional/resource/remote_file_spec.rb +10 -3
- data/spec/functional/tiny_server_spec.rb +5 -4
- data/spec/spec_helper.rb +2 -0
- data/spec/support/chef_helpers.rb +13 -0
- data/spec/support/platform_helpers.rb +8 -0
- data/spec/support/shared/functional/file_resource.rb +12 -4
- data/spec/support/shared/functional/securable_resource.rb +4 -0
- data/spec/tiny_server.rb +29 -10
- data/spec/unit/knife/bootstrap_spec.rb +10 -0
- data/spec/unit/provider/deploy/revision_spec.rb +2 -2
- data/spec/unit/provider/deploy_spec.rb +2 -2
- data/spec/unit/provider/directory_spec.rb +7 -4
- data/spec/unit/provider/file_spec.rb +4 -2
- data/spec/unit/provider/link_spec.rb +1 -1
- data/spec/unit/provider/remote_directory_spec.rb +4 -4
- metadata +846 -848
data/Rakefile
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Stephen Delano (<stephen@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2012 Opscode, 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
|
+
# == FileUtils::Entry_ (Patch)
|
20
|
+
# On Ruby 1.9.3 and earlier, FileUtils.cp_r(foo, bar, :preserve => true) fails
|
21
|
+
# when attempting to copy a directory containing symlinks. This has been
|
22
|
+
# patched in the trunk of Ruby, and this is a monkey patch of the offending
|
23
|
+
# code.
|
24
|
+
|
25
|
+
unless RUBY_VERSION =~ /^2/
|
26
|
+
require 'fileutils'
|
27
|
+
|
28
|
+
class FileUtils::Entry_
|
29
|
+
def copy_metadata(path)
|
30
|
+
st = lstat()
|
31
|
+
if !st.symlink?
|
32
|
+
File.utime st.atime, st.mtime, path
|
33
|
+
end
|
34
|
+
begin
|
35
|
+
if st.symlink?
|
36
|
+
begin
|
37
|
+
File.lchown st.uid, st.gid, path
|
38
|
+
rescue NotImplementedError
|
39
|
+
end
|
40
|
+
else
|
41
|
+
File.chown st.uid, st.gid, path
|
42
|
+
end
|
43
|
+
rescue Errno::EPERM
|
44
|
+
# clear setuid/setgid
|
45
|
+
if st.symlink?
|
46
|
+
begin
|
47
|
+
File.lchmod st.mode & 01777, path
|
48
|
+
rescue NotImplementedError
|
49
|
+
end
|
50
|
+
else
|
51
|
+
File.chmod st.mode & 01777, path
|
52
|
+
end
|
53
|
+
else
|
54
|
+
if st.symlink?
|
55
|
+
begin
|
56
|
+
File.lchmod st.mode, path
|
57
|
+
rescue NotImplementedError
|
58
|
+
end
|
59
|
+
else
|
60
|
+
File.chmod st.mode, path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/chef/provider/deploy.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
|
19
19
|
require "chef/mixin/command"
|
20
20
|
require "chef/mixin/from_file"
|
21
|
+
require "chef/monkey_patches/fileutils"
|
21
22
|
require "chef/provider/git"
|
22
23
|
require "chef/provider/subversion"
|
23
24
|
|
@@ -262,7 +263,7 @@ class Chef
|
|
262
263
|
target_dir_path = @new_resource.deploy_to + "/releases"
|
263
264
|
converge_by("deploy from repo to #{@target_dir_path} ") do
|
264
265
|
FileUtils.mkdir_p(target_dir_path)
|
265
|
-
|
266
|
+
FileUtils.cp_r(::File.join(@new_resource.destination, "."), release_path, :preserve => true)
|
266
267
|
Chef::Log.info "#{@new_resource} copied the cached checkout to #{release_path}"
|
267
268
|
release_created(release_path)
|
268
269
|
end
|
@@ -61,7 +61,7 @@ class Chef
|
|
61
61
|
description << diff_current(rendered_template.path)
|
62
62
|
converge_by(description) do
|
63
63
|
backup
|
64
|
-
FileUtils.
|
64
|
+
FileUtils.cp(rendered_template.path, @new_resource.path)
|
65
65
|
Chef::Log.info("#{@new_resource} updated content")
|
66
66
|
access_controls.set_all!
|
67
67
|
stat = ::File.stat(@new_resource.path)
|
data/lib/chef/version.rb
CHANGED
Binary file
|
@@ -6,9 +6,9 @@
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
8
8
|
# You may obtain a copy of the License at
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Unless required by applicable law or agreed to in writing, software
|
13
13
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
14
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -23,8 +23,6 @@ describe Chef::Knife::Exec do
|
|
23
23
|
before(:all) do
|
24
24
|
@original_config = Chef::Config.hash_dup
|
25
25
|
|
26
|
-
Thin::Logging.silent = false
|
27
|
-
|
28
26
|
@server = TinyServer::Manager.new#(:debug => true)
|
29
27
|
@server.start
|
30
28
|
end
|
@@ -24,7 +24,13 @@ describe Chef::Resource::CookbookFile do
|
|
24
24
|
let(:file_base) { 'cookbook_file_spec' }
|
25
25
|
let(:source) { 'java.response' }
|
26
26
|
let(:cookbook_name) { 'java' }
|
27
|
-
let(:expected_content)
|
27
|
+
let(:expected_content) do
|
28
|
+
content = File.open(File.join(CHEF_SPEC_DATA, 'cookbooks', 'java', 'files', 'default', 'java.response'), "rb") do |f|
|
29
|
+
f.read
|
30
|
+
end
|
31
|
+
content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
|
32
|
+
content
|
33
|
+
end
|
28
34
|
|
29
35
|
def create_resource
|
30
36
|
# set up cookbook collection for this run to use, based on our
|
@@ -69,16 +69,20 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
|
|
69
69
|
|
70
70
|
let(:git_bundle_with_in_repo_callbacks) { File.expand_path("git_bundles/sinatra-test-app-with-callback-files.gitbundle", CHEF_SPEC_DATA) }
|
71
71
|
|
72
|
+
let(:git_bundle_with_in_repo_symlinks) { File.expand_path("git_bundles/sinatra-test-app-with-symlinks.gitbundle", CHEF_SPEC_DATA) }
|
73
|
+
|
72
74
|
# This is the fourth version
|
73
75
|
let(:latest_rev) { "3eb5ca6c353c83d9179dd3b29347539829b401f3" }
|
74
76
|
|
75
77
|
# This is the third version
|
76
78
|
let(:previous_rev) { "6d19a6dbecc8e37f5b2277345885c0c783eb8fb1" }
|
77
79
|
|
78
|
-
|
79
80
|
# This is the sixth version, it is on the "with-deploy-scripts" branch
|
80
81
|
let(:rev_with_in_repo_callbacks) { "2404d015882659754bdb93ad6e4b4d3d02691a82" }
|
81
82
|
|
83
|
+
# This is the fifth version in the "with-symlinks" branch
|
84
|
+
let(:rev_with_in_repo_symlinks) { "5a4748c52aaea8250b4346a9b8ede95ee3755e28" }
|
85
|
+
|
82
86
|
# Read values from the +observe_order_file+ and split each line. This way you
|
83
87
|
# can see in which order things really happened.
|
84
88
|
def actual_operations_order
|
@@ -494,6 +498,18 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
|
|
494
498
|
end
|
495
499
|
end
|
496
500
|
|
501
|
+
context "when deploying an app with in-repo symlinks" do
|
502
|
+
let(:deploy_with_in_repo_symlinks) do
|
503
|
+
basic_deploy_resource.dup.tap do |r|
|
504
|
+
r.repo git_bundle_with_in_repo_symlinks
|
505
|
+
r.revision rev_with_in_repo_symlinks
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
it "should not raise an exception calling File.utime on symlinks" do
|
510
|
+
lambda { deploy_with_in_repo_symlinks.run_action(:deploy) }.should_not raise_error
|
511
|
+
end
|
512
|
+
end
|
497
513
|
end
|
498
514
|
|
499
515
|
|
@@ -24,7 +24,13 @@ describe Chef::Resource::RemoteFile do
|
|
24
24
|
|
25
25
|
let(:file_base) { "remote_file_spec" }
|
26
26
|
let(:source) { 'http://localhost:9000/nyan_cat.png' }
|
27
|
-
let(:expected_content)
|
27
|
+
let(:expected_content) do
|
28
|
+
content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f|
|
29
|
+
f.read
|
30
|
+
end
|
31
|
+
content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
|
32
|
+
content
|
33
|
+
end
|
28
34
|
|
29
35
|
def create_resource
|
30
36
|
node = Chef::Node.new
|
@@ -40,13 +46,14 @@ describe Chef::Resource::RemoteFile do
|
|
40
46
|
end
|
41
47
|
|
42
48
|
before(:all) do
|
43
|
-
Thin::Logging.silent = false
|
44
49
|
@server = TinyServer::Manager.new
|
45
50
|
@server.start
|
46
51
|
@api = TinyServer::API.instance
|
47
52
|
@api.clear
|
48
53
|
@api.get("/nyan_cat.png", 200) {
|
49
|
-
|
54
|
+
File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f|
|
55
|
+
f.read
|
56
|
+
end
|
50
57
|
}
|
51
58
|
end
|
52
59
|
|
@@ -37,15 +37,16 @@ describe TinyServer::API do
|
|
37
37
|
|
38
38
|
it "creates a route for a GET request" do
|
39
39
|
@api.get('/foo/bar', 200, 'hello foobar')
|
40
|
-
|
41
|
-
response.
|
40
|
+
# WEBrick gives you the full URI with host, Thin only gave the part after scheme+host+port
|
41
|
+
response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/foo/bar')
|
42
|
+
response.should == [200, {'Content-Type' => 'application/json'}, [ 'hello foobar' ]]
|
42
43
|
end
|
43
44
|
|
44
45
|
it "creates a route for a request with a block" do
|
45
46
|
block_called = false
|
46
47
|
@api.get('/bar/baz', 200) { block_called = true; 'hello barbaz' }
|
47
|
-
response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => '/bar/baz')
|
48
|
-
response.should == [200, {'Content-Type' => 'application/json'}, 'hello barbaz']
|
48
|
+
response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/bar/baz')
|
49
|
+
response.should == [200, {'Content-Type' => 'application/json'}, [ 'hello barbaz' ]]
|
49
50
|
block_called.should be_true
|
50
51
|
end
|
51
52
|
|
data/spec/spec_helper.rb
CHANGED
@@ -66,11 +66,13 @@ RSpec.configure do |config|
|
|
66
66
|
|
67
67
|
# Add jruby filters here
|
68
68
|
config.filter_run_excluding :windows_only => true unless windows?
|
69
|
+
config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3?
|
69
70
|
config.filter_run_excluding :unix_only => true unless unix?
|
70
71
|
config.filter_run_excluding :ruby_18_only => true unless ruby_18?
|
71
72
|
config.filter_run_excluding :ruby_19_only => true unless ruby_19?
|
72
73
|
config.filter_run_excluding :requires_root => true unless ENV['USER'] == 'root'
|
73
74
|
config.filter_run_excluding :requires_unprivileged_user => true if ENV['USER'] == 'root'
|
75
|
+
config.filter_run_excluding :uses_diff => true unless has_diff?
|
74
76
|
|
75
77
|
config.run_all_when_everything_filtered = true
|
76
78
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
@@ -50,3 +50,16 @@ def make_tmpname(prefix_suffix, n)
|
|
50
50
|
path << "-#{n}" if n
|
51
51
|
path << suffix
|
52
52
|
end
|
53
|
+
|
54
|
+
# NOTE:
|
55
|
+
# This is a temporary fix to get tests passing on systems that have no `diff`
|
56
|
+
# until we can replace shelling out to `diff` with ruby diff-lcs
|
57
|
+
def has_diff?
|
58
|
+
begin
|
59
|
+
diff_cmd = Mixlib::ShellOut.new("diff -v")
|
60
|
+
diff_cmd.run_command
|
61
|
+
true
|
62
|
+
rescue Errno::ENOENT
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
@@ -10,6 +10,14 @@ def windows?
|
|
10
10
|
!!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
|
11
11
|
end
|
12
12
|
|
13
|
+
def windows_win2k3?
|
14
|
+
return false unless windows?
|
15
|
+
require 'ruby-wmi'
|
16
|
+
|
17
|
+
host = WMI::Win32_OperatingSystem.find(:first)
|
18
|
+
(host.version && host.version.start_with?("5.2"))
|
19
|
+
end
|
20
|
+
|
13
21
|
# def jruby?
|
14
22
|
|
15
23
|
def unix?
|
@@ -78,6 +78,14 @@ shared_examples_for "a file resource" do
|
|
78
78
|
# note the stripping of the drive letter from the tmpdir on windows
|
79
79
|
let(:backup_glob) { File.join(CHEF_SPEC_BACKUP_PATH, Dir.tmpdir.sub(/^([A-Za-z]:)/, ""), "#{file_base}*") }
|
80
80
|
|
81
|
+
def binread(file)
|
82
|
+
content = File.open(file, "rb") do |f|
|
83
|
+
f.read
|
84
|
+
end
|
85
|
+
content.force_encoding(Encoding::BINARY) if "".respond_to?(:force_encoding)
|
86
|
+
content
|
87
|
+
end
|
88
|
+
|
81
89
|
context "when the target file does not exist" do
|
82
90
|
it "creates the file when the :create action is run" do
|
83
91
|
resource.run_action(:create)
|
@@ -86,12 +94,12 @@ shared_examples_for "a file resource" do
|
|
86
94
|
|
87
95
|
it "creates the file with the correct content when the :create action is run" do
|
88
96
|
resource.run_action(:create)
|
89
|
-
|
97
|
+
binread(path).should == expected_content
|
90
98
|
end
|
91
99
|
|
92
100
|
it "creates the file with the correct content when the :create_if_missing action is run" do
|
93
101
|
resource.run_action(:create_if_missing)
|
94
|
-
|
102
|
+
binread(path).should == expected_content
|
95
103
|
end
|
96
104
|
|
97
105
|
it "deletes the file when the :delete action is run" do
|
@@ -112,7 +120,7 @@ shared_examples_for "a file resource" do
|
|
112
120
|
|
113
121
|
context "when the target file has the wrong content" do
|
114
122
|
before(:each) do
|
115
|
-
File.open(path, "
|
123
|
+
File.open(path, "wb") { |f| f.print "This is so wrong!!!" }
|
116
124
|
@expected_mtime = File.stat(path).mtime
|
117
125
|
@expected_checksum = sha256_checksum(path)
|
118
126
|
end
|
@@ -136,7 +144,7 @@ shared_examples_for "a file resource" do
|
|
136
144
|
|
137
145
|
context "when the target file has the correct content" do
|
138
146
|
before(:each) do
|
139
|
-
File.open(path, "
|
147
|
+
File.open(path, "wb") { |f| f.print expected_content }
|
140
148
|
@expected_mtime = File.stat(path).mtime
|
141
149
|
@expected_atime = File.stat(path).atime
|
142
150
|
@expected_checksum = sha256_checksum(path)
|
@@ -29,12 +29,16 @@ shared_context "setup correct permissions" do
|
|
29
29
|
before :each do
|
30
30
|
File.chown(Etc.getpwnam('nobody').uid, 1337, path)
|
31
31
|
File.chmod(0776, path)
|
32
|
+
now = Time.now.to_i
|
33
|
+
File.utime(now - 9000, now - 9000, path)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
37
|
context "without root", :requires_unprivileged_user do
|
36
38
|
before :each do
|
37
39
|
File.chmod(0776, path)
|
40
|
+
now = Time.now.to_i
|
41
|
+
File.utime(now - 9000, now - 9000, path)
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
data/spec/tiny_server.rb
CHANGED
@@ -17,11 +17,13 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'rubygems'
|
20
|
+
require 'webrick'
|
20
21
|
require 'rack'
|
21
|
-
require 'thin'
|
22
|
+
#require 'thin'
|
22
23
|
require 'singleton'
|
23
24
|
require 'chef/json_compat'
|
24
25
|
require 'open-uri'
|
26
|
+
require 'chef/config'
|
25
27
|
|
26
28
|
module TinyServer
|
27
29
|
|
@@ -29,30 +31,42 @@ module TinyServer
|
|
29
31
|
|
30
32
|
attr_writer :app
|
31
33
|
|
32
|
-
def self.
|
34
|
+
def self.setup(options=nil, &block)
|
33
35
|
tiny_app = new(options)
|
34
36
|
app_code = Rack::Builder.new(&block).to_app
|
35
37
|
tiny_app.app = app_code
|
36
|
-
tiny_app
|
38
|
+
tiny_app
|
39
|
+
end
|
40
|
+
|
41
|
+
def shutdown
|
42
|
+
server.shutdown
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
40
46
|
class Manager
|
41
47
|
|
42
|
-
|
48
|
+
# 5 == debug, 3 == warning
|
49
|
+
LOGGER = WEBrick::Log.new(STDOUT, 3)
|
50
|
+
DEFAULT_OPTIONS = {
|
51
|
+
:server => 'webrick',
|
52
|
+
:Port => 9000,
|
53
|
+
:Host => 'localhost',
|
54
|
+
:environment => :none,
|
55
|
+
:Logger => LOGGER,
|
56
|
+
:AccessLog => [] # Remove this option to enable the access log when debugging.
|
57
|
+
}
|
43
58
|
|
44
59
|
def initialize(options=nil)
|
45
60
|
@options = options ? DEFAULT_OPTIONS.merge(options) : DEFAULT_OPTIONS
|
46
61
|
@creator = caller.first
|
47
|
-
|
48
|
-
Thin::Logging.silent = !@options[:debug]
|
49
62
|
end
|
50
63
|
|
51
64
|
def start
|
52
65
|
@server_thread = Thread.new do
|
53
|
-
@server = Server.
|
66
|
+
@server = Server.setup(@options) do
|
54
67
|
run API.instance
|
55
68
|
end
|
69
|
+
@server.start
|
56
70
|
end
|
57
71
|
block_until_started
|
58
72
|
end
|
@@ -63,7 +77,10 @@ module TinyServer
|
|
63
77
|
|
64
78
|
def block_until_started
|
65
79
|
200.times do
|
66
|
-
|
80
|
+
if started?
|
81
|
+
raise "ivar weirdness" if @server.nil?
|
82
|
+
return true
|
83
|
+
end
|
67
84
|
end
|
68
85
|
raise "TinyServer failed to boot :/"
|
69
86
|
end
|
@@ -84,6 +101,7 @@ module TinyServer
|
|
84
101
|
|
85
102
|
def stop
|
86
103
|
# yes, this is terrible.
|
104
|
+
@server.shutdown
|
87
105
|
@server_thread.kill
|
88
106
|
@server_thread.join
|
89
107
|
@server_thread = nil
|
@@ -132,7 +150,7 @@ module TinyServer
|
|
132
150
|
debug_info = {:message => "no data matches the request for #{env['REQUEST_URI']}",
|
133
151
|
:available_routes => @routes, :request => env}
|
134
152
|
# Uncomment me for glorious debugging
|
135
|
-
#pp :not_found => debug_info
|
153
|
+
# pp :not_found => debug_info
|
136
154
|
[404, {'Content-Type' => 'application/json'}, debug_info.to_json]
|
137
155
|
end
|
138
156
|
end
|
@@ -152,6 +170,7 @@ module TinyServer
|
|
152
170
|
end
|
153
171
|
|
154
172
|
def matches_request?(uri)
|
173
|
+
uri = URI.parse(uri).request_uri
|
155
174
|
@path_spec === uri
|
156
175
|
end
|
157
176
|
|
@@ -171,7 +190,7 @@ module TinyServer
|
|
171
190
|
|
172
191
|
def call
|
173
192
|
data = @data || @block.call
|
174
|
-
[@response_code, HEADERS, data]
|
193
|
+
[@response_code, HEADERS, Array(data)]
|
175
194
|
end
|
176
195
|
|
177
196
|
def to_s
|