How to Dump multiple Variables to Excel file in ansible - ansible

I have data in 3 variable , I am able to dump this in file excel but it comes under Single Column instead of Multiple Columns, Any idea how can I get in Multiple Column
- name: Add mappings to /etc/hosts
lineinfile:
insertafter: EOF
dest: ~/test.xlxs
line: "\t {{ item.0 }} \t\t {{ item.1 }} \t\t {{ item.2 }}"
with_together:
- "{{ Test1 }}"
- "{{ Test2 }}"
- "{{ Test3 }}"
output of above :
Column1
a b c
Expected Output :
Column1 Column Colum3
a b c

Your task will produce a TSV file, which can be imported into Excel by changing the delimiter to Tab in Data >> Text to Columns. You can refer this link for the steps.
Else, you can create a CSV file which Excel should not have any trouble importing into its cells.
Just change the \t to , in your task,
- name: Add mappings to /etc/hosts
lineinfile:
insertafter: EOF
dest: ~/test.csv
line: "{{ item.0 }},{{ item.1 }},{{ item.2 }}"
with_together:
- "{{ Test1 }}"
- "{{ Test2 }}"
- "{{ Test3 }}"

Related

Sync files between 2 hosts using 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"

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.

Is there any method to map multiple attributes in ansible

I have an output from yum list module. The thing is I want to display the output without those number (epoch attribute). The problem is I couldn't find any solutions of mapping 2 attributes (name and version). All the solutions I found are connected to only 1 attribute ( envra) in my case.
- name: check packages
become: true
yum:
list: installed
register: output
- name: add lines to files
lineinfile:
dest: "./file.txt"
line: "{{ inventory_hostname }} {{ item }}"
with_items:
- "{{ output.results | map(attribute='envra') |list }}"
delegate_to: localhost
This is the output without any mapping. As you can see there are multiple attributes. I would like to display only name and version of the package.
10.112.65.15 {u'envra': u'0:GeoIP-1.5.0-14.el7.x86_64', u'name': u'GeoIP', u'repo': u'installed', u'epoch': u'0', u'version': u'1.5.0', u'release': u'14.el7', u'yumstate': u'installed', u'arch': u'x86_64'}
The closest to expected values is envra attribute, but still has those epoch number inside...
10.112.65.15 0:GeoIP-1.5.0-14.el7.x86_64
As I mentioned at the begging I would like to get output of something like that
10.112.65.15 GeoIP 1.5.0
or at least without epoch attribute.
I've also change approach and tried this method
- name: add lines to files
lineinfile:
dest: "./file.txt"
line: "{{ inventory_hostname }} {{ item }} "
with_items:
- "{{ output | json_query(my_query) | list }}"
delegate_to: localhost
vars:
my_query: "results[].[name, version]"
but received result was with '[]' and u' which I'd like to delete but don't exactly know how.
10.112.65.15 [u'GeoIP', u'1.5.0']
Why do you extract the attribute or use json query ? Simply use the hash and print out the needed fields. The following should work out of the box.
- name: add lines to files
lineinfile:
dest: "./file.txt"
line: "{{ inventory_hostname }} {{ item.name }} {{ item.version }}"
with_items:
- "{{ output.results }}"
delegate_to: localhost

Ansible Registers - Dynamic naming

I am trying to use a register in Ansible playbook to store my output. Below is the code which i am using.
I have tried below code
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: {{ item }}_service_status
with_items:
- XXX
- YYY
- ZZZ
I need different outputs to be stored in different register variables based on the items as mentioned in the code. It is failing and not able to proceed. Any help would be appreciated.
Updated answer
I think you need to put quotes around it:
register: "{{ item }}_service_status"
Or you can use set_fact (1, 2, 3, 4)
register all the output to a single static variable output and then use a loop to iteratively build a new variable service_status (a list) by looping over each item in the static variable output
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: output
with_items:
- XXX
- YYY
- ZZZ
- name: Setting fact using output of loop
set_fact:
service_status:
- rc: "{{ item.rc }}"
stdout: "{{ item.stdout }}"
id: "{{ item.id }}"
with_items:
- "{{ output }}"
- debug:
msg: "ID and stdout: {{ item.id }} - {{ item.stdout }}"
with_items:
- "{{ service_status }}"
Initial Answer
IIUC, this link from the Ansible docs shows how to use register inside a loop (see another example in this SO post).
A couple of points
it may be more convenient to assign the list (XXX, YYY, ZZZ) to a separate variable (eg. 1, 2)
I don't know if this is part of the problem, but with_items is no longer the recommended approach to loop over a variable: instead use loop - see here for an example
vars:
items:
- XXX
- YYY
- ZZZ
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: service_status
loop: "{{ items|flatten(levels=1) }}"
- name: Show the return code and stdout
debug:
msg: "Cmd {{ item.cmd }}, return code {{ item.rc }}, stdout {{ item.stdout }}"
when: item.rc != 0
with_items: "{{ service_status.results }}"

Ansible nested loops, how to set inner loop variable based on outer variable

I'm having problems with a nested loop on ansible.
I'm using ansible 2.5.2 with the following config files:
file hosts:
[group1]
host1
host2
host3
[group2]
hostA
file host_vars/host{N} (where N is the number for each host on group1):
variable:
- { line: "keyB" , file: "keyc"}
- { line: "key2" , file: "key3"}
I need to execute on hostA one task for each line in host_vars/host{N}.
in pseudo code, need something like this:
- name: modify file
for host in groups['group1']:
for item in host['variables']:
lineinfile: "path={{ host }}/{{ item.file }} line={{ item.line }}"
using jinja2 loops does not work:
- name: Modify files
lineinfile: "{% for linea in hostvars[item]['variables'] %}
path={{ item }}/{{ linea.file }}
line={{ linea.line }}
{% endfor %}"
loop: "{{ groups['group1'] }}"
normal nested loops does not work either because the inner loop deppends on the hostname:
- name: Modify files
lineinfile: "path={{ item[0] }}/{{ item[1]['file'] }} line={{ item[1]['line'] }}"
with_nested:
- "{{ groups['group1'] }}"
- "{{ hostvars[item[0]]['variables'] }}"
There is another way to cicle nested loops?
I solved my problem using loop_control,
I add a new file: inner.yml
- name: Modify files
lineinfile: "path={{ outer_item }}/{{ item.file }} line={{ item.line }}"
loop: "{{ hostvars[outer_item]['variables'] }}"
And defined my task file as follows
- include_tasks: inner.yml
loop: "{{ groups['group1'] }}"
loop_control:
loop_var: outer_item
which solves my problem of using two nested variables on loops.

Resources