From 25c6fd0c79a324bfaee98c09769c66a453e7c888 Mon Sep 17 00:00:00 2001 From: Muhammad Azam Date: Fri, 28 Aug 2026 12:14:30 -0400 Subject: [PATCH 1/2] Fix crash when ansible_default_ipv4.address is undefined (PE-1998) redis_bind and redis_sentinel_bind assumed ansible_default_ipv4.address always exists. On hosts with no default route, Ansible sets ansible_default_ipv4 to an empty dict, so accessing .address raised AnsibleUndefinedVariable and aborted the run. Both now check `is defined` first and fall back to binding on 127.0.0.1 only. Tested by: - Reproducing the crash with an ad-hoc command simulating the empty-fact case: `ansible localhost -m debug -a "msg={{ '127.0.0.1 ' ~ ansible_default_ipv4.address }}" -e '{"ansible_default_ipv4": {}}'` confirmed the pre-fix expression fails with "'dict object' has no attribute 'address'". - Re-running the same ad-hoc check against the new expression for both the empty-fact case (renders "127.0.0.1", no crash) and a populated case (`-e '{"ansible_default_ipv4": {"address": "10.0.0.5"}}'`, renders "127.0.0.1 10.0.0.5"), confirming existing behavior is unchanged. - Parsing both YAML files with PyYAML to confirm the folded scalar produces the identical single-line Jinja expression as before wrapping it for line length. - ansible-lint roles/redis/defaults/main/redis.yml roles/redis/defaults/main/sentinel.yml passes clean (0 failures, 0 warnings). --- roles/redis/defaults/main/redis.yml | 8 ++++++-- roles/redis/defaults/main/sentinel.yml | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/roles/redis/defaults/main/redis.yml b/roles/redis/defaults/main/redis.yml index cbf01e24..f534c917 100644 --- a/roles/redis/defaults/main/redis.yml +++ b/roles/redis/defaults/main/redis.yml @@ -26,8 +26,12 @@ redis_group: redis # Default redis port redis_port: "{{ redis_port_default }}" -# Bind to localhost + private network interface -redis_bind: 127.0.0.1 {{ ansible_default_ipv4.address }} +# Bind to localhost + private network interface. +# ansible_default_ipv4.address is not guaranteed to be present (e.g. hosts +# with no default route), so only append it when it is actually defined. +redis_bind: >- + 127.0.0.1{{ (' ' + ansible_default_ipv4.address) + if (ansible_default_ipv4.address is defined) else '' }} # Feature flags that can be overridden in the hosts file # Essentially, a default installation will have auth, but not tls diff --git a/roles/redis/defaults/main/sentinel.yml b/roles/redis/defaults/main/sentinel.yml index eca64d30..bba871f7 100644 --- a/roles/redis/defaults/main/sentinel.yml +++ b/roles/redis/defaults/main/sentinel.yml @@ -13,8 +13,12 @@ redis_sentinel_master_name: itentialmaster # The default redis sentinel listen port redis_sentinel_port: "{{ redis_sentinel_port_default }}" -# Bind to localhost + private network interface -redis_sentinel_bind: 127.0.0.1 {{ ansible_default_ipv4.address }} +# Bind to localhost + private network interface. +# ansible_default_ipv4.address is not guaranteed to be present (e.g. hosts +# with no default route), so only append it when it is actually defined. +redis_sentinel_bind: >- + 127.0.0.1{{ (' ' + ansible_default_ipv4.address) + if (ansible_default_ipv4.address is defined) else '' }} # Auto-calculate quorum based on sentinel count (recommended) # Set to explicit number to override (must be <= number of sentinels) From 7efaa5b650218be55fe0c467bc0b0d03b2563ba6 Mon Sep 17 00:00:00 2001 From: Muhammad Azam Date: Fri, 28 Aug 2026 14:37:31 -0400 Subject: [PATCH 2/2] Simplify undefined-fact fix using default() filter (PE-1998) Replace the ternary conditional with the simpler, more idiomatic `| default('')` filter, matching the pattern already used by every other reference to ansible_default_ipv4.address in this codebase (the three *-validation-report.md.j2 templates). Tested by: - Re-running the same ad-hoc reproduction checks against this new expression: undefined-fact case renders "127.0.0.1 " (trailing space, no crash); defined case renders "127.0.0.1 10.0.0.5" as before. - Confirmed the trailing space is harmless to Redis itself: ran a real redis:latest Docker container with a config file containing "bind 127.0.0.1 " (trailing space) - it loaded the config and reached "Ready to accept connections" with no parse error. - ansible-lint on both changed files passes clean (0 failures, 0 warnings). --- roles/redis/defaults/main/redis.yml | 6 ++---- roles/redis/defaults/main/sentinel.yml | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/roles/redis/defaults/main/redis.yml b/roles/redis/defaults/main/redis.yml index f534c917..05401e96 100644 --- a/roles/redis/defaults/main/redis.yml +++ b/roles/redis/defaults/main/redis.yml @@ -28,10 +28,8 @@ redis_port: "{{ redis_port_default }}" # Bind to localhost + private network interface. # ansible_default_ipv4.address is not guaranteed to be present (e.g. hosts -# with no default route), so only append it when it is actually defined. -redis_bind: >- - 127.0.0.1{{ (' ' + ansible_default_ipv4.address) - if (ansible_default_ipv4.address is defined) else '' }} +# with no default route), so fall back to an empty string when undefined. +redis_bind: "127.0.0.1 {{ ansible_default_ipv4.address | default('') }}" # Feature flags that can be overridden in the hosts file # Essentially, a default installation will have auth, but not tls diff --git a/roles/redis/defaults/main/sentinel.yml b/roles/redis/defaults/main/sentinel.yml index bba871f7..4569ce64 100644 --- a/roles/redis/defaults/main/sentinel.yml +++ b/roles/redis/defaults/main/sentinel.yml @@ -15,10 +15,8 @@ redis_sentinel_port: "{{ redis_sentinel_port_default }}" # Bind to localhost + private network interface. # ansible_default_ipv4.address is not guaranteed to be present (e.g. hosts -# with no default route), so only append it when it is actually defined. -redis_sentinel_bind: >- - 127.0.0.1{{ (' ' + ansible_default_ipv4.address) - if (ansible_default_ipv4.address is defined) else '' }} +# with no default route), so fall back to an empty string when undefined. +redis_sentinel_bind: "127.0.0.1 {{ ansible_default_ipv4.address | default('') }}" # Auto-calculate quorum based on sentinel count (recommended) # Set to explicit number to override (must be <= number of sentinels)