From 8d6affbbe3d6879a56c770e38328dd6063736ebc Mon Sep 17 00:00:00 2001 From: oddly Date: Thu, 6 Aug 2026 13:00:04 +0200 Subject: [PATCH] fix(elasticsearch): make cluster-settings robust to per-block check_mode Follow-up to #182. Re-including the role with check_mode: true on an outer block (as elasticsearch_no-security did to cover the guards #154 added) crashed on line 30 of elasticsearch-cluster-settings.yml with: 'dict object' has no attribute 'json' Root cause: ansible_check_mode is the PLAY-level check-mode flag; setting check_mode: true on a block does not flip it, but the uri module still honours the inherited override and returns without an HTTP body. The block-level 'when: not ansible_check_mode' guard then lets execution through anyway, and the next task dereferences _elasticsearch_current_cluster_settings.json which is missing. Two guards: - check_mode: false on the GET so a per-block override still runs the request (this is a pure read, safe to always execute) - default({}) around .persistent so the compare survives any other reason the response is missing Also re-adds the check-mode play to elasticsearch_no-security so the #154 guards actually stay covered. --- .../elasticsearch_no-security/converge.yml | 28 +++++++++++++++++++ .../tasks/elasticsearch-cluster-settings.yml | 8 +++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/molecule/elasticsearch_no-security/converge.yml b/molecule/elasticsearch_no-security/converge.yml index 3d84f896..f1257ef6 100644 --- a/molecule/elasticsearch_no-security/converge.yml +++ b/molecule/elasticsearch_no-security/converge.yml @@ -17,3 +17,31 @@ - name: Include Elasticsearch ansible.builtin.include_role: name: oddly.elasticstack.elasticsearch + +# Coverage for the `not ansible_check_mode` guards #154 added to the +# `Start Elasticsearch` and `Handle cluster setup without security` +# tasks/blocks, plus the `check_mode: false` shield this PR adds to +# the cluster-settings URI. Re-running the role with check_mode: true +# on the outer block previously exploded on the `.json` reference in +# elasticsearch-cluster-settings.yml because the URI honoured the +# check-mode override and returned without a body. +- name: "Re-include ES role in check mode (regression cover for #154)" + hosts: all + vars: + elasticsearch_security: false + elasticstack_security: false + elasticsearch_heap: "1" + elasticstack_release: "{{ lookup('env', 'ELASTIC_RELEASE') | default('9', true) | int }}" + elasticstack_no_log: false + elasticstack_elasticsearch_group_name: elasticsearchXYZ + tasks: + - name: Reset shared role import guard for re-run + ansible.builtin.set_fact: + _elasticstack_role_imported: false + + - name: Wrap the re-include so check_mode propagates + check_mode: true + block: + - name: Re-include Elasticsearch in check mode + ansible.builtin.include_role: + name: oddly.elasticstack.elasticsearch diff --git a/roles/elasticsearch/tasks/elasticsearch-cluster-settings.yml b/roles/elasticsearch/tasks/elasticsearch-cluster-settings.yml index 30336d7e..62b86ccd 100644 --- a/roles/elasticsearch/tasks/elasticsearch-cluster-settings.yml +++ b/roles/elasticsearch/tasks/elasticsearch-cluster-settings.yml @@ -25,13 +25,19 @@ validate_certs: "{{ elasticsearch_validate_api_certs }}" return_content: true register: _elasticsearch_current_cluster_settings + # The uri module honours check_mode inherited from a block/task-level + # override even when the play itself is not in --check, and returns + # without hitting the endpoint. `.json` is then missing on the + # registered result; guard the downstream compare so a per-block + # check_mode caller doesn't crash us. + check_mode: false no_log: "{{ elasticstack_no_log }}" - name: elasticsearch-cluster-settings | Check if settings already match ansible.builtin.set_fact: _elasticsearch_cluster_settings_changed: "{{ _needs_update | trim }}" vars: - _current: "{{ _elasticsearch_current_cluster_settings.json.persistent }}" + _current: "{{ (_elasticsearch_current_cluster_settings.json | default({})).persistent | default({}) }}" _needs_update: >- {% set ns = namespace(changed=false) %} {% for key, value in _elasticsearch_effective_cluster_settings.items() %}