Ansible: How to loop set_fact varaibles - ansible

i have a ansible-playbook that generates all elements output from remote server, and being saved into variables using set_fact.
i want to try and write each output into separate files using copy module with loop.
set_fact works to store the content but i am struggling to get them specified under copy module using loop.
- name: Playbook to get element details from server
uri:
url: https://10.10.10.19/rest/v1.1/nucli?SetType={{ item }}
body_format: raw
method: GET
headers:
Content-Type: application/xml
Accept: application/xml
Authorization: Bearer password
return_content: yes
register: fileout
with_items:
- My_var1
- My_var2
- My_var3
- My_var4
- set_fact:
My_var1: "{{ fileout.results[0].content }}"
My_var2: "{{ fileout.results[1].content }}"
My_var3: "{{ fileout.results[2].content }}"
My_var4: "{{ fileout.results[3].content }}"
- copy:
content: {{ item }}
dest: "/users/ansible/vars/{{ item }}.txt"
delegate_to: localhost
loop:
- My_var1
- My_var2
- My_var3
- My_var4
Playbook execution:
all steps executed successfully. but in copy module content: {{ item }} is not using set_fact variables, instead they are just copying string My_var1... etc.
Could anyone help me how to use loop for set_fact variable names? So that i can store the content that i have saved from set_fact (example - My_var1: "{{ fileout.results[0].content }}" )
Thanks in advance.

Related

How yo print API request and response with Ansible uri module?

I tried to find a way to print both an API request and response to a log file. But Ansible URI module does not provide the request data.
Does anyone know any mechanism to print the request and response to file in Ansible?
example:
name: update cms
uri:
url: '{{ cms_api.msg }}'
method: POST
body_format: json
body:
api_password: "{{ api_password }}"
name: "{{ item.Name }}"
ip_address: "{{ item.IPAddress }}"
subnet_mask: "{{ item.SubnetMask }}"
router: "{{ item.Router }}"
ip_range: "{{ item.IPAddresses }}"
options: "{{ item.Options }}"
pool_name: "{{ item.PoolName}}"
validate_certs: no
return_content: yes
register: dhcp_subnet_response
loop: "{{ ip_addrs_1.list }}"
delegate_to: localhost
I need to print above request and response both to a file. Since this api calling as a loop, I need to print request|response both for each request.
Since your post contains several different questions you may have a look into the general documentation first
Registering Variables
Return Values - Common
uri module – Interacts with webservices - Return Values and their Examples
After reading and regarding
But Ansible URI module not providing request data.
you may then have a look into the following example playbook
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Get response with 'uri' module
uri:
url: "https://example.com"
method: GET
body_format: raw # default
return_content: true # default 'false'
status_code: 200
register: result
- name: Show result
debug:
var: result
resulting into the content of https://example.com, an IANA-managed Reserved Domain.
Does anyone know any mechanism to print ...
The page content itself is accessible via
- name: Show content
debug:
msg: "{{ result.content }}"
print ... to file in Ansible?
and you can Write variable to a file in Ansible or Ansible - Save registered variable to file.

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 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.

How to render all ansible variables to yml file with ansible 2.3

I am storing all ansible variables to a yaml file (filtering out those that starting with 'ansible_') with this playbook:
- hosts: localhost
tasks:
- set_fact:
all_vars: "{{all_vars | default({}) |combine({item.key: item.value})}}"
when: "{{not item.key.startswith('ansible_')}}"
with_dict: "{{vars}}"
- copy:
content: "{{ all_vars }}"
dest: "/tmp/tmp.yml"
This is group_vars/all/defaults.yml
SOME_FACT1: "some-fact"
SOME_FACT2: "{{ SOME_FACT1 }}"
SOME_FACT3: "{{ SOME_FACT2 }}"
This works perfectly with ansible 2.2. But with ansible 2.3 (2.3.1.0) the variables are not rendered.
I get results like this:
... "SOME_FACT1": "some-fact", "SOME_FACT3": "{{ SOME_FACT2 }}", "SOME_FACT2": "{{ SOME_FACT1 }}" ...
How can i force ansible 2.3 to render the variables?
The problem seems, that ansible will not render vars and (I do not know why) all_vars. But any variable inside vars/all_vars is rendered properly when used directly.
So this works:
- hosts: localhost
tasks:
- set_fact:
all_vars: "{{all_vars | default([]) |union([item.key + ':{{' + item.key + '|to_json}}'])}}"
when: "{{not item.key.startswith('ansible_')}}"
with_dict: "{{vars}}"
- copy:
content: "{{ all_vars | join('\n') }}"
dest: "/tmp/tmp1.yml"
- template:
src: "/tmp/tmp1.yml"
dest: "/tmp/tmp.yml"
The idea is:
Create a file that lists all variables in the format
SOME_VAR: {{ SOME_VAR | to_json }}
...
Render that file using template.
Not very nice, but it works.

Adding field to dict items

Consider the following play. What I am trying to do is add a field, tmp_path which is basically the key and revision appended together to each element in the scripts dict.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
scripts:
a.pl:
revision: 123
b.pl:
revision: 456
tasks:
- with_dict: "{{ scripts }}"
debug:
msg: "{{ item.key }}_{{ item.value.revision }}"
# - with_items: "{{ scripts }}"
# set_fact: {{item.value.tmp_path}}="{{item.key}}_{{item.value.revision}}"
# - with_items: "{{ scripts }}"
# debug:
# msg: "{{ item.value.tmp_path }}"
...
Obviously the commented code doesn't work, any idea how I can get this working? Is it possible to alter the scripts dict directly, or should I somehow be creating a new dict to reference instead?
By the way welcome to correct the terminology for what I am trying to do.
OK, I think I got a solution (below), at least to let me move forwards with this. Disadvantages are it has removed the structure of my dict and also seems a bit redundant having to redefine all the fields and use a new variable, If anyone can provide a better solution I will accept that instead.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
scripts:
a.pl:
revision: 123
b.pl:
revision: 456
tasks:
- with_dict: "{{ scripts }}"
debug:
msg: "{{ item.key }}_{{ item.value.revision }}"
- with_dict: "{{ scripts }}"
set_fact:
new_scripts: "{{ (new_scripts | default([])) + [ {'name': item.key, 'revision': item.value.revision, 'tmp_path': item.key ~ '_' ~ item.value.revision}] }}"
# - debug:
# var: x
# - with_dict: "{{ scripts }}"
- with_items: "{{ new_scripts }}"
debug:
msg: "{{ item.tmp_path }}"
...
BTW credit to the following question which pointed me in the right direction:
Using Ansible set_fact to create a dictionary from register results

Resources