Pass ansible synchronize module file permission attribute upon user input - file

I have ansible variable "changeperm" set to true or false and decides if the file being copied from source to destination get its permissioned changed.
If changeperm is false the file permissions should be retained.
If changeperm is true another variable file_perm=774 decides what permissions the copied destination file should have.
Below is my approach playbook post suggestion by #Matt P which does not work.
tasks:
- set_fact:
final_file_perm: "--chmod=F{{ file_perm }}"
when: changeperm
- set_fact:
ret_perm: 'yes'
when: not changeperm
- debug:
msg: "Permission is {{ final_file_perm | default(omit) }} and retain_permission is {{ ret_perm | default(omit) }}"
- name: Copying from "{{ inventory_hostname }}" to this ansible server.
synchronize:
src: "{{ item }}"
dest: "{{ playbook_dir }}/tmpfiles/{{ Latest_Build_Number }}"
perms: "{{ ret_perm | default(omit) }}"
rsync_opts: "{{ final_file_perm | default(omit) }}"
mode: pull
with_items:
- "{{ source_file.split(',') }}"
This is how I run the playbook:
ansible-playbook -i /var/inventory.hosts /var/test.yml -e changeperm=false -e file_perm=774 -e source_file=/tmp/sixhundredperm.txt
This works fine.
However, the below does not work
rsync_opts:
- "{{ final_file_perm | default(omit) }}"
Can you please suggest how can I get this to work when the attribute of rsync_opts is in the next new line ?

Related

Ansible find matched patterns directory, remove all but keep the last 3 versions

I have surf the stackoverflow site around but couldn't find anything similar to what I want to achieve and hope that someone can point me out would be much appreciated.
I have a directory which stored all the artifacts Release Candidate and Dev versions when ever there is a bamboo build kick in. So far, I can figure out how to find the directory patterns and verify the results to remove. But could not filter the results to exclude the last 3 latest versions which I want to keep.
Here is the structures and the code
Structures
---
- name: Ansible find match directory, keep the last 3 version and remove all other
hosts: localhost
connection: local
vars:
base_dir: "/opt/repo/"
artifacts:
- "subject-mapper"
- "artemis-margin-api"
tasks:
- name: Find Release Candidate Directory Packages
become: yes
find:
paths: "{{ base_dir }}/{{ item }}"
patterns:
- "{{ item }}-[0-9]*.[0-9]*.[0-9]*$"
use_regex: yes
recurse: no
file_type: directory
loop: "{{ artifacts }}"
register: output
- debug:
msg: "{{ output }}"
- name: Filter out the Release Candidate results and keep the last 3 versions
set_fact:
files_to_delete: "{{ (files_to_delete|default([])) + (item['files'] | sort(attribute='mtime'))[:-3] }}"
loop: "{{ output['results'] }}"
- debug:
msg: "{{ files_to_delete }}"
- name: Delete the filtered results but keep the last 3 version
file:
path: "{{ item.path }}"
state: absent
loop: "{{ files_to_delete }}"
when: confirm|default(false)|bool
register: output_delete
- debug:
msg: "{{ output_delete }}"
here
Simplest way would be to pop first three matches from each result:
- set_fact:
files_to_delete: "{{ (files_to_delete|default([])) + (item['files'] | sort(attribute='mtime'))[3:] }}"
loop: "{{ output['results'] }}"

Is There a Way to Have a Value Stored in an Array Every Time the Loop Occurs in Ansible?

