aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorColin Wilk <colin@wilk.cx>2026-07-21 19:58:10 +0200
committerColin Wilk <colin@wilk.cx>2026-07-21 19:58:10 +0200
commitc33948c219032977779a7ef6d82c16e84f37b81a (patch)
treef5a897d933639cdf97da2564d976610259115159
parent0055971afd5524f0df00fc8d2203a80f828885f7 (diff)
downloadansible-role-prometheus-target-c33948c219032977779a7ef6d82c16e84f37b81a.tar.gz
ansible-role-prometheus-target-c33948c219032977779a7ef6d82c16e84f37b81a.zip
test: expand Molecule coverage for exporter behavior
Cover lineinfile and YAML behavior for default exporters, skipped defaults, exporters without IDs, duplicate definitions, path and host overrides, path-prefix precedence, and inherited label overrides. Verify YAML handling of null documents, multiple files, labeled and unlabeled groups, and duplicate targets. Add test coverage for command and shell handlers using run-once, per-host, disabled, and non-become configurations.
-rw-r--r--meta/argument_specs.yml45
-rw-r--r--molecule/default/converge.yml294
-rw-r--r--molecule/default/molecule.yml1
-rw-r--r--molecule/default/prepare.yml55
-rw-r--r--molecule/default/tests/test_lineinfile_strategy.py38
-rw-r--r--molecule/default/tests/test_yaml_strategy.py51
6 files changed, 460 insertions, 24 deletions
diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml
index f7b6c43..b35c993 100644
--- a/meta/argument_specs.yml
+++ b/meta/argument_specs.yml
@@ -26,6 +26,16 @@ argument_specs:
- lineinfile
- yaml
+ prometheus_target_strategy_lineinfile_prefix:
+ type: str
+ required: false
+ default: " - "
+
+ prometheus_target_strategy_lineinfile_suffix:
+ type: str
+ required: false
+ default: ""
+
prometheus_target_handler_command_enabled:
type: bool
required: false
@@ -36,6 +46,14 @@ argument_specs:
required: false
default: true
+ prometheus_target_handler_command_become_method:
+ type: str
+ required: false
+
+ prometheus_target_handler_command_become_user:
+ type: str
+ required: false
+
prometheus_target_handler_command_run_once:
type: bool
required: false
@@ -57,6 +75,14 @@ argument_specs:
required: false
default: true
+ prometheus_target_handler_shell_become_method:
+ type: str
+ required: false
+
+ prometheus_target_handler_shell_become_user:
+ type: str
+ required: false
+
prometheus_target_handler_shell_run_once:
type: bool
required: false
@@ -100,7 +126,24 @@ argument_specs:
type: list
required: false
default: []
- elements: str
+ elements: dict
+ options:
+ id:
+ type: str
+ required: false
+ path:
+ type: str
+ required: false
+ path_prefix:
+ type: str
+ required: false
+ host:
+ type: str
+ required: false
+ labels:
+ type: dict
+ required: false
+ description: Labels to match the target group in the YAML file (yaml strategy only)
prometheus_target_skip_default_exporters:
type: bool
diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml
index f882c44..59d63bc 100644
--- a/molecule/default/converge.yml
+++ b/molecule/default/converge.yml
@@ -4,12 +4,6 @@
- name: Lineinfile bootstrap and subsequent hosts
hosts: application
pre_tasks:
- - name: Create test user
- ansible.builtin.user:
- name: prometheus
- become: true
- delegate_to: "{{ prometheus_target_host }}"
-
- name: Create lineinfile bootstrap target
ansible.builtin.copy:
dest: /opt/lineinfile_bootstrap.yml
@@ -182,23 +176,6 @@
################################################################################
- name: YAML subsequent hosts and parallel writes
hosts: application_group
- pre_tasks:
- - name: Create yaml parallel target
- ansible.builtin.copy:
- dest: "{{ item }}"
- mode: "0644"
- content: |
- - labels:
- job: node
- targets:
- - existing:9100
- force: true
- delegate_to: "{{ prometheus_target_host }}"
- run_once: true
- loop:
- - /opt/yaml_parallel.yml
- - /opt/yaml_parallel_second.yml
-
vars:
prometheus_target_host: prometheus
prometheus_target_strategy: yaml
@@ -495,3 +472,274 @@
prometheus_target_exporter:
- path: /opt/hook_target.yml
host: "{{ inventory_hostname }}"
+
+################################################################################
+################################################################################
+- name: Lineinfile exporter resolution matrix
+ hosts: application
+ pre_tasks:
+ - name: Create lineinfile resolution target files
+ ansible.builtin.copy:
+ dest: "{{ item }}"
+ content: ""
+ mode: "0644"
+ force: false
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+ loop:
+ - /opt/lineinfile_defaults.yml
+ - /opt/lineinfile_no_id.yml
+ - /opt/lineinfile_override.yml
+ - /opt/lineinfile_skipped.yml
+
+ - name: Create lineinfile default prefix directory
+ ansible.builtin.file:
+ path: /opt/lineinfile-prefix
+ state: directory
+ mode: "0755"
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+
+ - name: Create lineinfile prefixed target
+ ansible.builtin.copy:
+ dest: /opt/lineinfile-prefix/default-prefix.yml
+ content: ""
+ mode: "0644"
+ force: false
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+
+ vars:
+ prometheus_target_host: prometheus
+ prometheus_target_exporter_target_prefix: /opt/
+ prometheus_target_exporter_defaults:
+ inherited:
+ path: lineinfile_defaults.yml
+ host: inherited-default
+ default_only:
+ path: lineinfile_defaults.yml
+ host: appended-default
+ overridden:
+ path: unused.yml
+ host: unused-host
+ prefixed:
+ path: default-prefix.yml
+ host: prefixed-default
+ path_prefix: /opt/lineinfile-prefix/
+ prometheus_target_default_exporters:
+ - id: default_only
+
+ roles:
+ - role: kliwniloc.prometheus_target
+ prometheus_target_strategy_lineinfile_prefix: "- "
+ prometheus_target_exporter:
+ - id: inherited
+ - id: inherited
+ - path: lineinfile_no_id.yml
+ host: no-id
+ - id: overridden
+ path: /opt/lineinfile_override.yml
+ path_prefix: ""
+ host: item-override
+ - id: prefixed
+
+################################################################################
+################################################################################
+- name: Lineinfile skips default exporters
+ hosts: application
+ vars:
+ prometheus_target_host: prometheus
+ prometheus_target_skip_default_exporters: true
+ prometheus_target_exporter_defaults:
+ skipped:
+ path: /opt/lineinfile_skipped.yml
+ host: must-not-appear
+ prometheus_target_default_exporters:
+ - id: skipped
+
+ roles:
+ - role: kliwniloc.prometheus_target
+
+################################################################################
+################################################################################
+- name: YAML exporter resolution matrix
+ hosts: application
+ pre_tasks:
+ - name: Create YAML resolution target files
+ ansible.builtin.copy:
+ dest: "{{ item.path }}"
+ content: "{{ item.content }}"
+ mode: "0644"
+ force: false
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+ loop:
+ - path: /opt/yaml_defaults.yml
+ content: ""
+ - path: /opt/yaml_no_id.yml
+ content: ""
+ - path: /opt/yaml_override.yml
+ content: ""
+ - path: /opt/yaml_null.yml
+ content: "~\n"
+ - path: /opt/yaml_skipped.yml
+ content: ""
+
+ - name: Create YAML default prefix directory
+ ansible.builtin.file:
+ path: /opt/yaml-prefix
+ state: directory
+ mode: "0755"
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+
+ - name: Create YAML prefixed target
+ ansible.builtin.copy:
+ dest: /opt/yaml-prefix/default-prefix.yml
+ content: ""
+ mode: "0644"
+ force: false
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+
+ vars:
+ prometheus_target_host: prometheus
+ prometheus_target_strategy: yaml
+ prometheus_target_exporter_target_prefix: /opt/
+ prometheus_target_exporter_defaults:
+ inherited:
+ path: yaml_defaults.yml
+ host: inherited-default:9700
+ labels:
+ job: inherited
+ environment: production
+ default_only:
+ path: yaml_defaults.yml
+ host: appended-default:9701
+ labels:
+ job: default
+ overridden:
+ path: unused.yml
+ host: unused-host
+ labels:
+ job: unused
+ prefixed:
+ path: default-prefix.yml
+ host: prefixed-default:9702
+ path_prefix: /opt/yaml-prefix/
+ labels:
+ job: prefixed
+ prometheus_target_default_exporters:
+ - id: default_only
+
+ roles:
+ - role: kliwniloc.prometheus_target
+ prometheus_target_exporter:
+ - id: inherited
+ host: application:9700
+ labels:
+ environment: staging
+ - id: inherited
+ host: application:9700
+ labels:
+ environment: staging
+ - path: yaml_no_id.yml
+ host: no-id:9700
+ labels:
+ job: no-id
+ - id: overridden
+ path: /opt/yaml_override.yml
+ path_prefix: ""
+ host: item-override:9700
+ labels:
+ job: override
+ - id: prefixed
+ - path: yaml_null.yml
+ host: from-null:9700
+
+################################################################################
+################################################################################
+- name: YAML skips default exporters
+ hosts: application
+ vars:
+ prometheus_target_host: prometheus
+ prometheus_target_strategy: yaml
+ prometheus_target_skip_default_exporters: true
+ prometheus_target_exporter_defaults:
+ skipped:
+ path: /opt/yaml_skipped.yml
+ host: must-not-appear:9700
+ labels:
+ job: skipped
+ prometheus_target_default_exporters:
+ - id: skipped
+
+ roles:
+ - role: kliwniloc.prometheus_target
+
+################################################################################
+################################################################################
+- name: Handler execution matrix
+ hosts: application_group
+ pre_tasks:
+ - name: Create handler matrix target
+ ansible.builtin.copy:
+ dest: /opt/handler_matrix.yml
+ content: ""
+ mode: "0644"
+ force: false
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+ run_once: true
+
+ vars:
+ prometheus_target_host: prometheus
+ prometheus_target_handler_command_enabled: true
+ prometheus_target_handler_command_become: false
+ prometheus_target_handler_command_run_once: false
+ prometheus_target_handler_command:
+ cmd: "touch /tmp/command-handler-{{ inventory_hostname }}"
+ creates: "/tmp/command-handler-{{ inventory_hostname }}"
+ prometheus_target_handler_shell_enabled: true
+ prometheus_target_handler_shell_become: false
+ prometheus_target_handler_shell_run_once: true
+ prometheus_target_handler_shell:
+ cmd: touch /tmp/shell-handler-run-once
+ creates: /tmp/shell-handler-run-once
+
+ roles:
+ - role: kliwniloc.prometheus_target
+ prometheus_target_strategy_lineinfile_prefix: "- "
+ prometheus_target_exporter:
+ - path: /opt/handler_matrix.yml
+ host: "{{ inventory_hostname }}"
+
+################################################################################
+################################################################################
+- name: Disabled handlers do not execute
+ hosts: application
+ pre_tasks:
+ - name: Create disabled handler target
+ ansible.builtin.copy:
+ dest: /opt/handler_disabled.yml
+ content: ""
+ mode: "0644"
+ force: false
+ become: true
+ delegate_to: "{{ prometheus_target_host }}"
+
+ vars:
+ prometheus_target_host: prometheus
+ prometheus_target_handler_command_enabled: false
+ prometheus_target_handler_command:
+ cmd: touch /tmp/disabled-command-handler
+ prometheus_target_handler_shell_enabled: false
+ prometheus_target_handler_shell:
+ cmd: touch /tmp/disabled-shell-handler
+
+ roles:
+ - role: kliwniloc.prometheus_target
+ prometheus_target_strategy_lineinfile_prefix: "- "
+ prometheus_target_exporter:
+ - path: /opt/handler_disabled.yml
+ host: application
diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml
index d143303..04d4391 100644
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -53,6 +53,7 @@ platforms:
provisioner:
name: ansible
playbooks:
+ prepare: prepare.yml
converge: ${MOLECULE_PLAYBOOK:-converge.yml}
verifier:
diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml
new file mode 100644
index 0000000..70764e7
--- /dev/null
+++ b/molecule/default/prepare.yml
@@ -0,0 +1,55 @@
+---
+- name: Prepare Prometheus target fixtures
+ hosts: prometheus
+ gather_facts: false
+ become: true
+
+ tasks:
+ - name: Create Prometheus test user
+ ansible.builtin.user:
+ name: prometheus
+
+ - name: Reset fixtures that exercise parallel writes
+ ansible.builtin.copy:
+ dest: "{{ item }}"
+ mode: "0644"
+ content: |
+ - labels:
+ job: node
+ targets:
+ - existing:9100
+ loop:
+ - /opt/yaml_parallel.yml
+ - /opt/yaml_parallel_second.yml
+
+ # These are intentionally not consumed yet. They provide stable starting
+ # states for the planned exporter state/removal coverage in both strategies.
+ - name: Prepare future YAML removal fixture
+ ansible.builtin.copy:
+ dest: /opt/yaml_state_removal.yml
+ mode: "0644"
+ content: |
+ - labels:
+ job: shared
+ targets:
+ - keep:9100
+ - remove:9100
+ - labels:
+ job: remove_last
+ targets:
+ - remove:9200
+
+ - name: Prepare future lineinfile removal fixture
+ ansible.builtin.copy:
+ dest: /opt/lineinfile_state_removal.yml
+ mode: "0644"
+ content: |
+ - labels:
+ job: shared
+ targets:
+ - keep:9100
+ - remove:9100
+ - labels:
+ job: remove_last
+ targets:
+ - remove:9200
diff --git a/molecule/default/tests/test_lineinfile_strategy.py b/molecule/default/tests/test_lineinfile_strategy.py
index b75a656..770459e 100644
--- a/molecule/default/tests/test_lineinfile_strategy.py
+++ b/molecule/default/tests/test_lineinfile_strategy.py
@@ -92,3 +92,41 @@ def test_lineinfile_hooks_still_run(host):
assert host.file("/opt/hook1").exists
assert host.file("/opt/hook2").content_string == "hello\nhello\nhello\nhello\n"
+
+
+def test_lineinfile_exporter_defaults_overrides_and_duplicates(host):
+ assert read_yaml_file(host, "/opt/lineinfile_defaults.yml") == [
+ "inherited-default",
+ "appended-default",
+ ]
+ assert read_yaml_file(host, "/opt/lineinfile_no_id.yml") == ["no-id"]
+ assert read_yaml_file(host, "/opt/lineinfile_override.yml") == ["item-override"]
+ assert read_yaml_file(host, "/opt/lineinfile-prefix/default-prefix.yml") == [
+ "prefixed-default"
+ ]
+
+
+def test_lineinfile_skip_default_exporters(host):
+ assert read_file(host, "/opt/lineinfile_skipped.yml").content_string == ""
+
+
+def test_handler_run_once_and_per_host_modes(host):
+ for application in ["application", "application2", "application3", "application4"]:
+ assert host.file(f"/tmp/command-handler-{application}").exists
+
+ assert host.file("/tmp/shell-handler-run-once").exists
+
+
+def test_disabled_handlers_do_not_run(host):
+ assert not host.file("/tmp/disabled-command-handler").exists
+ assert not host.file("/tmp/disabled-shell-handler").exists
+
+
+def test_future_lineinfile_removal_fixture_is_untouched(host):
+ assert read_yaml_file(host, "/opt/lineinfile_state_removal.yml") == [
+ {
+ "labels": {"job": "shared"},
+ "targets": ["keep:9100", "remove:9100"],
+ },
+ {"labels": {"job": "remove_last"}, "targets": ["remove:9200"]},
+ ]
diff --git a/molecule/default/tests/test_yaml_strategy.py b/molecule/default/tests/test_yaml_strategy.py
index 7ba834e..c3d0dd9 100644
--- a/molecule/default/tests/test_yaml_strategy.py
+++ b/molecule/default/tests/test_yaml_strategy.py
@@ -92,6 +92,12 @@ def test_yaml_output_remains_parseable_after_all_operations(host):
"/opt/yaml_branch_matrix.yml",
"/opt/yaml_missing_labeled.yml",
"/opt/yaml_missing_unlabeled.yml",
+ "/opt/yaml_defaults.yml",
+ "/opt/yaml_no_id.yml",
+ "/opt/yaml_override.yml",
+ "/opt/yaml_null.yml",
+ "/opt/yaml-prefix/default-prefix.yml",
+ "/opt/yaml_state_removal.yml",
]:
assert read_yaml_file(host, path) is not None
@@ -154,3 +160,48 @@ def test_yaml_branch_matrix_creates_missing_file_groups_for_labeled_and_unlabele
assert read_yaml_file(host, "/opt/yaml_missing_unlabeled.yml") == [
{"targets": ["application4:9601"]}
]
+
+
+def test_yaml_exporter_defaults_merge_labels_and_deduplicate(host):
+ groups = read_yaml_file(host, "/opt/yaml_defaults.yml")
+
+ assert get_group_by_labels(
+ groups, {"job": "inherited", "environment": "staging"}
+ )["targets"] == ["application:9700"]
+ assert get_group_by_labels(groups, {"job": "default"})["targets"] == [
+ "appended-default:9701"
+ ]
+
+
+def test_yaml_exporter_without_id_and_item_overrides(host):
+ assert read_yaml_file(host, "/opt/yaml_no_id.yml") == [
+ {"labels": {"job": "no-id"}, "targets": ["no-id:9700"]}
+ ]
+ assert read_yaml_file(host, "/opt/yaml_override.yml") == [
+ {"labels": {"job": "override"}, "targets": ["item-override:9700"]}
+ ]
+ assert read_yaml_file(host, "/opt/yaml-prefix/default-prefix.yml") == [
+ {"labels": {"job": "prefixed"}, "targets": ["prefixed-default:9702"]}
+ ]
+
+
+def test_yaml_null_document_is_initialized(host):
+ assert read_yaml_file(host, "/opt/yaml_null.yml") == [
+ {"targets": ["from-null:9700"]}
+ ]
+
+
+def test_yaml_skip_default_exporters(host):
+ target = host.file("/opt/yaml_skipped.yml")
+ assert target.exists
+ assert target.content_string == ""
+
+
+def test_future_yaml_removal_fixture_is_untouched(host):
+ assert read_yaml_file(host, "/opt/yaml_state_removal.yml") == [
+ {
+ "labels": {"job": "shared"},
+ "targets": ["keep:9100", "remove:9100"],
+ },
+ {"labels": {"job": "remove_last"}, "targets": ["remove:9200"]},
+ ]