dynamic variable content

I am trying to define a variable in defaults.yml with some kind of dynamic. Conrete creating a directory with the current timestamp at the end of the name.

   data_dir: /file/to/dir_$(date +%F_%H%M%S)

gives me exactly the directory name 'dir_$(date +%F_%H%M%S)' and not dir_2023_03_23_115122.

How can I achieve such?

You are using shell command inside an ansible vars file. That will not work.
Take a look at https://docs.ansible.com/ansible/latest/collections/ansible/builtin/strftime_filter.html

Templating + now()

➜ cat defaults.yml
current: “{{ now(‘True’,‘%F_%H%M%S’) }}”

➜ cat datetime.yml

make a variable with the current date

  • hosts: localhost
    vars_files:
  • ./defaults.yml
    tasks:
  • name: echo
    ansible.builtin.debug:

var: current

➜ ansible-adhoc ansible-playbook ./datetime.yml

TASK [echo] *************************************************************************************************************
ok: [localhost] => {
“current”: “2023-03-23_110205”
}

ok that works to some extent. But I probably seem to need someting not toooo dynamic after all :-/

I did not get this entirely when we started.

I need to create the variable value once at the beginning of the playbook but need to get back to it later down the road with the same initial value. So more like it works inside a bash script (despite the fact it's a playbook).

I can think of a workaround for my current task, but still would be wondering whether this can be done.

If you can use a file (defaults.yml or whatever) for only this variable, it’s easy to check for the file’s existence, write to it if it doesn’t exist, and then just use it again and again later on. It will persist until removed.

make a variable with the current date

  • name: preflight
    hosts: localhost
    tasks:

  • name: check for existing date_saved yaml file
    stat:
    path: ./defaults.yml
    register: date_saved

  • name: write current date to date.saved file
    when: not date_saved.stat.exists
    copy:
    content: “data_dir: "/file/to/dir_{{ now(‘True’,‘%F_%H%M%S’) }}"”
    dest: ./defaults.yml

  • name: main
    hosts: localhost
    vars_files:

  • ./defaults.yml

tasks:

  • name: echo
    ansible.builtin.debug:
    var: data_dir

rm defaults.yml
ansible-playbook ./datetime.yml
PLAY [preflight] ********************************************************************************************************

TASK [check for existing date_saved yaml file] **************************************************************************
ok: [localhost]

TASK [write current date to date.saved file] ****************************************************************************
changed: [localhost]

PLAY [main] *************************************************************************************************************

TASK [echo] *************************************************************************************************************
ok: [localhost] => {
“data_dir”: “/file/to/dir_2023-03-24_021041”
}

PLAY RECAP **************************************************************************************************************
localhost : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

ansible-playbook ./datetime.yml
PLAY [preflight] ********************************************************************************************************

TASK [check for existing date_saved yaml file] **************************************************************************
ok: [localhost]

TASK [write current date to date.saved file] ****************************************************************************
skipping: [localhost]

PLAY [main] *************************************************************************************************************

TASK [echo] *************************************************************************************************************
ok: [localhost] => {
“data_dir”: “/file/to/dir_2023-03-24_021041”
}

There is an undocumented* but intentional interaction between ansible.builtin.set_fact and the run_once parameter. You are in luck, because it solves exactly this problem in a clean way. When you use set_fact to create a variable with run_once: true, it sets the variable for all hosts in the play. So you can say:

 **- name: Snarf the playbook start time on all host**<b>s
</b> **ansible.builtin.set_fact:**  **ansible_playbook_starttime: "{{ now('True', '%F_%H%M%S') }}"**  **run_once: true**

After this step runs, all hosts will have the same ansible_playbook_starttime variable with a fully templated out value.

This differs from, say, setting the same variable in group_vars/all or in your playbook’s vars: section. If you create the variable any of these other ways, “lazy evaluation” will cause the variable’s template to be re-evaluated each time it is used. In contrast, set_fact will produce ‘static’ values, i.e. not subject to or requiring further template evaluation on subsequent uses.

*Arguably one could read ansible-doc -t module set_fact with a lawyer’s eye and discern this behavior, but I’ve read it a dozen or more times and never once did it occur to me that run_once: true would have this effect across all hosts. There is a bug report about it from October 2018 that spells it out. Otherwise it’s one of those serendipitous discoveries that either makes your day or ruins your weekend.