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 CHANGED
@@ -21,7 +21,7 @@ require File.dirname(__FILE__) + '/lib/chef/version'
21
21
 
22
22
  require 'rubygems'
23
23
  require 'rubygems/package_task'
24
- require 'rake/rdoctask'
24
+ require 'rdoc/task'
25
25
  require './tasks/rspec.rb'
26
26
 
27
27
  GEM_NAME = "chef"
@@ -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
@@ -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
- run_command(:command => "cp -RPp #{::File.join(@new_resource.destination, ".")} #{release_path}")
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.mv(rendered_template.path, @new_resource.path)
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)
@@ -17,7 +17,7 @@
17
17
 
18
18
  class Chef
19
19
  CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
20
- VERSION = '10.16.4'
20
+ VERSION = '10.16.6.rc.0'
21
21
  end
22
22
 
23
23
  # NOTE: the Chef::Version class is defined in version_class.rb
@@ -23,8 +23,6 @@ describe Chef::Knife::CookbookDelete do
23
23
  before(:all) do
24
24
  @original_config = Chef::Config.hash_dup
25
25
 
26
- Thin::Logging.silent = true
27
-
28
26
  @server = TinyServer::Manager.new
29
27
  @server.start
30
28
  end
@@ -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,6 @@ describe Chef::Knife::Ssh do
24
24
  before(:all) do
25
25
  @original_config = Chef::Config.hash_dup
26
26
  Chef::Knife::Ssh.load_deps
27
- Thin::Logging.silent = true
28
27
  @server = TinyServer::Manager.new
29
28
  @server.start
30
29
  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) { IO.read(File.join(CHEF_SPEC_DATA, 'cookbooks', 'java', 'files', 'default', 'java.response')) }
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
 
@@ -22,7 +22,7 @@ if windows?
22
22
  require 'chef/win32/file' #probably need this in spec_helper
23
23
  end
24
24
 
25
- describe Chef::Resource::Link do
25
+ describe Chef::Resource::Link, :not_supported_on_win2k3 do
26
26
  let(:file_base) { "file_spec" }
27
27
 
28
28
  let(:base_dir) do
@@ -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) { IO.read(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png')) }
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
- IO.read(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'))
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
- response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => '/foo/bar')
41
- response.should == [200, {'Content-Type' => 'application/json'}, 'hello foobar']
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
 
@@ -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
- IO.read(path).should == expected_content
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
- IO.read(path).should == expected_content
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, "w") { |f| f.print "This is so wrong!!!" }
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, "w") { |f| f.print expected_content }
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
@@ -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.run(options=nil, &block)
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.start
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
- DEFAULT_OPTIONS = {:server => 'thin', :Port => 9000, :Host => 'localhost', :environment => :none}
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.run(@options) do
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
- return true if started?
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