Access Node attributes in Chef Library

Thomas Orozco picture Thomas Orozco · Feb 27, 2014 · Viewed 10k times · Source

I'd like to create a Chef library that:

  • Provides a few namespaced functions
  • Accesses the node's attributes

That library is meant to interface with an external system and retrieve some inputs from there. I need to access the node attributes to allow the user to override the inputs received from the external system:

Desired Usage (Recipe)

inputs = MyLib.get_inputs

Library (What I have now)

This is inspired by those docs.

class Chef::Recipe::MyLib
  def self.get_inputs
    override_inputs = node.fetch(:mylib, Hash.new).fetch(:override_inputs, nil)

    unless override_inputs.nil?
      return override_inputs
    end

    # Do stuff and return inputs (no problem here)
    # ...
  end
end

Problem

Right now I'm getting:

undefined local variable or method `node' for Chef::Recipe::Scalr:Class

Answer

sethvargo picture sethvargo · Feb 27, 2014

You don't have access to the node object in a library unless you pass it into the initializer:

class MyHelper
  def self.get_inputs_for(node)
    # Your code will work fine
  end
end

Then you call it with:

inputs = MyHelper.get_inputs_for(node)

Alternative, you can to create a module and mix it into the Chef Recipe DSL:

module MyHelper
  def get_inputs
    # Same code, but you'll get "node" since this is a mixin
  end
end

Chef::Recipe.send(:include, MyHelper)

Then you have access to the get_inputs method right in a recipe:

inputs = get_inputs

Notice this is an instance method versus a class method.

In short, libraries don't have access to the node object unless given as a parameter. Modules will, if they are mixed into the Recipe DSL. Additionally, the node object is actually an instance variable, so it's not available at the class level (i.e. self.).