I want to wait for some DNS record registered in DNS server. For example, A record. So I try to use this task:
name: Wait DNS A record host.example.com registered
set_fact:
lookup_result: “{{ lookup(‘dig’, ‘host.example.com.’) }}”
until: lookup_result != ‘NXDOMAIN’
retries: 20
delay: 3
But looks like lookup runs only single time at start and never again. I checked it with tcpdump:
$ sudo tcpdump udp port 53
Only single request/response on first loop iteration.
So, looks like lookup_result setted to value ‘NXDOMAIN’ and this value checked with effectively “until: ‘NXDOMAIN’ != ‘NXDOMAIN’” 20 times without success.
How can I force run lookup on every loop iteration?
name: Test random
set_fact:
rand_result: “{{ 5 | random }}”
until: rand_result == ‘NEVER’
retries: 10
delay: 1
If I run ansible in verbose mode I see that on all iterations rand_result var have the same value, so jinja template evaluated once.
How can I force reevaluate it on every iteration?
name: Test random
set_fact:
rand_result: “{{ 5 |random }}”
with_sequence: count=10
Basically the change of item forces a re-evaluation, even though nothing is changing inside the loop.
However: You may still have a problem with DNS. A failed lookup (NXDOMAIN) will set a negative cache time on the result; no nameserver will issue a new query until the negative cache time has expired. The negative cache time is commonly set to values between five minutes and a few hours; very stable zones may set higher values. If the zone is under your control - which it looks like it is - set the negative cache time low when you are working on the zone. It’s the last field in the SOA.
There are two ways around this. One way is to add “+trace” to your dig command to force the query to begin at the root every time. It is poor form to do this rapidly or frequently, so put a nice long pause between the name setup and your first attempt to check the new name (aim for the time it usually takes for a name to propagate for that zone), then use another nice long pause between checks - at least a minute. Checking once per second for an hour is very uncivilised indeed.
A better alternative is to do an SOA lookup, get the negative cache time value, add one minute, and use that as your pause time.
name: Test random
set_fact:
rand_result: “{{ 5 |random }}”
with_sequence: count=10
Basically the change of item forces a re-evaluation, even though nothing is changing inside the loop.
I tried to use this:
name: Wait DNS A record host.example.com registered
set_fact:
lookup_result: “{{ lookup(‘dig’, ‘host.example.com.’) }}”
until: lookup_result != ‘NXDOMAIN’
retries: 1
delay: 3
with_sequence: count=20
But the overall result of the task is a failure (I think this is because there is fail iterations at start).
Another flaw of this workaround is that task runs all 20 iterations even if there is DNS record, say, on 7 iteration (no ‘break loop’ logic).
I replace my task with this workaround:
name: Wait DNS A record host.example.com registered
command: “dig host.example.com +short”
register: dig_result
until: dig_result.stdout != ‘’
retries: 20
delay: 3
However: You may still have a problem with DNS. A failed lookup (NXDOMAIN) will set a negative cache time on the result; no nameserver will issue a new query until the negative cache time has expired. The negative cache time is commonly set to values between five minutes and a few hours; very stable zones may set higher values. If the zone is under your control - which it looks like it is - set the negative cache time low when you are working on the zone. It’s the last field in the SOA.
Yes, this is private zone under my control and negative cache already set to 60 seconds which is fine for me.