mpmackenna
mpmackenna

Reputation: 443

Create a constant from a lookup in Ansible

I am trying to create a variable from a lookup in Ansible. I then want to use that variable as a constant throughout the rest of the role. Here are a couple of lines from defaults/main.yml.

job_start_time: "{{ lookup('pipe','date +%Y%m%d_%H%M%S') }}"
new_virtual_machine_name: "{{ template_name }}-pkrclone-{{ job_start_time }}"

The result of running the role causes an error as the lookup happens again when the new_virtual_machine_name variable is used in tasks/main.yml. You can see the second increment in subsequent tasks.

TASK [update_vsphere_template : Write vsphere source file] changed: [localhost] => {"changed": true, "checksum": "c2ee7ed6fad0b26aea825233f3e714862de3ac28", "dest": "packer-DevOps-Windows2019-Base-DevOps-Windows2019-Base-pkrclone-20210819_**093122**/vsphere-source-DevOps-Windows2019-Base-DevOps-Windows2019-Base-pkrclone-20210819_**093122**.pkr.hcl", 148765781020136/source", "state": "file", "uid": 1000}

TASK [update_vsphere_template : Write the template update file] *fatal: [localhost]: FAILED! => {"changed": false, "checksum": "6fd97c1d2373b9c71ad6b5246529c46a38f55c48", "msg": "Destination directory packer-DevOps-Windows2019-Base-DevOps-Windows2019-Base-pkrclone-20210819_**093123** does not exist"}

Here is how I am referencing the new_virtual_machine_name variable in tasks/main.yml

- name: Write vsphere source file
  template:
    src: ../templates/vsphere-source.j2
    dest: 'packer-{{template_name}}-{{ new_virtual_machine_name }}/vsphere-source-{{ template_name }}-{{ new_virtual_machine_name }}.pkr.hcl'

- name: Write the template update file
  template:
    src: ../templates/update-template.j2
    dest: 'packer-{{template_name}}-{{ new_virtual_machine_name }}/update-{{ template_name }}-{{ new_virtual_machine_name }}.pkr.hcl'

How can I keep Ansible from running the lookup every time I reference the variable that is created from the lookup at the start of the job? Thank you.

Upvotes: 1

Views: 550

Answers (2)

Zeitounator
Zeitounator

Reputation: 44605

Yes, variables are evaluated every time you call them. A way to work around this is to store a fact using set_facts which will be evaluated only at time it is set and stored as a static values for the host.

Edit: Note that, as pointed out in @vladimir's answer (and discussed in comments), using the pipe lookup to get such an info is not really a good practice when you have the strftime filter available in core Ansible. So I changed it in my below example.

To illustrate, the following playbook:

---
- hosts: localhost
  gather_facts: false

  vars:
    _job_start_time: "{{ '%Y%m%d_%H%M%S'| strftime }}"

  tasks:
    - name: Force var into a fact that will be constant throughout play
      set_fact:
        job_start_time: "{{ _job_start_time }}"

    - name: Wait a bit making sure time goes on
      pause:
        seconds: 1

    - name: Show that fact is constant whereas inital var changes
      debug:
        msg: "var is: {{ _job_start_time }}, fact is: {{ job_start_time }}"

    - name: Wait a bit making sure time goes on
      pause:
        seconds: 1

    - name: Show that fact is constant whereas inital var changes
      debug:
        msg: "var is: {{ _job_start_time }}, fact is: {{ job_start_time }}"

Gives:

PLAY [localhost] ***********************************************************************************************************************************************************************************************************************

TASK [Force var into a fact that will be constant throughout play] *********************************************************************************************************************************************************************
ok: [localhost]

TASK [Wait a bit making sure time goes on] *********************************************************************************************************************************************************************************************
Pausing for 1 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

TASK [Show that fact is constant whereas inital var changes] ***************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "var is: 20210819_172528, fact is: 20210819_172527"
}

TASK [Wait a bit making sure time goes on] *********************************************************************************************************************************************************************************************
Pausing for 1 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

TASK [Show that fact is constant whereas inital var changes] ***************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "var is: 20210819_172529, fact is: 20210819_172527"
}

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

Upvotes: 2

Vladimir Botka
Vladimir Botka

Reputation: 67984

Q: "How can I keep Ansible from running the lookup every time I reference the variable?"

A: Use strftime, you'll get the current date each time you call the filter, e.g.

    - set_fact:
        job_start_time: "{{ '%Y%m%d_%H%M%S'|strftime }}"
    - debug:
        msg: "pkrclone-{{ job_start_time }}"
    - wait_for:
        timeout: 3
    - debug:
        msg: "pkrclone-{{ job_start_time }}"
    - set_fact:
        job_start_time: "{{ '%Y%m%d_%H%M%S'|strftime }}"
    - debug:
        msg: "pkrclone-{{ job_start_time }}"

gives

  msg: pkrclone-20210819_174748
  msg: pkrclone-20210819_174748
  msg: pkrclone-20210819_174753

Upvotes: 2

Related Questions