class ChefConfig::Config

def self._this_file

Path to this file in the current install.
def self._this_file
  File.expand_path(__FILE__)
end

def self.add_event_logger(logger)

def self.add_event_logger(logger)
  event_handlers << logger
end

def self.add_formatter(name, file_path = nil)

def self.add_formatter(name, file_path = nil)
  formatters << [name, file_path]
end

def self.apply_extra_config_options(extra_config_options)

def self.apply_extra_config_options(extra_config_options)
  if extra_config_options
    extra_parsed_options = extra_config_options.inject({}) do |memo, option|
      # Sanity check value.
      if option.empty? || !option.include?("=")
        raise UnparsableConfigOption, "Unparsable config option #{option.inspect}"
      end
      # Split including whitespace if someone does truly odd like
      # --config-option "foo = bar"
      key, value = option.split(/\s*=\s*/, 2)
      # Call to_sym because Chef::Config expects only symbol keys. Also
      # runs a simple parse on the string for some common types.
      memo[key.to_sym] = YAML.safe_load(value)
      memo
    end
    merge!(extra_parsed_options)
  end
end

def self.derive_path_from_chef_repo_path(child_path)

def self.derive_path_from_chef_repo_path(child_path)
  if chef_repo_path.kind_of?(String)
    PathHelper.join(chef_repo_path, child_path)
  else
    chef_repo_path.uniq.map { |path| PathHelper.join(path, child_path) }
  end
end

def self.embedded_dir

omnibus. This is used to locate the cacert.pem file on windows.
"embedded" directory which contains all of the software packaged with
If installed via an omnibus installer, this gives the path to the
def self.embedded_dir
  Pathname.new(_this_file).ascend do |path|
    if path.basename.to_s == "embedded"
      return path.to_s
    end
  end
  nil
end

def self.enable_fips_mode

Other tags:
    Api: - private
def self.enable_fips_mode
  OpenSSL.fips_mode = true
  require "digest"
  require "digest/sha1"
  require "digest/md5"
  # Remove pre-existing constants if they do exist to reduce the
  # amount of log spam and warnings.
  Digest.send(:remove_const, "SHA1") if Digest.const_defined?("SHA1")
  Digest.const_set("SHA1", OpenSSL::Digest::SHA1)
  OpenSSL::Digest.send(:remove_const, "MD5") if OpenSSL::Digest.const_defined?("MD5")
  OpenSSL::Digest.const_set("MD5", Digest::MD5)
  ChefConfig.logger.debug "FIPS mode is enabled."
end

def self.env

global state in tests.
This provides a hook which rspec can stub so that we can avoid twiddling
def self.env
  ENV
end

def self.export_no_proxy(value)

Other tags:
    Api: - private
def self.export_no_proxy(value)
  ENV["no_proxy"] = value unless ENV["no_proxy"]
  ENV["NO_PROXY"] = value unless ENV["NO_PROXY"]
end

def self.export_proxies

users don't have to
TODO add some post-file-parsing logic that automatically calls this so
parsed and loaded.
environment variables. This method should be called after the config file is
Public method that users should call to export proxies to the appropriate
def self.export_proxies
  export_proxy("http", http_proxy, http_proxy_user, http_proxy_pass) if key?(:http_proxy) && http_proxy
  export_proxy("https", https_proxy, https_proxy_user, https_proxy_pass) if key?(:https_proxy) && https_proxy
  export_proxy("ftp", ftp_proxy, ftp_proxy_user, ftp_proxy_pass) if key?(:ftp_proxy) && ftp_proxy
  export_no_proxy(no_proxy) if key?(:no_proxy) && no_proxy
end

def self.export_proxy(scheme, path, user, pass)

Other tags:
    Api: - private
def self.export_proxy(scheme, path, user, pass)
  path = "#{scheme}://#{path}" unless path.include?("://")
  # URI.split returns the following parts:
  # [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
  uri = Addressable::URI.encode(path, Addressable::URI)
  if user && !user.empty?
    userinfo = Addressable::URI.encode_component(user, USER)
    if pass
      userinfo << ":#{Addressable::URI.encode_component(pass, PASSWORD)}"
    end
    uri.userinfo = userinfo
  end
  path = uri.to_s
  ENV["#{scheme}_proxy".downcase] = path unless ENV["#{scheme}_proxy".downcase]
  ENV["#{scheme}_proxy".upcase] = path unless ENV["#{scheme}_proxy".upcase]
end

def self.find_chef_repo_path(cwd)

def self.find_chef_repo_path(cwd)
  # In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it.
  # This allows us to run config-free.
  path = cwd
  until File.directory?(PathHelper.join(path, "cookbooks")) || File.directory?(PathHelper.join(path, "cookbook_artifacts"))
    new_path = File.expand_path("..", path)
    if new_path == path
      ChefConfig.logger.warn("No cookbooks directory found at or above current directory.  Assuming #{cwd}.")
      return cwd
    end
    path = new_path
  end
  ChefConfig.logger.info("Auto-discovered chef repository at #{path}")
  path
end

def self.from_string(string, filename)

+filename+ is used for context in stacktraces, but doesn't need to be the name of an actual file.

