Use Jinja template for »value« - ansible

Within a playbook one can include Jinja Templated like so:
tasks:
name: 'Foo Bar'
template:
src: '~/tmpl/baz.j2'
dest: '/dev/null'
That renders the template and copies it over to the remote host. But is it possible to use a jinja template to generate a value for a module argument?
What I would like to do is:
tasks:
name: 'create server'
a_cloude_server_create:
…
user_data: "{{ render(./tmpl/cloud-init.yml.j2) }}"
…
Can that be done?

Use template lookup, as Ansible documentation is bad recently, check local docs for lookup plugin via ansible-doc -t lookup template.

Related

How to write a variable value in a file using ansible.builtin.template module?

I wanted to log content of a variable in a file. I did it like this,
- name: write infraID to somefile.log
copy:
content: "{{ infraID.stdout }}"
dest: somefile.log
And it worked. But in the documentation for copy here, I found that they have recommended to use template instead of copy in such cases.
For advanced formatting or if content contains a variable, use the
ansible.builtin.template module.
I went through the examples given at the documentation for template module here. But I was unable to figure out something that works in my scenario. Could you please show me how to do this properly in recommended way ?
Thanks in advance !! Cheers!
The template module does not have a content property.
You have to create a file that contains your template, for example:
templates/infra-id-template
{{ infraID.stdoud }}
playbook
---
- hosts: localhost
tasks:
- name: Get infra ID
shell: echo "my-infra-id"
register: infraID
- name: Template the file
template:
src: infra-id-template
dest: infra-id-file

Ansible - How to use lookup in remote servers

I have a file called values.txt on each of the server in the directory /tmp/values.txt and it has some values. And I have a jinja template and I am substituting some values from the the values.txt
But the problem is, when i use the lookup command it looks in the controller server and not the remote servers
Here's what I tried:
- name: Create /etc/systemd/system/etcd.service
template:
src: etcd.service.j2
dest: /etc/systemd/system/etcd.service
vars:
value_from_file: "{{ lookup('file', '/tmp/values.txt').split('\n') }}"
vars_from_jinja: [SELF_NAME, SELF_IP, NODE_1_NAME, NODE_1_IP, NODE_2_NAME, NODE_2_IP, NODE_3_NAME, NODE_3_IP, NODE_4_NAME, NODE_4_IP]
my_dict: "{{ dict(vars_from_jinja|zip(value_from_file)) }}"
How can I can this task remotely? Or is there another workaround to substitute the values to the jinja template?
PS: I can't fetch the values.txt to the controller because the content of values.txt in each server is slightly different from the other.
Can someone please help me?
The lookup find the file (or stream) on the controller. If you file is on the remote node, you can't use the lookup
Lookup plugins are an Ansible-specific extension to the Jinja2 templating language. You can use lookup plugins to access data from outside sources (files, databases, key/value stores, APIs, and other services) within your playbooks. Like all templating, lookups execute and are evaluated on the Ansible control machine. Ansible makes the data returned by a lookup plugin available using the standard templating system. You can use lookup plugins to load variables or templates with information from external sources.
try the cat file instead:
- name: read the values.txt
shell: cat /tmp/values.txt
register: data
- name: Create /etc/systemd/system/etcd.service
template:
src: etcd.service.j2
dest: /etc/systemd/system/etcd.service
vars:
value_from_file: "{{ data.stdout_lines }}"
vars_from_jinja: [ SELF_NAME, SELF_IP, NODE_1_NAME, NODE_1_IP, NODE_2_NAME, NODE_2_IP, NODE_3_NAME, NODE_3_IP, NODE_4_NAME, NODE_4_IP ]
my_dict: "{{ dict(vars_from_jinja|zip(value_from_file)) }}"
Use slurp:
- name: read remote values.txt
register: values
ansible.builtin.slurp:
src: /tmp/values.txt
- name: Create /etc/systemd/system/etcd.service
template:
src: etcd.service.j2
dest: /etc/systemd/system/etcd.service
vars:
value_from_file: "{{ (values.content | b64decode).split('\n') }}"
vars_from_jinja: [SELF_NAME, SELF_IP, NODE_1_NAME, NODE_1_IP, NODE_2_NAME, NODE_2_IP, NODE_3_NAME, NODE_3_IP, NODE_4_NAME, NODE_4_IP]
my_dict: "{{ dict(vars_from_jinja|zip(value_from_file)) }}"