I have an ansible-playbook which aims to display an A Record of a particular host from a DNS Server within Domain Controller. Here’s what I did on Ansible-Playbook:
Use powershell to obtain information related to A Record on the DNS Server.
Save it as a variable named test_var.
Divide the contents of the variable test_var into line by line.
Retrieves the important line containing the string host I'm looking for.
Take the important attributes of those important lines and show it as msg.
Here's the code:
# hostname and domain are necessary
---
- hosts: all
gather_facts: no
vars:
search_name: "{{hostname}}"
tasks:
- name: powershell query
win_shell: "Get-DnsServerResourceRecord -Name '{{hostname}}' -ZoneName '{{domain}}' -RRType A"
register: result1
when: (hostname is defined) and (domain is defined)
- set_fact:
test_var: "{{ result1.stdout_lines }}"
- name: pickup lines
set_fact:
important_lines: "{{ important_lines |default([]) + [item] }}"
with_items:
- "{{ test_var }}"
- name: find the line
set_fact:
target_line: "{{item}}"
when: item|trim is search(search_name)
loop: "{{ important_lines | flatten(1) }}"
- name: get all attributes
set_fact:
attribute_record: "{{ target_line.split()[1]|trim}}"
attribute_type: "{{ target_line.split()[2]|trim}}"
attribute_timestamp: "{{ target_line.split()[3]|trim}}"
attribute_timetolive: "{{ target_line.split()[4]|trim}}"
attribute_ipaddress: "{{ target_line.split()[5]|trim}}"
- name: print results
debug:
msg: "name: {{search_name}}, Ip Address: {{attribute_ipaddress}}"
And here's my DNS Server configuration:
And the results are as follows (host=test1):
However, I have a problem. In the Find the line task which runs the loop, the target_line variable stores only the last line at the end of the task. So, when the print results task is executed, only the last host and IP address are displayed. The question is, is there some way to have each line stored in an array every time the loop occurs? Thus, I can call the contents of the array to display it one by one. Thank you.
Here's the solution that I got:
# hostname and domain are necessary
---
- hosts: all
gather_facts: no
vars:
correct_line: []
search_name: "{{hostname}}"
tasks:
- name: powershell query
win_shell: "Get-DnsServerResourceRecord -Name '{{hostname}}' -ZoneName '{{domain}}' -RRType A"
register: result1
when: (hostname is defined) and (domain is defined)
- set_fact:
test_var: "{{ result1.stdout_lines }}"
- name: pickup lines
set_fact:
important_lines: "{{ important_lines |default([]) + [item] }}"
with_items:
- "{{ test_var }}"
- name: find the line
set_fact:
correct_line: "{{correct_line + [item]}}"
when: item|trim is search(search_name)
loop: "{{ important_lines | flatten(1) }}"
- name: print results
debug:
msg: "name: {{item.split()[0]|trim}}, Ip Address: {{item.split()[5]|trim}}"
loop: "{{ correct_line | flatten(1) }}"
And here's the result:

how to pass split values into a loop in ansible based on input range?

