summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_NOTES.md2
-rw-r--r--lib/chef/config.rb76
-rw-r--r--lib/chef/exceptions.rb7
-rw-r--r--lib/chef/file_content_management/tempfile.rb38
-rw-r--r--lib/chef/shell.rb12
-rw-r--r--spec/unit/config_spec.rb6
-rw-r--r--spec/unit/provider/file/content_spec.rb25
7 files changed, 108 insertions, 58 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 6faeacdde8..c20b486f43 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -52,7 +52,7 @@ when using `knife.rb`. Once third-party application developers have had
sufficient time to adapt to the change, `knife.rb` will become
deprecated and config.rb will be preferred.
-## Boostrap Changes
+## Bootstrap Changes
Chef Client 12 introduces a set of changes to `knife bootstrap`. Here is the list of changes:
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index d3871c38e8..08ce1a8ff6 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -560,10 +560,12 @@ class Chef
# used to update files.
default :file_atomic_update, true
- # If false file staging is will be done via tempfiles that are
- # created under ENV['TMP'] otherwise tempfiles will be created in
- # the directory that files are going to reside.
- default :file_staging_uses_destdir, true
+ # There are 3 possible values for this configuration setting.
+ # true => file staging is done in the destination directory
+ # false => file staging is done via tempfiles under ENV['TMP']
+ # :auto => file staging will try using destination directory if possible and
+ # will fall back to ENV['TMP'] if destination directory is not usable.
+ default :file_staging_uses_destdir, :auto
# Exit if another run is in progress and the chef-client is unable to
# get the lock before time expires. If nil, no timeout is enforced. (Exits
@@ -623,44 +625,44 @@ class Chef
#
# If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
# available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
- default :internal_locale do
- begin
- # https://github.com/opscode/chef/issues/2181
- # Some systems have the `locale -a` command, but the result has
- # invalid characters for the default encoding.
- #
- # For example, on CentOS 6 with ENV['LANG'] = "en_US.UTF-8",
- # `locale -a`.split fails with ArgumentError invalid UTF-8 encoding.
- locales = shell_out_with_systems_locale("locale -a").stdout.split
- case
- when locales.include?('C.UTF-8')
- 'C.UTF-8'
- when locales.include?('en_US.UTF-8'), locales.include?('en_US.utf8')
- 'en_US.UTF-8'
- when locales.include?('en.UTF-8')
- 'en.UTF-8'
- else
- # Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
- guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
- unless guesses.empty?
- guessed_locale = guesses.first
- # Transform into the form en_ZZ.UTF-8
- guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
- else
- Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
- 'C'
- end
- end
- rescue
- if Chef::Platform.windows?
- Chef::Log.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
+ def self.guess_internal_locale
+ # https://github.com/opscode/chef/issues/2181
+ # Some systems have the `locale -a` command, but the result has
+ # invalid characters for the default encoding.
+ #
+ # For example, on CentOS 6 with ENV['LANG'] = "en_US.UTF-8",
+ # `locale -a`.split fails with ArgumentError invalid UTF-8 encoding.
+ locales = shell_out_with_systems_locale("locale -a").stdout.split
+ case
+ when locales.include?('C.UTF-8')
+ 'C.UTF-8'
+ when locales.include?('en_US.UTF-8'), locales.include?('en_US.utf8')
+ 'en_US.UTF-8'
+ when locales.include?('en.UTF-8')
+ 'en.UTF-8'
+ else
+ # Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
+ guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
+ unless guesses.empty?
+ guessed_locale = guesses.first
+ # Transform into the form en_ZZ.UTF-8
+ guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
else
- Chef::Log.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
+ Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
+ 'C'
end
- 'en_US.UTF-8'
end
+ rescue
+ if Chef::Platform.windows?
+ Chef::Log.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
+ else
+ Chef::Log.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
+ end
+ 'en_US.UTF-8'
end
+ default :internal_locale, guess_internal_locale
+
# Force UTF-8 Encoding, for when we fire up in the 'C' locale or other strange locales (e.g.
# japanese windows encodings). If we do not do this, then knife upload will fail when a cookbook's
# README.md has UTF-8 characters that do not encode in whatever surrounding encoding we have been
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 25f08455fc..93fdd414e4 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -126,6 +126,13 @@ class Chef
class CannotDetermineHomebrewOwner < Package; end
+ # Can not create staging file during file deployment
+ class FileContentStagingError < RuntimeError
+ def initialize(errors)
+ super "Staging tempfile can not be created during file deployment.\n Errors: #{errors.join('\n')}!"
+ end
+ end
+
# A different version of a cookbook was added to a
# VersionedRecipeList than the one already there.
class CookbookVersionConflict < ArgumentError ; end
diff --git a/lib/chef/file_content_management/tempfile.rb b/lib/chef/file_content_management/tempfile.rb
index 61a5ce2a7c..2dde0ce21b 100644
--- a/lib/chef/file_content_management/tempfile.rb
+++ b/lib/chef/file_content_management/tempfile.rb
@@ -35,7 +35,22 @@ class Chef
private
def tempfile_open
- tf = ::Tempfile.open(tempfile_basename, tempfile_dirname)
+ tf = nil
+ errors = [ ]
+
+ tempfile_dirnames.each do |tempfile_dirname|
+ begin
+ tf = ::Tempfile.open(tempfile_basename, tempfile_dirname)
+ break
+ rescue SystemCallError => e
+ message = "Creating temp file under '#{tempfile_dirname}' failed with: '#{e.message}'"
+ Chef::Log.debug(message)
+ errors << message
+ end
+ end
+
+ raise Chef::Exceptions::FileContentStagingError(errors) if tf.nil?
+
# We always process the tempfile in binmode so that we
# preserve the line endings of the content.
tf.binmode
@@ -53,16 +68,29 @@ class Chef
basename
end
- def tempfile_dirname
+ # Returns the possible directories for the tempfile to be created in.
+ def tempfile_dirnames
# in why-run mode we need to create a Tempfile to compare against, which we will never
# wind up deploying, but our enclosing directory for the destdir may not exist yet, so
# instead we can reliably always create a Tempfile to compare against in Dir::tmpdir
- if Chef::Config[:file_staging_uses_destdir] && !Chef::Config[:why_run]
- ::File.dirname(@new_resource.path)
+ if Chef::Config[:why_run]
+ [ Dir.tmpdir ]
else
- Dir::tmpdir
+ case Chef::Config[:file_staging_uses_destdir]
+ when :auto
+ # In auto mode we try the destination directory first and fallback to ENV['TMP'] if
+ # that doesn't work.
+ [ ::File.dirname(@new_resource.path), Dir.tmpdir ]
+ when true
+ [ ::File.dirname(@new_resource.path) ]
+ when false
+ [ Dir.tmpdir ]
+ else
+ raise Chef::Exceptions::ConfigurationError, "Unknown setting '#{Chef::Config[:file_staging_uses_destdir]}' for Chef::Config[:file_staging_uses_destdir]. Possible values are :auto, true or false."
+ end
end
end
+
end
end
end
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index c5b8296c63..fed32b3795 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -308,17 +308,9 @@ FOOTER
elsif ENV['HOME'] && ::File.exist?(File.join(ENV['HOME'], '.chef', 'chef_shell.rb'))
File.join(ENV['HOME'], '.chef', 'chef_shell.rb')
elsif config[:solo]
- if Chef::Platform.windows?
- "C:\\chef\\solo.rb"
- else
- "/etc/chef/solo.rb"
- end
+ Chef::Config.platform_specific_path("/etc/chef/solo.rb")
elsif config[:client]
- if Chef::Platform.windows?
- "C:\\chef\\client.rb"
- else
- "/etc/chef/client.rb"
- end
+ Chef::Config.platform_specific_path("/etc/chef/client.rb")
else
nil
end
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index fb782da2c7..58fb229c96 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -434,7 +434,7 @@ describe Chef::Config do
expect(Chef::Log).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef to use/)
expect(Chef::Log).to_not receive(:debug).with(/Defaulting to locale en_US.UTF-8 on Windows/)
expect(Chef::Log).to_not receive(:debug).with(/No usable locale -a command found/)
- expect(Chef::Config[:internal_locale]).to eq expected_locale
+ expect(Chef::Config.guess_internal_locale).to eq expected_locale
end
end
@@ -485,7 +485,7 @@ describe Chef::Config do
it "should fall back to C locale" do
expect(Chef::Log).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
- expect(Chef::Config[:internal_locale]).to eq 'C'
+ expect(Chef::Config.guess_internal_locale).to eq 'C'
end
end
@@ -502,7 +502,7 @@ describe Chef::Config do
else
expect(Chef::Log).to receive(:debug).with("No usable locale -a command found, assuming you have en_US.UTF-8 installed.")
end
- expect(Chef::Config[:internal_locale]).to eq "en_US.UTF-8"
+ expect(Chef::Config.guess_internal_locale).to eq "en_US.UTF-8"
end
end
end
diff --git a/spec/unit/provider/file/content_spec.rb b/spec/unit/provider/file/content_spec.rb
index db0753bf8c..0a45d15bc9 100644
--- a/spec/unit/provider/file/content_spec.rb
+++ b/spec/unit/provider/file/content_spec.rb
@@ -70,12 +70,34 @@ describe Chef::Provider::File::Content do
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_falsey
end
- it "returns a tempfile in the destdir when :file_desployment_uses_destdir is not set" do
+ it "returns a tempfile in the destdir when :file_deployment_uses_destdir is set" do
Chef::Config[:file_staging_uses_destdir] = true
expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_falsey
expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_truthy
end
+ context "when creating a tempfiles in destdir fails" do
+ let(:enclosing_directory) {
+ canonicalize_path("/nonexisting/path")
+ }
+
+ it "returns a tempfile in the tempdir when :file_deployment_uses_destdir is set to :auto" do
+ Chef::Config[:file_staging_uses_destdir] = :auto
+ expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_truthy
+ expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_falsey
+ end
+
+ it "fails when :file_desployment_uses_destdir is set" do
+ Chef::Config[:file_staging_uses_destdir] = true
+ expect{content.tempfile}.to raise_error
+ end
+
+ it "returns a tempfile in the tempdir when :file_desployment_uses_destdir is not set" do
+ expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be_truthy
+ expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be_falsey
+ end
+ end
+
end
describe "when the resource does not have a content attribute set" do
@@ -90,4 +112,3 @@ describe Chef::Provider::File::Content do
end
end
-