Best pattern for automatically creating/deleting resources based on what has changed?


#1

Say I have a directory that Chef maintains which is full of JSON files. I
have an LWRP which writes these JSON files to the directory. For example’s
sake, let’s say the resource is widget:

widget “widget1” do
created_by "chris"
owned_by "john"
end

widget “widget2” do
created_by "john"
owned_by "chris"
end

etc…

Great. Chef runs, and it ensures that I have these JSON files and that the
content is what I expect. Now, if I want to remove a widget, I have to
update my cookbook and run Chef:

widget “widget2” do
action :delete
end

Obviously, this is clunky. I’d like to rewrite my LWRP so that it reads the
files in the directory, “plays” my changes on top of them, and then cleans
up what I don’t want. So, if I start with two files in that directory but
my Chef recipe only creates one widget, the other will automatically be
deleted. In my Chef output, I should see that one was deleted. Is the way
to approach this to create resources from each of the existing files, and
then run :delete on the difference?

Is there an existing pattern for this, or an example cookbook which already
does this that I can use as an example?

Any help is appreciated!

Thanks,
Chris


#2

I would read the json and construct an object, and then do the comparison.
this only the update bit will go inside the converge_by block.
if you split up your content into several file, syncing them will be a
pain. Because chef generates resources dynamically, at no point in chef run
you can decide that which of those files (that belong to a conf.d style
directory) are from your lwrp. That said we still use this pattern, but
only in one cookbook, i.e. iptables. Where we drop the rules based on roles
(one chain for each role, containing all hosts from that role) using lwrps
, but removing the files that are extra (stale roles etc) is done by a
handler. So the whole cookbook is a combination of lwrp + report handler.
We had to take the handler route also due to chef running delayed
notifications even if the chef-run fails. we didnt want to lock down our
instances if the chef run fails.
but now we are considering using the same pattern for nginx/apache/cron.d
style config management.

alternatively you can define resources explicitly with :delete action , but
then as time will go by, you’ll have resources with :delete actions even if
they dont need to (for newer nodes, where those files were not even
created). expanded run list will also increase , and so is chef run time.

On Wed, Oct 9, 2013 at 11:32 PM, Christopher Armstrong <
chris@chrisarmstrong.me> wrote:

Say I have a directory that Chef maintains which is full of JSON files. I
have an LWRP which writes these JSON files to the directory. For example’s
sake, let’s say the resource is widget:

widget “widget1” do
created_by "chris"
owned_by "john"
end

widget “widget2” do
created_by "john"
owned_by "chris"
end

etc…

Great. Chef runs, and it ensures that I have these JSON files and that the
content is what I expect. Now, if I want to remove a widget, I have to
update my cookbook and run Chef:

widget “widget2” do
action :delete
end

Obviously, this is clunky. I’d like to rewrite my LWRP so that it reads
the files in the directory, “plays” my changes on top of them, and then
cleans up what I don’t want. So, if I start with two files in that
directory but my Chef recipe only creates one widget, the other will
automatically be deleted. In my Chef output, I should see that one was
deleted. Is the way to approach this to create resources from each of the
existing files, and then run :delete on the difference?

Is there an existing pattern for this, or an example cookbook which
already does this that I can use as an example?

Any help is appreciated!

Thanks,
Chris


#3

Slightly different approach: use databags to manage all the widgets. In
your recipe iterate over the databag items and call your widget lwrp for
each of them. If you know that all your nodes are converged in a specific
interval you can purge the “action :delete” items later.

If you really don’t want the explicit :delete, is rm-rf’ing the widgets
directory beforehand an option? Otherwise the cleanup handler approach
seems much cleaner to me.
On Oct 10, 2013 9:13 AM, “Ranjib Dey” dey.ranjib@gmail.com wrote:

