Best Practices for dealing with multiple related sets of properties?

Hello all,

Suppose I want to deploy multiple versions of a service (let’s call them v1 and v2, though they could also be different services with the same setup steps) to two environments (dev and prod). Since steps to deploy each version of the service are pretty much the same a single role should be able to handle both, except for some settings that can vary by version and environment, like which db host to use.

My first instinct here is to store the settings in a hash with the version numbers as keys, and then pass e.g. someservice_config.v1 to the role, but it seems that Michael DeHaan feels very strongly that overriding individual dict values in the way I would need to make that work for dev/prod is Bad, and I really don’t want to have to redefine a whole hash just to change one or two values, so I’m trying to use flat vars like this:

`

roles/someservice/defaults/main.yml

Defaults

someservice_deft_db_host: db1
someservice_deft_db_name: service
someservice_deft_db_user: some_user
someservice_deft_db_pass: some_pass

v1-specific; mostly inherits defaults

someservice_v1_enabled: true

v2-specific; different server and db name

someservice_v2_enabled: false
someservice_v2_db_host: db2
someservice_v2_db_name: servicev2
`

`

group_vars/dev.yml

Dev servers run both versions, with a different database for v2

someservice_v2_enabled: true
someservice_v2_db_host: db2-dev

Nothing special in group_vars/prod.yml, meaning prod servers

inherit defaults and only deploy v1 with standard config (for now).

`

Ok, now I need to tell the role which set(s) of settings to use. The best I’ve been able to come up with so far is:

`

main_playbook.yml

  • roles:

Version 1

  • role: someservice
    db_name: “{{ someservice_v1_db_name| default(someservice_deft_db_name) }}”
    db_host: “{{ someservice_v1_db_host| default(someservice_deft_db_host) }}”
    db_user: “{{ someservice_v1_db_user| default(someservice_deft_db_user) }}”
    db_pass: “{{ someservice_v1_db_pass| default(someservice_deft_db_pass) }}”
    when: someservice_v1_enabled

Version 2

  • role: someservice
    db_name: “{{ someservice_v2_db_name| default(someservice_deft_db_name) }}”
    db_host: “{{ someservice_v2_db_host| default(someservice_deft_db_host) }}”
    db_user: “{{ someservice_v2_db_user| default(someservice_deft_db_user) }}”
    db_pass: “{{ someservice_v2_db_pass| default(someservice_deft_db_pass) }}”
    when: someservice_v2_enabled

Copy/paste + search/replace as needed for future versions…

`

`

roles/someservice/tasks/main.yml

  • mysql_db: >
    name: {{ db_name }}
    login_host: {{ db_host }}
    login_user: {{ db_user }}
    login_password: {{ db_pass }}

… and so on

`

This approach seems to work, but feels… klunky to me, so I figured I’d come here and ask for a sanity check. Is there a better way to approach this sort of thing?

Thanks!
–Brad