Ansible & Jinja2 - Place template in directory per variable - ansible

Got a question which is hard to describe, suggestions for improvement to make this question more understandable is appreciated.
Goal:
First set a variable for a single template, then set a destination based on the variable set. Based on one template. I'd like to avoid using multiple templates for each directory.
Example: my_jinja.j2contains:
a line of code
/path{{ variable }}/something
another line of code
I want to set the template in the directory which is set with variable.
If variable contains:
- /tmp
- /var
If /tmp is set, the template should be set in /foo
If /var is set, I want to the template placed in /bar
The template for /tmp should look like:
a line of code
/path/tmp/something
another line of code

Worth a try:
template:
a line of code
/path{{ path_var }}/something
another line of code
var:
my_list:
- path: /tmp
dest: /foo
- path: /var
dest: /bar
task:
- template:
src: my_jinja.j2
dest: "/path/to/{{ item.dest }}"
vars:
path_var: "{{ item.path }}"
with_items: "{{ my_list }}"

Related

Error in launching ansible playbook with roles

trying to do playbook:
- hosts: win
gather_facts: no
roles:
- update_win
update_win mail.yml:
- name: Create Auto_deploy_temp folder on remoter host
win_file:
path: {{ disk }}\Auto_deploy_temp
state: directory
and vars in group vars file win.yml:
disk: 'c:'
but getting out:
ERROR! Syntax Error while loading YAML.
did not find expected key
The error appears to be in '/etc/ansible/roles/update_win/tasks/main.yml': line 3, column 19, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
win_file:
path: {{ disk }}\Auto_deploy_temp
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
can u help me with this issue?
P.S.: earlier i've launched some similar code, but there were no vars in the start of path expression, only in the end
Please provide path: "{{ disk }}\Auto_deploy_temp"
Update
Create a new var as path_dir: \Auto_deploy_temp, and use
path: "{{disk}}{{path_dir}}"
or
path: "{{ disk }}\\Auto_deploy_temp"
Escape '\'
win_file:
path: {{ disk }}\\Auto_deploy_temp

Ansible: remove files and folders while excluding some

In my Ansible Playbook I'd like to have a task that removes old files and folders from the application's directory. The twist to this otherwise simple task is that a few files or folders need to remain. Imagine something like this:
/opt/application
- /config
- *.properties
- special.yml
- /logs
- /bin
- /var
- /data
- /templates
Let's assume I'd like to keep /logs completely, /var/data and from /config I want to keep special.yml.
(I cannot provide exact code at the moment because I left work frustrated by this and, after cooling down, I am now writing up this question at home)
My idea was to have two lists of exclusions, one holding the folders and one the file. Then I use the find module to first get the folders in the application's directory into a variable and the same for the remaining files into another variable. Afterwards I wanted to remove every folder and file that are not in the lists of exclusions using the file module.
(Pseudo-YML because I'm not yet fluent enough in Ansible that I can whip up a properly structured example; it should be close enough though)
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ found_files_list.files }}"
when: well, that is the big question
What I can't figure out is how to properly construct the when clause. Is it even possible like this?
I don't believe there is a when clause with the file module.
But you can probably achieve what you need as follows:
- name: Find /opt/application all directories, exclude logs, data, and config
find:
paths: /opt/application
excludes: 'logs,data,config'
register: files_to_delete
- name: Ansible remove file glob
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ files_to_delete.files }}"
I hope this is what you need.
First use the find module like you said to get a total list of all files and directories. Register to a variable like all_objects.
- name: Get list of all files recursively
find:
path: /opt/application/
recurse: yes
register: all_objects
Then manually make a list of things you want to keep.
vars:
keep_these:
- /logs
- /var/data
- /config/special.yml
Then this task should delete everything except things in your list:
- name: Delete all files and directories except exclusions
file:
path: "{{ item.path }}"
state: absent
recurse: true
with_items: "{{ all_objects.files }}"
when: item.path not in keep_these
I think this general strategy should work... only thing I'm not sure about is the exact nesting heiararchy of the registered variable from the find module. You might have to play around with the debug module to get it exactly right.

Ansible: customizable template filenames

