I am looking for a way to set a default attribute from a custom resource in compile phase.
While using the older LWRP notation, I am able to do this by overriding getter/setter in the resource file. For example, in resources/foo.rb
:
attribute :bar, kind_of: Integer
def bar(arg = nil)
if arg
node.default['some_attribute'] = arg * 1024
end
set_or_return(:bar, arg, kind_of: [Integer])
end
This looks like a hack, and I have not been able to find a similar way to do something in compile phase (rather than in converge phase) while using the new single-file custom resource syntax.
Any advice or examples I could look at?
Can you describe what you’re actually trying to achieve? Because in general modifying a node attribute in a resource should not be necessary.
Sure, happy to describe the use case in more detail. In short, some of the cookbooks that a given custom resource needs to use provide a “data-driven API” and need to be configured via attributes.
Taking the fb_cron
example from the link above, imagine that I am adding a provider to configure web hosts, and each host needs to have a separate user, and a temporary directory which gets cleaned up regularly. I would like my resource to be used like this:
web_host 'foobar' do
user 'foobar-user'
...
end
My resource code will have the following:
user new_resource.user do
home "/home/www/#{new_resource.user}"
manage_home true
end
directory "/home/www/#{new_resource.user}/tmp"
owner new_resource.user
end
node.default['fb_cron']['jobs']["cleanup tmp for #{new_resource.user}"] = {
'command' => "find /home/www/#{new_resource.user}/tmp -mtime +2 -delete",
'time' => '0 0 * * *',
'user' => new_resource.user,
}
Now this will make the cronjob added to default attributes during converge phase, which I believe means that the cronjob will only be configured if template '/etc/cron.d/fb_crontab'
(part of fb_cron
cookbook) is later in the run list than my web_host 'foobar'
. I would like this to work independently on run list order, which means I need the default attribute to be set during compile phase rather than converge phase.
Does this make sense? I am not using fb_cron
specifically, but my other cookbooks use similar attribute-driven configuration pattern.
Any advice from someone familiar with Chef internals?
Or is overriding getter/setter still the best way to do this?
I could imagine several ways to achieve this. I’ll start by naming one and you let me know if that meets your needs.
The Chef::Resource
class (which every resource inherits from) has a hook (#after_created
) that is called after the resource is created (this is in the compile phase). In that hook you should be able to modify node attributes. That should be effectively the same-ish thing as setting node attributes in a recipe.
See this: https://github.com/chef/chef/blob/master/lib/chef/resource.rb#L928-L934
The hook is actually called here: https://github.com/chef/chef/blob/master/lib/chef/resource_builder.rb#L72-L73
To be clear: I’ve never done this personally, but I can’t imagine why it wouldn’t work for your use case.
Good luck and let me know how it goes!
Thanks, jasonwbarnett! after_created
seems to work great.
Just posting updated links that are pinned to a specific commit (05f63ca) so the intent isn’t lost, no matter how old this thread is.