Ruby Code Blocks and Chef

Ruby code blocks and Chef

If you come from another language (not Ruby), this syntax might seem very strange. Let's break down things.

When calling a method with parameters, in most cases the parentheses are optional:

  • foo(bar) is equivalent to foo bar
  • foo(bar, baz) is equivalent to foo bar, baz

A Ruby block of code can be wrapped in curly braces ({}) or inside a do..end block and can be passed to a method as its last parameters (but note that there's no comma and if you're using parentheses it goes after them. Some examples:

foo(bar) { # code here }

foo(bar) do
# code here
end

foo bar do
# code here
end

foo do
# code here
end

In some cases, code blocks can receive parameters, but in Chef the resources' blocks never do. Just for reference, the syntax for that is:

foo(bar) do |baz, qux|
baz + qux
end

Specifically about Chef resources, their syntax is usually:

resource_type(name) do
attribute1 value1
attribute2 value2
end

This means that, when you say:

log "a debug string" do
level :debug
end

you're actually creating a log resource whose name attribute is set to "a debug string". It can later be referred to (in other resources, for example) using log[a debug string].

AFAIK, the name attribute is mandatory for every Chef resource type as it's what makes it unique, and allows you to, among other things, call actions on it after it has been declared.


Side note: The ruby block is usually optional for a Chef resource. If you do something like:

directory "/some/path"

Chef will compile that resource using its default attributes (among which is action :create), and try to create the named directory using those.

How prevent chef failure on ruby code?

You didn't show where title comes from so they best I can say is to put your code in a ruby_block resource and use the ignore_failure property. You can also use normal Ruby rescue blocks for imperative code but be aware of how that interacts (or rather, doesn't) with resources, see https://coderanger.net/two-pass/ for some details on the loading process Chef uses.

Ruby blocks as used in Chef, trouble understanding syntax

I answered the same question at https://stackoverflow.com/a/20569738/123527

# Call the method directory passing the path and a block
# containing some code to be evaluated in the given context
template "/etc/profile.d/golang.sh" do

# Use the ERB template defined at "golang.sh.erb"
source "golang.sh.erb"

# chown the file to the user root
owner "root"
group "root"

# set the permissions to 0555
mode "0755"
end

Blocks are a convenient way to specify a group of operations (in this case create, set permissions, etc) to be evaluated in a single context (in this case in the context of that path).

template, source, owner, group, etc are all Ruby methods.

Chef - run install block based on variable condition

The problem is Chef's two-pass model. See https://coderanger.net/two-pass/ for the full explanation for for this you just need to move the condition check in to the only_if block itself since that is delayed until converge time: only_if { ::File.directory?('/opt/MyPkg/conf') }.

Using the fatal log level is also probably not a good idea as this isn't actually a fatal error as written.

How to use a Ruby block to assign variables in chef recipe

Your problem is compile time versus converge time. Your block will be run at converge time but at this time the node['host'] in the execute resource has already been evaluated.

The best solution in this case would be to use lazy evaluation so the variable will be expanded when the resource is converged instead of when it is compiled:

execute "Enable on hosts" do
command lazy { "#{path}/command --enable -N #{node['hosts']}" }
end

Here's a little warning though, the lazy operator has to include the full command attribute text and not only the variable, it can work only as first keyword after the attribute name.



Related Topics



Leave a reply



Submit