Variable state depending on existence of a file on host system - possible?

I’m currently having a var in my ./vars/default.yml, which is used at several points in my playbook for branching installation operations.

boolean_var: true

Depending on this I’m performing (or not) install steps


when: not boolean_var

So far so good. I’m also using this var in some j2 templates like so:

{% if boolean_var %}

{% endif %}

My problem is, that I mostly forget to set this variable to a proper state, which reflects the real status on the host system, so I have to abort an update.
I would rather like to derive it from a pre_task, checking the existence of a particular file on the host before starting all operations.

Is there a way to define a variable with the same scope (playbook and templates) at runtime?

You could use the assert task to check that the variable exist before starting the run

It is not the problem of existence. The var exists all the time. It is about the wrong state

Use stat module to get your required facts. Bring it into assert or fail

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/stat_module.html

Well, yes. I know, how to stat a file. I don’t know how to create a variable from that with the same scope as a variable defined in default.yml.

I thought I was precise enough. Never mind. Disregard my question. Will find it out.

It is the example. Register

Looks pretty verbose. I have some doubts to be able to use this in a .j2 file.

Why put in a jinja file? Run the assertion first in the role task /fail exit etc. Then run the template task

It is a grown project, I can’t change everything just because of this.

Anyway, if it is not possible, then ok. I can live with the glitch

Can’t see why you can’t just run it before the template task. But your choice really.

Exactly. Thanks

Well it is easier as I thought. Should have tried by myself before having asked here. Sharing the result. Still need to derive the var from the file stat, but hoping it is possible:

test.yml:

ansible-playbook -l offline -i hosts.cfg test.yml

  • hosts: all

vars:
test: true

tasks:

  • name: Copy config file, when test is defined
    tags: copy
    template:
    src: templates/test.j2
    dest: test.cfg
    when: test

  • name: Copy config file, when test is not defined
    tags: copy
    template:
    src: templates/test.j2
    dest: test.cfg
    when: not test

templates/test.j2:

{% if test %}
Test is defined
{% else %}
Test is not defined
{% endif %}

A run with test=true skips the second copy task (as desired) and produces a file, which states “Test is defined” (as desired). The other way around with test=false

And this is all I wanted:

ansible-playbook -l offline -i hosts.cfg test.yml

./test.yml:

  • hosts: all

pre_tasks:

Test if there was a previous source installation of KMS

  • name: Test if there was a KMS source installation running before
    stat:
    path: ~/.kms_installed_from_source
    register: kms_trace

vars:
kms_installed_from_source: ‘{{ true if (kms_trace.stat.exists) else false }}’

tasks:

  • name: Copy config file, when kms_installed_from_source is defined
    tags: copy
    template:
    src: templates/test.j2
    dest: test.cfg
    when: kms_installed_from_source

  • name: Copy config file, when kms_installed_from_source is not defined
    tags: copy
    template:
    src: templates/test.j2
    dest: test.cfg
    when: not kms_installed_from_source

  • name: Print
    debug:
    msg:

  • ‘Status of “kms_installed_from_source”: {{ kms_installed_from_source}}’

./templates/test.j2:

{% if kms_installed_from_source %}
kms_installed_from_source is defined
{% else %}
kms_installed_from_source is not defined
{% endif %}

Works

Which is if you look closely what I wrote. Similar to what I said :blush:. Register the results from stat. Feed that into template. Thank you for taking my suggestion.

Maybe I didn’t get it

Indeed. Glad that you got it sorted.

Hii

And this is all I wanted:

# ansible-playbook -l offline -i hosts.cfg test.yml

./test.yml:

- hosts: all

pre_tasks:
# Test if there was a previous source installation of KMS
- name: Test if there was a KMS source installation running before
stat:
path: ~/.kms_installed_from_source
register: kms_trace

vars:
kms_installed_from_source: '{{ true if (kms_trace.stat.exists) else false }}'

You have the 'vars' section after 'pre_tasks', giving the impression
that this matters, while it doesn't.
It can be anywhere.
However, while it can be listed anywhere, it won't always work,
because kms_installed_from_source won't be available if used in tasks
that are earlier than the 'stat' task.

Things will be less ambiguous if you use a set_fact task, so it is
clear where the variable is actually set.

Regarding 'pre_tasks' (as well as post_tasks), I find those somewhat
confusing. I always have just 'tasks' and then the order of the tasks
is as they appear in that list. I'm saying because I've seen
post_tasks being put at the beginning, and the other way around.

The "true if (kms_trace.stat.exists) else false" is unnecessary as
stat.exists is already a boolean.
Concluding, if you must use a dedicated variale, then this task (as
part of just 'tasks') should be sufficient:

- set_fact:
     kms_installed_from_source: '{{ kms_trace.stat.exists }}'

Obviously the stat task needs to be executed before this. But if
that's listed in that order, there is no ambiguity.

DIck

Hi Dick,
Thanks for your elaborated answer.

The reason for having vars after stat is that I feared the “not defined” issue. I never tried to have vars before, but since I will try your set_fact approach, this doesn’t matter either.

Thanks.

Yepp. Works. Many thanks. I also tried to simplify my true/false derivation before to no avail, but now it works.
Thanks

pre_task btw is just to have a means to print out some installation variables for quick check in order to be able to react and abort the installation, if something is not as desired.

It is also quite handy, if you for instance use foreign roles (like geerlinguys node js installer). That needs an apt-cache update on bionic, before the role jumps in. So I sometimes find it helpful to have an early quick spot on something.