In this post, we will see two excelent tools to get details on system properties within the Chef ecosystem. Ohai is a tool to collect system information and other information for Chef configuration management tool. This information is used to populate in cookbooks before they compile and execute when check client runs on the chef node. Suppose you want to set some swap size depending on swap details are set or not. The chef will never know what the swap size is, it depends on ohai to collect these system details. This is similar to Factor in Puppet, setup module in Ansible.

How to access attributes using Ohai?

The simplest way to access system information on the node is just to type ohai on chef-node.

Example:

ohai

Output(clipped):

[root@rhel74-kitchen ~]# ohai

[2018-07-20T06:13:18+10:00] INFO: The plugin path /etc/chef/ohai/plugins does not exist. Skipping...
{
  "cpu": {
    "0": {
      "vendor_id": "GenuineIntel",
      "family": "6",
      "model": "45",
      "model_name": "Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz",
      "stepping": "2",
      "mhz": "2593.958",
      "cache_size": "30720 KB",
      "physical_id": "0",
      "core_id": "0",
      "cores": "1",
      "flags": [
        "fpu",
        "vme",
        "de",
        "pse",
        "tsc",
        "msr",
        "pae",
        "mce",
        "cx8",
        "apic",
        "sep",
        "mtrr",
        "pge",
        "mca",
        "cmov",
        "pat",

I can see 9000+ lines with the above command, that will contain all the system details. From the above example if we want to see how many CPU’s are present in the system, we can use below ohai command.

ohai cpu/cores

Output:

[root@rhel74-kitchen kitchen]# ohai cpu/cores
[2018-07-20T06:21:39+10:00] INFO: The plugin path /etc/chef/ohai/plugins does not exist. Skipping...
2

Suppose if we want to see what version of python is installed we can use below example

[root@rhel74-kitchen kitchen]# ohai packages/python/version
[2018-07-20T06:23:05+10:00] INFO: The plugin path /etc/chef/ohai/plugins does not exist. Skipping...
[
  "2.7.5"
]

Similarly, we can check when this python package is installed or not.

[root@rhel74-kitchen kitchen]# ohai packages/python/installdate
[2018-07-20T06:25:07+10:00] INFO: The plugin path /etc/chef/ohai/plugins does not exist. Skipping...
[
  "1530271467"
]

How about if we query package which is not installed we will get an error. In my machine, I did not install nmap and see what error we get.

[root@rhel74-kitchen kitchen]# ohai packages/nmap
[2018-07-20T06:23:42+10:00] INFO: The plugin path /etc/chef/ohai/plugins does not exist. Skipping...
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/lib/ohai/system.rb:222:in `attributes_print': I cannot find an attribute named packages/nmap! (ArgumentError)
 from /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/lib/ohai/application.rb:101:in `block in run_application'
 from /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/lib/ohai/application.rb:100:in `each'
 from /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/lib/ohai/application.rb:100:in `run_application'
 from /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/lib/ohai/application.rb:80:in `block in run'
 from /opt/chef/embedded/lib/ruby/2.4.0/benchmark.rb:293:in `measure'
 from /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/lib/ohai/application.rb:78:in `run'
 from /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/ohai-13.10.0/bin/ohai:26:in `<top (required)>'
 from /usr/bin/ohai:44:in `load'
 from /usr/bin/ohai:44:in `<main>'

Similarly, we can use chef-shell which is an interactive tool to do all types of chef work. We will use this tool to get attribute values.

Just type chef-shell without any options

chef-shell

Once you are in interactive mode, we can access many sub-tools.

Example:

chef (13.10.0)> help
chef-shell Hel
================================================================================
| Command                  | Description
================================================================================
| help                     | prints this help message
| version                  | prints information about chef
| recipe_mode              | switch to recipe mode
| attributes_mode          | switch to attributes mode
| run_chef                 | run chef using the current recipe
| chef_run                 | returns an object to control a paused chef run
| chef_run.resume          | resume the chef run
| chef_run.step            | run only the next resource
| chef_run.skip_back       | move back in the run list
| chef_run.skip_forward    | move forward in the run list
| reset                    | resets the current recipe
| become_node              | assume the identity of another node.
| echo                     | turns printout of return values on or off
| echo?                    | says if echo is on or off
| tracing                  | turns on or off tracing of execution. *verbose*
| tracing?                 | says if tracing is on or off
| ls                       | simple ls style command
| node                     | returns the current node (i.e., this host)
| ohai                     | pretty print the node's attributes
| edit                     | edit an object in your EDITOR
| clients                  | Find and edit API clients
| clients.all              | list all api clients
| clients.show             | load an api client by name
| clients.search           | search for API clients
| clients.transform        | edit all api clients via a code block and save them
| cookbooks                | Find and edit cobooks
| cookbooks.all            | list all cookbooks
| cookbooks.show           | load a cookbook by name
| cookbooks.transform      | edit all cookbooks via a code block and save them
| nodes                    | Find and edit nodes via the API
| nodes.all                | list all nodes
| nodes.show               | load a node by name
| nodes.search             | search for nodes
| nodes.transform          | edit all nodes via a code block and save them
| roles                    | Find and edit roles via the API
| roles.all                | list all roles
| roles.show               | load a role by name
| roles.search             | search for roles
| roles.transform          | edit all roles via a code block and save them
| databags                 | Find and edit +databag_name+ via the api
| databags.all             | list all items in the data bag
| databags.show            | load a data bag item by id
| databags.search          | search for items in the data bag
| databags.transform       | edit all items via a code block and save them
| environments             | Find and edit environments via the API
| environments.all         | list all environments
| environments.show        | load an environment by name
| environments.search      | search for environments
| environments.transform   | edit all environments via a code block and save them
| api                      | A REST Client configured to authenticate with the API
================================================================================

Of these we will pickup attributes_mode for our post.

In attributes mode, we can start accessing attributes and their values similar to ohai.

Example:

[root@rhel74-kitchen cookbooks]# chef-shell
loading configuration: none (standalone session)
Session type: standalone
Loading....done.
This is the chef-shell.
 Chef Version: 13.10.
 https://www.chef.io/
 https://docs.chef.io/
run `help' for help, `exit' or ^D to quit.
Ohai2u root@rhel74-kitchen.localdomain!
chef (13.10.0)> attributes_mode

Get CPU details of the system:

chef:attributes (13.10.0)> attributes[:cpu]
 => {"0"=>{"vendor_id"=>"GenuineIntel", "family"=>"6", "model"=>"45", "model_name"=>"Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz", "stepping"=>"2", "mhz"=>"2593.958", "cache_size"=>"30720 KB", "physical_id"=>"0", "core_id"=>"0", "cores"=>"1", "flags"=>["fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "clflush", "dts", "mmx", "fxsr", "sse", "sse2", "ss", "syscall", "nx", "rdtscp", "lm", "constant_tsc", "arch_perfmon", "pebs", "bts", "nopl", "xtopology", "tsc_reliable", "nonstop_tsc", "aperfmperf", "pni", "pclmulqdq", "ssse3", "cx16", "pcid", "sse4_1", "sse4_2", "x2apic", "popcnt", "aes", "xsave", "avx", "hypervisor", "lahf_lm", "epb", "dtherm", "arat", "pln", "pts"]}, "1"=>{"vendor_id"=>"GenuineIntel", "family"=>"6", "model"=>"45", "model_name"=>"Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz", "stepping"=>"2", "mhz"=>"2593.958", "cache_size"=>"30720 KB", "physical_id"=>"2", "core_id"=>"0", "cores"=>"1", "flags"=>["fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "clflush", "dts", "mmx", "fxsr", "sse", "sse2", "ss", "syscall", "nx", "rdtscp", "lm", "constant_tsc", "arch_perfmon", "pebs", "bts", "nopl", "xtopology", "tsc_reliable", "nonstop_tsc", "aperfmperf", "pni", "pclmulqdq", "ssse3", "cx16", "pcid", "sse4_1", "sse4_2", "x2apic", "popcnt", "aes", "xsave", "avx", "hypervisor", "lahf_lm", "epb", "dtherm", "arat", "pln", "pts"]}, "total"=>2, "real"=>2, "cores"=>2} 

Get first processor details of the system

chef:attributes (13.10.0)> attributes[:cpu][:’0′]

=> {“vendor_id”=>”GenuineIntel”, “family”=>”6”, “model”=>”45”, “model_name”=>”Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz”, “stepping”=>”2”, “mhz”=>”2593.958”, “cache_size”=>”30720 KB”, “physical_id”=>”0”, “core_id”=>”0”, “cores”=>”1”, “flags”=>[“fpu”, “vme”, “de”, “pse”, “tsc”, “msr”, “pae”, “mce”, “cx8”, “apic”, “sep”, “mtrr”, “pge”, “mca”, “cmov”, “pat”, “pse36”, “clflush”, “dts”, “mmx”, “fxsr”, “sse”, “sse2”, “ss”, “syscall”, “nx”, “rdtscp”, “lm”, “constant_tsc”, “arch_perfmon”, “pebs”, “bts”, “nopl”, “xtopology”, “tsc_reliable”, “nonstop_tsc”, “aperfmperf”, “pni”, “pclmulqdq”, “ssse3”, “cx16”, “pcid”, “sse4_1”, “sse4_2”, “x2apic”, “popcnt”, “aes”, “xsave”, “avx”, “hypervisor”, “lahf_lm”, “epb”, “dtherm”, “arat”, “pln”, “pts”]}

Get vender name of first processor of the CPU

chef:attributes (13.10.0)> attributes[:cpu][:'0']['vendor_id']

 => "GenuineIntel" 

chef:attributes (13.10.0)> 

How to access custom attributes?

We can create custom attributes in Chef, by default we can access them with the above technique. We have to provide the client.rb file so that these tools will read path where ohai plugin directory is present.

Example:

chef-shell -c /etc/chef/client.rb

ohai -c /etc/chef/client.rb mycustom_variable/value

Hope this helps in understanding if there is an issue with attributes and values used in chef cookbooks.

The following two tabs change content below.
Mr Surendra Anne is from Vijayawada, Andhra Pradesh, India. He is a Linux/Open source supporter who believes in Hard work, A down to earth person, Likes to share knowledge with others, Loves dogs, Likes photography. He works as Devops Engineer with Taggle systems, an IOT automatic water metering company, Sydney . You can contact him at surendra (@) linuxnix dot com.