I am pretty new to Ansible loops.
I am trying to replace a set of ip addresses (oldip to newip) in a file.
It needs to accept the input ip address as a dynamic list in the form oldip1:newip1,oldip2:newip2,oldip3:newip3...
I want to split the above ip address pair (old:new) and then pass them over to Ansible replace module in a loop based on input list.
I am trying something like this, but am stuck on how to pass the dynamic range of ip address pair into the loop.
My input variable is like 192.123.12.11;192.123.12.20, 192.123.12.12;192.123.12.19 , 192.123.12.13;192.123.12.18 ... (dynamic ip pairs range)
vars:
ip_pairs: oldIP_newIP
tasks:
- debug: "{{ oldIP_newIP.split (',') }}"
- replace:
path: /home/ubuntu/cassandra.properties
regexp: "{{ item.regexp }}"
replace: "{{ item.replace }}"
backup: yes
with_items:
- { regexp = "{{ oldIP }}", replace = "{{ newIP }}"
- { regexp = "{{ oldIP }}", replace = "{{ newIP }}"
.
.
.
.
This loop should continue based on input ip pairs entry (5 times for 5 ip pairs (old;new).
Something really useful you can use in order to achieve this is the fact that you can register variables at the task level, via the vars property.
For exemple:
- name: This will display 'bar', the content of foo
debug:
msg: "{{ foo }}"
vars:
foo: 'bar'
Base on this, you can achieve what you want quite easily doing:
- name: Replace IPs
replace:
path: /home/ubuntu/cassandra.properties
regexp: "{{ oldNewIp[0] | trim }}"
replace: "{{ oldNewIp[1] | trim }}"
backup: yes
vars:
oldNewIp: "{{ item.split(';') }}"
with_items: "{{ ipPairs.split(',') }}"
Please mind that I added some extra Jinja trim in order to cope with the fact that, in your example input, you do have some space after your commas.
Here is a full example play to demo this:
Given the playbook
- hosts: local
vars:
ipPairs: '192.123.12.11;192.123.12.20, 192.123.12.12;192.123.12.19, 192.123.12.13;192.123.12.18'
tasks:
- name: Create an example file to replace in
copy:
dest: /tmp/ips.txt
content: ''
- name: Populate a file with old IPs
lineinfile:
path: /tmp/ips.txt
line: "{{ oldNewIp[0] | trim }}"
vars:
oldNewIp: "{{ item.split(';') }}"
with_items: "{{ ipPairs.split(',') }}"
- name: Replace IPs
replace:
path: /tmp/ips.txt
regexp: "{{ oldNewIp[0] | trim }}"
replace: "{{ oldNewIp[1] | trim }}"
backup: yes
vars:
oldNewIp: "{{ item.split(';') }}"
with_items: "{{ ipPairs.split(',') }}"
I have the following play:
/ # ansible-playbook -i inventory.yaml play.yaml
PLAY [local] *********************************************************************************************
TASK [Gathering Facts] ***********************************************************************************
[WARNING]: Platform linux on host local is using the discovered Python interpreter at /usr/bin/python3,
but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
ok: [local]
TASK [Create an example file to replace in] **************************************************************
changed: [local]
TASK [Populate a file with old IPs] ***********************************************************************
changed: [local] => (item=192.123.12.11;192.123.12.20)
changed: [local] => (item= 192.123.12.12;192.123.12.19)
changed: [local] => (item= 192.123.12.13;192.123.12.18)
TASK [Replace IPs] ***************************************************************************************
changed: [local] => (item=192.123.12.11;192.123.12.20)
changed: [local] => (item= 192.123.12.12;192.123.12.19)
changed: [local] => (item= 192.123.12.13;192.123.12.18)
PLAY RECAP ***********************************************************************************************
local : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
/ # cat /tmp/ips.txt
192.123.12.20
192.123.12.19
192.123.12.18

How to create a loop inside a loop in ansible and export variables?

So basically, I have these two dictionaries:
dict_1:
- name: one
- name: two
dict_2:
- identifier: one
type: typeA
- identifier: two
type: typeB
I need to iterate over both and "export" the vars to process.yml. This is what I am doing right now but not working properly:
#main.yml
- name:
include_tasks: process.yml
loop: "{{ dict_1 | flatten }}"
loop_control:
loop_var: entity
loop: "{{ dict_2 | selectattr('identifier', 'equalto', entity) | map(attribute='type') | flatten }}"
loop_control:
loop_var: type
#process.yml
- name: Print variables
debug:
msg: "{{ entity }}_{{ type }}"
What I wanted to see after this was:
one_typeA
two_typeB
How can I get this result from the loop?
I think your original solution is close, just a little more complicated than it needs to be. Please note that this solution assumes that there will not be more than one item from dict2 that you will be finding using the value from dict1, it's just the order that you can't predict.
- debug: msg="{{ item.name }}_{{ dict_2 | selectattr('identifier', 'equalto', item.name) | map(attribute='type') | list | join() }}"
with_items: "{{ dict_1 }}"
If you CAN control order of the lists, this gets even easier.
- debug: msg="{{ item.0.name }}_{{ item.1.type }}"
with_together:
- "{{ dict_1 }}"
- "{{ dict_2 }}"
And if you can control the order and the content, and you want to have every possible combination of the two lists, you can do this:
- debug: msg="{{ item.0.name }}_{{ item.1.type }}"
with_cartesian:
- "{{ dict_1 }}"
- "{{ dict_2 }}"

Ansible 2.7.5 | ERROR! 'set_fact' is not a valid attribute for a Play

I need to do multiple tasks over one list. So, I created tasks list and
include it in the main playbook.
However, it looks like ansible doesn't recognise the tasks list as tasks list, but as playbook:
ERROR! 'set_fact' is not a valid attribute for a Play
main playbook:
---
- name: main playbook
hosts: all
tasks:
- name: subtasks.yaml
include_tasks: subtasks.yaml
loop: "{{ names_list }}"
loop_control:
loop_var: name
tasks list:
---
- name: "create name for the future vm {{ name }}_{{ ansible_date_time.iso8601 }}"
set_fact:
cloned_vm_name: "{{ name }}_{{ ansible_date_time.iso8601 }}"
ansible version : 2.7.5
OS: Ubuntu 16.04.3
after searching tones online, I found a similar answer for include_role - here
and it was life changing!
before:
---
- name: main playbook
hosts: all
tasks:
- name: subtasks.yaml
include_tasks: subtasks.yaml
loop: "{{ names_list }}"
loop_control:
loop_var: name
after:
---
- name: main playbook
hosts: all
tasks:
- name: subtasks.yaml
include_tasks: subtasks.yaml
vars:
name: "{{ item }}"
with_items: "{{ names_list }}"

Resources