Sync files between 2 hosts using ansible - ansible

I'm looking for a way to sync files between 2 hosts in ansible. The scenario is as follows. I have a CSV file which contains 3 columns indicating directories which needs to be synced between 2 servers. the first 2 columns indicate the source and target servers and the third column indicates the directory
source, target, directory
src01, tgt02, dir0003
src02, tgt05, dir0004
src10, tgt68, dir1022
I found this answer for syncing files between 2 hosts - How to copy files between two nodes using ansible
Is there any way to parameterize this using a csv config file?

Yes. It's possible. In the first play read the CSV file and create group of targets. Use the new group in the second play and loop the synchronize module. For example the playbook
- hosts: localhost
tasks:
- read_csv:
path: db.csv
register: my_db
- add_host:
hostname: "{{ item.target }}"
groups: my_targets
my_list: "{{ my_db.list }}"
loop: "{{ my_db.list }}"
- hosts: my_targets
tasks:
- debug:
msg: "Copy {{ item.directory }} from {{ item.source }} to {{ inventory_hostname }}"
loop: "{{ my_list|json_query(query) }}"
vars:
query: "[?target == '{{ inventory_hostname }}']"
- name: Copy
synchronize:
src: "{{ item.directory }}"
dest: "{{ item.directory }}"
delegate_to: "{{ item.source }}"
loop: "{{ my_list|json_query(query) }}"
vars:
query: "[?target == '{{ inventory_hostname }}']"
(not tested)
gives
"msg": "Copy dir0004 from src02 to tgt05"
"msg": "Copy dir0003 from src01 to tgt02"
"msg": "Copy dir1022 from src10 to tgt68"

Related

Ansible - loop over multiple items in stdout_lines

I am performing a grep with multiple items.
---
- hosts: my_host
gather_facts: false
vars:
my_list:
- whatever
- something
tasks:
- name: grep for item in search path
shell: "grep -rIL {{ item }} /tmp"
register: the_grep
loop: "{{ my_list }}"
- debug:
msg: "{{ item.stdout_lines }}"
loop: "{{ the_grep.results }}"
Depending on the result, multiple files could match.
msg:
- /tmp/something.conf
- /tmp/folder/file.txt
Q: How would I configure Ansible to loop over the items in stdout_lines?
The use case I'm solving is to delete .ini sections based on the item, but in this case, Ansible doesn't loop over the stdout_lines.
- name: remove stanza from ini file
ini_file:
path: "{{ item.stdout_lines }}"
section: "{{ item.item }}"
mode: '0600'
state: absent
loop: "{{ the_grep.results }}"
when: item.stdout_lines | length > 0
It seems that this doesn't work, but configuring item.stdout_lines[0] gives the partially expected result, since Ansible will use only the first item in that list. But ofc, not the 2nd and so on.
Perhaps there's a prettier answer, but solved it by using with_nested and creating a json_query:
- name: remove stanza from ini file
ini_file:
path: "{{ item.0 }}"
section: "{{ item.1.item }}"
mode: '0600'
state: absent
with_nested:
- "{{ the_grep | json_query('results[].stdout_lines[]') }}"
- "{{ the_grep.results }}"

get ansible groups by looping with_items

