Chef Custom Resources : mutable property or an alternative

977 views Asked by At

I read that as of 2016 OpsCode recommends against LWRP and the alternative HWRP. They rather recommend to use custom resources.

While this makes sense it leaves a lot to be desired in terms of leveraging ruby (unless I've misunderstood?)

I would like to be able to modify an array based on some boolean properties. I can then use that array to pass to the template, as in:

property :get_iptables_info, [TrueClass, FalseClass], default: false
property :get_pkglist, [TrueClass, FalseClass], default: false
property :cw_logs, Array, default: [], required: false

action :create do

  ruby_block 'cw_iptables' do
    block do
      new_resource.cw_logs.push({ "#{new_resource.custom_dir}/iptables/iptables.txt" => { "log_group_name" => new_resource.log_group_name+"/iptables"}})
    end
    action :run
    only_if {new_resource.get_iptables_info}
  end

  template "my_template" do
    variables ({:logstreams => cw_logs})
  end

end

Then in my template:

<% @logstreams.each_pair do |path, _object| %>
["#{path}"]
log_group_name = _object["log_group_name"]
<% end %>

The problem is that properties are immutable. So I get the error:

RuntimeError
------------
ruby_block[cw_iptables] (/tmp/kitchen/cache/cookbooks/custom_cw/resources/logs.rb line 43) had an error: RuntimeError: can't modify frozen Array

What's the correct way to do this? What's the correct way to write ruby code within the resource so that it's more modular and uses methods/functions?

1

There are 1 answers

3
coderanger On BEST ANSWER

Mutating properties inside a custom resource is generally a bad idea (there are exceptions but this isn't one of them). Better would be to use a local variable. Related, you don't need to use a ruby_block like that when you're already in a custom resource's action:

action :create do
  cw_logs = new_resource.cw_logs
  if new_resource.get_iptables_info
    cw_logs += [whatever extra stuff you want]
  end

  template "my_template" do
    variables logstreams: cw_logs
  end
end

Notably that's using += instead of push which doesn't mutate the original. If you used push you would want cw_logs = new_resource.cw_logs.dup or similar.