Chef

Table Of Contents

About Ohai

Ohai is a tool that is used to detect attributes on a node, and then provide these attributes to the chef-client at the start of every chef-client run. Ohai is required by the chef-client and must be present on a node. (Ohai is installed on a node as part of the chef-client install process.)

The types of attributes Ohai collects include (but are not limited to):

  • Platform details
  • Network usage
  • Memory usage
  • Processor usage
  • Kernel data
  • Host names
  • Fully qualified domain names
  • Other configuration details

Attributes that are collected by Ohai are automatic attributes, in that these attributes are used by the chef-client to ensure that these attributes remain unchanged after the chef-client is done configuring the node.

Ohai collects data for many platforms, including AIX, Darwin, HP-UX, Linux, FreeBSD, OpenBSD, NetBSD, Solaris, and any Microsoft Windows operating system based off the Windows_NT kernel and has access to win32 or win64 sub-systems.

Warning

Ohai 7 is planned to be fully integrated into the chef-client starting with the 11.12.0 release (~April 2014). The current version is Ohai 6.

Automatic Attributes

An automatic attribute is a specific detail about a node, such as an IP address, a host name, a list of loaded kernel modules, and so on. Automatic attributes are detected by Ohai and are then used by the chef-client to ensure that these attribute are handled properly during every chef-client run. The most commonly accessed automatic attributes are:

Attribute Description
node['platform'] The platform on which a node is running. This attribute helps determine which providers will be used.
node['platform_version'] The version of the platform. This attribute helps determine which providers will be used.
node['ipaddress'] The IP address for a node. If the node has a default route, this is the IPV4 address for the interface. If the node does not have a default route, the value for this attribute should be nil. The IP address for default route is the recommended default value.
node['macaddress'] The MAC address for a node, determined by the same interface that detects the node['ipaddress'].
node['fqdn'] The fully qualified domain name for a node. This is used as the name of a node unless otherwise set.
node['hostname'] The host name for the node.
node['domain'] The domain for the node.
node['recipes'] A list of recipes associated with a node (and part of that node’s run-list).
node['roles'] A list of roles associated with a node (and part of that node’s run-list).
node['ohai_time'] The time at which Ohai was last run. This attribute is not commonly used in recipes, but it is saved to the Chef server and can be accessed using the knife status sub-command.

Get a list of automatic attributes for a node

The list of automatic attributes that are collected by Ohai at the start of each chef-client run vary from organization to organization, and will often vary between the various server types being configured and the platforms on which those servers are run. All attributes collected by Ohai are unmodifiable by the chef-client. To see which automatic attributes are collected by Ohai for a particular node, run the following command:

ohai$ grep -R "provides" -h lib/ohai/plugins|sed 's/^\s*//g'|sed "s/\\\"/\'/g"|sort|uniq|grep ^provides

Note

Attributes can be configured in cookbooks (attribute files and recipes), roles, and environments. In addition, Ohai collects attribute data about each node at the start of the chef-client run. See http://docs.opscode.com/chef_overview_attributes.html for more information about how all of these attributes fit together.

Attribute Persistence

At the beginning of a chef-client run, all default, override, and automatic attributes are reset. The chef-client rebuilds them using data collected by Ohai at the beginning of the chef-client run and by attributes that are defined in cookbooks, roles, and environments. Normal attributes are never reset. All attributes are then merged and applied to the node according to attribute precedence. At the conclusion of the chef-client run, all default, override, and automatic attributes disappear, leaving only a collection of normal attributes that will persist until the next chef-client run.

Attribute Precedence

Attributes are always applied by the chef-client in the following order:

  1. A default attribute located in a cookbook attribute file
  2. A default attribute located in a recipe
  3. A default attribute located in an environment
  4. A default attribute located in role
  5. A force_default attribute located in a cookbook attribute file
  6. A force_default attribute located in a recipe
  7. A normal attribute located in a cookbook attribute file
  8. A normal attribute located in a recipe
  9. An override attribute located in a cookbook attribute file
  10. An override attribute located in a recipe
  11. An override attribute located in a role
  12. An override attribute located in an environment
  13. A force_override attribute located in a cookbook attribute file
  14. A force_override attribute located in a recipe
  15. An automatic attribute identified by Ohai at the start of the chef-client run

