Class: ChefConfig::Config

Inherits:
Object
  • Object
show all
Extended by:
Mixin::FuzzyHostnameMatcher, Mixlib::Config
Defined in:
lib/chef-config/config.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixin::FuzzyHostnameMatcher

fuzzy_hostname_match?, fuzzy_hostname_match_any?

Class Method Details

._this_fileObject

Path to this file in the current install.



1297
1298
1299
# File 'lib/chef-config/config.rb', line 1297

def self._this_file
  File.expand_path(__FILE__)
end

.add_event_logger(logger) ⇒ Object

Parameters:

  • logger (String)


165
166
167
# File 'lib/chef-config/config.rb', line 165

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

.add_formatter(name, file_path = nil) ⇒ Object

Parameters:

  • name (String)
  • file_path (String) (defaults to: nil)


160
161
162
# 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) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# 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?) ⇒ String

On windows, C:/chef/

(should only be called in a windows-context)

Returns:

  • (String)

    the platform-specific path



126
127
128
129
# 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?) ⇒ String

On windows, C:/opscode

(should only be called in a windows-context)

Returns:

  • (String)

    the platform-specific path



137
138
139
140
# 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) ⇒ Object

Parameters:

  • child_path (String)


288
289
290
291
292
293
294
# 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_dirObject

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.



1286
1287
1288
1289
1290
1291
1292
1293
1294
# 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_modeObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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



1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
# 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

.envObject

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



970
971
972
# File 'lib/chef-config/config.rb', line 970

def self.env
  ENV
end

.etc_chef_dir(windows: ChefUtils.windows?) ⇒ String

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

Parameters:

  • windows (Boolean) (defaults to: ChefUtils.windows?)

    optional flag to force to windows or unix-style

Returns:

  • (String)

    the platform-specific path



86
87
88
89
90
91
92
# 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) ⇒ Object



236
237
238
239
240
241
242
243
244
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1189
1190
1191
1192
# 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_proxiesObject

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



1145
1146
1147
1148
1149
1150
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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


1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
# 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) ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# 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) ⇒ Object

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.



53
54
55
# File 'lib/chef-config/config.rb', line 53

def self.from_string(string, filename)
  instance_eval(string, filename, 1)
end

.guess_internal_localeObject

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



1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
# 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_opensslObject

Initialize openssl



748
749
750
751
752
# File 'lib/chef-config/config.rb', line 748

def self.init_openssl
  if fips
    enable_fips_mode
  end
end

.inspectObject



57
58
59
# File 'lib/chef-config/config.rb', line 57

def self.inspect
  configuration.inspect
end

.is_valid_url?(uri) ⇒ Boolean

Returns is the URL valid.

Parameters:

  • uri (String)

    the URI to validate

Returns:

  • (Boolean)

    is the URL valid



213
214
215
216
# 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) ⇒ Boolean

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

Parameters:

  • path (String)

Returns:

  • (Boolean)


394
395
396
# 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) ⇒ String

given a *nix style config path return the platform specific path to that same config file

Examples:

client.pem path on Windows

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

Parameters:

  • path (String)

    The unix path to convert to a platform specific path

Returns:

  • (String)

    a platform specific path



67
68
69
70
71
72
73
74
75
76
77
78
79
# 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) ⇒ Object

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



1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
# 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_nixObject



948
949
950
951
952
953
954
955
956
957
958
# 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_windowsObject



937
938
939
940
941
942
943
944
945
946
# 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) ⇒ Object

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



191
192
193
194
195
# 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?Boolean

Returns:

  • (Boolean)


559
560
561
# File 'lib/chef-config/config.rb', line 559

def self.target_mode?
  target_mode.enabled
end

.var_chef_dir(windows: ChefUtils.windows?) ⇒ String

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

Parameters:

  • windows (Boolean) (defaults to: ChefUtils.windows?)

    optional flag to force to windows or unix-style

Returns:

  • (String)

    the platform-specific path



99
100
101
102
103
104
105
# 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?) ⇒ String

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

Parameters:

  • windows (Boolean) (defaults to: ChefUtils.windows?)

    optional flag to force to windows or unix-style

Returns:

  • (String)

    the platform-specific path



112
113
114
115
116
117
118
# 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_pathObject



974
975
976
977
# 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_driveString

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)

Returns:

  • (String)

    the drive letter



150
151
152
153
154
155
156
# 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

Instance Method Details

#userObject

Daemonization Settings ## What user should Chef run as?



435
# File 'lib/chef-config/config.rb', line 435

default :user, nil