class ChefConfig::Config

Public Class Methods

_this_file() click to toggle source

Path to this file in the current install.

# File lib/chef-config/config.rb, line 1297
def self._this_file
  File.expand_path(__FILE__)
end
add_event_logger(logger) click to toggle source

@param logger [String]

# File lib/chef-config/config.rb, line 165
def self.add_event_logger(logger)
  event_handlers << logger
end
add_formatter(name, file_path = nil) click to toggle source

@param name [String] @param file_path [String]

# File lib/chef-config/config.rb, line 160
def self.add_formatter(name, file_path = nil)
  formatters << [name, file_path]
end
apply_extra_config_options(extra_config_options) click to toggle source
# File lib/chef-config/config.rb, line 169
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, permitted_classes: [Date])
      memo
    end
    set_extra_config_options(extra_parsed_options)
  end
end
c_chef_dir(windows: ChefUtils.windows?) click to toggle source

On windows, C:/chef/

(should only be called in a windows-context)

@return [String] the platform-specific path

# File lib/chef-config/config.rb, line 126
def self.c_chef_dir(windows: ChefUtils.windows?)
  drive = windows_installation_drive || "C:"
  PathHelper.join(drive, ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
end
c_opscode_dir(windows: ChefUtils.windows?) click to toggle source

On windows, C:/opscode

(should only be called in a windows-context)

@return [String] the platform-specific path

# File lib/chef-config/config.rb, line 137
def self.c_opscode_dir(windows: ChefUtils.windows?)
  drive = windows_installation_drive || "C:"
  PathHelper.join(drive, ChefUtils::Dist::Org::LEGACY_CONF_DIR, ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
end
derive_path_from_chef_repo_path(child_path) click to toggle source

@param child_path [String]

# File lib/chef-config/config.rb, line 288
def self.derive_path_from_chef_repo_path(child_path)
  if chef_repo_path.is_a?(String)
    PathHelper.join(chef_repo_path, child_path)
  else
    chef_repo_path.uniq.map { |path| PathHelper.join(path, child_path) }
  end
end
embedded_dir() click to toggle source

If installed via an omnibus installer, this gives the path to the “embedded” directory which contains all of the software packaged with omnibus. This is used to locate the cacert.pem file on windows.

# File lib/chef-config/config.rb, line 1286
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
enable_fips_mode() click to toggle source

Set fips mode in openssl. Do any patching necessary to make sure Chef runs do not crash. @api private

# File lib/chef-config/config.rb, line 1304
def self.enable_fips_mode
  OpenSSL.fips_mode = true
  require "digest" unless defined?(Digest)
  require "digest/sha1" unless defined?(Digest::SHA1)
  require "digest/md5" unless defined?(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
env() click to toggle source

This provides a hook which rspec can stub so that we can avoid twiddling global state in tests.

# File lib/chef-config/config.rb, line 970
def self.env
  ENV
end
etc_chef_dir(windows: ChefUtils.windows?) click to toggle source

On *nix, /etc/chef, on Windows C:chef

@param windows [Boolean] optional flag to force to windows or unix-style @return [String] the platform-specific path

# File lib/chef-config/config.rb, line 86
def self.etc_chef_dir(windows: ChefUtils.windows?)
  @etc_chef_dir ||= {}
  @etc_chef_dir[windows] ||= begin
    path = windows ? c_chef_dir : PathHelper.join("/etc", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
    PathHelper.cleanpath(path, windows: windows)
  end
end
expand_relative_paths(path) click to toggle source
# File lib/chef-config/config.rb, line 236
def self.expand_relative_paths(path)
  unless path.nil?
    if path.is_a?(String)
      File.expand_path(path)
    else
      Array(path).map { |path| File.expand_path(path) }
    end
  end
end
export_no_proxy(value) click to toggle source

@api private

# File lib/chef-config/config.rb, line 1189
def self.export_no_proxy(value)
  ENV["no_proxy"] = value unless ENV["no_proxy"]
  ENV["NO_PROXY"] = value unless ENV["NO_PROXY"]
end
export_proxies() click to toggle source

Public method that users should call to export proxies to the appropriate environment variables. This method should be called after the config file is parsed and loaded. TODO add some post-file-parsing logic that automatically calls this so users don’t have to

# File lib/chef-config/config.rb, line 1145
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
export_proxy(scheme, path, user, pass) click to toggle source

Builds a proxy uri and exports it to the appropriate environment variables. Examples:

http://username:password@hostname:port
https://username@hostname:port
ftp://hostname:port

when

scheme = "http", "https", or "ftp"
hostport = hostname:port or scheme://hostname:port
user = username
pass = password

@api private

# File lib/chef-config/config.rb, line 1162
def self.export_proxy(scheme, path, user, pass)
  # Character classes for Addressable
  # See https://www.ietf.org/rfc/rfc3986.txt 3.2.1
  # The user part may not have a : in it
  user_class = Addressable::URI::CharacterClasses::UNRESERVED + Addressable::URI::CharacterClasses::SUB_DELIMS
  # The password part may have any valid USERINFO characters
  password_class = user_class + "\\:"

  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_class)
    if pass
      userinfo << ":#{Addressable::URI.encode_component(pass, password_class)}"
    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
find_chef_repo_path(cwd) click to toggle source
# File lib/chef-config/config.rb, line 271
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 #{ChefUtils::Dist::Infra::SHORT} repository at #{path}")
  path
end
from_string(string, filename) click to toggle source

Evaluates the given string as config.

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

# File lib/chef-config/config.rb, line 53
def self.from_string(string, filename)
  instance_eval(string, filename, 1)
end
guess_internal_locale() click to toggle source

Chef requires an English-language UTF-8 locale to function properly. We attempt to use the ‘locale -a’ command and search through a list of preferences until we find one that we can use. On Ubuntu systems we should find ‘C.UTF-8’ and be able to use that even if there is no English locale on the server, but Mac, Solaris, AIX, etc do not have that locale. We then try to find an English locale and fall back to ‘C’ if we do not. The choice of fallback is pick-your-poison. If we try to do the work to return a non-US UTF-8 locale then we fail inside of providers when things like ‘svn info’ return Japanese and we can’t parse them. OTOH, if we pick ‘C’ then we will blow up on UTF-8 characters. Between the warn we throw and the Encoding exception that ruby will throw it is more obvious what is broken if we drop UTF-8 by default rather than drop English.

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’.

# File lib/chef-config/config.rb, line 1228
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.grep(/^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 #{ChefUtils::Dist::Infra::PRODUCT} to use, falling back to C locale and disabling UTF-8 support."
      "C"
    end
  end
rescue
  if ChefUtils.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
init_openssl() click to toggle source

Initialize openssl

# File lib/chef-config/config.rb, line 748
def self.init_openssl
  if fips
    enable_fips_mode
  end
end
inspect() click to toggle source
# File lib/chef-config/config.rb, line 57
def self.inspect
  configuration.inspect
end
is_valid_url?(uri) click to toggle source

@param uri [String] the URI to validate

@return [Boolean] is the URL valid

# File lib/chef-config/config.rb, line 213
def self.is_valid_url?(uri)
  url = uri.to_s.strip
  %r{^http://} =~ url || %r{^https://} =~ url || /^chefzero:/ =~ url
end
path_accessible?(path) click to toggle source

Returns true only if the path exists and is readable and writeable for the user.

@param path [String]

# File lib/chef-config/config.rb, line 394
def self.path_accessible?(path)
  File.exist?(path) && File.readable?(path) && File.writable?(path)
end
platform_specific_path(path) click to toggle source

given a *nix style config path return the platform specific path to that same config file @example client.pem path on Windows

platform_specific_path("/etc/chef/client.pem") #=> "C:\\chef\\client.pem"

@param path [String] The unix path to convert to a platform specific path @return [String] a platform specific path

# File lib/chef-config/config.rb, line 67
def self.platform_specific_path(path)
  path = PathHelper.cleanpath(path)
  if ChefUtils.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
proxy_uri(scheme, host, port) click to toggle source

Given a scheme, host, and port, return the correct proxy URI based on the set environment variables, unless excluded by no_proxy, in which case nil is returned

# File lib/chef-config/config.rb, line 1197
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 = unless proxy_env_var.empty?
            if %r{^.*://}.match?(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
set_defaults_for_nix() click to toggle source
# File lib/chef-config/config.rb, line 948
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
set_defaults_for_windows() click to toggle source
# File lib/chef-config/config.rb, line 937
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
set_extra_config_options(extra_parsed_options) click to toggle source

We use :[]= assignment here to not bypass any coercions that happen via mixlib-config writes_value callbacks

# File lib/chef-config/config.rb, line 191
def self.set_extra_config_options(extra_parsed_options)
  extra_parsed_options.each do |key, value|
    self[key.to_sym] = value
  end
end
target_mode?() click to toggle source
# File lib/chef-config/config.rb, line 559
def self.target_mode?
  target_mode.enabled
end
var_chef_dir(windows: ChefUtils.windows?) click to toggle source

On *nix, /var/chef, on Windows C:chef

@param windows [Boolean] optional flag to force to windows or unix-style @return [String] the platform-specific path

# File lib/chef-config/config.rb, line 99
def self.var_chef_dir(windows: ChefUtils.windows?)
  @var_chef_dir ||= {}
  @var_chef_dir[windows] ||= begin
    path = windows ? c_chef_dir : PathHelper.join("/var", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
    PathHelper.cleanpath(path, windows: windows)
  end
end
var_root_dir(windows: ChefUtils.windows?) click to toggle source

On *nix, /var, on Windows C:\

@param windows [Boolean] optional flag to force to windows or unix-style @return [String] the platform-specific path

# File lib/chef-config/config.rb, line 112
def self.var_root_dir(windows: ChefUtils.windows?)
  @var_root_dir ||= {}
  @var_root_dir[windows] ||= begin
    path = windows ? "C:\\" : "/var"
    PathHelper.cleanpath(path, windows: windows)
  end
end
windows_home_path() click to toggle source
# File lib/chef-config/config.rb, line 974
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
windows_installation_drive() click to toggle source

the drive where Chef is installed on a windows host. This is determined either by the drive containing the current file or by the SYSTEMDRIVE ENV variable

(should only be called in a windows-context)

@return [String] the drive letter

# File lib/chef-config/config.rb, line 150
def self.windows_installation_drive
  if ChefUtils.windows?
    drive = File.expand_path(__FILE__).split("/", 2)[0]
    drive = ENV["SYSTEMDRIVE"] if drive.to_s == ""
    drive
  end
end