Variables in attributes file

Is it possible to create attributes based on a dynamic variables?

Example

default[‘ipdns’][’#{int}’][‘address’] = ‘#{ip}’

Code

node[‘network’][“interfaces”].each do | int, parms |

if int =~ /eth/

File.open("/etc/sysconfig/network-scripts/ifcfg-#{int}") do |f|

  f.each_line do |line|

    if line.strip == "ONBOOT=yes"

      node['network']["interfaces"]["#{int}"]["addresses"].each do |ip,

params|

        if params['family'] == ('inet')

          #puts "#{int} - #{ip}"

          #puts "default['ipdns']['#{int}']['address'] = '#{ip}'"

          default['ipdns']['#{int}']['address'] = '#{ip}'

          #puts { "int" => "{int}", "ip" => "{ip}" }

        end

      end

    end

  end

end

end

end

Set up a ruby_block in a recipe with a node.set, like so:

ruby_block "do something" do
block do
bar, baz = # something
node.set["foo"][bar] = baz
node.save # only if chef-zero/chef-client
end
end

That block can subscribe or be notified by other resources. Not sure if it
works, at all, with chef solo, but give chef zero a try.

-Carlton

On Tue, Sep 3, 2013 at 10:50 PM, Alex alex@libalex.so wrote:

Is it possible to create attributes based on a dynamic variables?

Example

default['ipdns']['#{int}']['address'] = '#{ip}'

Code

node['network']["interfaces"].each do | int, parms |

if int =~ /eth/

File.open("/etc/sysconfig/network-scripts/ifcfg-#{int}") do |f|

  f.each_line do |line|

    if line.strip == "ONBOOT=yes"

      node['network']["interfaces"]["#{int}"]["addresses"].each do

|ip, params|

        if params['family'] == ('inet')

          #puts "#{int} - #{ip}"

          #puts "default['ipdns']['#{int}']['address'] = '#{ip}'"

          default['ipdns']['#{int}']['address'] = '#{ip}'

          #puts { "int" => "{int}", "ip" => "{ip}" }

        end

      end

    end

  end

end

end

end

Have a use case where I want to let a node compile and then converge to a specific point in the resource collection and if that specific resource is hit (driven by compile time whether it gets put on the collection) I would like to basically “fast forward to the end” and not run any more resources.

I can do this with an error end by calling Chef::Application.exit! or Chef::Application.fatal! in a ruby_block resource but am wondering if there is a more elegant way to do this that doesn’t cause a SystemExit error to be thrown and basically tells Chef to stop processing and move to the handlers.

It would basically have to be an exit point in the execute_each_resource method but not sure if such an exit point exists or if the SystemExit approach is the only way?

Thanks!

Kevin Moser

On Wednesday, September 4, 2013 at 8:39 AM, Moser, Kevin wrote:

Have a use case where I want to let a node compile and then converge to a specific point in the resource collection and if that specific resource is hit (driven by compile time whether it gets put on the collection) I would like to basically "fast forward to the end" and not run any more resources.

I can do this with an error end by calling Chef::Application.exit! or Chef::Application.fatal! in a ruby_block resource but am wondering if there is a more elegant way to do this that doesn't cause a SystemExit error to be thrown and basically tells Chef to stop processing and move to the handlers.

It would basically have to be an exit point in the execute_each_resource method but not sure if such an exit point exists or if the SystemExit approach is the only way?

Thanks!

Kevin Moser
There isn't an elegant way to make chef skip to the end the way you want. You could raise a different exception type, which is maybe a little better than a SystemExit error.

Since your use-case is driven by compile-time logic, you could instead wrap calls to include_recipe with your conditional logic to include them or not as desired.

--
Daniel DeLeo

Carlton,

It's ironic that you replied since I'm trying to generate these attributes
to use with the dynect cookbook.

Is it possible to do it in the attributes file?

On Wed, Sep 4, 2013 at 11:31 AM, Carlton Stedman cstedman@dyn.com wrote:

Set up a ruby_block in a recipe with a node.set, like so:

ruby_block "do something" do
block do
bar, baz = # something
node.set["foo"][bar] = baz
node.save # only if chef-zero/chef-client
end
end

That block can subscribe or be notified by other resources. Not sure if it
works, at all, with chef solo, but give chef zero a try.

-Carlton

On Tue, Sep 3, 2013 at 10:50 PM, Alex alex@libalex.so wrote:

Is it possible to create attributes based on a dynamic variables?

Example

default['ipdns']['#{int}']['address'] = '#{ip}'

Code

node['network']["interfaces"].each do | int, parms |

if int =~ /eth/

File.open("/etc/sysconfig/network-scripts/ifcfg-#{int}") do |f|

  f.each_line do |line|

    if line.strip == "ONBOOT=yes"

      node['network']["interfaces"]["#{int}"]["addresses"].each do

|ip, params|

        if params['family'] == ('inet')

          #puts "#{int} - #{ip}"

          #puts "default['ipdns']['#{int}']['address'] = '#{ip}'"

          default['ipdns']['#{int}']['address'] = '#{ip}'

          #puts { "int" => "{int}", "ip" => "{ip}" }

        end

      end

    end

  end

end

end

end

The attributes files are just rb, so logic could be put in there.

However, as a best practice, I generally do little/no logic in the
attributes files, treating them more as strict data. I would generate
derived node attributes (using node.set/node.save as in above ruby_block)
in recipes.

The reason for this is if I override an attribute in a wrapper cookbook,
then I don't want to have to put the logic in the wrapper cookbook, just
override an attribute and have the base (wrapped) cookbook do the logic
using the overridden attribute.

On Wed, Sep 4, 2013 at 6:30 PM, Alex alex@libalex.so wrote:

Carlton,

It's ironic that you replied since I'm trying to generate these attributes
to use with the dynect cookbook.

Is it possible to do it in the attributes file?

On Wed, Sep 4, 2013 at 11:31 AM, Carlton Stedman cstedman@dyn.com wrote:

Set up a ruby_block in a recipe with a node.set, like so:

ruby_block "do something" do
block do
bar, baz = # something
node.set["foo"][bar] = baz
node.save # only if chef-zero/chef-client
end
end

That block can subscribe or be notified by other resources. Not sure if
it works, at all, with chef solo, but give chef zero a try.

-Carlton

On Tue, Sep 3, 2013 at 10:50 PM, Alex alex@libalex.so wrote:

Is it possible to create attributes based on a dynamic variables?

Example

default['ipdns']['#{int}']['address'] = '#{ip}'

Code

node['network']["interfaces"].each do | int, parms |

if int =~ /eth/

File.open("/etc/sysconfig/network-scripts/ifcfg-#{int}") do |f|

  f.each_line do |line|

    if line.strip == "ONBOOT=yes"

      node['network']["interfaces"]["#{int}"]["addresses"].each do

|ip, params|

        if params['family'] == ('inet')

          #puts "#{int} - #{ip}"

          #puts "default['ipdns']['#{int}']['address'] = '#{ip}'"

          default['ipdns']['#{int}']['address'] = '#{ip}'

          #puts { "int" => "{int}", "ip" => "{ip}" }

        end

      end

    end

  end

end

end

end

Carlton,

I also favor the approach of doing little or no logic in the attributes
files.

However I typically avoid using normal-level attributes from a recipe and I
also typically avoid saving the node explicitly in the middle of a chef
run. I favor leaving normal-level attributes to the sysadmin's discretion
and I favor letting the node be saved only at the end of a successful
converge. This avoids any problems such as the run failing after the first
explicit save but before the final save, leaving the node data in an
inconsistent state.

Cheers,
Jay Feldblum

On Tue, Sep 10, 2013 at 8:03 AM, Carlton Stedman cstedman@dyn.com wrote:

The attributes files are just rb, so logic could be put in there.

However, as a best practice, I generally do little/no logic in the
attributes files, treating them more as strict data. I would generate
derived node attributes (using node.set/node.save as in above ruby_block)
in recipes.

The reason for this is if I override an attribute in a wrapper cookbook,
then I don't want to have to put the logic in the wrapper cookbook, just
override an attribute and have the base (wrapped) cookbook do the logic
using the overridden attribute.