1

I want to execute tasks only if a file exists on the target.

I can do that, of course, with

- ansible.builtin.stat:
  path: <remote_file>
  register: remote_file

- name: ...
  something:
  when: remote_file.stat.exists

but is there something smaller?

You can, for example, check files on the host with

when: '/tmp/file.txt' is file

But that only checks files on host.

Is there also something like that available for files on remotes?


Added, as according the comment section I need to be bit more specific.

I want to run tasks on the target, and on the next run, they shouldn´t be executed again. So I thought to put a file somewhere on the target, and on the next run, when this file exists, the tasks should not be executed anymore.

- name: do big stuff 
  bigsgtuff:
  when: not <file> exists 

They should be executed, if the file does not exists.

U880D
  • 8,601
  • 6
  • 24
  • 40
Wurzelseppi
  • 95
  • 1
  • 10
  • 1
    Please ground your example to a real use case rather than being evasive with pseudo code. Which kind of module do you want to play in your task exactly ? a shell task ? Some modules have a `creates` option which will let you skip the task if the given file already exists on host. In other cases, the only good option I know is the one your already described. Else using custom facts as described in U880D answer can be an option. – Zeitounator Feb 10 '22 at 21:29

1 Answers1

2

I am not aware of a way to let the Control Node know during templating or compile time if there exist a specific file on Remote Node(s).

I understand your question that you

... want to execute tasks on the target ...

only if a certain condition is met on the target.

This sounds to be impossible without taking a look on the target before or do a lookup somewhere else, in example in a Configuration Management Database (CMDB).

... is there something smaller?

It will depend on your task, what you try to achieve and how do you like to declare a configuration state.

In example, if you you like to declare the absence of a file, there is no need to check if it exists before. Just make sure it becomes deleted.

---
- hosts: test
  become: false
  gather_facts: false

  tasks:

  - name: Remove file
    shell:
      cmd: "rm /home/{{ ansible_user }}/test.txt"
      warn: false
    register: result
    changed_when: result.rc != 1
    failed_when: result.rc != 0 and result.rc != 1

  - name: Show result
    debug:
      msg: "{{ result }}"

As you see, it will be necessary to Defining failure and control how the task behaves. Another example for showing the content.

---
- hosts: test
  become: false
  gather_facts: false

  tasks:

  - name: Gather file content
    shell:
      cmd: "cat /home/{{ ansible_user }}/test.txt"
    register: result
    changed_when: false
    failed_when: result.rc != 0 and result.rc != 1

  - name: Show result
    debug:
      msg: "{{ result.stdout }}"

Please take note, for the given example tasks there are already specific Ansible modules available which do the job better.


According the additional given information in your comments I understand that you like to install or configure "something" and like to leave that fact left on the remote node(s). You like to run the task the next time on the remote node(s) in fact only if it is wasn't successful performed before.

To do so, you may have a look into Ansible facts and Discovering variables: facts and magic variables, especially into Adding custom facts.

What your installation or configuration tasks could do, is leaving a custom .fact file with meaningful keys and values after they were successful running.

During next playbook execution and if gather_facts: true, the information would be gathered from the setup module and you can than let tasks run based on conditions in ansible_local.

Further Q&A

Whereby the host facts can be considered as kind of distributed CMDB, by using facts Cache

fact_caching            = yaml
fact_caching_connection = /tmp/ansible/facts_cache
fact_caching_timeout    = 129600

you can have the information also available on the Control Node. It might even be possible to organize it in host_vars and group_vars.

U880D
  • 8,601
  • 6
  • 24
  • 40
  • 1
    I need to be bit more specific, then. I want to run tasks on the target, and on the next run, they shouldn´t be executed again. So I thought to put a file somewhere on the target, and on the next run, when this file exists, the tasks should not be executed anymore. So, I thought of something like - name: do big stuff bigsgtuff when: not exists originaly I said, they should be executed when the file exists. It´s the other way around. They shoould be executed, if the file does not exists. <--- Sorry – Wurzelseppi Feb 10 '22 at 13:54
  • @Wurzelseppi, right, without further information and description about the use case, what you try to achieve, not much guidedance can be provided. – U880D Feb 10 '22 at 13:56
  • @Wurzelseppi, regardig "_I want to run tasks on the target, and on the next run, they shouldn´t be executed again_", what kind of task is it, what is the task doing? – U880D Feb 10 '22 at 14:05
  • It´s a bunch of tasks in a role (ansible-hardening). Takes awhile to execute, and I want to run it just once, but the workboom is going to be executed multiple times on same target for deployment purposes. – Wurzelseppi Feb 19 '22 at 21:05
  • @Wurzelseppi, since you are applying a full role (hardening), custom facts seems to be the best practice. I am using the similar approach to apply antivirus, backup, remote log forwarder, security scan and other roles to a system and have this information within a CMDB in sync. – U880D Feb 20 '22 at 16:51