Ansible is just a great peace of work.
# START Blha Blha Blha
We are using it more and more every day at ${myDayJob}, and it helps us in every aspects of configuration management, deployment, and orchestration
If you still don't know it : Just GO check it out -> http://www.ansibleworks.com/docs/
One important aspect with making good Ansible playbooks is to respect idempotency
Wikipedia Source : Idempotence is the property of certain operations in mathematics and computer science, that can be applied multiple times without changing the result beyond
That means we want to be able to use a playbook to deploy, configure or update our full solution stack, but also make sure the already deployed blocks are conformed to what Ansible knows to be right about the topology and configuration, BUT without modifying any of those configurations if they comply with Ansible inventory/desired configuration.
# END Blha Blha Blha
When dealing with /etc/hosts files, we had a solution based on dynamically creating fragments from a template looking like bellow, and then using the assemble module to apply changes to the target servers :
{% for k, v in hostvars.iteritems() -%}
{{ hostvars[k]['ansible_default_ipv4']['address'] }} {{ k }} {{ v['ansible_hostname'] }}
{% endfor %}
The drawback with this method was that the already existing file on the target was deleted and copied over by the newly created one, (discarding any changes made locally on the target, but this is not the point here, and local changes are a bad habit any way), marking the task step as "changed" and the Ansible "PLAY RECAP" displaying this change.
We wanted to respect a true idempotence and get rid of those undesired/unnecessary modification.
After a few miss-steps we came up with the following solution :
- lineinfile: dest=/etc/hosts regexp='.*{{item}}$'
line='${hostvars.${item}.ansible_default_ipv4.address} ${item}'
state=present
only_if: is_set('${hostvars.${item}.ansible_default_ipv4.address}')
with_items: '{{groups.all}}'
What it does is pretty straight forward :for all target hosts defined by the playbook
for all hosts defined in the groups, set {{item}} value to its corresponding hostname
find any line matching the regexp '.*{{item}}$' in /etc/hosts -> eg : '192.168.0.1 appServer1'
if found check it matches the desired couple "hostname" "ip" (with "ip" being '${hostvars.${item}.ansible_default_ipv4.address})
if it matches, don't change any thing
else change it to the desired "hostname ip"
else (if not found), add the desired "hostname ip" at the end of file
The "only_if" statement is used to skip hosts we couldn't get facts from (host couldn't be reached, etc ...), thus preventing from adding garbage info into the target /etc/hosts
Use it / Share it / Comment it / Improve it
---
Juts writing this quick post make me realize (once again) how power full is Ansible :
- 3 lines of statements to described the desired configuration state and apply eventual changes
- 7 lines to explain it in plain english (and not even sure I am cristal clear ...)
---
[EDIT] : Thanks to @rothgar
As Justin mentioned in his comment, this syntax is now deprecated
Please use this one :
# Idempotent way to build a /etc/hosts file with Ansible using your Ansible hosts inventory for a source.
# Will include all hosts the playbook is run on.
# Inspired from http://xmeblog.blogspot.com/2013/06/ansible-dynamicaly-update-etchosts.html
- name: "Build hosts file"
lineinfile: dest=/etc/hosts
regexp='.*{{ item }}$
line="{{ hostvars[item].ansible_default_ipv4.address }} {{item}}"
state=present
when: hostvars[item].ansible_default_ipv4.address is defined
with_items: groups['all']
11 comments:
Very nice. Thank you.
This syntax is old and shouldn't be used anymore. Here's new syntax for using lineinfile to iterate over your hosts
https://gist.github.com/rothgar/8793800
- lineinfile: dest=/etc/hosts regexp='.*{{ item }}$' line="{{ hostvars[item]['ansible_default_ipv4']['address'] }} {{item}}" state=present
when: hostvars[item]['ansible_default_ipv4']['address'] is defined
with_items: groups['all']
I had to change it in Ansible 2.7.6:
- name: Add the inventory into /etc/hosts
lineinfile:
dest: /etc/hosts
regexp: '.*{{ item }}$'
line: "{{ hostvars[item]['ansible_default_ipv4']['address'] }} {{item}}"
state: present
when: hostvars[item]['ansible_facts']['default_ipv4'] is defined
with_items:
- "{{ groups['all'] }}"
not working any one of above for ansible 2.7.4
hosts file
[local_host]
localhost
[local_host:vars]
ssh_key_filename="id_rsa"
remote_machine_username="root"
remote_machine_password="jas"
ansible_user=root
ansible_password=J@ckp0t5
ansible_port= "22"
[ansible_setup_passwordless_setup_group]
test12
[dbservers]
test1
test2
---
- hosts: localhost
gather_facts: false
connection: local
tasks:
- name: "Build hosts file"
lineinfile:
dest=/etc/hosts
regexp='.*{{ item }}$'
line="{{ hostvars[item]['ansible_default_ipv4']}}"
state=present
with_items: groups['dbservers']
ERROR:-
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: u\"hostvars['groups['dbservers']']\" is undefined\n\nThe error appears to have been in '/root/test.yaml': line 6, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: \"Build hosts file\"\n ^ here\n"}
update more different ideas with us.
DevOps Online Training
This syntax works with Ansible 2.8
- hosts: all
become: yes
tasks:
- name: "Build hosts file"
lineinfile: dest=/etc/hosts regexp='.*{{ item }}$' line="{{ hostvars[item].ansible_default_ipv4.address }} {{item}}" state=present
when: hostvars[item].ansible_default_ipv4.address is defined
with_items: "{{ groups['all'] }}"
Nice Post. Well Written. Keep sharing more and more DevOps Online Training
DevOps Online Training India
DevOps Online Training hyderabad
Good job! Fruitful article. I like this very much. It is very useful for my research. It shows your interest in this topic very well. I hope you will post some more information about the software. Please keep sharing!!
Oracle Training in Chennai | Certification | Online Training Course | Oracle Training in Bangalore | Certification | Online Training Course | Oracle Training in Hyderabad | Certification | Online Training Course | Oracle Training in Online | Oracle Certification Online Training Course | Hadoop Training in Chennai | Certification | Big Data Online Training Course
Wow, this is quite amazing. I think it would be that many people still find these stories.
DevOps Training in Bangalore | Certification | Online Training Course institute | DevOps Training in Hyderabad | Certification | Online Training Course institute | DevOps Training in Coimbatore | Certification | Online Training Course institute | DevOps Online Training | Certification | Devops Training Online
aws solution architect training
azure solution architect certification
azure data engineer certification
openshift certification
oracle cloud integration training
Post a Comment