Reputation: 443
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
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
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