title: Manage conflicting roles in chef
body: <p>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:</p>
  
  <p>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.</p>
  
  <p>The best way I can think of to describe it is with an example:</p>
  
  <p>syslog1, syslog2</p>
  
  <p>web1, web2, web3</p>
  
  <p>db1, db2</p>
  
  <p>mail1, mail2</p>
  
  <p>Every server within this environment(dozens) has a role called syslog_client, except syslog1 and syslog2, which need to have the role syslog_server.</p>
  
  <p>The syslog-server and syslog-client roles conflict, because they configure the same pieces of software differently. </p>
  
  <p>These are roles rather than recipes because they actually encompass several recipes. </p>
  
  <p>I thought of doing something like this:</p>
  
  <p>roles/base.rb:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>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:</p>
  
  <pre><code>unless node[:roles].include?('syslog_server')
    node[:roles]+=['syslog_client']
  end
  </code></pre>
  
  <p>This adds syslog_client to the roles attribute (or doesn't) correctly, but it never actually runs the syslog_client role.</p>
  
  <p>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 <code>include_recipe "syslog::client"</code>. 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.</p>
  
  <p>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. </p>
  
  <p>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.</p>
  
  <p>So to wrap up, I think what I need is someone to tell me how to:</p>
  
  <ol>
  <li>Make the first solution work. Add a role to a run list only if another role is not present</li>
  <li>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</li>
  </ol>
  
  <p>Please let me know if I'm missing any details about our chef setup that will be helpful.</p>
  
  <p><strong>Disclaimer</strong>: 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.</p>