Home > Net >  in ruby/chef, what is the difference between "end if" and only_if"?
in ruby/chef, what is the difference between "end if" and only_if"?

Time:06-29

In chef (therefor, ruby), I've seen two ways of declaring conditionals

resource 'foo' do
  echo "Ubuntu"
end if node['platform'] == 'ubuntu'

and

resource 'foo' do
  echo "Ubuntu"
  only_if node['platform'] == 'ubuntu'
end

Don't these effectively do the same thing? In the official docs, it seems "only_if" is the preferred way, and I can't find many examples of the "end if", but just curious if they, as they seem, do the same thing (execute the block only if the conditional is true).

Thanks!

CodePudding user response:

Chef Resource Guard Clauses vs. Expression Post-Conditions

only_if is a guard clause that's part of the Chef DSL. However, do...end if is a Ruby modifier control expression (sometimes called a post-condition) applied to a block that functions the same way a normal Ruby if/then statement works. Note that even though the if is placed after the expression to be evaluated, the post-condition is still evaluated first.

Think of only_if as a Chef-specific resource statement. The other is just syntactic sugar supported by Ruby's interpreter, and the example you cited (assuming it works in Chef outside a Ruby resource block; I didn't bother to test it) is the same as writing the block inside a more standard if-statement like this one:

if node['platform'] == 'ubuntu'
  resource 'foo' do
    echo "Ubuntu"
  end 
end

Most Chef resources should follow the current style guides and DSL features, but post-conditions are very common in idiomatic Ruby because they emphasize the expression rather than the conditional and because they allow for more brevity of code.

CodePudding user response:

There is a subtle difference in how only_if and end if behave when a node is converged (in Chef speak). In simple terms, when chef-client starts, it compiles the cookbooks and creates a collection of resources that will converge on the node.

For the sake of example, let's say we have a cookbook cookbook1 with only 1 resource in the recipe. When we run such cookbook in below scenarios:

Scenario 1:

Using do .. end if:

The resource is removed from the compilation when the condition is not matched. So there will be no resources to run. Example output from chef-client run when node['platform'] is not ubuntu.

Compiling Cookbooks...
Converging 0 resources

Scenario 2:

Using only_if guard

The resource remains in the collection, but it is skipped when node['platform'] is not ubuntu.

Compiling Cookbooks...
Converging 1 resources
Recipe: cookbook1::default
  * resource[foo] action run (skipped due to only_if)

In short, pure Ruby code, such as if conditions will run during "compile" phase itself. Chef resources run during the "converge" phase. See the Chef Infra Client documentation for details.

  • Related