Ansible write on file from jinja file - variables

I want to lanch a application :
command=/usr/bin/toto --config /var/toto/conf1.json /var/toto/conf2.json /var/toto/conf3.json
the config file are on /var/toto directory
task.yml
- name: Ansible find file
find:
paths: "/var/toto"
register: found_files
- name: print files
debug:
msg: "{{ found_files['files'] | map(attribute='path') | map('regex_replace','^.*/(.*)$','\\1') | list }}"
register: file_name
- name: Create the Jinja2 based template
template:
src: "etc/control/config.conf.j2"
dest: "/etc/control/config.conf"
with_dict: "{{ file_name }}"
config.conf.j2
command=/usr/bin/toto --config {% for item in file_name %} /var/toto/{{ item }} {% endfor %}
but, I have get this on my file
/etc/control/config.conf
command=/usr/bin/toto --config /var/opt/msg /var/opt/failed /var/opt/changed
varfile_name :
"msg": [ "conf1.json", "conf2.json", "conf3.json"
]

You're iterating over the dictionary in file_name, which is a task result. If you were to print that out, you would find that it contains something like:
TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => {
"file_name": {
"changed": false,
"failed": false,
"msg": [
"file1",
"file2",
"file3"
]
}
}
So when you iterate over it using for item in file_name, you're iterating over the top level keys (changed, failed, msg).
But this is all the wrong way to do it. You never use the debug module to create variables; that's what set_fact is for. You want something like:
- name: build list of files
set_fact:
file_name: "{{ found_files['files'] | map(attribute='path') | map('regex_replace','^.*/(.*)$','\\1') | list }}"
- name: Create the Jinja2 based template
template:
src: "config.conf.j2"
dest: "config.conf"
After the set_fact task, the variable file_name will contain a
list of file names.
It looks like you're using that regular expression to get the basename
of the files found in your find task. There's a basename filter
that can do that with less complexity:
- name: print files
set_fact:
file_name: "{{ found_files['files'] | map(attribute='path') | map('basename') | list }}"
- name: Create the Jinja2 based template
template:
src: "config.conf.j2"
dest: "config.conf"
Here's the playbook I'm using to test this locally:
- hosts: localhost
gather_facts: true
tasks:
- name: find files
find:
paths: /tmp/example
register: found_files
- name: print files
set_fact:
file_name: "{{ found_files['files'] | map(attribute='path') | map('basename') | list }}"
- name: Create the Jinja2 based template
template:
src: "config.conf.j2"
dest: "config.conf"
Before running this, I run:
mkdir /tmp/example
touch /tmp/exampe/file{1,2,3}
This produces a config.conf file that looks like:
command=/usr/bin/toto --config /var/toto/file3 /var/toto/file2 /var/toto/file1

Related

Build a variable in a playbook with the hostname and call it in a task

I have a two main variable with subvariables. The main variable VELABx and VELABy match the ansible_hostnames. Following an example of the variables mentioned:
VELABx
location: "text1.1"
initialism: "text1.2"
VELABy
location: "text2.1"
initialism: "text2.2"
Now I'd like to run a task which replaces a regexp with the location variable based on the current ansible_hostname. So, I tried this code, but it leads into an error.
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ {{ansible_hostname}}.location }}"
remote_user: rssuser
become: no
when: ansible_hostname == "VELABx"
What am I doing wrong? How can I solve this? Can anyone bring up a solution?
Things are always easier when you manage to create a proper structure of data. For example, given the dictionaries in a file
shell> cat velab.yml
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
you can include the data from the file into a dictionary, e.g.
- hosts: VELABx,VELABy,VELABz
tasks:
- include_vars:
file: velab.yml
name: velab
run_once: true
- debug:
var: velab
run_once: true
gives
velab:
VELABx:
initialism: text1.2
location: text1.1
VELABy:
initialism: text2.2
location: text2.1
The data you provided in the question are not YAML dictionaries. The colon is missing behind the keys. Either fix it, if you can or parse the file. Anyway, create the dictionary whatever is the source.
Then, given the files
shell> ssh admin#10.1.0.61 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.62 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.63 cat /tmp/velab.txt
location
the task to replace the location is simple
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location'] }}"
when: velab[inventory_hostname] is defined
gives
shell> ansible-playbook playbook.yml -CD
PLAY [VELABx,VELABy,VELABz] ******************************************
...
TASK [Replace location for VELAB*] ***********************************
skipping: [VELABz]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text1.1
changed: [VELABx]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text2.1
changed: [VELABy]
The next option is to remove the condition and use the default value, instead of skipping the host, when the host is missing in the dictionary
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location']|
default(default_location) }}"
vars:
default_location: "text99.1"
you must use loopkup, {{}} inside other {{}} is incorrect
---
- hosts: localhost
gather_facts: false
vars:
ansible_hostname: VELABx
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
tasks:
- name: DEBUG
debug:
msg: "{{ lookup('vars', ansible_hostname ).location }}"
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ lookup('vars', ansible_hostname ).location }}"
when: ansible_hostname == "VELABx"

Ansible use variables in tags option