where the last attribute in the list is the one that is applied to the node.

Note

The attribute precedence order for roles and environments is reversed for default and override attributes. The precedence order for default attributes is environment, then role. The precedence order for override attributes is role, then environment. Applying environment override attributes after role override attributes allows the same role to be used across multiple environments, yet ensuring that values can be set that are specific to each environment (when required). For example, the role for an application server may exist in all environments, yet one environment may use a database server that is different from other environments.

Attribute precedence, viewed from the same perspective as the overview diagram, where the numbers in the diagram match the order of attribute precedence:

_images/overview_chef_attributes_precedence.png

Attribute precedence, when viewed as a table:

_images/overview_chef_attributes_table.png

Custom Plugins

A custom Ohai plugin describes a set of attributes to be collected by Ohai, and then provided to the chef-client at the start of the chef-client run.

Warning

The syntax for custom plugins changes significantly between Ohai 6 and Ohai 7. This page is about Ohai 7 plugins and this page is about Ohai 6 plugins). While Chef has worked to ensure backwards compatibility for all plugins in Ohai 7, a plan should be put in place to update the syntax for all Ohai 6 plugins so they are using the Ohai 7 pattern. Once updated, please test and verify those plugins before running them in a production environment.

Syntax

The syntax for an Ohai plugin is as follows:

Ohai.plugin(:Name) do
  include Ohai::Name
  provides "attribute", "attribute/subattribute"
  depends "attribute", "attribute"

  def shared_method
    # some Ruby code that defines the shared method
    attribute my_data
  end

  collect_data(:default) do
    # some Ruby code
    attribute my_data
  end

  collect_data(:platform...) do
    # some Ruby code that defines platform-specific requirements
    attribute my_data
  end

end

