Multiple different commands in loop - ansible

I am trying to convert a yml file into json. I need to pick the list of yml files from file1.txt and convert all those files to json.
Below is the code that I am using
- hosts: localhost
tasks:
- name: convert yml to json
shell: cat /home/testadmin/{{ item }}.yml
register: result
- copy:
dest: ./{{ item }}.json
content: "{{ result.stdout | from_yaml | to_nice_json }}"
with_lines: cat file1.txt
The code should pick up the filename from file1.txt and then convert the file 1 by 1. I would like to know how to put all these commands to convert yml to json in a loop.
The actual result should replace all the .yml files in file1.txt and convered into the json format with the same name

A loop only works on the task that it is attached to. To wrap multiple tasks in a loop, you need to split them out to another file, use an include statement to load them, and then attach the loop to that include statement.
In your case tho, none of that is required. I think this should do what you are looking for, presuming that file1.txt contains a list of file names, one per line & without file extension:
- host: localhost
connection: local
tasks:
- name: Convert each file listed in file1.txt
copy:
dest: "./{{ item | trim }}.json"
content: "{{ lookup('file', item + '.yml') | from_yaml | to_nice_json }}"
with_lines: cat ./file1.txt
connection: local stops Ansible opening a SSH connection to the localhost
{{ item | trim }} takes each item from the list and trims any leading or trailing whitespace
lookup('file', item + '.yml') reads a file. item is the default variable name used in loops to contain the contents of each element of the loop
with_lines only works locally, so if you need to run this remotely, you will need to modify this

Related

Ansible tower survey transforming survey string values

I currently pass parameters to my script which an ansible tower job template/role calls. In order to make it more user friendly, I have decided to use a survey to do this. The script takes on filenames as parameters.
The script accepts the parameters in this format
'file1.txt','file2.txt','file3.txt'
However, here is the problem
The file could be one, it could be 2 or three up to possibly 5.
I have thought about a solution and I think the best design is to have a comma delimited list of files coming from ansible survey, for example file1, file2, file3
How can I have a logic whereby with the list of files, they can be split and a loop used to copy them one by one if there are more than one file provided in the list, then have a variable that will add single quotes and a comma to the file list. For example in the survey the values provided such as file1.txt, file2.txt, file3.txt will then be transformed into a variable which contains the following
'file1.txt','file2.txt','file3.txt'
The other issue is this.
The ansible role copies the given file name onto a directory, I know the split function can be used to split a comma separated list, how can I then copy them onto a folder in a loop ? If we look at the example below, it only works for a single file.
EDIT.
I have looked at the split function and combining it with a loop. I get an error when I run it. Template error while templating string
---
- name: Set file name
set_fact:
file1: "file1.txt"
file_list: "file1.txt"
- name: Set working directory
set_fact:
standard_path: "{{ansible_user_dir}}\\execution"
content_file: "{{standard_path}}\\{{file1}}"
- name: Copy file to working directory
win_copy:
src: "file1.txt"
dest: "{{content_file}}"
- name: Set parameters for script
set_fact:
params: "-filenames '{{content_file}}'"
- name: Run a loop to copy the files.
win_copy:
src: "{{ item }}"
dest: "{{standard_path \\ item }}"
with_items: "{{file_list.split(',') }}"
The section within the code that was throwing an exception has now been fixed.
The jinja2 standard requires the variables to be in separate {{}} as seen below.
- name: Run a loop to copy the files.
win_copy:
src: "{{ item }}"
dest: "{{standard_path}}\\{{item }}"
with_items: "{{file_list.split(',') }}"

How to substitute values to a conf file using Ansible

