Ansible How to loop inside the files for templates - ansible

Need to loop through the source files one by one for all hosts.
- hosts: epson*
become: yes
tasks:
- name: replace id
vars:
id: abc
template:
src: epson1.j2
dest: /home/epson.config
HOSTS FILE
[epson1]
1.1.1.1
[epson2]
1.1.1.1
[epson3]
1.1.1.1
and many more
epson1.j2
create element edge0 {
state="ENABLED"
id="{{ id }}"}
epson2.j2
create element edge1 {
state="ENABLED"
id="{{ id }}"}
I have many template files like epson1.j2, epson2.j2 and so on.
Right now i am able to do template variable replace for 1 host and for 1 file. How can I do for all files for all hosts.
like - host:epson1, src: epson1.j2, dest: /home/epson.config
host:epson2, src: epson2.j2, dest: /home/epson.config
host:epson3, src: epson3.j2, dest: /home/epson.config
need looping inside src for every hosts

You should be able to accomplish this simply by using the inventory_hostname magic variable.
- hosts: epson*
become: yes
tasks:
- name: replace id
vars:
id: abc
template:
src: {{ inventory_hostname }}.j2
dest: /home/epson.config
The Play will run once for each host and the correct .j2 will be used.

Related

Ansible How to iterate through filenames for making symlinks?

Here is my specifications in Ansible Play-Book, to make symlinks:
---
- hosts: DEVSRV
become: yes
tasks:
- name: symlink deploy_config scripts
file:
src: "{{ item }}"
dest: "/usr/local/bin/"
state: link
loop:
- "/home/foo/bar/deploy/config/dev_deploy_config.sh"
- "/home/foo/bar/deploy/config/int_deploy_config.sh"
- "/home/foo/bar/deploy/config/prod_deploy_config.sh"
In src: it iterates over the path and filenames within loop: which is good. However, how can I use just filenames for dest: without the path?
this task should do it, and its pretty self-explanatory:
- name: symlink deploy_config scripts
file:
src: "{{ item }}"
dest: "/usr/local/bin/{{ item.split('/') | last }}"
state: link
loop:
- "/home/foo/bar/deploy/config/dev_deploy_config.sh"
- "/home/foo/bar/deploy/config/int_deploy_config.sh"
- "/home/foo/bar/deploy/config/prod_deploy_config.sh"
hope it helps!

Ansible conditionally loop through with_items?

Is it possible to loop through a list of items if a string is defined in a variable i will specify.
Essentially i want to have a list of variables defined and utilized the aws_s3 module to download the files only if they are defined when running the playbook
e.g
say i have the list "var1,var2"
and I have the following variables defined:
apps_location:
- { name: 'vars1', src: 'vars1.tgz', dest: '/tmp/vars1_file.tgz' }
- { name: 'vars2', src: 'vars2.tgz', dest: '/tmp/vars2_file.tgz' }
- { name: 'vars3', src: 'vars3.tgz', dest: '/tmp/vars3_file.tgz' }
Task:
- name: "Splunk Search Head | Download Splunk Apps from S3"
aws_s3:
bucket: "{{ resource_bucket_name }}"
object: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: get
with_items: "{{ apps_location }}"
I want to run the command:
ansible-playbook -i inventory -e "var1,var2"
and download only var1 and var2 on that specific run.
I tried utilizing "lookups" but couldnt get the syntax right. Im not entirely sure if this best way of doing this, but i want to have a predefined list of file locations and only download the ones that i'm passing during runtime.
Note the only reason "name" exists in apps_location is to see if i can do a lookup and only install that one but i couldnt get the syntax right.
Define a variable containing a list of defined apps. I'm trying:
- name: "Set Fact"
set_fact:
dict: "{{ apps_location[item].dest }}"
with_items: "{{ my_vars|default([]) }}"
However whenever I output dict I only get the last value.
Any help would be appreciated :)
The extra-vars must be an assignment of a variable and value. For example
shell> ansible-playbook -i inventory -e "my_vars=['vars1','vars2']"
A more convenient structure of the data would be a dictionary for this purpose. For example
apps_location:
vars1:
src: 'vars1.tgz'
dest: '/tmp/vars1_file.tgz'
vars2:
src: 'vars2.tgz'
dest: '/tmp/vars2_file.tgz'
vars3:
src: 'vars3.tgz'
dest: '/tmp/vars3_file.tgz'
Then the loop might look like
- aws_s3:
bucket: "{{ resource_bucket_name }}"
object: "{{ apps_location[item].src }}"
dest: "{{ apps_location[item].dest }}"
mode: get
loop: "{{ my_vars|default([]) }}"
Q: "Define a variable containing a list of defined apps."
A: Try this
- set_fact:
my_list: "{{ my_list(default([]) +
[apps_location[item].dest] }}"
loop: "{{ my_vars|default([]) }}"
(not tested)

