Configuring Chef-Solo-different override_attributes in one role

chefchef-solo

First off, I'm using Chef Solo and I would like things to stay as automated as possible. So I have a problem that I'm not quite sure how to solve. I'm setting up the deployment of a lot of different Linux boxes, and all of them are going to require custom installation nodes/roles.
Example:

/nodes/app_server.json

{
"run_list": [ "role[app_server]" ]
}

/roles/app_server.rb

name 'app_server'
description 'App_Server'
override_attributes({ "apache" => {
                                      "proxypass" => [" /  http://localhost:8080/"]
                                  }
                   })
run_list 'recipe[app_server]'

My issue is that I'm going to be running a script to install chef on all these different boxes, but each one is going to have a different ip in-between http://[xxxxxx]:8080/

I need a way to be able to -via command line- specify those ip's without having to create like a hundred node or role files.

I've looked at an example on their website that shows:

The Web Server Role

description "The base role for systems that serve HTTP traffic"
run_list "recipe[apache2]", "recipe[apache2::mod_ssl]", "role[monitor]"
env_run_lists "prod" => ["recipe[apache2]"], "staging" => ["recipe[apache2::staging]"],"_default" => []
default_attributes "apache2" => { "listen_ports" => [ "80", "443" ] }
override_attributes "apache2" => { "max_children" => "50" }

which seems like it would be useful, but I would like to set different override set's for each env_run_list config and then when I run all the chef commands, be able to target each one that I want.

Am I going about this in the wrong fashion? I've scoured all of the docs for nodes/roles/environments etc and haven't found any solution that requires me to not have to make a dozen different files.

Best Answer

Without access to your app_server recipe, I infer that you are using the node['apache']['proxypass'] attribute to populate a line in an apache config file generated from a template.

My guess is that the relevant line in your template looks something like this:

ProxyPass <%= node['apache']['proxypass'] %>

I think you will have greater success if you use more granular elements to compose that line in your template. If the IP address you wish to proxy requests to will differ in every environment, you can make use of Chef's search facilities to determine the required IP address and pass that IP address to the template as a variable.

The code in your recipe might look something like this:

# this search assumes that the role 'myapp_backend' is in the run list of the backend server you need to discover.
# the search returns an array of node objects, for simplicity we'll just take the first result.
proxypass_backend = search(:node, "roles:myapp_backend AND chef_environment:#{node.chef_environment}").first

template ::File.join(node['apache']['dir'],'sites-available','myapp.conf') do
  variables({
    :proxypass_local_path => '/',
    :proxypass_remote_ip => proxypass_backend['ipaddress'],
    :proxypass_remote_port => '8080',
    :proxypass_remote_path => '/'
  })
  source 'myapp.conf.erb'
end

And the line in your template would look something like this:

ProxyPass <%= @proxypass_local_path %> http://<%= @proxypass_remote_ip %>:<%= proxypass_remote_port %><%= @proxypass_remote_path %>

For the sake of simplicity I've specified static values for the remote port and path, but those could also be set using attribute values that can be overridden at the role or environment level. Because search returns entire node objects, any attribute of a node returned by a search (e.g. the port a service is running on) can be used to populate template variables as well (e.g. proxypass_remote_port).

Related Topic