aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tasks/strategy_yaml.yml
blob: 24cd6c8840c34cb2b13b49ce5a4a49cdf2b70bcd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
---
- name: Prepare YAML exporter updates
  ansible.builtin.set_fact:
    _prometheus_target_yaml_updates: >-
      {%- set ns = namespace(updates=[]) -%}
      {%- set exporters = prometheus_target_exporter +
          ([] if prometheus_target_skip_default_exporters else prometheus_target_default_exporters) -%}
      {%- for exporter in exporters -%}
        {%- set defaults = prometheus_target_exporter_defaults[exporter.id] | default({})
            if exporter.id is defined else {} -%}
        {%- set path =
            (exporter.path_prefix if exporter.path_prefix is defined else
             (defaults.path_prefix | default(prometheus_target_exporter_target_prefix))) ~
            ((exporter.path if exporter.path is defined else defaults.path) | mandatory) -%}
        {%- set host = (exporter.host if exporter.host is defined else defaults.host) | mandatory -%}
        {%- set labels = (defaults.labels | default({})) | combine(exporter.labels | default({})) -%}
        {%- set _ = ns.updates.append({'path': path, 'host': host, 'labels': labels}) -%}
      {%- endfor -%}
      {{ ns.updates }}

# Every play host prepares its values above. Applying all updates from one host
# prevents parallel Ansible forks from overwriting each other's YAML changes.
- name: Aggregate YAML exporter updates
  ansible.builtin.set_fact:
    _prometheus_target_yaml_updates_all: >-
      {%- set ns = namespace(updates=[]) -%}
      {%- for target_host in ansible_play_batch -%}
        {%- for update in hostvars[target_host]._prometheus_target_yaml_updates -%}
          {%- set _ = ns.updates.append(update) -%}
        {%- endfor -%}
      {%- endfor -%}
      {{ ns.updates }}
  run_once: true

- name: Collect YAML target paths
  ansible.builtin.set_fact:
    _prometheus_target_yaml_paths: >-
      {{ _prometheus_target_yaml_updates_all | map(attribute='path') | unique | list }}
  run_once: true

- name: Read YAML target files
  ansible.builtin.slurp:
    src: "{{ _yaml_path }}"
  delegate_to: "{{ prometheus_target_host }}"
  loop: "{{ _prometheus_target_yaml_paths }}"
  loop_control:
    loop_var: _yaml_path
  register: _yaml_target_files
  failed_when: false
  run_once: true

# Build each destination completely in memory and write it once. Besides
# avoiding lost updates, this keeps updates to different files independent.
- name: Build updated YAML target files
  ansible.builtin.set_fact:
    _prometheus_target_yaml_files: >-
      {%- set output = namespace(files=[]) -%}
      {%- for file in _yaml_target_files.results -%}
        {%- set state = namespace(groups=(file.content | b64decode | from_yaml)
            if file.content is defined else []) -%}
        {%- set state.groups = state.groups if state.groups is not none else [] -%}
        {%- for update in _prometheus_target_yaml_updates_all if update.path == file._yaml_path -%}
          {%- set next = namespace(found=false, groups=[]) -%}
          {%- for group in state.groups -%}
            {%- set group_labels = group.labels | default({}) -%}
            {%- if group_labels == update.labels -%}
              {%- if update.host not in group.targets -%}
                {%- set _ = group.targets.append(update.host) -%}
              {%- endif -%}
              {%- set next.found = true -%}
              {%- set _ = next.groups.append(group) -%}
            {%- else -%}
              {%- set filtered = group.targets | reject('equalto', update.host) | list -%}
              {%- if filtered | length > 0 -%}
                {%- set replacement = {'targets': filtered} -%}
                {%- if group_labels | length > 0 -%}
                  {%- set _ = replacement.update({'labels': group_labels}) -%}
                {%- endif -%}
                {%- set _ = next.groups.append(replacement) -%}
              {%- endif -%}
            {%- endif -%}
          {%- endfor -%}
          {%- if not next.found -%}
            {%- set new_group = {'targets': [update.host]} -%}
            {%- if update.labels | length > 0 -%}
              {%- set _ = new_group.update({'labels': update.labels}) -%}
            {%- endif -%}
            {%- set _ = next.groups.append(new_group) -%}
          {%- endif -%}
          {%- set state.groups = next.groups -%}
        {%- endfor -%}
        {%- set _ = output.files.append({'path': file._yaml_path, 'groups': state.groups}) -%}
      {%- endfor -%}
      {{ output.files }}
  run_once: true

- name: Write updated YAML target files
  ansible.builtin.copy:
    content: "{{ _yaml_file.groups | to_nice_yaml(indent=2, width=1337) }}"
    dest: "{{ _yaml_file.path }}"
    mode: "0644"
  delegate_to: "{{ prometheus_target_host }}"
  become: true
  loop: "{{ _prometheus_target_yaml_files }}"
  loop_control:
    loop_var: _yaml_file
    label: "{{ _yaml_file.path }}"
  register: _yaml_results
  run_once: true

- name: Track aggregated YAML changes on each host
  ansible.builtin.set_fact:
    changed: >-
      {{ hostvars[ansible_play_batch | first]._yaml_results.results |
         selectattr('changed') | list | length > 0 }}