my ansible tasks/main.yml looks like this atm:
---
- name: Create Directories
file:
path: "{{ item.path }}"
recurse: yes
owner: "{{ item.owner | default(\"nobody\") }}"
group: "{{ item.group | default(\"nogroup\") }}"
state: directory
with_items:
- "{{ app_dirs }}"
- name: Move Templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner | default(\"nobody\") }}"
group: "{{ item.group | default(\"nogroup\") }}"
with_items: "{{ app_templates }}"
- name: Move Dependencies
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner | default(\"nobody\") }}"
group: "{{ item.group | default(\"nogroup\") }}"
with_items: "{{ app_dependencies }}"
I have to move a couple of dependencies and templates to the remote machine. Now I need to add some conditionals or tags so we can decide if we want to copy all depedencies or just a few of them. I tried it like this:
- name: Create Directories
file:
path: "{{ item.path }}"
recurse: yes
owner: "{{ item.owner | default(\"nobody\") }}"
group: "{{ item.group | default(\"nogroup\") }}"
state: directory
tags: "{{ item.tag }}"
with_items:
- "{{ app_dirs }}"
But Ansible throws this error: ERROR! 'item' is undefined. Probably the tags option has to be inside the "file" block so with_items knows where to item.tag from. But the tags option has to be intended like that. Is there a way to use variables for the tags options? I actually liked the structure of this tasks/main.yml, it was easier to handle all variables in one place. My other idea was to create blocks with when conditions like this:
tasks:
- name: Install app1
block:
- name: Create Directory
file:
....
- name: Move Templates
template:
....
- name: Move Dependencies
copy:
....
tags:
- app1
- name: Install app2
block: .....
With this approach I can't store all variables as a dictonary like before. If there is no other way I'll use the block approach but I hope that someone has a better idea. Thanks in advance!

How can i fix this playbook

how can i use service_name in the condition, i tryed with set_fact but it doesn't work.
- name: "create systemd service"
template:
src: "service.j2"
dest: "/etc/systemd/system/{{ systemd_service[item].service_name | default(item) }}.service"
set_fact: service_name= "{{ systemd_service[item].service_name }}"
with_items: "{{ systemd_service | list }}"
when:
- service_name == "oracle"
set_fact is the name of a module; it's not an argument to the template module. Fortunately, you don't need it; you can just write:
- name: "create systemd service"
template:
src: "service.j2"
dest: "/etc/systemd/system/{{ systemd_service[item].service_name | default(item) }}.service"
with_items: "{{ systemd_service | list }}"
when:
- systemd_service[item].service_name == "oracle"
- env_vars.stdout.find('ORACLE=True') != -1

Using variables from one yml file in another playbook

I am new to ansible and am trying to use variables from a vars.yml file in a playbook.yml file.
vars.yml
---
- firstvar:
id: 1
name: One
- secondvar:
id: 2
name: two
playbook.yml
---
- hosts: localhost
tasks:
- name: Import vars
include_vars:
file: ./vars.yml
name: vardata
- name: Use FirstVar
iso_vlan:
vlan_id: "{{ vardata.firstvar.id }}"
name: "{{ vardata.firstvar.name }}"
state: present
- name: Use Secondvar
iso_vlan:
vlan_id: "{{ vardata.secondvar.id }}"
name: "{{ vardata.secondvar.name }}"
state: present
So you can see here I am treating the imported variable data, which is stored in vardata, as object and trying to call each of them in other tasks. I am pretty sure these imported vars at the first task are only available in that very task. How can I use that in other tasks? It would output as variables undefined for each tasks. Any input is appreciated.
Your vars.yml file isn't formatted correctly.
Try this:
---
firstvar:
id: 1
name: One
secondvar:
id: 2
name: two
I used this to test it:
---
- hosts: localhost
tasks:
- name: Import vars
include_vars:
file: ./vars.yml
name: vardata
- name: debug
debug:
msg: "{{ vardata.firstvar.name }}"
- name: more debug
debug:
msg: "{{ vardata.secondvar.id }}"
On top of the error you made when declaring the variables (syntax is very important), you can also define include_vars: ./vars.yml such that you can just call {{ firstvar.name }}, {{ firstvar.id }} immediately. Much more leaner/shorter.

Multiple Ansible archive(s) are not created

im trying to create 2 archives out of 2 folders by using archive module.
Unfortunately it´s not working without any error.
My tasks looks like this:
tasks:
- name: create a tarball of logfiles
archive:
path: "{{ item.path }}"
dest: /tmp/{{ ansible_hostname }}_{{ item.name }}_{{ ansible_date_time.date }}.tar.gz
register: ausgabe
with_items:
- { name: 'xxxxxx', path: '/opt/jira/xxx/xxxxxx' }
- { name: 'xxxxxxx', path: '/opt/jira/xxxx/xxxxxxx' }
Output:
TASK [create a tarball of logfiles] ************************************************************************************************************************************************
ok: [xxxxxxx] => (item={u'path': u'/opt/jira/xxx/xxxx', u'name': u'xxxxx'})
ok: [xxxxxxx] => (item={u'path': u'/opt/jira/xxx/xxxx', u'name': u'xxxxxx'})
The tar.gz files are not created.
Can somebody help me on this?
Thx
Harry
Whenever you are using variables or 'templating' your playbook make sure that you use " (inverted-commas) properly.
I have modified your archive module's statements and I got the required result.
archive:
dest: "/tmp/{{ ansible_hostname }}_{{ item.name }}_{{ ansible_date_time.date }}.tar.gz"
path: "{{ item.path }}"
Output:
myHost_xxxxxx_2018-06-12.tar.gz
myHost_xxxxxxx_2018-06-12.tar.gz