Changing attributes in provider


#1

Hi

Need some help here
I’m trying to implement provider which is supposed to update node attributes
Recipe has something like

resource_name ‘foo’ do

  • action :get*
  • destination node.override[:test]*
    end

Provider draft:

def destination

  • new_resource.destination*
    end

destination.update( {“foo” => “bar”} )

When I call
Chef::Log.info node[:test]
from provider - it echoes {“foo”=>“bar”}, just as supposed to
But following actions in a recipe can see no changes in this attribute, it
remains empty


#2

The provider only gets run at converge time (late), the references that
you’re using to that attribute later are running at compile time
(early).

For what you’re trying to do this is probably the worst available
option. If you need to pass attributes from one recipe to another the
first choice is using attribute files (particularly if they are
consumed by later resources and you’re not trying to dep inject
computed attributes into earlier recipes). To pass state between
recipes you can also use the node.run_state instead of using
attributes. And if all you are doing is writing some DSL sauce around
setting attributes you should probably use a definition (compile time
macro) instead of a provider. The other direction you could go is to
not consume the attributes directly in compile mode in recipes and wrap
the later consumers of the node attributes in a provider in which case
they’ll also be called at converge time after the earlier provider sets
the value. You can also use lazy {} on the later attribute, although
if you adopt this pattern generally like it seems like you might be
trying to do this tends to wind up with lazy {} everywhere in your
recipes which bypasses the resource input validation (and in some cases
we have bugs where the input validation on the resource fails on a lazy
block).

On Thu Nov 6 11:09:40 2014, Sergey Motovilovets wrote:

Hi

Need some help here
I’m trying to implement provider which is supposed to update node
attributes
Recipe has something like

/resource_name ‘foo’ do/
/ action :get/
/ destination node.override[:test]/
/end/

Provider draft:
/…/
/def destination/
/ new_resource.destination/
/end/
/…/
/destination.update( {“foo” => “bar”} )
/
/…/

When I call
/Chef::Log.info node[:test]/
from provider - it echoes {“foo”=>“bar”}, just as supposed to
But following actions in a recipe can see no changes in this
attribute, it remains empty


#3

Thanks for the quick reply!

I’m experimenting with synchronization of execution steps across multiple
nodes using 3-rd party key-value store; and yay, I was thinking about
creating a wrapper around setting attributes dynamically, based on the
contents of that store.
Seems like definitions are gonna work for me, will try.
Thanks again!

2014-11-06 21:44 GMT+02:00 Lamont Granquist lamont@opscode.com:

The provider only gets run at converge time (late), the references that
you’re using to that attribute later are running at compile time (early).

For what you’re trying to do this is probably the worst available option.
If you need to pass attributes from one recipe to another the first choice
is using attribute files (particularly if they are consumed by later
resources and you’re not trying to dep inject computed attributes into
earlier recipes). To pass state between recipes you can also use the
node.run_state instead of using attributes. And if all you are doing is
writing some DSL sauce around setting attributes you should probably use a
definition (compile time macro) instead of a provider. The other direction
you could go is to not consume the attributes directly in compile mode in
recipes and wrap the later consumers of the node attributes in a provider
in which case they’ll also be called at converge time after the earlier
provider sets the value. You can also use lazy {} on the later attribute,
although if you adopt this pattern generally like it seems like you might
be trying to do this tends to wind up with lazy {} everywhere in your
recipes which bypasses the resource input validation (and in some cases we
have bugs where the input validation on the resource fails on a lazy block).

On Thu Nov 6 11:09:40 2014, Sergey Motovilovets wrote:

Hi

Need some help here
I’m trying to implement provider which is supposed to update node
attributes
Recipe has something like

/resource_name ‘foo’ do/
/ action :get/
/ destination node.override[:test]/
/end/

Provider draft:
/…/
/def destination/
/ new_resource.destination/
/end/
/…/
/destination.update( {“foo” => “bar”} )
/
/…/

When I call
/Chef::Log.info node[:test]/
from provider - it echoes {“foo”=>“bar”}, just as supposed to
But following actions in a recipe can see no changes in this
attribute, it remains empty


#4

On Thu Nov 6 12:15:37 2014, Sergey Motovilovets wrote:

Thanks for the quick reply!

I’m experimenting with synchronization of execution steps across
multiple nodes using 3-rd party key-value store; and yay, I was
thinking about creating a wrapper around setting attributes
dynamically, based on the contents of that store.
Seems like definitions are gonna work for me, will try.
Thanks again!

you can also call libraries from attributes files and you could load
the key value data into attributes there. you also might be able to
write an ohai plugin to query the store and load up attributes very
early.