diff options
| -rw-r--r-- | meta/argument_specs.yml | 45 | ||||
| -rw-r--r-- | molecule/default/converge.yml | 294 | ||||
| -rw-r--r-- | molecule/default/molecule.yml | 1 | ||||
| -rw-r--r-- | molecule/default/prepare.yml | 55 | ||||
| -rw-r--r-- | molecule/default/tests/test_lineinfile_strategy.py | 38 | ||||
| -rw-r--r-- | molecule/default/tests/test_yaml_strategy.py | 51 |
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"]}, + ] |