Can't copy files using loop

I'm trying to copy many files using ansible.
this is my playbook :
- name: Copy the scenario test
copy:
src: files/{{ scenario_name }}
dest: /home/{{ user }}/scenario_creation
mode: '0644'
run_once: true
loop: "{{ scenario_name }}"
tags:
- user
- scenario
and this is my roles/scenario_test/defaults/main.yml
scenario_name: ['topup-scenario.json', 'test.json']
when I execute my playbook it says:
"msg": "Could not find or access 'files/[u'topup-scenario.json', u'test.json']'\nSearched in:\n\t/home/path/ansible/plays/files/[u'topup-scenario.json', u'test.json']\n\t/home/path/ansible/plays/files/[u'topup-scenario.json', u'test.json'] on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"
}
any help ?
Change:
src: files/
to
src: ./files/
You need to change your code to this:
- name: Copy the scenario test
copy:
src: files/{{ item }}
dest: /home/{{ user }}/scenario_creation
mode: '0644'
run_once: true
loop: "{{ scenario_name }}"
tags:
- user
- scenario
The loop iterates the list to the term 'item', unless you redefine it with the loop_var option. So when you call scenario_name in your src line, you are actually calling the entire list, not an iteration of it.

Ansible access same variables from multiple Json files

I have multiple .json files on local host where I place my playbook:
json-file-path/{{ testName }}.json
{{ testName }}.json are: testA.json, testB.json, testC.json ... etc.
All .json files have same keys with different values like this:
json-file-path/testA.json:
{
“a_key”: “a_value1”
“b_key”: “b_value1”
}
json-file-path/testB.json:
{
“a_key”: “a_value2”
“b_key”: “b_value2”
}
json-file-path/testC.json:
{
“a_key”: “a_value3”
“b_key”: “b_value3”
}
.....
I need to access the key-value variables from all .json files and if the values meet some condition, I will perform some task in target host. For example, I have:
a_value1=3
a_value2=4
a_value3=1
I go through my .json file one by one, if a_key[value]>3, I will copy this .json file to target host, otherwise skip the task. In this case, I will only copy testC.json to target host.
How would I achieve this? I was thinking of re-constructing my .json files using {{ testName }} as dynamic key of dict like this:
{
“testName”: “testA”
{
“a_key”: “a_value1”
“b_key”: “b_value1”
}
So I can access my variable as {{ testName}}.a_key. So far I haven’t been able to achieve this.
I have tried the following in my playbook:
—-
- host: localhost
tasks:
- name: construct json files
vars:
my_vars:
a_key: “{{ a_value }}”
b_key: “{{ b_value }}”
with_dict: “{{ testName }}”
copy:
content: “{{ my_vars | to_nice_json }}”
dest: /json-file-path/{{ testName }}.json
My updated playbook are:
/mypath/tmp/include.yaml:
—-
- hosts: remote_hostName
tasks:
- name: load json files
set_fact:
json_data: “{{ lookup(‘file’, item) | from_json }}”
- name: copy json file if condition meets
copy:
src: “{{ item }}”
dest: “{{ /remote_host_path/tmp}}/{{item | basename }}”
delegate_to: “{{ remote_hostName }}”
when: json_data.a_key|int>5
/mypath/test.yml:
—-
- hosts: localhost
vars:
local_src_ dir: /mypath/tmp
remote_host: remote_hostName
remote_dest_dir: /remote_host_path/tmp
tasks:
- name: looping
include: include.yaml
with_fileglob:
- “{{ local_src_dir }}/*json”
All json files on localhost under /mypath/tmp/.
Latest version of playbook. It is working now:
/mypath/tmp/include.yaml:
—-
- name: loafing json flies
include_vars:
file: “{{ item }}”
name: json_data
- name: copy json file to remote if condition meets
copy:
src: “{{ item }}”
dest: ‘/remote_host_path/tmp/{{item | basename}}’
delegate_to: “{{ remote_host }}”
when: json_data.a_key > 5
/mypath/test.yml:
—-
- hosts: localhost
vars:
local_src_dir: /mypath/tmp
remote_host: remote_hostName
remote_dest_dir: /remote_host_path/tmp
tasks:
- name: looping json files
include: include.yaml
with_fileglob:
- “{{ local_src_dir }}”/*json”
I am hoping that I have understood your requirements correctly, and that this helps move you forward.
Fundamentally, you can load each of the JSON files so you can query the values as native Ansible variables. Therefore you can loop through all the files, read each one, compare the value you are interested in and then conditionally copy to your remote host via a delegated task. Therefore, give this a try:
Create an include file include.yaml:
---
# 'item' contains a path to a local JSON file on each pass of the loop
- name: Load the json file
set_fact:
json_data: "{{ lookup('file', item) | from_json }}"
- name: Delegate a copy task to the remote host conditionally
copy:
src: "{{ item }}"
dest: "{{ remote_dest_dir }}/{{ item | basename }}"
delegate_to: "{{ remote_host }}"
when: json_data.a_key > value_threshold
then in your playbook:
---
- hosts: localhost
connection: local
# Set some example vars, tho these could be placed in a variety of places
vars:
local_src_dir: /some/local/path
remote_host: <some_inventory_hostname>
remote_dest_dir: /some/remote/path
value_threshold: 3
tasks:
- name: Loop through all *json files, passing matches to include.yaml
include: include.yaml
loop: "{{ lookup('fileglob', local_src_dir + '/*json').split(',') }}"
Note: As you are running an old version of Ansible, you may need older alternate syntax for all of this to work:
In your include file:
- name: Load the json file
set_fact:
include_vars: "{{ item }}"
- name: Delegate a copy task to the remote host conditionally
copy:
src: "{{ item }}"
dest: "{{ remote_dest_dir }}/{{ item | basename }}"
delegate_to: "{{ remote_host }}"
when: a_key > value_threshold
and in your playbook:
- name: Loop through all *json files, passing matches to include.yaml
include: include.yaml
with_fileglob:
- "{{ local_src_dir }}/*json"

Ansible - Filter host groups by prefix

I'm trying to fetch the names of host groups in Ansible that have a specific prefix. Right now, I'm trying to delegate a template task to servers under host groups with the prefix "config_".
I'm using json_query which uses JMESPath expressions. The query however is incorrect. Can anyone guess what I'm missing?
- name: Create configsvr config file
template: src=mongod.conf.j2 dest={{ mongod.conf.path }} owner=mongod group=mongod mode=0600
delegate_to: "{{ groups|json_query([?starts_with(#, `config_`)]) }}"
Error msg:
FAILED! => {"failed": true, "msg": "template error while templating string: unexpected char u'?' at 22. String: {{ groups|json_query([?starts_with(#, `config_m`)]) }}"}
You should simply use built-in patterns to select your target hosts.
---
- hosts: conf_*
tasks:
- name: Create configsvr config file
template:
src: mongod.conf.j2
dest: "{{ mongod.conf.path }}"
owner: mongod
group: mongod
mode: 0600
You can improve your inventory by using groups of groups, like so:
[conf:children]
conf_a
conf_b
conf_c
[conf_a]
srv1
[conf_b]
srv2
[conf_c]
srv3
And then target conf group in your playbook:
---
- hosts: conf
tasks:
- name: Create configsvr config file
template:
src: mongod.conf.j2
dest: "{{ mongod.conf.path }}"
owner: mongod
group: mongod
mode: 0600

Resources