This question already has an answer here:
-
Ansible : host in multiple groups
2 answers
I am using ansible to manage configuration as for production, as well as for vagrant box.
I have file with default values: group_vars/all.
---
env: prod
wwwuser: www-data
db:
root_pwd: root_pwd
pdo_driver: pdo_mysql
host: localhost
name: test
user: test
pwd: test
charset: utf8
domain: somedomain
projectdir: /var/www/application
webrootdir: "{{ projectdir }}/web"
In host_vars/vagrantbox I want tohave something like:
db:
root_pwd: super_easy_password
But this one is overriding completely db dictrionary, while I want to override single key.
How to achieve that?
UPDATE 1
Just checked with ansible.cfg:
[defaults]
host_key_checking=false
hash_behaviour=merge
groups_vars/all
db:
root_pwd: some_strong_pwd
pdo_driver: pdo_mysql
host: localhost
name: dbname
user: dbuser
pwd: some password
charset: utf8
host_vars/vagrantbox
db:
root_pwd: root
I am getting following error:
One or more undefined variables: 'dict object' has no attribute 'name'
What I do wrong?
By default, Ansible overrides variables at the first level. If you want to be able to merge dictionaries, you have to change your ansible.cfg
file and set :
hash_behaviour=merge
(the default value being replace
).
Note that the Ansible team does not recommend this (but do not explain why).
I guess this is a real dividing setting between users. A kind of decision that is done once for all : when you start using this feature, you can not go back, and you probably can not share your playbook with replace
-type people.
However, you can still benefit from the playbooks out there (I don't hink playbooks use replace
behaviour as a "feature"). It's like having an AB blood type, being an universal receiver... but since the magic usually happens at variable resolution, not inside tasks or templates, I think it is often possible to share your roles without any changes.
If you need to override a single key from, let's say, role parameters, you'll have to pass parameters in some convoluted way.
For instance, to override post_max_size
and upload_max_size
keys in a php5
dictionnary for a specific role, you'll have to do it this way :
- { role: php5-fpm, php5: { post_max_size: 40M,
upload_max_filesize: 20M }}
This being said, I use merge
behaviour since the beginning, and I'm pretty happy with it. It is very handy to keep variables organised.
Starting with Ansible 2.0, you can use the Jinja2 combine
filter to merge YAML hashes/dictionaries without having to set hash_behavior=merge
at a global level in your ansible.cfg
file.
Relevant docs: http://docs.ansible.com/ansible/playbooks_filters.html#combining-hashes-dictionaries
The best way I have found is to use variables as the value of the dictionary item, and override that. I find this allows simple and powerful variable precedence with regards to ansible's order of variable
role/parent/defaults/main.yml
---
root_pw_value: ParentPassword
parent_dict:
- root_pw: "{{ root_pw_value }}"
role/child/defaults/main.yml
Note: role/child/meta/main.yml
contains dependencies: - { role: parent }
---
root_pw_value: ChildPassword
play-me.yml
---
- hosts: all
roles:
- child
roles/parent/tasks/main.yml & roles/child/tasks/main.yml
- debug: var=parent_dict
Run ansible -i localhost, --connection="local" play-me.yml
and you get the following output:
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [parent | debug var=parent_dict] ****************************************
ok: [localhost] => {
"var": {
"parent_dict": [
{
"root_pw": "ParentPassword"
}
]
}
}
TASK: [child | debug var=parent_dict] *****************************************
ok: [localhost] => {
"var": {
"parent_dict": [
{
"root_pw": "ChildPassword"
}
]
}
}
PLAY RECAP ********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
And these are defaults. If you specify root_pw_value
at more specific levels of precedence, such as inventory group/host variables, role variables, extra_vars on the command line, or anything from the precedence order[0] you'll get those.
[0] http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable
Just tried with ansible 1.9.3 and it works fine. Not sure but it seems you just have a typo within name of group_vars
directory (not groups_vars
).