Defining dynamic global custom variables once for all recipes during chef run


#1

Scenario:

  • Two custom variables are dynamically assigned based on
    node.chef_environment via a targeted search and subsequent for-loop against
    a max of 10 top-level data bag items.
  • Both variables are a DataBagItem.
  • They are defined within any recipe that needs these values.
  • Setting this in every recipe doesn’t scale.

Is there a way to define these variables once in a separate, single-purpose
cookbook recipe, and have them reliably made available to all recipes
within the chef run?

What is the best direction for this? Setting attributes via
attributes/default.rb or creating a custom library with a ruby block?

Thanks!
-Mat


#2

You can use node.run_state[:foo] ||= “bar” style code blocks to do this.
i generally prefer to move this into a library, and if possible back it by
a separate singleton class, this is a common requirement, like if you are
using some data bag across recipes etc, this helps avoiding making multiple
chef server api call during a single chef run.
i have thought of raising an RFC for this, i.e. a global (chef-client),
locally cached version of data store, but the ordering bit (where you’ll
define it, if recipe, how you ensure its executed in the beginning. should
we introduce some like initializers… etc?)

On Tue, Apr 28, 2015 at 10:28 AM, Mathew Crane mathew.crane@gmail.com
wrote:

Scenario:

  • Two custom variables are dynamically assigned based on
    node.chef_environment via a targeted search and subsequent for-loop against
    a max of 10 top-level data bag items.
  • Both variables are a DataBagItem.
  • They are defined within any recipe that needs these values.
  • Setting this in every recipe doesn’t scale.

Is there a way to define these variables once in a separate,
single-purpose cookbook recipe, and have them reliably made available to
all recipes within the chef run?

What is the best direction for this? Setting attributes via
attributes/default.rb or creating a custom library with a ruby block?

Thanks!
-Mat


#3

I don't know if it's the best way but we so this with an Env cookbook with many attributes files, one common for all invariable values and one file per Env starting With 'return unless node.chef_environment == "target_env"'

Le 28 avr. 2015 19:28, Mathew Crane <mathew.crane@gmail.com> a écrit :

Scenario:
  • Two custom variables are dynamically assigned based on node.chef_environment via a targeted search and subsequent for-loop against a max of 10 top-level data bag items.- Both variables are a DataBagItem.- They are defined within any recipe that needs these values.

  • Setting this in every recipe doesn’t scale.

Is there a way to define these variables once in a separate, single-purpose cookbook recipe, and have them reliably made available to all recipes within the chef run?

What is the best direction for this? Setting attributes via attributes/default.rb or creating a custom library with a ruby block?

Thanks!-Mat


#4

Thanks. I made a library instance method to access these attributes
dynamically. This solves the code duplication issue.

However, I’m still unaware of a good way to ‘set’ these variables
automatically via a library so that they become available to all recipes
within the Chef run. Ideally the variables become available to all
cookbooks that have ‘depend “helper-cookbook”’ in metadata.rb, and
redundant calls to the Chef API are eliminated. Is this even possible?

How it exists currently:

cookbooks/helper-cookbook/libraries/helper-module.rb

module helper
def my_helper_module
…code…
return env, server
end
end

reference:

cookbooks/dependent-cookbook/metadata.rb:

depends “helper-cookbook”

cookbooks/dependent-cookbook/recipes/default.rb:

env, server = my_helper_module

Any tips or suggestions?

On Tue, Apr 28, 2015 at 5:21 PM, Tensibai Zhaoying tensibai@iabis.net
wrote:

I don’t know if it’s the best way but we so this with an Env cookbook with
many attributes files, one common for all invariable values and one file
per Env starting With 'return unless node.chef_environment == “target_env”'
Le 28 avr. 2015 19:28, Mathew Crane mathew.crane@gmail.com a écrit :

Scenario:

  • Two custom variables are dynamically assigned based on
    node.chef_environment via a targeted search and subsequent for-loop against
    a max of 10 top-level data bag items.
  • Both variables are a DataBagItem.
  • They are defined within any recipe that needs these values.
  • Setting this in every recipe doesn’t scale.

Is there a way to define these variables once in a separate,
single-purpose cookbook recipe, and have them reliably made available to
all recipes within the chef run?

What is the best direction for this? Setting attributes via
attributes/default.rb or creating a custom library with a ruby block?

Thanks!
-Mat


#5

On Thursday, April 30, 2015 at 7:08 AM, Mathew Crane wrote:

Thanks. I made a library instance method to access these attributes dynamically. This solves the code duplication issue.

However, I’m still unaware of a good way to ‘set’ these variables automatically via a library so that they become available to all recipes within the Chef run. Ideally the variables become available to all cookbooks that have ‘depend “helper-cookbook”’ in metadata.rb, and redundant calls to the Chef API are eliminated. Is this even possible?

How it exists currently:

cookbooks/helper-cookbook/libraries/helper-module.rb

module helper
def my_helper_module
…code…
return env, server
end
end

reference: http://stackoverflow.com/questions/22078318/access-node-attributes-in-chef-library

cookbooks/dependent-cookbook/metadata.rb:

depends “helper-cookbook”

cookbooks/dependent-cookbook/recipes/default.rb:

env, server = my_helper_module

Any tips or suggestions?
The simplest way to go is to define your helper methods as class methods (actually module methods since they’d be defined on a module, but the difference is pedantic).

This blog post is a bit old and rails-centric but describes how they work well enough: http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/

With a bit more work, it’s possible to mix your module in to Chef’s DSL, but this can be a bit confusing because the recipe DSL and resource DSLs are separate things, so you’ll probably stub your toe on that.


Daniel DeLeo