Ansible - How to use register name from with_items - ansible

In my current playbook, I have something like the following:
- name: Copy cov-analysis-linux64-8.0.0.tgz
copy: src=/home/devops/chroot/cov-analysis-linux64-8.0.0.tgz dest=/var/tmp/cov-analysis.tgz owner=devops
register: coverity
- name: Copy fortidev-2.02.chroot.tar.bz2
copy: src=/home/devops/chroot/fortidev-2.02.chroot.tar.bz2
dest=/var/tmp/fortidev2.chroot.tar.bz2 owner=devops
register: fortidev2
The list is getting longer and longer and for code readability, I want to use with_items to do it. I've updated it to something like:
- name: copy chroot tarball to the servers
copy: src={{ item.src }} dest={{ item.dest }} owner=devops
register: "{{ item.register }}"
with_items:
- { src: /home/devops/chroot/cov-analysis-linux64-8.0.0.tgz,
dest: /var/tmp/cov-analysis.tgz,
register: coverity
}
- { src: /home/devops/chroot/fortidev-2.02.chroot.tar.bz2,
dest: /var/tmp/fortidev2.chroot.tar.bz2,
register: fortidev2
}
- { src: /home/devops/chroot/fmdev-6.0.tar.xz,
dest: /var/tmp/fmdev6.tar.xz,
register: fmdev6
}
The problem is now when I want to refer to one of the registers in subsequent tasks, it couldn't find the variable. The code to refer it is:
- name: umount fortidev2 /proc|/dev|/tmp|/cov-analysis
command: umount {{ item }}
become: yes
when: fortidev2.changed
with_items:
- /home/devops/fortidev2/proc
- /home/devops/fortidev2/dev
- /home/devops/fortidev2/tmp
ignore_errors: yes
The error is
{"failed": true, "msg": "The conditional check 'fortidev2.changed' failed. The error was: error while evaluating conditional (fortidev2.changed): 'fortidev2' is undefined\n\nThe error appears to have been in '/var/lib/jenkins/jobs/Devops/jobs/update_chroot/workspace/roles/chroot/tasks/main.yml': line 70, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# unmount /proc and /dev first before deleting the folder\n- name: umount fortidev2 /proc|/dev|/tmp|/cov-analysis\n ^ here\n"}

Try this:
- name: copy chroot tarball to the servers
copy: src={{ item.src }} dest={{ item.dest }} owner=devops
register: tarballs
with_items:
- { src: /home/devops/chroot/cov-analysis-linux64-8.0.0.tgz,
dest: /var/tmp/cov-analysis.tgz,
name: coverity
}
- { src: /home/devops/chroot/fortidev-2.02.chroot.tar.bz2,
dest: /var/tmp/fortidev2.chroot.tar.bz2,
name: fortidev2
}
- { src: /home/devops/chroot/fmdev-6.0.tar.xz,
dest: /var/tmp/fmdev6.tar.xz,
name: fmdev6
}
- name: umount fortidev2 /proc|/dev|/tmp|/cov-analysis
command: umount {{ item }}
become: yes
when: tarballs.results | selectattr('item.name','equalto','fortidev2') | join('',attribute='changed') | bool
with_items:
- /home/devops/fortidev2/proc
- /home/devops/fortidev2/dev
- /home/devops/fortidev2/tmp

Related

What is the ansible equivalent to find -exec cp with file extensions filtered?

