Ohai User Configuration

Provides a standard for passing configuration settings to Ohai to configure its behavior as well as that of plugins.

Motivation

As a Chef user,
I want to easily configure Ohai,
so that it behaves optimally on my infrastructure.

As an Ohai user,
I want Ohai to load configuration settings from my client.rb,
so that it behaves the same as it does during a chef-client run.

Current State

The lack of a configuration file has been a major impediment to many improvements in Ohai and plugin behavior.

Previously Ohai has not had a configuration file. A small number of Ohai configuration settings do exist that can be specified in the Chef client 'client.rb' file which is parsed by Mixlib::Config. These settings are then passed to Ohai during a client run. For example, additional locations on the file system can be searched for plugins by adding paths to the Ohai::Config[:plugin_path] array. However, the 'client.rb' file is only loaded by the Chef client and does not affect Ohai when being run on the command line nor any other programs loading Ohai as a library, causing inconsistent Ohai results.

Hints

The existing hints system was designed to provide facts about a system that Ohai would be unable to or have difficulty to determine on its own. The most common use case is informing a knife plugin that the system is in a particular cloud environment, enabling the plugin to collect appropriate metadata. Sometimes the plugin also passes metadata to Ohai to become attributes that Ohai would otherwise be unable to collect. For this purpose it was decided to use JSON as a data interchange format.

When a 'hintname.json' file exists in the directory specified by `Ohai::Config[:hintspath],Ohai::Hints.hint?(hint_name)` will return non-nil. If the file contains JSON data, it will be returned as a hash. If the file is empty, an empty hash will be returned.

The hints system should only be used by other tools to assist Ohai in collecting data. It should not otherwise be used to configure the behavior or Ohai or its plugins. That is the purpose of the new configuration system. The hints system may be combined with the configuration system in the future and deprecated for general ease of use of Ohai.

Specification

The Ohai::Config Ruby class will use the new ChefConfig library that is currently bundled with the Chef client source but shipped separately. Configuration will be set in a configuration file using a Mixlib::Config config_context named 'ohai'. Here is an example 'client.rb' file that would configure both the client and Ohai.

log_level        :info
log_location     STDOUT
chef_server_url  "https://api.chef.io/organizations/oneofus"
ohai.plugin_path = "/etc/chef/ohai/plugins.local"
ohai.plugin[:hostname][:fqdn_using] = [ :hostname, :nis, :dns ]

Because at the top level (outside of a configcontext) the Ohai::Config class will be the same as ChefConfig and Chef::Config, existing top level configuration options like `Ohai::Config[:disabledplugins]will be deprecated in favor of new settings within the config_context, i.e.Ohai::Config.ohai.disabled_plugins`. Until support for those top-level settings is removed, their values will be copied as appropriate for backward compatibility.

For convenience, a config method will be added to the Ohai class to access Ohai::Config.ohai, allowing the use of Ohai.config[:plugin_path] instead of Ohai::Config.ohai[:plugin_path] throughout the code. All existing uses of Ohai::Config in Ohai will need to be updated accordingly.

Example accessing the disabled_plugins configuration setting:

Ohai::Config[:disabled_plugins] # Current pattern
Ohai::Config.ohai[:disabled_plugins] # Proposed pattern
Ohai.config[:disabled_plugins] # Proposed shortcut

Configuration Files

When run from the command line, Ohai should load the workstation 'config.rb' and then the 'client.rb' files from the appropriate platform specific path, unless an alternate configuration file is provided as a command line argument. This provides similar behavior to knife which loads 'config.rb' and then 'knife.rb'. This facilitates reducing the number of separate configuration files to maintain for command line behavior.

When loaded as a library, Ohai must not load a configuration file and will expect to be provided any necessary configuration options. For example, when loaded by the Chef client, configuration values will be located in the 'client.rb' file, or the file passed to the Chef client as the configuration file. Using the same file for configuration simplifies configuration file creation during bootstrap for the client.

Plugin Namespacing

To reduce the risk of built-in and custom plugins using the same configuration setting for conflicting purposes, it is recommended that all plugins prefix their configuration settings with [:plugin] and the snake-case name of the plugin consuming the setting, as set in the plugin itself. The exposed overlap is intended, to facilitate passing a configuration option to the same plugin for multiple platforms but only specifying it once.

For example, configuration file settings would look like:

ohai[:plugin][:memory][:unit] = "mb"
ohai[:plugin][:dmi][:all_ids] = true
ohai[:plugin][:ec2][:silly_magic_arp] = "de:ad:de:ad:de:ad"
ohai[:plugin][:platform][:amazon_is_amazon] = true

Settings would be read in code as:

Ohai.config[:plugin][:memory][:unit]
Ohai.config[:plugin][:dmi][:all_ids]
Ohai.config[:plugin][:ec2][:silly_magic_arp]
Ohai.config[:plugin][:platform][:amazon_is_amazon]

Note that the filename on disk does not always match the plugin name. In the case of the 'darwin/system_profiler.rb' file, the plugin name is 'SystemProfile', and the correct plugin namespace would be Ohai::Config.ohai[:plugin][:system_profile].

Configuration Hash Nesting

Rather than auto-vivify nested hashes, each plugin's configuration is limited to a single level.

ohai[:plugin][:dmi][:all_ids] = true is allowed ohai[:plugin][:dmi][:ids][:cpu] = true is not allowed

Plugin authors are recommended to use underscores in variable names to manage multiple levels of configuration values. For example:

ohai[:plugin][:dmi][:id_cpu] = true
ohai[:plugin][:dmi][:id_memory] = true
ohai[:plugin][:dmi][:id_disk] = false

Configuration values may be hashes, but a hash must be explicitly set.

ohai[:plugin][:dmi][:id] = { :cpu => true, :memory => true, :disk => false }
Ohai.config[:plugin][:dmi][:id][:disk] => false

Plugin configuration lookup DSL method

To facilitate lookup of plugin configuration options, a new method will be added to the plugin DSL: configuration. The configuration method accepts as parameter the configuration option to fetch (as a Symbol).

For example, a plugin author may write

Ohai.plugin(:Foo) do
  provides 'foo'

  collect_data do
    if configuration(:foo_option)
      # ...
    end
  end
end

A user would configure

ohai.plugin[:foo][:foo_option] = true

The configuration method is intended only to be used to access top-level configuration options. If the plugin author chooses to require plugin configuration to be a Hash, the author must access those configuration options as Hash elements. That is, configuration(:one_two_three) cannot be used to look up plugin[:foo][:one][:two][:three].

Copyright

This work is in the public domain. In jurisdictions that do not allow for this, this work is available under CC0. To the extent possible under law, the person who associated CC0 with this work has waived all copyright and related or neighboring rights to this work.