fix: avoid crash when host has no default_ipv6 fact - #412
Open
freedomwarrior wants to merge 1 commit into
Open
Conversation
Jinja's default() filter evaluates its fallback argument eagerly, even
when the primary value already resolved. On hosts with no IPv6 default
route, ansible_facts has no default_ipv6 key at all, so chaining
['address']/.address/.interface onto the missing key raises:
'dict object' has no attribute 'default_ipv6'
...even though default_ipv4 would have been used. This hit role
argument validation (rke2_api_ip default in argument_specs.yml) on any
IPv4-only host, before the role even started.
Replace the dict['key']/.key chains with .get(key, {}).get(subkey),
which returns None instead of raising when the key is absent, and use
`or` instead of default() so None/empty still falls through to the
IPv6 branch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On a host with no IPv6 default route,
ansible_factshas nodefault_ipv6key at all. Several places in the role fall back to it like this:default()is just a normal Jinja filter — it evaluates both its input and its fallback argument before deciding which to use, it does not short-circuit. So even whendefault_ipv4resolves fine, thedefault_ipv6branch is evaluated anyway. Accessing the missingdefault_ipv6key returns Jinja's Undefined placeholder, and the immediately-chained.address/.interface/['address']on that placeholder raises:This hits
rke2_api_ip's default inargument_specs.ymlduring role argument validation, before the role even runs a single task, on any IPv4-only host.default_ipv4 | default(default_ipv6)fallback pattern assumingdefault()short-circuits like||.ansible_default_ipv4→ansible_facts['default_ipv4']but kept the same fallback shape.Fix
Replace the
dict['key']['subkey']/dict.key.subkeychains withdict.get('key', {}).get('subkey'), which returnsNoneinstead of raising when the outer key is absent, and useorinstead ofdefault()so aNone/empty primary value still falls through to the IPv6 branch.Fixed in:
meta/argument_specs.yml(rke2_api_ipdefault — the one that breaks argument validation)defaults/main.yml(same pattern, legacyansible_default_ipv4/ansible_default_ipv6names)templates/keepalived.conf.j2(interface, unicast_src_ip, unicast_peer)templates/kube-vip/kube-vip.yml.j2(vip_interface)Test plan
default_ipv6fact present), confirmansible-playbookno longer fails at "Validating arguments against arg spec 'main'" with'dict object' has no attribute 'default_ipv6'rke2_api_ipstill resolves to the IPv4 address as before on IPv4-only hostsdefault_ipv4fact)