I need to replace this kind of command:
- name: Copy files .par
shell: find {{ path_src }}/* -name '*.ext' -exec cp {} {{ path_dest }} \; | find {{ path_src }}/ -type f -a ! -name "*.*" -exec cp {} {{ part_dest }} \;
ignore_errors: yes
The '.ext' can be different on the same task and it's linked to the destination if i find '.sql' i want it to go to the destination .sql
I try this kind of solution
- name: TEST COPY
hosts: localhost
tasks:
- name: Test Find
find:
paths: /home/me/test/find_cpy
file_type: file
recurse: yes
patterns: ['*.ext','*.sql','*.sh']
register: find_list
- name:
debug: var=find_list
- name: test set fact
set_fact:
path_file: "{{ find_list.files | map(attribute='path') | list }}"
register: test_fact
- debug: var=test_fact
- name: test sql copy
copy:
src: "{{ test_fact.path}}"
dest: "/home/me/test/test_copy/sql"
owner: me
mode: 0755
when: ????
- name: test register
copy:
src: "{{ item.path }}"
dest: "/home/me/test/test_copy/"
owner: me
mode: 0755
with_items: "{{ find_list.files }}"
The test register is ok but the test sql copy i have no idea.
Any Ideas
Thanks
Only few changes are needed
- name: TEST COPY
hosts: localhost
gather_facts: false
tasks:
- name: Test Find
find:
paths: /home/me/test/find_cpy
file_type: file
recurse: yes
patterns: ['*.ext','*.sql','*.sh']
register: find_list
- name:
debug: var=find_list
- name: test set fact
set_fact:
path_file: "{{ find_list.files | map(attribute='path') | list }}"
# register: test_fact
Registered variable test_fact is not needed. The list of the paths has been stored in path_file.
- debug: var=path_file
- name: test sql copy
copy:
# src: "{{ test_fact.path}}"
src: "{{ item }}"
dest: "/home/me/test/test_copy/sql"
owner: me
mode: 0755
loop: "{{ path_file }}"
Loop the list of paths path_file and copy items to the destination.
- name: test register
copy:
# src: "{{ item.path }}"
src: "{{ item }}"
dest: "/home/me/test/test_copy/"
owner: me
mode: 0755
# with_items: "{{ find_list.files }}"
loop: "{{ path_file }}"
Loop find_list.files and item.path gives the same results as path_file and item. I'm not sure what the purpose of this task should be.

In Ansible loop, test existence of files from registered results

I have several files that I need to backup in different directories. I have tried the code below and not working for me.
vars:
file_vars:
- {name: /file1}
- {name: /etc/file2}
- {name: /etc/file/file3}
tasks:
- name: "Checking if config files exists"
stat:
path: "{{ item.name }}"
with_items: "{{ file_vars }}"
register: stat_result
- name: Backup Files
copy: src={{ item.name }} dest={{ item.name }}{{ ansible_date_time.date }}.bak
with_items: "{{ file_vars }}"
remote_src: yes
when: stat_result.stat.exists == True
The problem is the condition
when: stat_result.stat.exists == True
There is no attribute stat_result.stat. Instead, the attribute stat_result.results is a list of the results from the loop. It's possible to create a dictionary of files and their statuses. For example
- set_fact:
files_stats: "{{ dict(my_files|zip(my_stats)) }}"
vars:
my_files: "{{ stat_result.results|json_query('[].item.name') }}"
my_stats: "{{ stat_result.results|json_query('[].stat.exists') }}"
Then simply use this dictionary in the condition
when: files_stats[item.name]
Below is a shorter version which creates the dictionary more efficiently
- set_fact:
files_stats: "{{ dict(stat_result.results|
json_query('[].[item.name, stat.exists]')) }}"
Please try using below worked for me:
---
- name: Copy files
hosts: localhost
become: yes
become_user: root
vars_files:
- files.yml
tasks:
- name: "Checking if config files exists"
stat:
path: "{{ item }}"
with_items: "{{ files }}"
register: stat_result
- name: Ansible
debug:
msg: "{{ stat_result }}"
- name: Backup Files
copy:
src: "{{ item }}"
dest: "{{ item.bak }}"
with_items: "{{ files }}"
when: stat_result == "True"
and files.yml will look like:
---
files:
- /tmp/file1
- /tmp/file2
you can check you playbook syntax using below command:
ansible-playbook copy.yml --syntax-check
Also you do dry run your playbook before actual execution.
ansible-playbook -i localhost copy.yml --check

Run Ansible Task in localhost

I need to check one file (/tmp/test.html) exist on localhost and if it exist execute the other tasks.
Can you please help to run this first task (name: Check exist and copy) in localhost(workstation).
localhost: workstation
remotehost: servera,serverb
Below is my playbook.yml
---
- name: Check exist and copy
hosts: all
tasks:
- name: check if file is exists #need to execute this task in workstation
stat:
path: /tmp/test.html
register: file_present
- name: copy to taggroup 1
copy:
src: /tmp/test.html
dest: /tmp/dest1.html
when: file_present.stat.exists == 0 and inventory_hostname in groups ['taggroup1']
- name: copy to taggroup 2
copy:
src: /tmp/test.html
dest: /tmp/dest2.html
when: file_present.stat.exists == 0 and inventory_hostname in groups ['taggroup2']
Module stat is not needed when paths are tested at localhost. For example fail the play if the file /tmp/test.html does not exist and continue the play otherwise.
- hosts: all
vars:
my_file: '/tmp/test.html'
tasks:
- fail:
msg: "{{ my_file }} does not exist. End of play."
when: my_file is not exists
delegate_to: localhost
run_once: true
- debug:
msg: "Continue play."
run_once: true
Try the following:
---
- name: Check exist and copy
hosts: all
tasks:
- name: check if file is exists #need to execute this task in workstation
stat:
path: /tmp/test.html
register: file_present
delegate_to: localhost
- name: copy to taggroup 1
copy:
src: /tmp/test.html
dest: /tmp/dest1.html
when: file_present.stat.exists and inventory_hostname in groups ['taggroup1']
- name: copy to taggroup 2
copy:
src: /tmp/test.html
dest: /tmp/dest2.html
when: file_present.stat.exists and inventory_hostname in groups ['taggroup2']
See the docs.
You can use delegate_to: to run a task on a different machine than the current ansible_host.
Try following
---
- name: Check exist and copy
hosts: all
tasks:
- name: check if file is exists #need to execute this task in workstation
stat: path=/tmp/test.html
register: file_present
delegate_to: localhost
- name: copy to taggroup 1
copy:
src: /tmp/test.html
dest: /tmp/dest1.html
when: file_present.stat.exists and inventory_hostname in groups ['taggroup1']
- name: copy to taggroup 2
copy:
src: /tmp/test.html
dest: /tmp/dest2.html
when: file_present.stat.exists and inventory_hostname in groups ['taggroup2']
Thanks all for the great support. This is the fixed answer.
---
- name: Check exist and copy
hosts: all
tasks:
- name: check if file is exists #need to execute this task in workstation
stat:
path: /tmp/test.html
register: file_present
delegate_to: localhost
run_once_ true
- name: copy to taggroup 1
copy:
src: /tmp/test.html
dest: /tmp/dest1.html
when: file_present.stat.exists and inventory_hostname in groups ['taggroup1']
- name: copy to taggroup 2
copy:
src: /tmp/test.html
dest: /tmp/dest2.html
when: file_present.stat.exists and inventory_hostname in groups ['taggroup2']

How do you copy multiple files using remote_src in Ansible?

When I run the command remote_src: true I get the error
ERROR! 'remote_src' is not a valid attribute for a Task
I was wondering if there is a better way to write the code or if this is a bug
Tried to remove the offending line of code, however, the files exist on the remote host so I'm unable to copy the files into the correct location
- hosts: openvpn_server
vars:
file_vars:
- { name: ca }
- { name: server }
tasks:
- name: check if ca.crt and server.crt exists
stat:
path: /tmp/{{ item.name }}.crt
with_items: "{{ file_vars }}"
register: ensure_ca_crt_exists
- name: copying server.crt and ca.crt
become: true
copy: src={{ item.src }} dest={{ item.dest }}
with_items:
- { src: '/tmp/server.crt' , dest: '/etc/openvpn/server.crt' }
- { src: '/tmp/ca.crt' , dest: '/etc/openvpn/ca.crt' }
remote_src: true
when: ensure_ca_crt_exists.results
- name: creating Diffie-Hellman key to use during key exchange
shell: ./easyrsa gen-dh
args:
chdir: ~/EasyRSA-v3.0.6/
- name: Generating HMAC signature to strengthen servers TLS integrity
shell: openvpn --genkey --secret ta.key
- name: copying ta.key and dh.pem to /etc/openvpn
become: true
copy: src={{ item.src }} dest={{ item.dest }}
with_items:
- { src: '/home/dc/EasyRSA-v3.0.6/ta.key' , dest: '/etc/openvpn/ta.key' }
- { src: '/home/dc/EasyRSA-v3.0.6/dh.pem' , dest: '/etc/openvpn/dh.pem' }
I should be able to copy the file from the tmp folder to /etc/openvpn folder
via the remote_src command, apologizes for the badly configured register I'm fairly new to ansible
ERROR! 'remote_src' is not a valid attribute for a Task
Indentation is wrong
- name: copying server.crt and ca.crt
become: true
copy: src={{ item.src }} dest={{ item.dest }}
with_items:
- { src: '/tmp/server.crt' , dest: '/etc/openvpn/server.crt' }
- { src: '/tmp/ca.crt' , dest: '/etc/openvpn/ca.crt' }
remote_src: true
Correct
- name: copying server.crt and ca.crt
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
remote_src: true
loop:
- {src: '/tmp/server.crt', dest: '/etc/openvpn/server.crt'}
- {src: '/tmp/ca.crt', dest: '/etc/openvpn/ca.crt'}
become: true

looping using with_fileglob

How do i loop using "with_fileglob". I am trying to copy files matching wildcard, but with different permissions at the destination.
- hosts: myhost
gather_facts: no
tasks:
- name: Ansible copy test
copy:
src: "{{ item.origin }}"
dest: /home/user1/tmps/
owner: user1
mode: "{{item.mode}}"
with_fileglob:
- { origin: '/tmp/hello*', mode: '640'}
- { origin: '/tmp/hi*', mode: '600'}
It throws error as below:
An exception occurred during task execution. To see the full traceback, use
-vvv. The error was: AttributeError: 'dict' object has no attribute 'rfind'
I think the cleanest way is to implement this, would be a nested loop with include_tasks.
Where you main playbook file contains:
...
vars:
my_patterns:
- origin: "/tmp/hello*"
mode: "0640"
- origin: "/tmp/hi*"
mode: "0600"
tasks:
- include_tasks: "my_glob.yml"
with_items: "{{ my_patterns }}"
loop_control:
loop_var: my_pattern
...
and a subordinate my_glob.yml-tasks file:
---
- name: Ansible copy test
copy:
src: "{{ item }}"
dest: /home/user1/tmps/
owner: user1
mode: "{{ my_pattern.mode }}"
with_fileglob: "{{ my_pattern.origin }}"
Alternative method
Using Jinja2 to populate a list of objects { 'path': '...', 'mode': '...' }' based on fileglob-lookup plugin results.
vars:
my_patterns:
- origin: '/tmp/hello*'
mode: '0640'
- origin: '/tmp/hi*'
mode: '0600'
tasks:
- copy:
src: "{{ item.paht }}"
dest: /home/user1/tmps/
owner: user1
mode: "{{ item.mode }}"
with_items: "[{% for match in my_patterns %}{% for file in lookup('fileglob', match.origin, wantlist=True) %}{ 'path':'{{ file }}','mode':'{{ match.mode }}'}{% if not loop.last %},{% endif %}{% endfor %}{% if not loop.last %},{% endif %}{% endfor %}]"
The above works if patterns are matched, you'd need to add checks if the results are not empty.
according to the documentation, you cant pass to the fileglob a dictionary variable, adding the desired file permissions after copy as you have attempted (i mean the declaration { origin: '/tmp/hello*', mode: '640'}).
simple module call that will work for you:
- hosts: localhost
gather_facts: no
tasks:
- name: Ansible copy test
copy:
src: "{{ item }}"
dest: /SAMBA_ROOT/TEMP/
owner: root
with_fileglob:
- '/tmp/hello*'
- '/tmp/hi*'
if you want to have each of the file group have different file permissions, i suggest you use 2 different calls where the mode is "hardcoded", for example:
- hosts: localhost
gather_facts: no
tasks:
- name: copy hello files
copy:
src: "{{ item }}"
dest: /SAMBA_ROOT/TEMP/
owner: root
mode: 0640
with_fileglob:
- '/tmp/hello*'
- name: copy hi files
copy:
src: "{{ item }}"
dest: /SAMBA_ROOT/TEMP/
owner: root
mode: 0600
with_fileglob:
- '/tmp/hi*'

Resources