# InSpec conditional testing based on node attributes

**URL:** <https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908>\
**Category:** Chef InSpec\
**Created:** [July 11, 2016, 8:11pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908 "2016-07-11T20:11:27Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![OxHobbs](https://avatars.discourse-cdn.com/v4/letter/o/977dab/32.png) [@OxHobbs](https://discourse.chef.io/u/OxHobbs)\
**Post date:** [July 11, 2016, 8:11pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/1 "2016-07-11T20:11:27Z")

</div>

Hi chefs, I have a question regarding using _Inspec_ to test my cookbooks.

I have a cookbook that installs numerous Windows features. Some of which aren’t always necessary (such as management tools). So, I wanted to use an attribute so that those certain install components are easily disabled.

To verify that my recipe is working as expected I need a test for when the attribute is true and one when it is false; however, I am not able to access the node attributes from the test. I did try the [JSON trick](http://www.hurryupandwait.io/blog/accessing-chef-node-attributes-from-kitchen-tests) here but _Inspec_ doesn’t let me use the conditional inside the describe block and if I define that method outside of the blocks it runs in the context of my dev workstation.

```ruby
if node['clustering']['install_ps_tools']
  describe windows_feature('rsat-clustering-powershell') do
    it { should be_installed }
  end
end

```

Of course, if this is bad design I’d take that criticism as well.

---

<div class="post-metadata">

**Author:** ![Matt\_Wrock](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/matt_wrock/32/3394_2.png) [@Matt\_Wrock](https://discourse.chef.io/u/Matt_Wrock)\
**Post date:** [July 17, 2016, 3:30am UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/2 "2016-07-17T03:30:05Z")

</div>

You can access the node from inside the `describe` and I would use `skip` which is the idiomatic rspec way for doing what you are trying to achieve. So assuming your `node` has a `foo` attribute. and you want to skip the test(s) if its value is `bar`, you could do this:

```auto
describe file(File.join("/tmp", "export-node", "node.json")) do
  let(:parent) { File.join("/tmp", "kitchen") }
  let(:node) { json(File.join(parent, "chef_node.json")).params }

  before do
    skip if node["normal"]["foo"] == "bar"
  end

  it { should be_file }  
  its(:content) {
    should match /^mac: #{node["automatic"]["macaddress"]}$/
  }
end

```

which yields:

```auto
  ○ 2 skipped
     skip:
     skip:

Summary: 0 successful, 0 failures, 2 skipped

```

You could move the `skip` to individual `it` blocks if you just want to skip a single example.

---

<div class="post-metadata">

**Author:** ![OxHobbs](https://avatars.discourse-cdn.com/v4/letter/o/977dab/32.png) [@OxHobbs](https://discourse.chef.io/u/OxHobbs)\
**Post date:** [July 18, 2016, 12:39pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/3 "2016-07-18T12:39:13Z")

</div>

Perfect, thanks a bunch!

---

<div class="post-metadata">

**Author:** ![skohrs](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/skohrs/32/1604_2.png) [@skohrs](https://discourse.chef.io/u/skohrs)\
**Post date:** [August 3, 2016, 9:28pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/4 "2016-08-03T21:28:22Z")

</div>

I tried to follow this example, but it resulted in a Ruby error:

```
Failures:

  1) File /u01/app/oracle/product/11.2.0.4/dbhome_1 
     Failure/Error: skip unless node['oracle']['db_version'] == "11.2.0.4"
     
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # ./test/integration/default/inspec/db_install_spec.rb:10:in `block (2 levels) in load'
     # /Users/skohrs/.chefdk/gem/ruby/2.1.0/gems/inspec-0.27.1/lib/inspec/runner_rspec.rb:78:in `run'
     # /Users/skohrs/.chefdk/gem/ruby/2.1.0/gems/kitchen-inspec-0.15.0/lib/kitchen/verifier/inspec.rb:75:in `call'

```

Here is the InSpec test:

```
describe file('/u01/app/oracle/product/11.2.0.4/dbhome_1') do
  let(:node) { json('/tmp/kitchen/chef_node.json').params }

  before do
    skip unless node['oracle']['db_version'] == "11.2.0.4"
  end

  it { should be_directory }
  its('owner') { should eq 'oracle' }
  its('group') { should eq 'oinstall' }
end

```

Any suggestions?

---

<div class="post-metadata">

**Author:** ![Matt\_Wrock](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/matt_wrock/32/3394_2.png) [@Matt\_Wrock](https://discourse.chef.io/u/Matt_Wrock)\
**Post date:** [August 3, 2016, 9:41pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/5 "2016-08-03T21:41:17Z")

</div>

Try `node['automatic']['oracle']['db_version']` keeping in mind that the json includes a level for the attribute type that the node object would conveniently hide in a recipe.

---

<div class="post-metadata">

**Author:** ![skohrs](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/skohrs/32/1604_2.png) [@skohrs](https://discourse.chef.io/u/skohrs)\
**Post date:** [August 3, 2016, 9:49pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/6 "2016-08-03T21:49:25Z")

</div>

Thank you, Matt!

In my case, `node['default']['oracle']['db_version']` held the attribute I was testing against.

---

<div class="post-metadata">

**Author:** ![Victor](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/victor/32/1259_2.png) [@Victor](https://discourse.chef.io/u/Victor)\
**Post date:** [September 14, 2016, 3:07pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/7 "2016-09-14T15:07:49Z")

</div>

Is there a way to use an attribute such as in the following example?

describe file (node[‘normal’][‘path’]) do  
…

---

<div class="post-metadata">

**Author:** ![christian.leinweber](https://avatars.discourse-cdn.com/v4/letter/c/c57346/32.png) [@christian.leinweber](https://discourse.chef.io/u/christian.leinweber)\
**Post date:** [September 23, 2016, 11:43am UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/8 "2016-09-23T11:43:52Z")

</div>

Hi,

i need this too. Like this

describe service(node[servicename]) do  
…  
end

---

<div class="post-metadata">

**Author:** ![sabat](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/sabat/32/1628_2.png) [@sabat](https://discourse.chef.io/u/sabat)\
**Post date:** [October 3, 2016, 11:17pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/9 "2016-10-03T23:17:48Z")

</div>

Unless there’s been a big change to InSpec in the past couple of months, I don’t see how this ever worked.

```
   [1, 10] in test/recipes/default/default_test.rb
1: require 'byebug'
2: describe package 'nagios-plugins-minion' do
3: before do
4: byebug
=> 5: skip unless ... (redacted)
6: end
7:
8: it { should be_installed }
9: end
10:
(byebug) node
*** NameError Exception: undefined local variable or method `node' for #<RSpec::ExampleGroups::SystemPackageNagiosPluginsMinion:0x007fbbc3076440>

```

The node object is not accessible via the describe block.

Further, is this really how it should work? Wouldn’t it be a lot better if there was a facility to say “in this circumstance, test this” and so on?

Edit: using Test Kitchen. From .kitchen.yml:

```
verifier:
  name: inspec
```

---

<div class="post-metadata">

**Author:** ![apop](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@apop](https://discourse.chef.io/u/apop)\
**Post date:** [October 4, 2016, 3:23pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/10 "2016-10-04T15:23:00Z")

</div>

I had a look into this, but was unable to reproduce the issue. Here are my files:

```bash
$ cat /tmp/attrs.json
{
  "chef_client": {
    "interval": "3600",
    "owner": "root"
  }
}

$ cat /tmp/node-test.rb
describe file('/etc/hosts') do
  let(:node) { json('/tmp/attrs.json').params }
  before do
    skip unless node['chef_client']['interval'] == "3600"
  end
  its('owner') { should eq(node['chef_client']['owner']) }
end

```

Using InSpec directly with the implicit localhost target:

```auto
$ ls -l /tmp/attrs.json
-rw-r--r-- 1 root staff 71 Oct 4 15:48 /tmp/attrs.json

$ inspec version
1.0.0

$ inspec exec /tmp/node-test.rb

Target: local://

  File /etc/hosts
     ✔ owner should eq "root"

Test Summary: 1 successful, 0 failures, 0 skipped

```

Using InSpec via `kitchen-inspec` targetting the converged VM:

```bash
$ rm /tmp/attrs.json
$ kitchen verify
-----> Starting Kitchen (v1.13.0)
-----> Verifying <mysuite-centos6>...
       Use `/Users/apop/git/myapache-cookbook/test/integration/mysuite` for testing

Target: ssh://root@127.0.0.1:2222

  File /etc/hosts
     ✔ owner should eq "root"

Summary: 1 successful, 0 failures, 0 skipped

```

Behind the scenes InSpec is invoked like this:

```bash
inspec exec test/integration/mysuite/ -t ssh://root@127.0.0.1:2222 --password vagrant

```

This means that when using resources like json(’/tmp/attrs.json’) or command(‘ls /tmp’) in your tests, they will use the target node/container to read ‘/tmp/attrs.json’ or to execute the command on.

---

<div class="post-metadata">

**Author:** ![vasdevneha](https://avatars.discourse-cdn.com/v4/letter/v/58956e/32.png) [@vasdevneha](https://discourse.chef.io/u/vasdevneha)\
**Post date:** [September 18, 2017, 7:25am UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/11 "2017-09-18T07:25:54Z")

</div>

Hi  
how we can skip any condition based on role attached to that node

describe service(‘xyz’) do  
before do  
skip if node[“roles”] == "abc"  
end  
it { should be\_installed }  
it { should be\_enabled }  
it { should be\_running }  
end

this one is giving me error that undefined function node.

---

<div class="post-metadata">

**Author:** ![raghureddy45](https://avatars.discourse-cdn.com/v4/letter/r/f14d63/32.png) [@raghureddy45](https://discourse.chef.io/u/raghureddy45)\
**Post date:** [January 15, 2018, 5:22pm UTC](https://discourse.chef.io/t/inspec-conditional-testing-based-on-node-attributes/8908/12 "2018-01-15T17:22:08Z")

</div>

```auto
describe service(‘xyz’) do
  let(:node) { json('/tmp/kitchen/nodes/default-rhel-73.json').params }
before do
  skip if node['roles'] == "abc"
end
 it { should be_installed }
 it { should be_enabled }
 it { should be_running }
end

```

/tmp/kitchen/nodes/default-rhel-73.json change it accordingly.!!