I'm trying to get the inventory host group names by below process which is not working
- debug:
msg: "{{ groups['{{ item }}'] }}"
with_items: "{{ vm.stdout_lines }}"
this is what actually I'm trying to do
I will get a list of servers by a shell script
- name: Getting the servers list
shell: |
sh getServers.sh
register: vm
Then adding them into inventory by add_host
- name: Creating Logical host_group for each server
add_host:
name: "{{ item }}"
groups: ["{{item }}"]
with_items: "{{ vm.stdout_lines }}"
register: inv
Here I'm trying to get the only groups I've added in above step instead of all groups
- debug:
msg: "{{ groups['{{ item }}'] }}"
with_items: "{{ vm.stdout_lines }}"
Error is
{"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute '{{ item }}'
Appreciate help on this!
Fix the syntax
msg: "{{ groups[item] }}"

In Ansible loop, test existence of files from registered results

I have several files that I need to backup in different directories. I have tried the code below and not working for me.
vars:
file_vars:
- {name: /file1}
- {name: /etc/file2}
- {name: /etc/file/file3}
tasks:
- name: "Checking if config files exists"
stat:
path: "{{ item.name }}"
with_items: "{{ file_vars }}"
register: stat_result
- name: Backup Files
copy: src={{ item.name }} dest={{ item.name }}{{ ansible_date_time.date }}.bak
with_items: "{{ file_vars }}"
remote_src: yes
when: stat_result.stat.exists == True
The problem is the condition
when: stat_result.stat.exists == True
There is no attribute stat_result.stat. Instead, the attribute stat_result.results is a list of the results from the loop. It's possible to create a dictionary of files and their statuses. For example
- set_fact:
files_stats: "{{ dict(my_files|zip(my_stats)) }}"
vars:
my_files: "{{ stat_result.results|json_query('[].item.name') }}"
my_stats: "{{ stat_result.results|json_query('[].stat.exists') }}"
Then simply use this dictionary in the condition
when: files_stats[item.name]
Below is a shorter version which creates the dictionary more efficiently
- set_fact:
files_stats: "{{ dict(stat_result.results|
json_query('[].[item.name, stat.exists]')) }}"
Please try using below worked for me:
---
- name: Copy files
hosts: localhost
become: yes
become_user: root
vars_files:
- files.yml
tasks:
- name: "Checking if config files exists"
stat:
path: "{{ item }}"
with_items: "{{ files }}"
register: stat_result
- name: Ansible
debug:
msg: "{{ stat_result }}"
- name: Backup Files
copy:
src: "{{ item }}"
dest: "{{ item.bak }}"
with_items: "{{ files }}"
when: stat_result == "True"
and files.yml will look like:
---
files:
- /tmp/file1
- /tmp/file2
you can check you playbook syntax using below command:
ansible-playbook copy.yml --syntax-check
Also you do dry run your playbook before actual execution.
ansible-playbook -i localhost copy.yml --check

Can we have 2 with_items in ansible in a single task

Below is the condition
- name: Find the image
slurp:
src: "{{ IMAGE }}"
register: slurp_results
- name: Upload image
shell: |
skopeo copy -docker-archive:{{ item }}.tar docker://{{ URL }}/TESTIMAGE
with_items: "{{ (slurp_results.content|b64decode).splitlines() }}"
The above code works.
But I would need "TESTIMAGE" also to be replaced as {{ item }} like below.
skopeo copy -docker-archive:{{ item }}.tar docker://{{ URL }}/{{ item }}
How to define 2 with_items in a single shell task with 2 different slurp results
I believe you can by using the subelements module. Here is a link. Try going by this example:
- name: Setup MySQL users, given the mysql hosts and privs subkey lists
mysql_user:
name: "{{ item.0.name }}"
password: "{{ item.0.mysql.password }}"
host: "{{ item.1 }}"
priv: "{{ item.0.mysql.privs | join('/') }}"
with_subelements:
- "{{ users }}"
- mysql.hosts
Users is referred to as item.0 and hosts as item.1 and so on.

printing the host name from group in inventory

I have below inventory file:
[web]
10.0.1.0
[db]
10.0.3.0
[frontend]
10.0.5.0
[X_all:children]
web
db
frontend
Now in my playbook: I'm trying to print the hostname under X_all group in the name line.
- name: "Copying the output of Registry run to local machine from {{ hostvars[item]['inventory_hostname'] }}"
become: true
become_user: "{{ login }}"
fetch:
src: /tmp/DeploymentRegistry.txt
dest: /tmp/DeploymentRegistry-{{ inventory_hostname }}.txt
flat: yes
with_items:
- "{{ groups['X_all'] }}"
Is it even possible to add the hostname in the name line?
I tried replacing {{ hostvars[item]['inventory_hostname'] }} with inventory_hostname but it's also not working.
Regarding your requirement
I'm trying to print the hostname under test group in the name line.
take note that the group has more than one member and therefore more than one hostname, but a list of hostnames.
- name: Show hosts {{ groups['test'] }}
delegate_to: localhost
debug:
msg: "{{ item }}" # will show the group member hostname(s)
with_items:
- "{{ groups['test'] }}"
Is it even possible to add the hostname in the name line? I tried ... with inventory_hostname but it's also not working.
Yes, it is.
- name: Show host {{ inventory_hostname }}
debug:
msg: "{{ item }}"
with_items:
- "{{ groups['test'] }}"
But it will print the first hostname from list only.

Resources