I'm writing an Ansible role where I have some templates that must be present multiple times with different names in a single destination directory. In order not to have to handle each of these files separately I would need to be able to apply templating or some other form of placeholder substitution also to their names. To give a concrete example, I might have a file named
{{ Client }}DataSourceContext.xml
which I need to change into, say,
AcmeDataSourceContext.xml
I have many files of this kind that have to be installed in different directories, but all copies of a single file go to the same directory. If I didn't need to change their names or duplicate them I could handle a whole bunch of such files with something like
- name: Process a whole subtree of templates
template:
src: "{{ item.src }}"
dest: "/path/to/{{ item.path }}"
with_filetree: ../templates/my-templates/
when: item.state == 'file'
I guess what I'd like is a magic consider_filenames_as_templates toggle that turned on filename preprocessing. Is there any way to approximate this behaviour?
Pretty much anywhere you can put a literal value in Ansible you can instead substitute the value of a a variable. So for example, you could do something like this:
- template:
src: sometemplate.xml
dest: "/path/to/{{ item }}DataSourceContext.xml"
loop:
- client1
- client2
This would end up creating templates
/path/to/client1DataSourceContext.xml and
/path/to/client2DataSourceContext.xml.
Update 1
For the question you've posed in your update:
I guess what I'd like is a magic consider_filenames_as_templates toggle that turned on filename preprocessing. Is there any way to approximate this behaviour?
It seems like you could just do something like:
- name: Process a whole subtree of templates
template:
src: "{{ item.src }}"
dest: "/path/to/{{ item.path.replace('__client__', client_name) }}"
with_filetree: ../templates/my-templates/
when: item.state == 'file'
That is, replace the string __client__ in your filenames with the
value of the client_name variable.

Ansible - How loop over registered

I'm using the module stat for checking if some files exists in a remote server and registering their result in a variable. i.e. config files I'm looking for: conf_dev.conf, conf_pred.conf, conf_pro.conf.
Later I'm using the copy module for transfering only the files that are missing using a conditional based on an attribute stored in
variable.results.{{(ITEM)index}}.stat.exists.
This returnsTRUE if file exists and FALSE if does not.
For running properly As the register variable is an array there are an index storing the result for each file I'm asking so I don't know how to convert the item in a index (0,1,2,3)
Does anyone know how to get the index of an item? I've tried this (look at the last line):
- name: Checking if common configuration files exists
stat:
path: "{{HOME_COMUN_CONFIG}}/{{item}}"
with_items: "{{LIST_COMMON_CONFIGURATION_ARTIFACTS}}"
register: store_results
- name: debug existe_app_comun
debug:
var: store_results
- name: Deploying missing files
copy:
src: "{{DIRTEMP_COMUN_CONFIG}}/{{item}}"
dest: "{{HOME_COMUN_CONFIG}}/{{item}}"
with_items: "{{LIST_COMMON_CONFIGURATION_ARTIFACTS}}"
when: existe_app_comun.results.{{index(item)}}.stat.exists is defined
Why do you loop over LIST_COMMON_CONFIGURATION_ARTIFACTS if you want to loop over registered variable?
- name: Deploying missing files
copy:
src: "{{DIRTEMP_COMUN_CONFIG}}/{{ item.item }}"
dest: "{{HOME_COMUN_CONFIG}}/{{ item.item }}"
with_items: "{{ existe_app_comun.results }}"
when: item.stat.exists
Here item is an element of results and item.item is an element of original loop.
P.S. if files at destination folder are not modified and should be same as in DIRTEMP_COMUN_CONFIG, then you must not use stat+copy, but just use copy – because it's idempotent and will not copy the same file twice.

Ansible Playbook - Synchronize module - Register variable and with_items

I'm trying to write a playbook that will rsync the folders from source to target after a database refresh. Our Peoplesoft HR application also requires a filesystem refresh along with database. I'm new to ansible and not an expert with python. I've written this but my playbook fails if any of the with_items doesn't exist. I'd like to use this playbook for all apps and the folders may differ between apps. How can I skip the folders that doesn't exist in source. I'm passing {{ target }} at command line.
---
- hosts: '<hostname>'
remote_user: <user>
tasks:
- shell: ls -l /opt/custhome/prod/
register: folders
- name: "Copy PROD filesystem to target"
synchronize:
src: "/opt/custhome/prod/{{ item }}"
dest: "/opt/custhome/dev/"
delete: yes
when: "{{ folders == item }}"
with_items:
- 'src/cbl/'
- 'sqr/'
- 'bin/'
- 'NVISION/'
In this case, NVISION doesn't exist in HR app but it does in FIN app. But the playbook is failing coz that folder doesn't exist in source.
You can use find module to find and store paths to source folders and then to iterate over results. Example playbook:
- hosts: '<hostname>'
remote_user: <user>
tasks:
- name: find all directories
find:
file_type: directory
paths: /opt/custhome/prod/
patterns:
- "src"
- "sqr"
- "bin"
register: folders
#debug to understand contents of {{ folders }} variable
# - debug: msg="{{ folders }}"
- name: "Copy PROD filesystem to target"
synchronize:
src: "{{ item.path }}"
dest: "/opt/custhome/dev/"
delete: yes
with_items: "{{ folders.files }}"
You may want to use recurse to descend into subdirectories and use_regex to use the power of python regex instead of shell globbing.

Resources