ben
ben

Reputation: 83

Manage conflicting roles in chef

I am relatively new to chef, so I may be missing something extremely basic. After much searching I am not finding what I need, so here goes:

In Chef, I have roles that are conflicting. I need for all servers of a certain type to have roleA, except for servers with roleB.

The best way I can think of to describe it is with an example:

syslog1, syslog2

web1, web2, web3

db1, db2

mail1, mail2

Every server within this environment(dozens) has a role called syslog_client, except syslog1 and syslog2, which need to have the role syslog_server.

The syslog-server and syslog-client roles conflict, because they configure the same pieces of software differently.

These are roles rather than recipes because they actually encompass several recipes.

I thought of doing something like this:

roles/base.rb:

name "base"
description "base configuration"
override_attributes(
)
default_attributes(
)
run_list(
  "recipe[one]",
  "recipe[two]",
  "recipe[three]",
  "role[uno]"
)

unless node[:roles].include?('syslog_server')
  run_list('role[syslog_client]')
end

The problem there is that the node object does not exist at this point. I have thought about moving it into the recipe, but I could not come up with a good way to do it there either. I was able to use this in the base recipe:

unless node[:roles].include?('syslog_server')
  node[:roles]+=['syslog_client']
end

This adds syslog_client to the roles attribute (or doesn't) correctly, but it never actually runs the syslog_client role.

I have considered moving syslog_client into a self-contained recipe rather than a role, and moving the role attributes to the environment. This would work, because then I can just call include_recipe "syslog::client". The problem there is that virtually all of our recipes are assigned from roles (not from other recipes), and I fear that making this change will create a one-off that will be hard to keep track of. Besides that, as I mentioned already, these are actually several recipes, so adding them as a single recipe is not ideal.

We have many different server types/roles in the environment I'm currently working in, and adding role[syslog_client] to them is feasible, but not ideal. With multiple people working on this, it seems likely that someone will forget to add the recipe to a new role.

In an ideal world, something like my first solution would be possible, because that allows us to keep our environment as consistent as possible. I am open to other options though.

So to wrap up, I think what I need is someone to tell me how to:

  1. Make the first solution work. Add a role to a run list only if another role is not present
  2. If I cannot have #1, I'd like opinions on the best way to achieve this using the ways I've listed or other ideas I have not thought of

Please let me know if I'm missing any details about our chef setup that will be helpful.

Disclaimer: The above example is really a very simplified version of what I'm actually trying to achieve. I'm not even working with syslog, but the company it is for is very security-conscious and would not be happy with details of their environment being posted publicly. I will be as detailed as I possibly can if I've left anything out and I need to add further info.

Upvotes: 3

Views: 1755

Answers (1)

PatrickWalker
PatrickWalker

Reputation: 550

Extending what was said above what's the issue with creating two roles. A Client and a server

The Client role includes the base role and the client function. It will get applied to all servers through replacing references to 'base' with this role in all other roles. Meaning those roles still get base but get client as well.

The server is a stand-alone role which only applies to those servers and has the base and then the server role?

That way both client and server get the base role applied to them without duplicating the definition of what the base role is. You still manage that base role as you want but you use aggregation in the creation of roles?

When a new role is created the user won't start by adding base but instead adding the syslog_client role which gives them base as well.

To me that feels like the way Chef is pushing you with the creation of roles. What we have is 1 role that applies to all servers, some that apply to 1 subtype of servers but not anothers. That way our leaf role as in the one that gets applied actually consists of 4 or 5 other roles. What's common is modelled in a way that can be shared without the need for logic within?

The other option would be to add the client recipe to every node and the first exeuction step is to check the nodes role and if it says server just basically skip the recipe execution? Which would be the same as the logic which you were wanting to use to add the recipe but it would live in the recipe and control the execution?

unless node[:roles].include?('syslog_server')
   #Do your client install
end

Upvotes: 1

Related Questions