Search code examples
ansibleansible-2.xansible-inventoryansible-facts

Ansible timestamp which is the same for all nodes during the whole play


I would like to have a timestamp variable, which is the same across across all hosts. (I include this in the name of directories: it must be the same on all hosts)

My initial idea was to add a declaration into group_vars/all.yml, since that has a relatively high precedence and should be shared.

group_vars/all.yml:

my_timestamp: "{{ ansible_date_time.date }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}{{ ansible_date_time.second }}"

When tried, the values were different across hosts, making my directory structure inconsistent. I suspect this is because the variable is only evaluated lazily, when the referred ansible_date_time object already has a different value on each host, depending on the exact moment execution reaches the variable reference and resolves the value.

The same issue happens when I try to set_fact in my playbook, at the very beginning.

site.yml:

---
# This playbook performs the deployment

- name: Prepare playbook settings
  hosts: all
  tasks:
    - name: Generate my timestamp
      set_fact:
        my_timestamp: "{{ ansible_date_time.date }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}{{ ansible_date_time.second }}"

The question is: how could I set a constant, shared timestamp, which is the same on all nodes during the whole execution of a playbook? What would be the clean Ansible way of generating a consistent, constant time-stamp? Without passing as a command line argument, printing to a file and the reading back the value etc.

I am on Ansible 2.9.23.


Solution

  • Your base problem is that, using set_fact or not, you are parsing a value that is populated in the gathered facts for each host. Since the ssh connection to your targets will never happen at the exact same time, each host will have different values

    The solution is to use one single timestamp from one single host for all of them. One way is to get it from the controller (localhost) but you can decide to get it elsewhere (i.e. the first host in your group during your deploy play using set_facts and run_once for example).

    Here is the idea using the controller. Adapt to your own requirements

    ---
    - name: Make sure we gather facts from localhost
      hosts: localhost
    
    - name: Make my actual deployment
      hosts: all
    
      vars:
        # declare timestamp using localhost values
        my_timestamp: >-
          {{
            hostvars['localhost'].ansible_date_time.date
          }}{{
            hostvars['localhost'].ansible_date_time.hour
          }}{{
            hostvars['localhost'].ansible_date_time.minute
          }}{{
            hostvars['localhost'].ansible_date_time.second
          }}      
    
      tasks:
        - name: Make sure timestamp value is the same everywhere
          debug:
            var: my_timestamp
    
        #... rest of your tasks...