diff --git a/osism/utils/rabbitmq.py b/osism/utils/rabbitmq.py index 53a6c85e..7892b23d 100644 --- a/osism/utils/rabbitmq.py +++ b/osism/utils/rabbitmq.py @@ -14,12 +14,21 @@ resolve_in_host_context, ) -# The node's internal address. Ansible names interface facts with "-" replaced -# by "_" and dots left alone (PrefixFactNamespace._underscore), so "br-ex" is -# ansible_br_ex while "bond0.100" is ansible_bond0.100. +# The node's internal address, resolved the way osism/defaults resolves it +# (defaults/manager/000-defaults.yml), including the console_interface +# fallback: an operator may set console_interface explicitly and leave +# internal_interface unset, which works in the deployment and must work here. +# With neither set, defaults/all/099-interfaces.yml resolves console_interface +# to the undefined "loopback0", so this fails loudly rather than inventing an +# address. +# +# Ansible names interface facts with "-" replaced by "_" and dots left alone +# (PrefixFactNamespace._underscore), so "br-ex" is ansible_br_ex while +# "bond0.100" is ansible_bond0.100. INTERNAL_ADDRESS_EXPRESSION = ( "hostvars[inventory_hostname]" - "['ansible_' + (internal_interface | replace('-', '_'))]" + "['ansible_' + ((internal_interface | default(console_interface))" + " | replace('-', '_'))]" "['ipv4']['address']" ) diff --git a/tests/integration/test_rabbitmq_addresses.py b/tests/integration/test_rabbitmq_addresses.py index 8fb89da6..ae15fd76 100644 --- a/tests/integration/test_rabbitmq_addresses.py +++ b/tests/integration/test_rabbitmq_addresses.py @@ -151,6 +151,18 @@ def test_interface_from_inventory_variable(scenario): assert rabbitmq.get_rabbitmq_node_addresses() == [("10.74.34.11", host)] +def test_console_interface_fallback(scenario): + # osism/defaults resolves this address as + # internal_interface|default(console_interface), so a host that sets only + # console_interface resolves in the deployment and has to resolve here. + host = scenario( + "ctl9", + {"console_interface": "eth7"}, + {"ansible_eth7": {"ipv4": {"address": "10.9.9.9"}}}, + ) + assert rabbitmq.get_rabbitmq_node_addresses() == [("10.9.9.9", host)] + + def test_missing_internal_interface_yields_no_addresses(scenario): scenario("ctl6", {}, {"ansible_eth0": {"ipv4": {"address": "10.0.0.9"}}}) assert rabbitmq.get_rabbitmq_node_addresses() is None diff --git a/tests/unit/utils/test_rabbitmq.py b/tests/unit/utils/test_rabbitmq.py index 64a28f1f..792d5c3e 100644 --- a/tests/unit/utils/test_rabbitmq.py +++ b/tests/unit/utils/test_rabbitmq.py @@ -263,6 +263,16 @@ def test_resolver_receives_cached_facts_verbatim( ) ] + def test_expression_falls_back_to_console_interface(self): + # osism/defaults resolves this address as + # internal_interface|default(console_interface); an operator may set + # console_interface explicitly and leave internal_interface unset, which + # works in the deployment and must therefore work here too. + assert ( + "internal_interface | default(console_interface)" + in rabbitmq.INTERNAL_ADDRESS_EXPRESSION + ) + def test_expression_normalizes_dashes_but_not_dots(self): # Ansible names interface facts with "-" replaced by "_" and leaves # dots alone (PrefixFactNamespace._underscore), so the expression must