Evaluates the given string as config.
def self.from_string(string, filename)
  instance_eval(string, filename, 1)
end

def self.guess_internal_locale

available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly

default rather than drop English.
exception that ruby will throw it is more obvious what is broken if we drop UTF-8 by
we will blow up on UTF-8 characters. Between the warn we throw and the Encoding
things like 'svn info' return Japanese and we can't parse them. OTOH, if we pick 'C' then
to do the work to return a non-US UTF-8 locale then we fail inside of providers when
back to 'C' if we do not. The choice of fallback is pick-your-poison. If we try
AIX, etc do not have that locale. We then try to find an English locale and fall
able to use that even if there is no English locale on the server, but Mac, Solaris,
find one that we can use. On Ubuntu systems we should find 'C.UTF-8' and be
to use the 'locale -a' command and search through a list of preferences until we
Chef requires an English-language UTF-8 locale to function properly. We attempt
def self.guess_internal_locale
  # https://github.com/chef/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.
  cmd = Mixlib::ShellOut.new("locale -a").run_command
  cmd.error!
  locales = cmd.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
      ChefConfig.logger.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 ChefConfig.windows?
    ChefConfig.logger.trace "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
  else
    ChefConfig.logger.trace "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
  end
  "en_US.UTF-8"
end

def self.init_openssl

Initialize openssl
def self.init_openssl
  if fips
    enable_fips_mode
  end
end

def self.inspect

def self.inspect
  configuration.inspect
end

def self.is_valid_url?(uri)

def self.is_valid_url?(uri)
  url = uri.to_s.strip
  /^http:\/\// =~ url || /^https:\/\// =~ url || /^chefzero:/ =~ url
end

def self.path_accessible?(path)

Returns true only if the path exists and is readable and writeable for the user.
def self.path_accessible?(path)
  File.exists?(path) && File.readable?(path) && File.writable?(path)
end

def self.platform_specific_path(path)

Returns:
  • (String) - a platform specific path

Parameters:
  • path (String) -- The unix path to convert to a platform specific path

Other tags:
    Example: client.pem path on Windows -
def self.platform_specific_path(path)
  path = PathHelper.cleanpath(path)
  if ChefConfig.windows?
    # turns \etc\chef\client.rb and \var\chef\client.rb into C:/chef/client.rb
    # Some installations will be on different drives so use the drive that
    # the expanded path to __FILE__ is found.
    drive = windows_installation_drive
    if drive && path[0] == '\\' && path.split('\\')[2] == "chef"
      path = PathHelper.join(drive, path.split('\\', 3)[2])
    end
  end
  path
end

def self.proxy_uri(scheme, host, port)

is returned
set environment variables, unless exluded by no_proxy, in which case nil
Given a scheme, host, and port, return the correct proxy URI based on the
def self.proxy_uri(scheme, host, port)
  proxy_env_var = ENV["#{scheme}_proxy"].to_s.strip
  # Check if the proxy string contains a scheme. If not, add the url's scheme to the
  # proxy before parsing. The regex /^.*:\/\// matches, for example, http://. Reusing proxy
  # here since we are really just trying to get the string built correctly.
  proxy = if !proxy_env_var.empty?
            if proxy_env_var =~ /^.*:\/\//
              URI.parse(proxy_env_var)
            else
              URI.parse("#{scheme}://#{proxy_env_var}")
            end
          end
  return proxy unless fuzzy_hostname_match_any?(host, ENV["no_proxy"])
end

def self.set_defaults_for_nix

def self.set_defaults_for_nix
  # Those lists of regular expressions define what chef considers a
  # valid user and group name
  #
  # user/group cannot start with '-', '+' or '~'
  # user/group cannot contain ':', ',' or non-space-whitespace or null byte
  # everything else is allowed (UTF-8, spaces, etc) and we delegate to your O/S useradd program to barf or not
  # copies: http://anonscm.debian.org/viewvc/pkg-shadow/debian/trunk/debian/patches/506_relaxed_usernames?view=markup
  default :user_valid_regex, [ /^[^-+~:,\t\r\n\f\0]+[^:,\t\r\n\f\0]*$/ ]
  default :group_valid_regex, [ /^[^-+~:,\t\r\n\f\0]+[^:,\t\r\n\f\0]*$/ ]
end

def self.set_defaults_for_windows

def self.set_defaults_for_windows
  # Those lists of regular expressions define what chef considers a
  # valid user and group name
  # From http://technet.microsoft.com/en-us/library/cc776019(WS.10).aspx
  principal_valid_regex_part = '[^"\/\\\\\[\]\:;|=,+*?<>]+'
  default :user_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
  default :group_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
  default :fatal_windows_admin_check, false
end

def self.windows_home_path

def self.windows_home_path
  ChefConfig.logger.deprecation("Chef::Config.windows_home_path is now deprecated.  Consider using Chef::Util::PathHelper.home instead.")
  PathHelper.home
end

def self.windows_installation_drive

Returns:
  • (String) - the drive letter
def self.windows_installation_drive
  if ChefConfig.windows?
    drive = File.expand_path(__FILE__).split("/", 2)[0]
    drive = ENV["SYSTEMDRIVE"] if drive.to_s == ""
    drive
  end
end