summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/chef/audit/runner.rb12
-rw-r--r--lib/chef/client.rb3
-rw-r--r--lib/chef/config.rb8
-rw-r--r--lib/chef/knife/bootstrap.rb3
-rw-r--r--lib/chef/knife/core/subcommand_loader.rb18
-rw-r--r--lib/chef/knife/exec.rb3
-rw-r--r--lib/chef/knife/ssh.rb7
-rw-r--r--lib/chef/provider/group.rb10
-rw-r--r--lib/chef/provider/package/openbsd.rb67
-rw-r--r--lib/chef/provider/service/macosx.rb3
-rw-r--r--lib/chef/shell.rb12
-rw-r--r--lib/chef/util/path_helper.rb76
-rw-r--r--lib/chef/workstation_config_loader.rb7
13 files changed, 181 insertions, 48 deletions
diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb
index 13ba95428c..13c2823dca 100644
--- a/lib/chef/audit/runner.rb
+++ b/lib/chef/audit/runner.rb
@@ -79,11 +79,15 @@ class Chef
require 'rspec'
require 'rspec/its'
require 'specinfra'
+ require 'specinfra/helper'
+ require 'specinfra/helper/set'
require 'serverspec/helper'
require 'serverspec/matcher'
require 'serverspec/subject'
require 'chef/audit/audit_event_proxy'
require 'chef/audit/rspec_formatter'
+
+ Specinfra::Backend::Cmd.send(:include, Specinfra::Helper::Set)
end
# Configure RSpec just the way we like it:
@@ -136,9 +140,13 @@ class Chef
end
end
- # Set up the backend for Specinfra/Serverspec. :exec is the local system.
+ # Set up the backend for Specinfra/Serverspec. :exec is the local system; on Windows, it is :cmd
def configure_specinfra
- Specinfra.configuration.backend = :exec
+ if Chef::Platform.windows?
+ Specinfra.configuration.backend = :cmd
+ else
+ Specinfra.configuration.backend = :exec
+ end
end
# Iterates through the control groups registered to this run_context, builds an
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index 7fd7bd9e3f..f5cde4bfb3 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -331,8 +331,8 @@ class Chef
runner.converge
@events.converge_complete
rescue Exception => e
- Chef::Log.error("Converge failed with error message #{e.message}")
@events.converge_failed(e)
+ raise e if Chef::Config[:audit_mode] == :disabled
converge_exception = e
end
end
@@ -347,6 +347,7 @@ class Chef
begin
save_updated_node
rescue Exception => e
+ raise e if Chef::Config[:audit_mode] == :disabled
converge_exception = e
end
end
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 4e60ad652b..a9fa9f1552 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -497,7 +497,8 @@ class Chef
default(:syntax_check_cache_path) { cache_options[:path] }
# Deprecated:
- default(:cache_options) { { :path => PathHelper.join(file_cache_path, "checksums") } }
+ # Move this to the default value of syntax_cache_path when this is removed.
+ default(:cache_options) { { :path => PathHelper.join(config_dir, "syntaxcache") } }
# Whether errors should be raised for deprecation warnings. When set to
# `false` (the default setting), a warning is emitted but code using
@@ -570,11 +571,12 @@ class Chef
end
def self.windows_home_path
- env['SYSTEMDRIVE'] + env['HOMEPATH'] if env['SYSTEMDRIVE'] && env['HOMEPATH']
+ Chef::Log.deprecation("Chef::Config.windows_home_path is now deprecated. Consider using Chef::Util::PathHelper.home instead.")
+ PathHelper.home
end
# returns a platform specific path to the user home dir if set, otherwise default to current directory.
- default( :user_home ) { env['HOME'] || windows_home_path || env['USERPROFILE'] || Dir.pwd }
+ default( :user_home ) { PathHelper.home || Dir.pwd }
# Enable file permission fixup for selinux. Fixup will be done
# only if selinux is enabled in the system.
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index e168a6bd9b..64d1d0c378 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -21,6 +21,7 @@ require 'chef/knife/data_bag_secret_options'
require 'erubis'
require 'chef/knife/bootstrap/chef_vault_handler'
require 'chef/knife/bootstrap/client_builder'
+require 'chef/util/path_helper'
class Chef
class Knife
@@ -268,7 +269,7 @@ class Chef
bootstrap_files = []
bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap/templates', "#{template}.erb")
bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
- bootstrap_files << File.join(ENV['HOME'], '.chef', 'bootstrap', "#{template}.erb") if ENV['HOME']
+ Chef::Util::PathHelper.home('.chef', 'bootstrap', "#{template}.erb") {|p| bootstrap_files << p}
bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
bootstrap_files.flatten!
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb
index f9b8f5008e..1f59515f44 100644
--- a/lib/chef/knife/core/subcommand_loader.rb
+++ b/lib/chef/knife/core/subcommand_loader.rb
@@ -28,9 +28,15 @@ class Chef
attr_reader :chef_config_dir
attr_reader :env
- def initialize(chef_config_dir, env=ENV)
- @chef_config_dir, @env = chef_config_dir, env
+ def initialize(chef_config_dir, env=nil)
+ @chef_config_dir = chef_config_dir
@forced_activate = {}
+
+ # Deprecated and un-used instance variable.
+ @env = env
+ unless env.nil?
+ Chef::Log.deprecation("The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
+ end
end
# Load all the sub-commands
@@ -49,7 +55,9 @@ class Chef
end
# finally search ~/.chef/plugins/knife/*.rb
- user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(env['HOME'], '.chef', 'plugins', 'knife'), '*.rb')) if env['HOME']
+ Chef::Util::PathHelper.home('.chef', 'plugins', 'knife') do |p|
+ user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(p), '*.rb'))
+ end
user_specific_files
end
@@ -140,7 +148,7 @@ class Chef
end
def have_plugin_manifest?
- ENV["HOME"] && File.exist?(plugin_manifest_path)
+ plugin_manifest_path && File.exist?(plugin_manifest_path)
end
def plugin_manifest
@@ -148,7 +156,7 @@ class Chef
end
def plugin_manifest_path
- File.join(ENV['HOME'], '.chef', 'plugin_manifest.json')
+ Chef::Util::PathHelper.home('.chef', 'plugin_manifest.json')
end
private
diff --git a/lib/chef/knife/exec.rb b/lib/chef/knife/exec.rb
index 3e8196c616..ace4ee2300 100644
--- a/lib/chef/knife/exec.rb
+++ b/lib/chef/knife/exec.rb
@@ -17,6 +17,7 @@
#
require 'chef/knife'
+require 'chef/util/path_helper'
class Chef::Knife::Exec < Chef::Knife
@@ -42,7 +43,7 @@ class Chef::Knife::Exec < Chef::Knife
# Default script paths are chef-repo/.chef/scripts and ~/.chef/scripts
config[:script_path] << File.join(Chef::Knife.chef_config_dir, 'scripts') if Chef::Knife.chef_config_dir
- config[:script_path] << File.join(ENV['HOME'], '.chef', 'scripts') if ENV['HOME']
+ Chef::Util::PathHelper.home('.chef', 'scripts') { |p| config[:script_path] << p }
scripts = Array(name_args)
context = Object.new
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index db0fb7dd41..50fedd0e49 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -31,6 +31,7 @@ class Chef
require 'chef/search/query'
require 'chef/mixin/shell_out'
require 'chef/mixin/command'
+ require 'chef/util/path_helper'
require 'mixlib/shellout'
end
@@ -342,8 +343,10 @@ class Chef
def screen
tf = Tempfile.new("knife-ssh-screen")
- if File.exist? "#{ENV["HOME"]}/.screenrc"
- tf.puts("source #{ENV["HOME"]}/.screenrc")
+ Chef::Util::PathHelper.home('.screenrc') do |screenrc_path|
+ if File.exist? screenrc_path
+ tf.puts("source #{screenrc_path}")
+ end
end
tf.puts("caption always '%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<'")
tf.puts("hardstatus alwayslastline 'knife ssh #{@name_args[0]}'")
diff --git a/lib/chef/provider/group.rb b/lib/chef/provider/group.rb
index 29738cc046..a802758dce 100644
--- a/lib/chef/provider/group.rb
+++ b/lib/chef/provider/group.rb
@@ -125,13 +125,13 @@ class Chef
def action_create
case @group_exists
when false
- converge_by("create #{@new_resource}") do
+ converge_by("create #{@new_resource.group_name}") do
create_group
Chef::Log.info("#{@new_resource} created")
end
else
if compare_group
- converge_by(["alter group #{@new_resource}"] + change_desc) do
+ converge_by(["alter group #{@new_resource.group_name}"] + change_desc) do
manage_group
Chef::Log.info("#{@new_resource} altered")
end
@@ -141,7 +141,7 @@ class Chef
def action_remove
if @group_exists
- converge_by("remove group #{@new_resource}") do
+ converge_by("remove group #{@new_resource.group_name}") do
remove_group
Chef::Log.info("#{@new_resource} removed")
end
@@ -150,7 +150,7 @@ class Chef
def action_manage
if @group_exists && compare_group
- converge_by(["manage group #{@new_resource}"] + change_desc) do
+ converge_by(["manage group #{@new_resource.group_name}"] + change_desc) do
manage_group
Chef::Log.info("#{@new_resource} managed")
end
@@ -159,7 +159,7 @@ class Chef
def action_modify
if compare_group
- converge_by(["modify group #{@new_resource}"] + change_desc) do
+ converge_by(["modify group #{@new_resource.group_name}"] + change_desc) do
manage_group
Chef::Log.info("#{@new_resource} modified")
end
diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb
index f0931d7555..82048c3bd4 100644
--- a/lib/chef/provider/package/openbsd.rb
+++ b/lib/chef/provider/package/openbsd.rb
@@ -24,6 +24,7 @@ require 'chef/resource/package'
require 'chef/provider/package'
require 'chef/mixin/shell_out'
require 'chef/mixin/get_source_from_package'
+require 'chef/exceptions'
class Chef
class Provider
@@ -37,25 +38,42 @@ class Chef
def initialize(*args)
super
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
- @new_resource.source(pkg_path) if !@new_resource.source
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
end
def load_current_resource
- @current_resource.package_name(@new_resource.package_name)
+ @current_resource.package_name(new_resource.package_name)
@current_resource.version(installed_version)
@current_resource
end
+ def define_resource_requirements
+ super
+
+ # Below are incomplete/missing features for this package provider
+ requirements.assert(:all_actions) do |a|
+ a.assertion { !new_resource.source }
+ a.failure_message(Chef::Exceptions::Package, 'The openbsd package provider does not support the source attribute')
+ end
+ requirements.assert(:all_actions) do |a|
+ a.assertion do
+ if new_resource.package_name =~ /^(.+?)--(.+)/
+ !new_resource.version
+ else
+ true
+ end
+ end
+ a.failure_message(Chef::Exceptions::Package, 'The openbsd package provider does not support providing a version and flavor')
+ end
+ end
+
def install_package(name, version)
unless @current_resource.version
- version_string = ''
- version_string += "-#{version}" if version
if parts = name.match(/^(.+?)--(.+)/) # use double-dash for stems with flavors, see man page for pkg_add
name = parts[1]
end
- shell_out!("pkg_add -r #{name}#{version_string}", :env => {"PKG_PATH" => @new_resource.source}).status
- Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
+ shell_out!("pkg_add -r #{name}#{version_string}", :env => {"PKG_PATH" => pkg_path}).status
+ Chef::Log.debug("#{new_resource.package_name} installed")
end
end
@@ -71,32 +89,45 @@ class Chef
private
def installed_version
- if parts = @new_resource.package_name.match(/^(.+?)--(.+)/)
+ if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
name = parts[1]
else
- name = @new_resource.package_name
+ name = new_resource.package_name
end
pkg_info = shell_out!("pkg_info -e \"#{name}->0\"", :env => nil, :returns => [0,1])
result = pkg_info.stdout[/^inst:#{Regexp.escape(name)}-(.+?)\s/, 1]
- Chef::Log.debug("installed_version of '#{@new_resource.package_name}' is '#{result}'")
+ Chef::Log.debug("installed_version of '#{new_resource.package_name}' is '#{result}'")
result
end
def candidate_version
@candidate_version ||= begin
- version_string = ''
- version_string += "-#{version}" if @new_resource.version
- pkg_info = shell_out!("pkg_info -I \"#{@new_resource.package_name}#{version_string}\"", :env => nil, :returns => [0,1])
- if parts = @new_resource.package_name.match(/^(.+?)--(.+)/)
- result = pkg_info.stdout[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1]
+ results = []
+ shell_out!("pkg_info -I \"#{new_resource.package_name}#{version_string}\"", :env => nil, :returns => [0,1]).stdout.each_line do |line|
+ if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
+ results << line[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1]
+ else
+ results << line[/^#{Regexp.escape(new_resource.package_name)}-(.+?)\s/, 1]
+ end
+ end
+ results = results.reject(&:nil?)
+ Chef::Log.debug("candidate versions of '#{new_resource.package_name}' are '#{results}'")
+ case results.length
+ when 0
+ []
+ when 1
+ results[0]
else
- result = pkg_info.stdout[/^#{Regexp.escape(@new_resource.package_name)}-(.+?)\s/, 1]
+ raise Chef::Exceptions::Package, "#{new_resource.name} has multiple matching candidates. Please use a more specific name" if results.length > 1
end
- Chef::Log.debug("candidate_version of '#{@new_resource.package_name}' is '#{result}'")
- result
end
end
+ def version_string
+ ver = ''
+ ver += "-#{new_resource.version}" if new_resource.version
+ end
+
def pkg_path
ENV['PKG_PATH'] || "http://ftp.OpenBSD.org/pub/#{node.kernel.name}/#{node.kernel.release}/packages/#{node.kernel.machine}/"
end
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 10ad1aa29d..df5be54fda 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -33,8 +33,7 @@ class Chef
/Library/LaunchDaemons
/System/Library/LaunchAgents
/System/Library/LaunchDaemons }
-
- locations << "#{ENV['HOME']}/Library/LaunchAgents" if ENV['HOME']
+ Chef::Util::PathHelper.home('Library', 'LaunchAgents') { |p| locations << p }
locations
end
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index fed32b3795..ee4fe78808 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -29,6 +29,7 @@ require 'chef/config_fetcher'
require 'chef/shell/shell_session'
require 'chef/shell/ext'
require 'chef/json_compat'
+require 'chef/util/path_helper'
# = Shell
# Shell is Chef in an IRB session. Shell can interact with a Chef server via the
@@ -101,7 +102,7 @@ module Shell
end
def self.configure_irb
- irb_conf[:HISTORY_FILE] = "~/.chef/chef_shell_history"
+ irb_conf[:HISTORY_FILE] = Chef::Util::PathHelper.home(".chef", "chef_shell_history")
irb_conf[:SAVE_HISTORY] = 1000
irb_conf[:IRB_RC] = lambda do |conf|
@@ -295,18 +296,19 @@ FOOTER
private
def config_file_for_shell_mode(environment)
+ dot_chef_dir = Chef::Util::PathHelper.home('.chef')
if config[:config_file]
config[:config_file]
- elsif environment && ENV['HOME']
+ elsif environment
Shell.env = environment
- config_file_to_try = ::File.join(ENV['HOME'], '.chef', environment, 'chef_shell.rb')
+ config_file_to_try = ::File.join(dot_chef_dir, environment, 'chef_shell.rb')
unless ::File.exist?(config_file_to_try)
puts "could not find chef-shell config for environment #{environment} at #{config_file_to_try}"
exit 1
end
config_file_to_try
- elsif ENV['HOME'] && ::File.exist?(File.join(ENV['HOME'], '.chef', 'chef_shell.rb'))
- File.join(ENV['HOME'], '.chef', 'chef_shell.rb')
+ elsif dot_chef_dir && ::File.exist?(File.join(dot_chef_dir, 'chef_shell.rb'))
+ File.join(dot_chef_dir, 'chef_shell.rb')
elsif config[:solo]
Chef::Config.platform_specific_path("/etc/chef/solo.rb")
elsif config[:client]
diff --git a/lib/chef/util/path_helper.rb b/lib/chef/util/path_helper.rb
index 1ae489598d..17c7175331 100644
--- a/lib/chef/util/path_helper.rb
+++ b/lib/chef/util/path_helper.rb
@@ -142,6 +142,82 @@ class Chef
def self.relative_path_from(from, to)
pathname = Pathname.new(Chef::Util::PathHelper.cleanpath(to)).relative_path_from(Pathname.new(Chef::Util::PathHelper.cleanpath(from)))
end
+
+ # Retrieves the "home directory" of the current user while trying to ascertain the existence
+ # of said directory. The path returned uses / for all separators (the ruby standard format).
+ # If the home directory doesn't exist or an error is otherwise encountered, nil is returned.
+ #
+ # If a set of path elements is provided, they are appended as-is to the home path if the
+ # homepath exists.
+ #
+ # If an optional block is provided, the joined path is passed to that block if the home path is
+ # valid and the result of the block is returned instead.
+ #
+ # Home-path discovery is performed once. If a path is discovered, that value is memoized so
+ # that subsequent calls to home_dir don't bounce around.
+ #
+ # See self.all_homes.
+ def self.home(*args)
+ @@home_dir ||= self.all_homes { |p| break p }
+ if @@home_dir
+ path = File.join(@@home_dir, *args)
+ block_given? ? (yield path) : path
+ end
+ end
+
+ # See self.home. This method performs a similar operation except that it yields all the different
+ # possible values of 'HOME' that one could have on this platform. Hence, on windows, if
+ # HOMEDRIVE\HOMEPATH and USERPROFILE are different, the provided block will be called twice.
+ # This method goes out and checks the existence of each location at the time of the call.
+ #
+ # The return is a list of all the returned values from each block invocation or a list of paths
+ # if no block is provided.
+ def self.all_homes(*args)
+ paths = []
+ if Chef::Platform.windows?
+ # By default, Ruby uses the the following environment variables to determine Dir.home:
+ # HOME
+ # HOMEDRIVE HOMEPATH
+ # USERPROFILE
+ # Ruby only checks to see if the variable is specified - not if the directory actually exists.
+ # On Windows, HOMEDRIVE HOMEPATH can point to a different location (such as an unavailable network mounted drive)
+ # while USERPROFILE points to the location where the user application settings and profile are stored. HOME
+ # is not defined as an environment variable (usually). If the home path actually uses UNC, then the prefix is
+ # HOMESHARE instead of HOMEDRIVE.
+ #
+ # We instead walk down the following and only include paths that actually exist.
+ # HOME
+ # HOMEDRIVE HOMEPATH
+ # HOMESHARE HOMEPATH
+ # USERPROFILE
+
+ paths << ENV['HOME']
+ paths << ENV['HOMEDRIVE'] + ENV['HOMEPATH'] if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
+ paths << ENV['HOMESHARE'] + ENV['HOMEPATH'] if ENV['HOMESHARE'] && ENV['HOMEPATH']
+ paths << ENV['USERPROFILE']
+ end
+ paths << Dir.home
+
+ # Depending on what environment variables we're using, the slashes can go in any which way.
+ # Just change them all to / to keep things consistent.
+ # Note: Maybe this is a bad idea on some unixy systems where \ might be a valid character depending on
+ # the particular brand of kool-aid you consume. This code assumes that \ and / are both
+ # path separators on any system being used.
+ paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
+
+ # Filter out duplicate paths and paths that don't exist.
+ valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path) }
+ valid_paths = valid_paths.uniq
+
+ # Join all optional path elements at the end.
+ # If a block is provided, invoke it - otherwise just return what we've got.
+ joined_paths = valid_paths.map { |home_path| File.join(home_path, *args) }
+ if block_given?
+ joined_paths.each { |p| yield p }
+ else
+ joined_paths
+ end
+ end
end
end
end
diff --git a/lib/chef/workstation_config_loader.rb b/lib/chef/workstation_config_loader.rb
index dd02ad9a66..2454c9cccf 100644
--- a/lib/chef/workstation_config_loader.rb
+++ b/lib/chef/workstation_config_loader.rb
@@ -19,6 +19,7 @@
require 'chef/config_fetcher'
require 'chef/config'
require 'chef/null_logger'
+require 'chef/util/path_helper'
class Chef
@@ -112,9 +113,9 @@ class Chef
candidate_configs << File.join(chef_config_dir, 'knife.rb')
end
# Look for $HOME/.chef/knife.rb
- if env['HOME']
- candidate_configs << File.join(env['HOME'], '.chef', 'config.rb')
- candidate_configs << File.join(env['HOME'], '.chef', 'knife.rb')
+ Chef::Util::PathHelper.home('.chef') do |dot_chef_dir|
+ candidate_configs << File.join(dot_chef_dir, 'config.rb')
+ candidate_configs << File.join(dot_chef_dir, 'knife.rb')
end
candidate_configs.find do | candidate_config |