0
votes

We have an application specific cookbook with three recipes

  • Recipe 1. Create storage on server

  • Recipe 2. Install ngnix

  • Recipe 3. Install JBOSS

Recipe 1, needs attributes to tell it how many logical volumes it should create for ngnix and Jboss along with size.

We also have three roles called web-server, app-server and standalone. standalone role converges all 3 recipes on the same VM. But we want to use web-server and app-server roles in Production.

The questions is now on how to split up the storage attributes because we would not want to provision Jboss FSs for web-server role.

We want to put the storage attributes in the roles, but that is apparently an anti-pattern.

Putting the attributes in recipes means we have to include Recipe 1 inside Recipes 2 and 3 which is not elegant because Jboss recipe is just supposed to install Jboss without worrying about storage, right?

Is there a good way to achieve this?

2
The role web-server will have Recipes 1 and 2 in its run-list, the app-server will have just Recipes 1 and 3. Standalone role will have all three. - dvlpr

2 Answers

1
votes

Assuming web-server, app-server, and standalone are all separate cookbooks, just put the data in the attributes files for web-server and app-server.

In web-server you would have something like:

# attributes/default.rb
default['mystorage']['nginxdata'] = 2 # Some size

# recipes/default.rb
include_recipe 'myapp::storage'
include_recipe 'myapp:nginx'

and in app-server you might have something like:

# attributes/default.rb
default['mystorage']['jboss1'] = 2 # Some size
default['mystorage']['jboss2'] = 2 # Some size

# recipes/default.rb
include_recipe 'myapp::storage'
include_recipe 'myapp:jboss'

In your storage recipe just iterate over the data to create your volumes:

node['mystorage'].each do |volume_name, size|
   # Something ...
end
1
votes

Writing this as an answer as the comment won't be clear enough in formatting.

I highly doubt nginx or jboss install method vary between your apps, so you just need to override attributes in your app cookbook.

So you end up with coderanger answer: 1 cookbook per infrastructure work (nginx, jboss, storage)

And then 1 application cookbook which - supply attributes values for this application to the infrastructure cookbooks. - depends on the infrastructure cookbooks on specific versions - have 3 recipes: - 1 including storage and nginx - 1 including storage and jboss - 1 including both previous (don't bother, 2 include_recipe for the same one will not be a problem, chef is smart enough to include only once)

On your node you'll set the runlist with one of this recipes. You gain control of which version of jboss or nginx is actually set up with your app at a particular time (which you can't have with role)

The way attribute loading and recipe compilation works will make your application cookbook attributes override the attributes from nginx cookbook (for exemple) and then will compile the recipe for nginx.

Just ensure the include_recipe nginx/jboss is before your application deployment code so you're sure nginx/jboss is setup before you try to deploy to it.

To expose my case (not so far from yours I think):

We have 53 in house apps, 53 cookbooks settings attributes (jvm options for exemple). We have 20 application servers pairs so roughly 60 cookbooks (1 for the cluster, and 1 for each instance in the cluster)

Each instance cookbook set up the server name and deployment directory. Each cluster cookbook depends on application cookbooks and include their recipes (which use the previsouly mentionned deployment directory)

Some tooling like berkshelf exist to help you maintain the whole chain with version constraint.

It sounds complex at first, but with time it saves you from unintentional changes in production because you did a change for staging and forgot it will be propagated (with a role).