where

  • Required. (:Name) is used to identify the plugin; when two plugins have the same (:Name), those plugins are joined together and run as if they were a single plugin. This value must be a valid Ruby class name, starting with a capital letter and containing only alphanumeric characters
  • include is a standard Ruby method that allows an Ohai plugin to include a class, such as Ohai::Mixin::ModuleName
  • Required. provides is a comma-separated list of one (or more) attributes that are defined by this plugin. This attribute will become an automatic attribute (i.e. node[:attribute]) after it is collected by Ohai at the start of the chef-client run. An attribute can also be defined using an attribute/subattribute pattern
  • depends is a comma-separated list of one (or more) attributes that are collected by another plugin; as long as the value is collected by another Ohai plugin, it can be used by any plugin
  • shared_method defines code that can be shared among one (or more) collect_data blocks; for example, instead of defining a mash for each collect_data block, the code can be defined as a shared method, and then called from any collect_data block
  • collect_data is a block of Ruby code that is called by Ohai when it runs; one (or more) collect_data blocks can be defined in a plugin, but only a single collect_data block is ever run.
  • collect_data(:default) is the code block that runs when a node’s platform is not defined by a platform-specific collect_data block
  • collect_data(:platform) is a platform-specific code block that is run when a match exists between the node’s platform and this collect_data block; only one collect_data block may exist for each platform; possible values: :aix, :darwin, :freebsd, :hpux, :linux, :openbsd, :netbsd, :solaris2, :windows, or any other value from RbConfig::CONFIG['host_os']
  • my_data is string (a string value) or an empty mash ({ :setting_a => "value_a", :setting_b" => "value_b" }). This is used to define the data that should be collected by the plugin

For example, the following plugin looks up data on virtual machines hosted in Amazon EC2, Google Compute Engine, Rackspace, Eucalyptus, Linode, OpenStack, and Microsoft Azure:

Ohai.plugin do
  provides "cloud"

  depends "ec2"
  depends "gce"
  depends "rackspace"
  depends "eucalyptus"
  depends "linode"
  depends "openstack"
  depends "azure"

  def create_objects
    cloud Mash.new
    cloud[:public_ips] = Array.new
    cloud[:private_ips] = Array.new
  end

  ...

  def on_gce?
    gce != nil
  end
  def get_gce_values
    cloud[:public_ipv4] = []
    cloud[:local_ipv4] = []

    public_ips = gce['network']["networkInterface"].collect do |interface|
      if interface.has_key?('accessConfiguration')
        interface['accessConfiguration'].collect{|ac| ac['externalIp']}
      end
    end.flatten.compact

    private_ips = gce['network']["networkInterface"].collect do |interface|
      interface['ip']
    end.compact

    cloud[:public_ips] += public_ips
    cloud[:private_ips] += private_ips
    cloud[:public_ipv4] +=  public_ips
    cloud[:public_hostname] = nil
    cloud[:local_ipv4] += private_ips
    cloud[:local_hostname] = gce['hostname']
    cloud[:provider] = "gce"
  end

  ...

  # with following similar code blocks for each cloud provider

where

  • provides defines the cloud attribute, which is then turned into an object using the create_objects shared method, which then generates a hash based on public or private IP addresses
  • if the cloud provider is Google Compute Engine, then based on the IP address for the node, the cloud attribute data is populated into a hash

To see the rest of the code in this plugin, go to : https://github.com/opscode/ohai/blob/master/lib/ohai/plugins/cloud.rb.

Ohai DSL Methods

The Ohai DSL is a Ruby DSL that is used to define an Ohai plugin and to ensure that Ohai collects the right data at the start of every chef-client run. The Ohai DSL is a small DSL with a single method that is specific to Ohai plugins. Because the Ohai DSL is a Ruby DSL, anything that can be done using Ruby can also be done when defining an Ohai plugin.

collect_data

The collect_data method is a block of Ruby code that is called by Ohai when it runs. One (or more) collect_data blocks can be defined in a plugin, but only a single collect_data block is ever run. The collect_data block that is run is determined by the platform on which the node is running, which is then matched up against the available collect_data blocks in the plugin.

  • A collect_data(:default) block is used when Ohai is not able to match the platform of the node with a collect_data(:platform) block in the plugin; collect_data can also be used to represent the default block
  • A collect_data(:platform) block is required for each platform

When Ohai runs, if there isn’t a matching collect_data block for a platform, the collect_data(:default) block is used. The syntax for the collect_data method is:

collect_data(:default) do
  # some Ruby code
end

or:

collect_data(:platform) do
  # some Ruby code
end

where:

  • :default is the name of the default collect_data block
  • :platform is the name of the platform, such as :aix for AIX or :windows for Microsoft Windows
Use a Mash

Use a mash to store data. This is done by creating a new mash, and then setting an attribute to it. For example:

provides "name_of_mash"
name_of_mash Mash.new
name_of_mash[:attribute] = "value"
Examples

The following examples show how to use the collect_data block:

Ohai.plugin(:Azure) do
  provides "azure"

  collect_data do
    azure_metadata_from_hints = hint?('azure')
    if azure_metadata_from_hints
      Ohai::Log.debug("azure_metadata_from_hints is present.")
      azure Mash.new
      azure_metadata_from_hints.each {|k, v| azure[k] = v }
    else
      Ohai::Log.debug("No hints present for azure.")
      false
    end
  end
end

or:

require 'ohai/mixin/ec2_metadata'
extend Ohai::Mixin::Ec2Metadata

Ohai.plugin do
  provides "openstack"

  collect_data do
    if hint?('openstack') || hint?('hp')
      Ohai::Log.debug("ohai openstack")
      openstack Mash.new
      if can_metadata_connect?(EC2_METADATA_ADDR,80)
        Ohai::Log.debug("connecting to the OpenStack metadata service")
        self.fetch_metadata.each {|k, v| openstack[k] = v }
        case
        when hint?('hp')
          openstack['provider'] = 'hp'
        else
          openstack['provider'] = 'openstack'
        end
      else
        Ohai::Log.debug("unable to connect to the OpenStack metadata service")
      end
    else
      Ohai::Log.debug("NOT ohai openstack")
    end
  end
end

require

The require method is a standard Ruby method that can be used to list files that may be required by a platform, such as an external class library. As a best practice, even though the require method is often used at the top of a Ruby file, it is recommended that the use of the require method be used as part of the platform-specific collect_data block. For example, the Ruby WMI is required with Microsoft Windows:

collect_data(:windows) do
  require 'ruby-wmi'
  WIN32OLE.codepage = WIN32OLE::CP_UTF8

  kernel Mash.new

  host = WMI::Win32_OperatingSystem.find(:first)
  kernel[:os_info] = Mash.new
  host.properties_.each do |p|
    kernel[:os_info][p.name.wmi_underscore.to_sym] = host.send(p.name)
  end

  ...

end

Ohai will attempt to fully qualify the name of any class by prepending Ohai:: to the loaded class. For example both:

require Ohai::Mixin::ShellOut

and:

require Mixin::ShellOut

are both understood by the Ohai in the same way: Ohai::Mixin::ShellOut.

When a class is an external class (and therefore should not have Ohai:: prepended), use :: to let the Ohai know. For example:

::External::Class::Library
/common Directory

The /common directory stores code that is used across all Ohai plugins. For example, a file in the /common directory named virtualization.rb that includes code like the following:

module Ohai
  module Common
    module Virtualization

      def host?(virtualization)
        !virtualization.nil? && virtualization[:role].eql?("host")
      end

      def open_virtconn(system)
        begin
          require 'libvirt'
          require 'hpricot'
        rescue LoadError => e
          Ohai::Log.debug("Cannot load gem: #{e}.")
        end

        emu = (system.eql?('kvm') ? 'qemu' : system)
        virtconn = Libvirt::open_read_only("#{emu}:///system")
      end

      ...

      def networks(virtconn)
        networks = Mash.new
        virtconn.list_networks.each do |n|
          nv = virtconn.lookup_network_by_name n
          networks[n] = Mash.new
          networks[n][:xml_desc] = (nv.xml_desc.split("\n").collect {|line| line.strip}).join
          ['bridge_name','uuid'].each {|a| networks[n][a] = nv.send(a)}
          #xdoc = Hpricot networks[n][:xml_desc]
        end
        networks
      end

      ...

    end
  end
end

can then be leveraged in a plugin by using the require method to require the virtualization.rb file and then later calling each of the methods in the required module:

require 'ohai/common/virtualization'

Ohai.plugin(:Virtualization) do
  include Ohai::Common::Virtualization

  provides "virtualization"
  %w{ capabilities domains networks storage }.each do |subattr|
    provides "virtualization/#{subattr}"
  end

  collect_data(:linux) do
    virtualization Mash.new

    ...

    if host?(virtualization)
      v = open_virtconn(virtualization[:system])

      virtualization[:libvirt_version] = libvirt_version(v)
      virtualization[:nodeinfo] = nodeinfo(v)
      virtualization[:uri] = uri(v)
      virtualization[:capabilities] = capabilities(v)
      virtualization[:domains] = domains(v)
      virtualization[:networks] = networks(v)
      virtualization[:storage] = storage(v)

      close_virtconn(v)
    end

Shared Methods

A shared method defines behavior that may be used by more than one collect_data block, such as a data structure, a hash, or a mash. The syntax for a shared method is:

def a_shared_method
  # some Ruby code that defines the shared method
end

For example, the following shared method is used to collect data about various cloud providers, depending on the cloud provider and the type of IP address:

def create_objects
  cloud Mash.new
  cloud[:public_ips] = Array.new
  cloud[:private_ips] = Array.new
end

and then later on in the same plugin, the cloud object can be reused:

def get_linode_values
  cloud[:public_ips] << linode['public_ip']
  cloud[:private_ips] << linode['private_ip']
  cloud[:public_ipv4] = linode['public_ipv4']
  cloud[:public_hostname] = linode['public_hostname']
  cloud[:local_ipv4] = linode['local_ipv4']
  cloud[:local_hostname] = linode['local_hostname']
  cloud[:provider] = "linode"
end

and

def get_azure_values
  cloud[:vm_name] = azure["vm_name"]
  cloud[:public_ips] << azure['public_ip']
  cloud[:public_fqdn] = azure['public_fqdn']
  cloud[:public_ssh_port] = azure['public_ssh_port'] if azure['public_ssh_port']
  cloud[:public_winrm_port] = azure['public_winrm_port'] if azure['public_winrm_port']
  cloud[:provider] = "azure"
end

and so on, for each of the various cloud providers.

Log Entries

Use the Chef::Log class in an Ohai plugin to define log entries that are created during a chef-client run. The syntax for a log message is as follows:

Chef::Log.log_type("message")

where

  • log_type can be .debug, .info, .warn, .error, or .fatal
  • "message" is the message that is logged.

For example:

Ohai.plugin do
  provides "openstack"

  collect_data do
    if hint?('openstack') || hint?('hp')
      Ohai::Log.debug("ohai openstack")
      openstack Mash.new
      if can_metadata_connect?(EC2_METADATA_ADDR,80)
        Ohai::Log.debug("connecting to the OpenStack metadata service")
        self.fetch_metadata.each {|k, v| openstack[k] = v }
        case
        when hint?('hp')
          openstack['provider'] = 'hp'
        else
          openstack['provider'] = 'openstack'
        end
      else
        Ohai::Log.debug("unable to connect to the OpenStack metadata service")
      end
    else
      Ohai::Log.debug("NOT ohai openstack")
    end
  end
end

rescue

Use the rescue clause to make sure that a log message is always provided. For example:

rescue LoadError => e
  Ohai::Log.debug("ip_scopes: cannot load gem, plugin disabled: #{e}")
end

Examples

The following examples show different ways of building Ohai plugins.

collect_data Blocks

The following Ohai plugin uses multiple collect_data blocks and shared methods to define platforms:

Ohai.plugin(:Hostname) do
  provides "domain", "fqdn", "hostname"

  def from_cmd(cmd)
    so = shell_out(cmd)
    so.stdout.split($/)[0]
  end

  def collect_domain
    if fqdn
      fqdn =~ /.+?\.(.*)/
      domain $1
    end
  end

  collect_data(:aix, :hpux) do
    hostname from_cmd("hostname -s")
    fqdn from_cmd("hostname")
    domain collect_domain
  end

  collect_data(:darwin, :netbsd, :openbsd) do
    hostname from_cmd("hostname -s")
    fqdn from_cmd("hostname")
    domain collect_domain
  end

  collect_data(:freebsd) do
    hostname from_cmd("hostname -s")
    fqdn from_cmd("hostname -f")
    domain collect_domain
  end

  collect_data(:linux) do
    hostname from_cmd("hostname -s")
    begin
      fqdn from_cmd("hostname --fqdn")
    rescue
      Ohai::Log.debug("hostname -f returned an error, probably no domain is set")
    end
    domain collect_domain
  end

  collect_data(:solaris2) do
    require 'socket'

    hostname from_cmd("hostname")

    fqdn_lookup = Socket.getaddrinfo(hostname, nil, nil, nil, nil, Socket::AI_CANONNAME).first[2]
    if fqdn_lookup.split('.').length > 1
      # we received an fqdn
      fqdn fqdn_lookup
    else
      # default to assembling one
      h = from_cmd("hostname")
      d = from_cmd("domainname")
      fqdn "#{h}.#{d}"
    end

    domain collect_domain
  end

  collect_data(:windows) do
    require 'ruby-wmi'
    require 'socket'

    host = WMI::Win32_ComputerSystem.find(:first)
    hostname "#{host.Name}"

    info = Socket.gethostbyname(Socket.gethostname)
    if info.first =~ /.+?\.(.*)/
      fqdn info.first
    else
      # host is not in dns. optionally use:
      # C:\WINDOWS\system32\drivers\etc\hosts
      fqdn Socket.gethostbyaddr(info.last).first
    end

   domain collect_domain
  end
end

Use a mixin Library

The following Ohai example shows a plugin can use a mixin library and also depend on another plugin:

require 'ohai/mixin/os'

Ohai.plugin(:Os) do
  provides "os", "os_version"
  depends 'kernel'

  collect_data do
    os collect_os
    os_version kernel[:release]
  end
end

Get Kernel Values

The following Ohai example shows part of a file that gets initial kernel attribute values:

Ohai.plugin(:Kernel) do
  provides "kernel", "kernel/modules"

  def init_kernel
    kernel Mash.new
    [["uname -s", :name], ["uname -r", :release],
    ["uname -v", :version], ["uname -m", :machine]].each do |cmd, property|
      so = shell_out(cmd)
      kernel[property] = so.stdout.split($/)[0]
    end
    kernel
  end

  ...

  collect_data(:darwin) do
    kernel init_kernel
    kernel[:os] = kernel[:name]

    so = shell_out("sysctl -n hw.optional.x86_64")
    if so.stdout.split($/)[0].to_i == 1
      kernel[:machine] = 'x86_64'
    end

    modules = Mash.new
    so = shell_out("kextstat -k -l")
    so.stdout.lines do |line|
      if line =~ /(\d+)\s+(\d+)\s+0x[0-9a-f]+\s+0x([0-9a-f]+)\s+0x[0-9a-f]+\s+([a-zA-Z0-9\.]+) \(([0-9\.]+)\)/
        kext[$4] = { :version => $5, :size => $3.hex, :index => $1, :refcount => $2 }
      end
    end

    kernel[:modules] = modules
  end

  ...

ohai Resource

A resource is a key part of a recipe that defines the actions that can be taken against a piece of the system. These actions are identified during each chef-client run as the resource collection is compiled. Once identified, each resource (in turn) is mapped to a provider, which then configures each piece of the system.

The ohai resource is used to reload the Ohai configuration on a node, which allows recipes that change system attributes (like adding a user) to refer to those attributes later on during the chef-client run.

Syntax

The syntax for using the ohai resource in a recipe is as follows:

ohai "name" do
  attribute "value" # see attributes section below
  ...
  action :action # see actions section below
end

where

  • ohai tells the chef-client to use the Chef::Provider::Ohai provider during the chef-client run
  • "name" is a friendly name for the action that is defined in the recipe
  • attribute is zero (or more) of the attributes that are available for this resource
  • :action is the step that the resource will ask the provider to take during the chef-client run

Actions

This resource has the following actions:

Action Description
:reload Default. Use to reload the Ohai configuration on a node.

Attributes

This resource has the following attributes:

Attribute Description
name Always the same value as the name of the resource block (see Syntax section above).
plugin Optional. Indicates that the specified plug-ins are reloaded by Ohai. The default behavior reloads all plug-ins.
provider Optional. Use to specify a provider by using its long name. For example: provider Chef::Provider::Long::Name. See the Providers section below for the list of providers available to this resource.

Providers

The following providers are available. Use the short name to call the provider from a recipe:

Long name Short name Notes
Chef::Provider::Ohai ohai The default provider for all platforms.

Examples

The following examples demonstrate various approaches for using resources in recipes. If you want to see examples of how Chef uses resources in recipes, take a closer look at the cookbooks that Chef authors and maintains: https://github.com/opscode-cookbooks.

Reload Ohai

ohai "reload" do
  action :reload
end

Reload Ohai after a new user is created

ohai "reload_passwd" do
  action :nothing
  plugin "passwd"
end

user "daemonuser" do
  home "/dev/null"
  shell "/sbin/nologin"
  system true
  notifies :reload, "ohai[reload_passwd]", :immediately
end

ruby_block "just an example" do
  block do
    # These variables will now have the new values
    puts node['etc']['passwd']['daemonuser']['uid']
    puts node['etc']['passwd']['daemonuser']['gid']
  end
end

ohai Cookbook

To download the ohai cookbook to the chef-repo run the following command:

$ knife cookbook site install ohai

Knife will return something similar to:

INFO: Downloading ohai from the cookbooks site at version 0.9.0
INFO: Cookbook saved: /Users/jtimberman/chef-repo/cookbooks/ohai.tar.gz
INFO: Checking out the master branch.
INFO: Checking the status of the vendor branch.
INFO: Creating vendor branch.
INFO: Removing pre-existing version.
INFO: Uncompressing ohai version 0.9.0.
INFO: Adding changes.
INFO: Committing changes.
INFO: Creating tag chef-vendor-ohai-0.9.0.
INFO: Checking out the master branch.
INFO: Merging changes from ohai version 0.9.0.
[ ... SNIP ... ]
INFO: Cookbook ohai version 0.9.0 successfully vendored!

Default Location

To change the directory in which plugins are located edit the attributes file in the ohai cookbook for the node[:ohai][:plugin_path] attribute. Change the value to the desired directory path. For example:

default[:ohai][:plugin_path] = "/etc/chef/ohai_plugins"

Upload Custom Plugins

To upload the ohai cookbook to the Chef server, use Knife and run the following:

knife cookbook upload ohai

to return something similar to:

INFO: Saving ohai
INFO: Validating ruby files
INFO: Validating templates
INFO: Syntax OK
INFO: Generating Metadata
INFO: Uploading files
[ ... SNIP ... ]

Add Ohai to a Run-list

The ohai recipe can be added to a run-list. First, ensure that any custom Ohai plugins are loaded and available to recipes. When the chef-client runs, the plugins will be copied into place and then loaded and merged with the node. This does cause Ohai to be run twice, which can increase the total run time for the chef-client.

ohai Command Line Tool

ohai is the command-line interface for Ohai, a tool that is used to detect attributes on a node, and then provide these attributes to the chef-client at the start of every chef-client run.

Options

This command has the following syntax:

ohai OPTION

This tool has the following options:

ATTRIBUTE_NAME ATTRIBUTE NAME ...
Use to have Ohai show only output for named attributes.
-d PATH, --directory PATH
The directory in which Ohai plugins are located. For example: /etc/ohai/plugins.
-h, --help
Shows help for the command.
-l LEVEL, --log_level LEVEL
The level of logging that will be stored in a log file.
-L LOGLOCATION, --logfile c
The location in which log file output files will be saved. If this location is set to something other than STDOUT, standard output logging will still be performed (otherwise there would be no output other than to a file).
-v, --version
The version of Ohai.

Examples

The following examples show how to use the Ohai command-line tool:

Run a plugin independently of a chef-client run

An Ohai plugin can be run independently of a chef-client run. First, ensure that the plugin is located in the /plugins directory and then use the -f option when running Ohai from the command line. For example, a plugin named sl_installed may look like the following:

Ohai.plugin(:sl) do
  provides "sl"

  collect_data(:default) do
    sl Mash.new

    if ::File.exists?("/usr/games/sl")
      sl[:installed] = true
    else
      sl[:installed] = false
    end

    # sl[:installed] = ::File.exists?("/usr/games/sl")

  end
end

To run that plugin from the command line, use the following command:

$ ohai --directory /path/to/plugin_file.rb sl

The command will return something similar to:

{
  "sl": {
    "installed": true
  }
}

Ohai Settings in client.rb

Ohai configuration settings can be added to the client.rb file.

Setting Description
Ohai::Config[:directory] The directory in which Ohai plugins are located.
Ohai::Config[:disabled_plugins]

An array of Ohai plugins to be disabled on a node. For example:

Ohai::Config[:disabled_plugins] = [:MyPlugin]

or:

Ohai::Config[:disabled_plugins] = [:MyPlugin, :MyPlugin, :MyPlugin]

or to disable both Ohai 6 and Ohai 7 versions:

Ohai::Config[:disabled_plugins] = [:MyPlugin, :MyPlugin, "my_ohai_6_plugin"]
Ohai::Config[:hints_path] The path to the file that contains hints for Ohai.
Ohai::Config[:log_level] The level of logging that will be stored in a log file.
Ohai::Config[:logfile] The location in which log file output files will be saved. If this location is set to something other than STDOUT, standard output logging will still be performed (otherwise there would be no output other than to a file).
Ohai::Config[:version] The version of Ohai.

Note

The Ohai executable ignores settings in the client.rb file when Ohai is run independently of the chef-client.