I would read the json and construct an object, and then do the comparison.
this only the update bit will go inside the converge_by block.
if you split up your content into several file, syncing them will be a
pain. Because chef generates resources dynamically, at no point in chef run
you can decide that which of those files (that belong to a conf.d style
directory) are from your lwrp. That said we still use this pattern, but
only in one cookbook, i.e. iptables. Where we drop the rules based on roles
(one chain for each role, containing all hosts from that role) using lwrps
, but removing the files that are extra (stale roles etc) is done by a
handler. So the whole cookbook is a combination of lwrp + report handler.
We had to take the handler route also due to chef running delayed
notifications even if the chef-run fails. we didnt want to lock down our
instances if the chef run fails.
but now we are considering using the same pattern for nginx/apache/cron.d
style config management.

alternatively you can define resources explicitly with :delete action ,
but then as time will go by, you’ll have resources with :delete actions
even if they dont need to (for newer nodes, where those files were not even
created). expanded run list will also increase , and so is chef run time.

On Wed, Oct 9, 2013 at 11:32 PM, Christopher Armstrong <
chris@chrisarmstrong.me> wrote:

Say I have a directory that Chef maintains which is full of JSON files. I
have an LWRP which writes these JSON files to the directory. For example’s
sake, let’s say the resource is widget:

widget “widget1” do
created_by "chris"
owned_by "john"
end

widget “widget2” do
created_by "john"
owned_by "chris"
end

etc…

Great. Chef runs, and it ensures that I have these JSON files and that
the content is what I expect. Now, if I want to remove a widget, I have to
update my cookbook and run Chef:

widget “widget2” do
action :delete
end

Obviously, this is clunky. I’d like to rewrite my LWRP so that it reads
the files in the directory, “plays” my changes on top of them, and then
cleans up what I don’t want. So, if I start with two files in that
directory but my Chef recipe only creates one widget, the other will
automatically be deleted. In my Chef output, I should see that one was
deleted. Is the way to approach this to create resources from each of the
existing files, and then run :delete on the difference?

Is there an existing pattern for this, or an example cookbook which
already does this that I can use as an example?

Any help is appreciated!

Thanks,
Chris


#4

If you rm -rf the directory, you’re regenerating it on every run. If this
is a config directory, that means you’re probably going to trigger a
service restart every time you converge.

What you could do is store the Chef-managed files / directory tree inside
the Chef file cache directory, then walk the cache directory and the target
directory. For every file in target that exists in cache, declare a file
(err… widget?) resource with a :created/:managey action. For other files
in target, declare a resource with a :removey/:uninstally action.

Assuming your LWRP can accurately determine whether or not the source and
target have changed, you should be able to manage the directory this way.

