Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/roles/elasticsearch.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,24 @@ elasticsearch_recovery_max_bytes_per_sec: ""

`elasticsearch_recovery_max_bytes_per_sec` throttles shard recovery bandwidth (e.g., `"100mb"`). When empty (the default), Elasticsearch uses its internal default (40 MB/s). Increase this on fast networks to speed up recovery after node restarts, or decrease it on shared networks to prevent saturation.

### Persistent Cluster Settings

```yaml
elasticsearch_cluster_settings: {}
```

`elasticsearch_cluster_settings` applies persistent cluster settings via the `PUT _cluster/settings` API after the cluster is healthy. Unlike `elasticsearch_extra_config` (which writes to `elasticsearch.yml` and requires a restart), cluster settings take effect immediately at runtime and apply cluster-wide. The task reads current settings first and only sends the PUT when values differ.

```yaml
elasticsearch_cluster_settings:
cluster.logsdb.enabled: true
indices.recovery.max_bytes_per_sec: "100mb"
cluster.routing.allocation.disk.watermark.low: "90%"
cluster.routing.allocation.disk.watermark.high: "95%"
```

Any setting supported by the [cluster settings API](https://www.elastic.co/docs/reference/elasticsearch/rest-api/cluster/update-cluster-settings) can be used. Values can be strings, numbers, booleans, or nested objects — the YAML dict is serialized to JSON directly.

### Temperature Attribute

```yaml
Expand Down
2 changes: 2 additions & 0 deletions molecule/elasticsearch_default/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
elasticstack_release: "{{ lookup('env', 'ELASTIC_RELEASE') | default('9', true) | int }}"
elasticsearch_heap: "1"
elasticstack_no_log: false
elasticsearch_cluster_settings:
action.destructive_requires_name: "true"
tasks:
- name: Include Elastics repos role
ansible.builtin.include_role:
Expand Down
20 changes: 20 additions & 0 deletions molecule/elasticsearch_default/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,23 @@
- health.json.number_of_nodes == groups['elasticsearch'] | length
fail_msg: "Expected {{ groups['elasticsearch'] | length }} nodes, got {{ health.json.number_of_nodes }}"
run_once: true # noqa: run-once[task]

- name: Read cluster settings # noqa: run-once[task]
ansible.builtin.uri:
url: "https://localhost:9200/_cluster/settings?flat_settings=true"
method: GET
user: elastic
password: "{{ elastic_pass.stdout }}"
force_basic_auth: true
validate_certs: false
register: cluster_settings
run_once: true

- name: Verify cluster settings were applied # noqa: run-once[task]
ansible.builtin.assert:
that:
- cluster_settings.json.persistent['action.destructive_requires_name'] == 'true'
fail_msg: >-
elasticsearch_cluster_settings not applied.
Got: {{ cluster_settings.json.persistent }}
run_once: true
10 changes: 10 additions & 0 deletions roles/elasticsearch/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ elasticsearch_http_cors_allow_headers: "X-Requested-With, Content-Type, Content-
# @var elasticsearch_http_cors_allow_credentials:description: Whether to send CORS credentials (cookies, auth headers)
elasticsearch_http_cors_allow_credentials: false

# @var elasticsearch_cluster_settings:description: >
# Persistent cluster settings applied via PUT _cluster/settings after the
# cluster is healthy. Accepts any setting the cluster settings API supports.
# Only applied when non-empty. Runs once per play on the CA host.
# Example:
# elasticsearch_cluster_settings:
# cluster.logsdb.enabled: true
# indices.recovery.max_bytes_per_sec: "100mb"
elasticsearch_cluster_settings: {}

# @var elasticsearch_initialized_file:description: Marker file path that indicates the cluster has been initialized
elasticsearch_initialized_file: "{{ elasticstack_initial_passwords | dirname }}/cluster_initialized"
# @var elasticsearch_tls_key_passphrase:description: Passphrase for the Elasticsearch node TLS private key
Expand Down
51 changes: 51 additions & 0 deletions roles/elasticsearch/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -582,3 +582,54 @@
when:
- elasticsearch_security | bool
- inventory_hostname == elasticstack_ca_host

# -- Persistent cluster settings via _cluster/settings API --

- name: Apply persistent cluster settings # noqa: run-once[task]
when:
- elasticsearch_cluster_settings | default({}) | length > 0
- not ansible_check_mode
run_once: true
delegate_to: "{{ elasticstack_ca_host | default(inventory_hostname) }}"
block:
- name: Read current persistent cluster settings
ansible.builtin.uri:
url: "{{ elasticsearch_http_protocol }}://{{ elasticsearch_api_host }}:{{ elasticstack_elasticsearch_http_port }}/_cluster/settings?flat_settings=true"
method: GET
user: "{{ 'elastic' if elasticsearch_security | bool else omit }}"
password: "{{ elasticstack_password.stdout if elasticsearch_security | bool else omit }}"
force_basic_auth: "{{ elasticsearch_security | bool }}"
validate_certs: "{{ elasticsearch_validate_api_certs }}"
return_content: true
register: _es_current_cluster_settings
no_log: "{{ elasticstack_no_log }}"

- name: Check if settings already match
ansible.builtin.set_fact:
_es_cluster_settings_changed: "{{ _needs_update }}"
vars:
_current: "{{ _es_current_cluster_settings.json.persistent }}"
_needs_update: >-
{% set ns = namespace(changed=false) %}
{% for key, value in elasticsearch_cluster_settings.items() %}
{% if _current.get(key) is none or _current[key] | string != value | string %}
{% set ns.changed = true %}
{% endif %}
{% endfor %}
{{ ns.changed }}

- name: Apply cluster settings
ansible.builtin.uri:
url: "{{ elasticsearch_http_protocol }}://{{ elasticsearch_api_host }}:{{ elasticstack_elasticsearch_http_port }}/_cluster/settings"
method: PUT
body_format: json
body:
persistent: "{{ elasticsearch_cluster_settings }}"
user: "{{ 'elastic' if elasticsearch_security | bool else omit }}"
password: "{{ elasticstack_password.stdout if elasticsearch_security | bool else omit }}"
force_basic_auth: "{{ elasticsearch_security | bool }}"
validate_certs: "{{ elasticsearch_validate_api_certs }}"
status_code: 200
no_log: "{{ elasticstack_no_log }}"
when: _es_cluster_settings_changed | bool
changed_when: true
Loading