Can I render ansible templates to a variable vs. to disk?

Is writing a file the only way to render an ansible template? In the past, with python and jinja2, I've rendered jinja templates to python vars directly and was hoping I can do the same with ansible.
What I'm trying to do is take the content of my template and pipe it to another command without writing the template to a file on disk and cat'ing the file. Doable?
You have several options for creating a variable from a template. For small templates, you can just use an inline template with set_fact:
- name: render a template to a variable
set_fact:
myvar: |-
This is a template.
This host is {{ inventory_hostname }}.
For longer templates, you can use the template lookup:
- name: render a template to a variable
set_fact:
myvar: "{{ lookup('template', 'template_name.j2') }}"
And of course this isn't limited to the set_fact module. You can do this anywhere you can put a string value in Ansible.

How do I save an ansible variable into a temporary file that is automatically removed at the end of playbook execution?

In order to perform some operations locally (not on the remote machine), I need to put the content of an ansible variable inside a temporary file.
Please note that I am looking for a solution that takes care of generating the temporary file to a location where it can be written (no hardcoded names) and also that takes care of the removal of the file as we do not want to leave things behind.
You should be able to use the tempfile module, followed by either the copy or template modules. Like so:
- hosts: localhost
tasks:
# Create a file named ansible.{random}.config
- tempfile:
state: file
suffix: config
register: temp_config
# Render template content to it
- template:
src: templates/configfile.j2
dest: "{{ temp_config.path }}"
vars:
username: admin
Or if you're running it in a role:
- tempfile:
state: file
suffix: config
register: temp_config
- copy:
content: "{{ lookup('template', 'configfile.j2') }}"
dest: "{{ temp_config.path }}"
vars:
username: admin
Then just pass temp_config.path to whatever module you need to pass the file to.
It's not a great solution, but the alternative is writing a custom module to do it in one step.
Rather than do it with a file, why not just use the environment? This wan you can easily work with the variable and it will be alive through the ansible session and you can easily retrieve it in any steps or outside of them.
Although using the shell/application environment is probably, if you specifically want to use a file to store variable data you could do something like this
- hosts: server1
tasks:
- shell: cat /etc/file.txt
register: some_data
- local_action: copy dest=/tmp/foo.txt content="{{some_data.stdout}}"
- hosts: localhost
tasks:
- set_fact: some_data="{{ lookup('file', '/tmp/foo.txt') }}"
- debug: var=some_data
As for your requirement to give the file a unique name and clean it up at the end of the play. I'll leave that implementation to you

Ansible playbook vars not working in templates

I have problem getting variables work in my templates. Variables work in my playbook but in templates, they are rendered 'as is' without getting replaced by their values. Here is a simple test-playbook.yml that I am trying.
---
- name: Test playbook vars
hosts: webservers
vars:
hello_var: Hello World
hello_file_path: /tmp/hello_file.txt
tasks:
- name: Copy hello world file
copy: src=templates/hello_world.txt.j2 dest={{ hello_file_path }}
In my templates/hello_world.txt.j2, I have the following contents
hi {{ hello_var }}
After running the playbook, I have on the host at /tmp/hello_world.txt the same content as in my template
hi {{ hello_var }}
The variable hello_file_path used in the playbook works but the variable hello_var used in my template is not working.
Inside the task you using copy module which simply copies the file without any template processing. In order to use template you need to use template module.
- name: Copy hello world file
template: src=templates/hello_world.txt.j2 dest={{ hello_file_path }}

Resources