You might need to play around with subscribe/notify on those resources and
potentially add an intermediary ruby_block to get the order of operations
right every time under all conditions (files exist in cache but not in
target, files exist in target but cache is empty/uncreated, nothing exists
anywhere, files exist in both places and one/both sets contain
modifications, files exist in both places and are the same.

On Thu, Oct 10, 2013 at 10:03 AM, Torben Knerr ukio@gmx.de wrote:

Slightly different approach: use databags to manage all the widgets. In
your recipe iterate over the databag items and call your widget lwrp for
each of them. If you know that all your nodes are converged in a specific
interval you can purge the “action :delete” items later.

If you really don’t want the explicit :delete, is rm-rf’ing the widgets
directory beforehand an option? Otherwise the cleanup handler approach
seems much cleaner to me.
On Oct 10, 2013 9:13 AM, “Ranjib Dey” dey.ranjib@gmail.com wrote:

I would read the json and construct an object, and then do the
comparison. this only the update bit will go inside the converge_by block.
if you split up your content into several file, syncing them will be a
pain. Because chef generates resources dynamically, at no point in chef run
you can decide that which of those files (that belong to a conf.d style
directory) are from your lwrp. That said we still use this pattern, but
only in one cookbook, i.e. iptables. Where we drop the rules based on roles
(one chain for each role, containing all hosts from that role) using lwrps
, but removing the files that are extra (stale roles etc) is done by a
handler. So the whole cookbook is a combination of lwrp + report handler.
We had to take the handler route also due to chef running delayed
notifications even if the chef-run fails. we didnt want to lock down our
instances if the chef run fails.
but now we are considering using the same pattern for nginx/apache/cron.d
style config management.

alternatively you can define resources explicitly with :delete action ,
but then as time will go by, you’ll have resources with :delete actions
even if they dont need to (for newer nodes, where those files were not even
created). expanded run list will also increase , and so is chef run time.

On Wed, Oct 9, 2013 at 11:32 PM, Christopher Armstrong <
chris@chrisarmstrong.me> wrote:

Say I have a directory that Chef maintains which is full of JSON files.
I have an LWRP which writes these JSON files to the directory. For
example’s sake, let’s say the resource is widget:

widget “widget1” do
created_by "chris"
owned_by "john"
end

widget “widget2” do
created_by "john"
owned_by "chris"
end

etc…

Great. Chef runs, and it ensures that I have these JSON files and that
the content is what I expect. Now, if I want to remove a widget, I have to
update my cookbook and run Chef:

widget “widget2” do
action :delete
end

Obviously, this is clunky. I’d like to rewrite my LWRP so that it reads
the files in the directory, “plays” my changes on top of them, and then
cleans up what I don’t want. So, if I start with two files in that
directory but my Chef recipe only creates one widget, the other will
automatically be deleted. In my Chef output, I should see that one was
deleted. Is the way to approach this to create resources from each of the
existing files, and then run :delete on the difference?

Is there an existing pattern for this, or an example cookbook which
already does this that I can use as an example?

Any help is appreciated!

Thanks,
Chris


#5

We do this pretty extensively in a lot of our cookbooks. The way we
have found that works best for us is to collect the complete set of
data for that widget system using arbitrary mechanism X (i.e. load it
out of data bags, search other nodes, load from ldap etc).

Then we record the complete state of the widget system as attributes
on the node. Then we call a recipe named something like
’widget::attribute_driven’. This recipe is responsible for
"interpreting" the attribute data and calling out to other resources
to do the work. At the end it will inspect the widget system and find
any widgets that are configured and not present in the attribute data.
It will then perform the appropriate ‘remove’.

Examples of this can be seen at [1] where we configure the glassfish
application server using this technique and [2] where we configure sql
server using this technique.

[1] https://github.com/realityforge/chef-glassfish/blob/master/recipes/attribute_driven_domain.rb
[2] https://github.com/realityforge/chef-sqlshell/blob/master/recipes/ms_attribute_driven.rb

HTH

On Thu, Oct 10, 2013 at 5:32 PM, Christopher Armstrong
chris@chrisarmstrong.me wrote:

Say I have a directory that Chef maintains which is full of JSON files. I
have an LWRP which writes these JSON files to the directory. For example’s
sake, let’s say the resource is widget:

widget “widget1” do
created_by "chris"
owned_by "john"
end

widget “widget2” do
created_by "john"
owned_by "chris"
end

etc…

Great. Chef runs, and it ensures that I have these JSON files and that the
content is what I expect. Now, if I want to remove a widget, I have to
update my cookbook and run Chef:

widget “widget2” do
action :delete
end

Obviously, this is clunky. I’d like to rewrite my LWRP so that it reads the
files in the directory, “plays” my changes on top of them, and then cleans
up what I don’t want. So, if I start with two files in that directory but my
Chef recipe only creates one widget, the other will automatically be
deleted. In my Chef output, I should see that one was deleted. Is the way to
approach this to create resources from each of the existing files, and then
run :delete on the difference?

Is there an existing pattern for this, or an example cookbook which already
does this that I can use as an example?

Any help is appreciated!

Thanks,
Chris


Cheers,

Peter Donald