I have an ansible playbook that has created a file (/tmp/values.txt) in each server with the following content
1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4
5.5.5.5
And I have a conf file named etcd.conf in the /tmp/etcd.conf with the following content
and I need to substitute the value of each line from /tmp/values.txt, so /tmp/etcd.conf will look like this:
SELF_IP=1.1.1.1
NODE_1_IP=2.2.2.2
NODE_2_IP=3.3.3.3
NODE_3_IP=4.4.4.4
NODE_4_IP=5.5.5.5
Is there a way I can do this? I used the following lookup method but it only works in the controll server
- name: Create etcd.conf
template:
src: etcd.conf.j2
dest: /tmp/etcd.conf
vars:
my_values: "{{ lookup('file', '/tmp/values.txt').split('\n') }}"
my_vars: [SELF_IP, NODE_1_IP, NODE_2_IP, NODE_3_IP, NODE_4_IP]
my_dict: "{{ dict(my_vars|zip(my_values)) }}"
You can use the slurp: task to grab the content for each machine, or use command: cat /tmp/values.txt and then examine the stdout_lines of its register:-ed variable to achieve that same .split("\n") behavior (I believe you'll still need to use that .split call after | b64decode if you use the slurp approach)
What will likely require some massaging is that you'll need to identify the group (which may very well include all) of inventory hostnames for which that command will produce content, and then grab the hostvar out of them to get all values
Conceptually, similar to [ hostvars[hv].tmp_values.stdout_lines for hv in groups[the_group] ] | join("\n"), but it'll be tedious to write out, so I'd only want to do that if you aren't able to get it to work on your own

ansible-playbook gather information from a file

I want to read a file by ansible and find specific thing and store all of them in a file in my localhost
for example there is /tmp/test file in all host and I want to grep specific thing in this file and store all of them in my home.
What should I do?
There might be many ways to accomplish this. The choice of Ansible modules (or even tools) can vary.
One approach is (using only Ansible):
Slurp the remote file
Write new file with filtered content
Fetch the file to Control machine
Example:
- hosts: remote_host
tasks:
# Slurp the file
- name: Get contents of file
slurp:
src: /tmp/test
register: testfile
# Filter the contents to new file
- name: Save contents to a variable for looping
set_fact:
testfile_contents: "{{ testfile.content | b64decode }}"
- name: Write a filtered file
lineinfile:
path: /tmp/filtered_test
line: "{{ item }}"
create: yes
when: "'TEXT_YOU_WANT' in item"
with_items: "{{ testfile_contents.split('\n') }}"
# Fetch the file
- name: Fetch the filtered file
fetch:
src: /tmp/filtered_test
dest: /tmp/
This will fetch the file to /tmp/<ANSIBLE_HOSTNAME>/tmp/filtered_test.
You can use the Ansible fetch module to download files from the remote system to your local system. You can then do the processing locally, as shown in this Ansible cli example:
REMOTE=[YOUR_REMOTE_SERVER]; \
ansible -m fetch -a "src=/tmp/test dest=/tmp/ansiblefetch/" $REMOTE && \
grep "[WHAT_YOU_ARE_INTERESTED_IN]" /tmp/ansiblefetch/$REMOTE/tmp/test > /home/user/ansible_files/$REMOTE
This snippet runs the ad-hoc version of Ansible, calling the module fetch with the source folder (on the remote) and the destination folder (locally) as arguments. Fetch copies the file into a folder [SRC]/[REMOTE_NAME]/[DEST], from which we then grep what we are interested in, and output that in the /home/user/ansible_files/$REMOTE.

Ansible: How to copy output of 4 commands

I would like to copy the content of the variable showoutput (in which there are 4 commands) in a file. But, when I execute my playbook, It copy only the first one command.
How to copy the four commands ?
Below my playbook:
- hosts: ios
vars:
command_list:
- show cdp neigh
- show ip interface brief
- show clock
- show arp
tasks:
- name: Run the SHOW commands and save output
ios_command:
commands: "{{ command_list }}"
register: showoutput
- name : Copy the result in a file
copy:
content: "{{showoutput.stdout[0]}}"
dest: "/home/net/output/{{hostvars.localhost.DTG}}/{{inventory_hostname}}-{{hostvars.localhost.DTG}}-test.txt"
Ansible's documentation on Registering variables,
When you register a variable in a task with a loop, the registered
variable contains a value for each item in the loop. The data
structure placed in the variable during the loop will contain a
results attribute, that is a list of all responses from the module.
The output of each command should be available in showoutput.results which is an array. You can loop over them as
- name : Copy the result in a file
copy:
content: "{{ item.stdout }}"
dest: "/home/net/output/{{hostvars.localhost.DTG}}/{{inventory_hostname}}-{{hostvars.localhost.DTG}}-test.txt"
with_items: "{{ showoutput.results }}"

Copy certain Files from a File that contains the specific Filenames with Ansible

I have a file which contains different filnames. What filenames are in that file, changes every time i run the playbook.
Though I found only ways to either copy all files in a directory or copy certain files that are defined static.
filenames.txt:
file1
file4
Directory that contains the files:
file1
file2
file3
file4
file5
My Plan was to create a variable in my vars sheet in which I save the file and then use it in my role.
copy-files: path/filenames.txt
Role to copy the files:
---
- name: Copy Files
copy:
src: "{{ item }}"
dest: "{{path2}}"
with_fileglob:
- "/pathtofiles/{{copy-files}}"
Sadly this doesen't work. Does somebody else know a different approach?
When I understand you right, you want to copy the files, listed in path/filenames.txt. You can do it with the following task:
- name: Copy Files to /tmp
copy:
src: "{{ item }}"
dest: "{{ hqlname_sys2 }}"
loop: "{{ lookup('file', 'path/filenames.txt').split('\n') }}"
The contents of path/filenames.txt is read with the lookup file plugin into a string and that string is splitted by the split function on the '\n' delimiter, so that you get an array with of filenames which is passed to the loop.

Resources