Access Node attributes in Chef Library
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.
).
How can I access the current node from a library in a Chef cookbook?
What you can do is to include the module in your recipe. That way, your module functions get access to the methods of the recipe, including node
.
I normally do this for my library modules:
# my_cookbook/libraries/helpers.rb
module MyCookbook
module Helpers
def foo
node["foo"]
end
end
end
Then, in the recipe, I include the module into the current instance of a recipe:
# my_cookbook/recipes/default.rb
extend MyCookbook::Helpers
That way, only the current recipe gets the module included, not all of them in the whole chef run (you thus avoid name clashes).
Alternatively, you could pass the current node as a parameter to the function. That way, you don't need to include the module (which has the upside of keeping the module namespaces) but has the downside of a more convoluted method call.
Chef - ServerSpec - Accessing Node attributes
According to the code there's no override_attrs method.
Here you'll have the cookbook's attributes under node.override
and the environment's attributes in node.env_override
, the node.combined_override
gives you the resulting attributes after deep merge.
The blog post is quite old, you should better use attrs = node.merged_attributes
to write the json file and get the resulting attributes from cookbook, roles and environments, using merged_attributes
should avoid the ohai
attributes to, keeping the json size low.
Accessing template attributes in Chef
Here are two of my favourite ways to do that:
- Use chef attributes.
Define the default for the attribute in an attribute file. so in <cookbook_name>/attributes/default.rb
file add this line:
default['instance_region'] = 'us-west-1'
and then in your recipe where you are adding the template:
variables(region: node['instance_region'])
you can access that in you template as you mentioned:
region =<%= @region %>
- Using chef library.
For wider usage you can define such value within a chef library. so in <cookbook>/libraries/common.rb
add:
module Common
def instance_region
# This will return the name of AWS region that the nodes is in.
shell_out!('curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone/').stdout
end
end
and then in your recipe you can use it just by calling plain instance_region
Chef node attributes
With newer Chef, you can use the node.read
method:
s3_bucket = node.read('elastic', 's3', 'bucket')
It will be nil
if any intervening key does not exist.
Chef - access new_resource from library
Use a normal mixin:
# libraries/default.rb
module MyLibrary
def script_path
case new_resource.server_type
when 'admin'
'/admin_server/bin/admin_cntl.sh'
when 'managed'
'/managed_server/bin/managed_cntl.sh'
end
end
end
# providers/default.rb
include MyLibrary
action :start do
execute 'my_script' do
command "./#{script_path} start"
end
end
action :remove do
execute 'my_script' do
command "./#{script_path} stop"
end
end
Also remember you can define methods directly in the provider if they are only useful for that one provider.
Chef::Node available in library called from recipe, but not when called through Singleton Class
I changed my approach to create a custom resource.
resource_name :otbo_service
actions [:stop, :start, :restart, :nothing]
default_action :nothing
property :service, Hash, required: true
action_class do
def control(commands)
handle(new_resource.service, commands)
end
end
def handle(service, commands)
name = service[:name]
for command in commands
service[command].call()
end
end
action :nothing do
Chef::Log.info('Nothing to do.')
end
action :stop do
control([:stop])
end
action :start do
control([:start])
end
action :restart do
control([:stop, :start])
end
I added a library function that can access the node variable.
module Common
module Util
def _WLStart()
Chef::Log.info("<< Starting WebLogic Server on Host: #{node['hostname']} >>")
end
def _WLShutdown()
Chef::Log.info("<< Stopping WebLogic Server on Host: #{node['hostname']} >>")
end
end
end
Chef::Recipe.send(:include, Common::Util)
Chef::Resource.send(:include, Common::Util)
In the recipe I can then call the custom resource via code something like the following.
extend Common::Util
weblogic = {
:name => 'weblogic',
:start => lambda { _WLStart() },
:stop => lambda { _WLShutdown() }
}
otbo_service 'Restart WebLogic' do
action :restart
service weblogic
end
How to access node attributes and recipe variables in ruby_block
You need double quotes. Single quotes in Ruby do not support the #{foo}
interpolation syntax.
Related Topics
Checking Whether the C Compiler Works... No
Verb-Agnostic Matching in Sinatra
Access Node Attributes in Chef Library
Get Title, Content via Link in Rails
Backspace and Arrow Keys Aren't Working in Irb(Git Bash Console) on Windows MAChine
Time.Use_Zone Is Not Working as Expected
Displaying Only the First X Words of a String in Rails
Model Using Modules in Rails Application
Why Do I Get "No Implicit Conversion of String into Integer (Typeerror)"
What Happens When Modifying Gemfile.Lock Directly
Using Soap and Other Standard Libraries in Ruby 1.9.2
Ruby Undefined Method 'Bytesize' for #<Hash:0X2954Fe8>
In Ruby, Should I Use ||= or If Defined? for Memoization