Including Cookbooks Conditionally

Hi,

New to chef, and trying to get my head around best practices.

I’m using Chef to automate the building of EC2 AMI images (from an EC2
instance). This is a bit of a special case, because I’m running chef
from within a chroot environment, so I can’t start services.

So, I can see four categories of cookbooks I need:

A. Third party cookbooks
B. My own original cookbooks to perform specific tasks (e.g.
installing required dev packages)
C. Cookbooks which perform necessary overrides to third party
cookbooks (e.g. I find a bug in the third party cookbook)

These first three categories are “normal”, and should be able to run
in the chroot environment, and also be run to update/fix EC2 images
which are created from the built AMI. However, the fourth is a
special case:

D. Cookbooks which perform overrides to third party cookbooks, in
order to prevent services from automatically
starting/stopping/restarting (which will fail in a chroot env).

Obviously, I only want to include this category when I’m building the
AMI, but not when running normally on an instance started from the
AMI.

So, questions:

  • Does anything sound wrong about this approach
  • How should I organize these cookbooks? I can have a custom repo,
    which includes all the third-party cookbooks (A) as submodules, and
    the others (B,C,D) checked in directly. However, I would want to
    conditionally exclude “D” from running if I’m not in a chroot
    environment.

Seems like I want to use “Roles” here to do some conditional logic
based on whether I’m in chroot env or not, but I’m not sure what it
should look like. I’m not even really sure where to stick the logic.
Right now I just have cookbooks listed in the ‘cookbook_path’ array in
node.rb. I’m having problems finding detailed examples online which
are similar to what I want to do. Pointers to docs/examples would be
greatly appreciated.

Thanks,
– Chad

On Sat, Apr 24, 2010 at 10:45 AM, Chad Woolley thewoolleyman@gmail.com wrote:

New to chef, and trying to get my head around best practices.

I'm using Chef to automate the building of EC2 AMI images (from an EC2
instance). This is a bit of a special case, because I'm running chef
from within a chroot environment, so I can't start services.

So, I can see four categories of cookbooks I need:

A. Third party cookbooks
B. My own original cookbooks to perform specific tasks (e.g.
installing required dev packages)
C. Cookbooks which perform necessary overrides to third party
cookbooks (e.g. I find a bug in the third party cookbook)

These first three categories are "normal", and should be able to run
in the chroot environment, and also be run to update/fix EC2 images
which are created from the built AMI. However, the fourth is a
special case:

D. Cookbooks which perform overrides to third party cookbooks, in
order to prevent services from automatically
starting/stopping/restarting (which will fail in a chroot env).

Obviously, I only want to include this category when I'm building the
AMI, but not when running normally on an instance started from the
AMI.

So, questions:

  • Does anything sound wrong about this approach
  • How should I organize these cookbooks? I can have a custom repo,
    which includes all the third-party cookbooks (A) as submodules, and
    the others (B,C,D) checked in directly. However, I would want to
    conditionally exclude "D" from running if I'm not in a chroot
    environment.

Seems like I want to use "Roles" here to do some conditional logic
based on whether I'm in chroot env or not, but I'm not sure what it
should look like. I'm not even really sure where to stick the logic.
Right now I just have cookbooks listed in the 'cookbook_path' array in
node.rb. I'm having problems finding detailed examples online which
are similar to what I want to do. Pointers to docs/examples would be
greatly appreciated.

Interesting use case.

For your wanting to make sure that no services get restarted, you can
probably do something like this. Make sure it's the last recipe in
the run list:

collection.each do |r|

Switch every service resource off

r.action :nothing if r.resource_name == :service

Find all notified/subscribed actions on services and switch them off too

r.actions.each do |action, timings|
timings.each do |timing, resources|
resources.each do |notified_resource|
notified_resource.action :nothing if
notified_resource.resource_name == :service
end
end
end
end

That's off the top of my head, so it may not run. But the idea here is:

If you are running in the chroot, and we don't want any service
actions to be taken, we walk the resource collection and set the
action for every service resource we encounter to :nothing. The
result will be that no service resources are ever run, no matter what
changes happen in the cookbooks you add.

The only caveat is that this must be the last recipe in the
run-list, or you're not certain to have seen every possible resource
in the collection.

The benefit should be obvious - just include this recipe when you want
to do your chroot sauce, and skip the need to do complicated overrides
entirely.

Adam

Opscode, Inc.
Adam Jacob, CTO
T: (206) 508-7449 E: adam@opscode.com

On Sun, Apr 25, 2010 at 10:06 AM, Adam Jacob adam@opscode.com wrote:

Interesting use case.

For your wanting to make sure that no services get restarted, you can
probably do something like this. Make sure it's the last recipe in
the run list:

collection.each do |r|

Switch every service resource off

r.action :nothing if r.resource_name == :service

Find all notified/subscribed actions on services and switch them off too

r.actions.each do |action, timings|
timings.each do |timing, resources|
resources.each do |notified_resource|
notified_resource.action :nothing if
notified_resource.resource_name == :service
end
end
end
end

That's off the top of my head, so it may not run. But the idea here is:

If you are running in the chroot, and we don't want any service
actions to be taken, we walk the resource collection and set the
action for every service resource we encounter to :nothing. The
result will be that no service resources are ever run, no matter what
changes happen in the cookbooks you add.

The only caveat is that this must be the last recipe in the
run-list, or you're not certain to have seen every possible resource
in the collection.

The benefit should be obvious - just include this recipe when you want
to do your chroot sauce, and skip the need to do complicated overrides
entirely.

This is working somewhat, but delayed actions are still executed. For
example, the mysql server grant:

http://github.com/opscode/cookbooks/blob/master/mysql/recipes/server.rb#L97

How can I disable this as well?

Thanks,
-- Chad

On Sun, May 23, 2010 at 10:04 PM, Chad Woolley thewoolleyman@gmail.com wrote:

This is working somewhat, but delayed actions are still executed. For
example, the mysql server grant:

http://github.com/opscode/cookbooks/blob/master/mysql/recipes/server.rb#L97

How can I disable this as well?

Here's what I ended up doing:

collection.all_resources.each do |resource|
if resource.to_s == 'template[/etc/mysql/grants.sql]'
resource.actions[:run][:delayed].clear
end
end