Can't copy files using loop - ansible

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.

Related

Resursively sync files and links to multiple users, preserving permissions, but not owner and group

I have a directory with several tools and text files that I would like to copy to multiple users homedirs on given host. There are couple of caveats:
I don't want to list the files in playbook
Some files are executable, some are not
I want the files to be owned by their respective users
I want the symlinks to be copied as-is
When pushing to ansible_user home dir, there's no issue as ansible.posix.synchronize does the job very well with archive=true and owner/group set to false:
- name: Sync testing_files repo to ansible_user
ansible.posix.synchronize:
src: ~/testing_files/
dest: ~/testing_files/
mode: push
archive: true
delete: true
owner: false
group: false
register: rsync_output
The links are properly handled as well (they are rsynced as symlinks).
However, the problem is with populating the same for other users. I tried the following approach:
- name: Sync testing_files repo to extra_users
ansible.builtin.copy:
src: ~/testing_files/
dest: ~{{ item }}/testing_files/
remote_src: true
mode: preserve
owner: "{{ item }}"
follow: true # I tried with `false` as well
with_items:
- "{{ extra_users if extra_users is not none else [] }}"
The file permissions are correct, the owner as well, however:
the group of file remains the same as source file
the symlinks are ignored
How can I make it work? For the group issue the only solution I came up is to have another task that will run stat to check group and save it for future use, e.g. like this:
- name: Get group of homedir
ansible.builtin.stat:
path: "~{{ item }}"
register: homedir
with_items:
- "{{ extra_users_or_empty }}"
- name: Sync testing_files repo to extra_users
ansible.builtin.copy:
src: ~/testing_files/
dest: "~{{ item }}/testing_files/"
remote_src: true
mode: preserve
owner: "{{ item }}"
group: "{{ homedir.results | selectattr('item', 'eq', item) | map(attribute='stat.gr_name') | first }}"
follow: true
with_items:
- "{{ extra_users_or_empty }}"
(NOTE: extra_users_or_empty: "{{ extra_users if extra_users is not none else [] }}")
However that feels like something that should be achieved in more elegant way. And for symlinks - I have no idea why the ansible.builtin.copy ignores them.
Any ideas?
Huh, ok, seems like when we're using remote_src, we should set local_follow, instead of follow. The following solution handles symlinks properly:
- name: Get group of homedir
ansible.builtin.stat:
path: "~{{ item }}"
register: homedir
with_items:
- "{{ extra_users_or_empty }}"
- name: Sync testing_files repo to extra_users
ansible.builtin.copy:
src: ~/testing_files/
dest: "~{{ item }}/testing_files/"
remote_src: true
mode: preserve
owner: "{{ item }}"
group: "{{ homedir.results | selectattr('item', 'eq', item) | map(attribute='stat.gr_name') | first }}"
local_follow: false
with_items:
- "{{ extra_users_or_empty }}"

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)

Anisble: get dynamic register from with_items

I've tried to create a register using with_items that can dynamically change with any added item.
- name: Set Openfile for specific user in /etc/security/limits.d/{{ user }}
copy:
dest: /etc/security/limits.d/"{{ item }}"
content: |
"{{ item }}" - nofile 128000
"{{ item }}" - nproc 65536
with_items:
- kube
register: ?
In the code above, I wanted to create a file in /etc/security/limits.d/{{user in with_items}} and store that value in register. So in this case, value in item will be 'kube'.
- name: set permission and change owner of /etc/security/limits.d/{{ user }}
file:
path: /etc/security/limits.d/"{{ user }}"
owner: root
group: root
mode: '0644'
Later, I want to change the directory permissions I've created so it will be /etc/security/limits.d/kube
How can I specify path in file module from the earlier register got from with_items in the copy module above?
Thanks
- name: Set Openfile for specific user in /etc/security/limits.d/{{ user }}
copy:
dest: "/etc/security/limits.d/{{ item }}"
content: |
"{{ item }}" - nofile 128000
"{{ item }}" - nproc 65536
with_items:
- kube
register: output
- debug:
msg: "{{item.item}}"
loop: "{{output.results}}"
loop_control:
label: "{{item.item}}"
- name: set permission and change owner of /etc/security/limits.d/{{ user }}
file:
path: "/etc/security/limits.d/{{ item.item }}"
owner: root
group: root
mode: '0644'
with_items:
"{{output.results}}"
Make sure to run this with become: yes. we are storing the output in the "output variable". if there are multiple values in with items. it will store the multiple items output in the output variable(output.results). the output.results was giving the complex data structure output. so i have use loop_control(lable) to limit the output. the item.item give the output kube.

How to create the multiple symlinks for the folders/files under the same source

I want to create the folder: temp2 which is able to store all the symlinks of the subfolders/files of other foder: temp1. with_items can help complete this task, but it needs to list down all the folder/file name as below script shown:
- name: "create folder: temp2 to store symlinks"
file:
path: "/etc/temp2"
state: directory
- name: "create symlinks & store in temp2"
file:
src: "/etc/temp1/{{ item.src }}"
dest: "/etc/temp2/{{ item.dest }}"
state: link
force: yes
with_items:
- { src: 'BEAM', dest: 'BEAM' }
- { src: 'cfg', dest: 'cfg' }
- { src: 'Core', dest: 'Core' }
- { src: 'Data', dest: 'Data' }
It is not flexible as the subfolders/files under temp1 would be added or removed, and I need to update above script frequently to keep the symlinks as updated
Is there any way to detect all the files/folder under temp1 automatically instead of maintaining the with_items list?
The following code works under Ansible-2.8:
- name: Find all files in ~/commands
find:
paths: ~/commands
register: find
- name: Create symlinks to /usr/local/bin
become: True
file:
src: "{{ item.path }}"
path: "/usr/local/bin/{{ item.path | basename }}"
state: link
with_items: "{{ find.files }}"
You can create a list of files using find module:
Return a list of files based on specific criteria. Multiple criteria are AND’d together.
You'll likely need to leave recurse set to false (default) since you assume subfolders might exist.
You need to register the results of the module with register declaration:
register: find
In the next step you need to iterate over the files list from the results:
with_items: "{{ find.results.files }}"
and refer to the value of the path key. You already know how to do it.
You will also need to extract the filename from the path, so that you can append it to the destination path. Use basename filter for that.

Resources