)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"aef1d17b368e73316dbef0d846b40c9e7e89b8bc","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"aeb13830_7c910761","updated":"2026-10-07 07:38:14.000000000","message":"Also a release note about fixing idempotency might be nice, but optional.","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"44d1726cc180d5ad00d66695769c4a9baa3dc4b8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"3eb8f49f_e1002337","updated":"2026-10-07 08:39:59.000000000","message":"recheck","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"}],"handlers/main.yml":[{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"aef1d17b368e73316dbef0d846b40c9e7e89b8bc","unresolved":true,"context_lines":[{"line_number":71,"context_line":"        mode: \"0640\""},{"line_number":72,"context_line":"      when: item.changed | default(false)"},{"line_number":73,"context_line":"      loop: \"{{ haproxy_service_change.results }}\""},{"line_number":74,"context_line":"    - name: Fail as we failed to assemble configuration"},{"line_number":75,"context_line":"      ansible.builtin.fail:"},{"line_number":76,"context_line":"        msg: Failed to assemble haproxy configuration"},{"line_number":77,"context_line":"  always:"}],"source_content_type":"text/x-yaml","patch_set":1,"id":"c872ace3_a5edd55c","line":74,"range":{"start_line":74,"start_character":0,"end_line":74,"end_character":55},"updated":"2026-10-07 07:38:14.000000000","message":"can you please insert new line in between, as otherwise this task hard to visually distinguish.","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"a326381b228857965652d5e442157a8e55b788c0","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        mode: \"0640\""},{"line_number":72,"context_line":"      when: item.changed | default(false)"},{"line_number":73,"context_line":"      loop: \"{{ haproxy_service_change.results }}\""},{"line_number":74,"context_line":"    - name: Fail as we failed to assemble configuration"},{"line_number":75,"context_line":"      ansible.builtin.fail:"},{"line_number":76,"context_line":"        msg: Failed to assemble haproxy configuration"},{"line_number":77,"context_line":"  always:"}],"source_content_type":"text/x-yaml","patch_set":1,"id":"2cd6bed7_6b904428","line":74,"range":{"start_line":74,"start_character":0,"end_line":74,"end_character":55},"in_reply_to":"5a92040b_0180f8b2","updated":"2026-10-20 15:20:32.000000000","message":"Done","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":32053,"name":"Denys Mishchenko","email":"denis@mischenko.org.ua","username":"arddennis"},"change_message_id":"523be3d06de4f8674eb59407c43450910f169ad0","unresolved":true,"context_lines":[{"line_number":71,"context_line":"        mode: \"0640\""},{"line_number":72,"context_line":"      when: item.changed | default(false)"},{"line_number":73,"context_line":"      loop: \"{{ haproxy_service_change.results }}\""},{"line_number":74,"context_line":"    - name: Fail as we failed to assemble configuration"},{"line_number":75,"context_line":"      ansible.builtin.fail:"},{"line_number":76,"context_line":"        msg: Failed to assemble haproxy configuration"},{"line_number":77,"context_line":"  always:"}],"source_content_type":"text/x-yaml","patch_set":1,"id":"5a92040b_0180f8b2","line":74,"range":{"start_line":74,"start_character":0,"end_line":74,"end_character":55},"in_reply_to":"c872ace3_a5edd55c","updated":"2026-10-07 22:53:53.000000000","message":"will keep new lines between tasks, sorry","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"aef1d17b368e73316dbef0d846b40c9e7e89b8bc","unresolved":true,"context_lines":[{"line_number":72,"context_line":"      when: item.changed | default(false)"},{"line_number":73,"context_line":"      loop: \"{{ haproxy_service_change.results }}\""},{"line_number":74,"context_line":"    - name: Fail as we failed to assemble configuration"},{"line_number":75,"context_line":"      ansible.builtin.fail:"},{"line_number":76,"context_line":"        msg: Failed to assemble haproxy configuration"},{"line_number":77,"context_line":"  always:"},{"line_number":78,"context_line":"    - name: Cleanup backup files"},{"line_number":79,"context_line":"      ansible.builtin.file:"}],"source_content_type":"text/x-yaml","patch_set":1,"id":"2ff76630_01e937a0","line":76,"range":{"start_line":75,"start_character":5,"end_line":76,"end_character":53},"updated":"2026-10-07 07:38:14.000000000","message":"Question - would we still see the error for assemble? I guess yes?\n\nJust thinking if we should register the assemble result and print out error here and hide details in prior task. But maybe not worth it.","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"a326381b228857965652d5e442157a8e55b788c0","unresolved":false,"context_lines":[{"line_number":72,"context_line":"      when: item.changed | default(false)"},{"line_number":73,"context_line":"      loop: \"{{ haproxy_service_change.results }}\""},{"line_number":74,"context_line":"    - name: Fail as we failed to assemble configuration"},{"line_number":75,"context_line":"      ansible.builtin.fail:"},{"line_number":76,"context_line":"        msg: Failed to assemble haproxy configuration"},{"line_number":77,"context_line":"  always:"},{"line_number":78,"context_line":"    - name: Cleanup backup files"},{"line_number":79,"context_line":"      ansible.builtin.file:"}],"source_content_type":"text/x-yaml","patch_set":1,"id":"ff5a1892_5d91d719","line":76,"range":{"start_line":75,"start_character":5,"end_line":76,"end_character":53},"in_reply_to":"26604e59_4a4bea60","updated":"2026-10-20 15:20:32.000000000","message":"Done","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":32053,"name":"Denys Mishchenko","email":"denis@mischenko.org.ua","username":"arddennis"},"change_message_id":"523be3d06de4f8674eb59407c43450910f169ad0","unresolved":true,"context_lines":[{"line_number":72,"context_line":"      when: item.changed | default(false)"},{"line_number":73,"context_line":"      loop: \"{{ haproxy_service_change.results }}\""},{"line_number":74,"context_line":"    - name: Fail as we failed to assemble configuration"},{"line_number":75,"context_line":"      ansible.builtin.fail:"},{"line_number":76,"context_line":"        msg: Failed to assemble haproxy configuration"},{"line_number":77,"context_line":"  always:"},{"line_number":78,"context_line":"    - name: Cleanup backup files"},{"line_number":79,"context_line":"      ansible.builtin.file:"}],"source_content_type":"text/x-yaml","patch_set":1,"id":"26604e59_4a4bea60","line":76,"range":{"start_line":75,"start_character":5,"end_line":76,"end_character":53},"in_reply_to":"2ff76630_01e937a0","updated":"2026-10-07 22:53:53.000000000","message":"as I needed to block fail on assemble. Due to block not properly working in handler (or I didn\u0027t manage to). I did like you suggested and printed fail message. That fail is text is also expected in negative test scenario which I\u0027ve added to the side-effects test.","commit_id":"62738ad5b3c2a607921b456556224bf7ade9274c"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"450e23c618d82fb728f3b1712abb93fe6b778617","unresolved":true,"context_lines":[{"line_number":41,"context_line":"- name: Regenerate maps"},{"line_number":42,"context_line":"  vars:"},{"line_number":43,"context_line":"    all_changed_results: \"{{ (map_create.results + map_delete.results) | select(\u0027changed\u0027) }}\""},{"line_number":44,"context_line":"  ansible.builtin.assemble:"},{"line_number":45,"context_line":"    src: \"/etc/haproxy/map.conf.d/{{ item }}\""},{"line_number":46,"context_line":"    dest: \"/etc/haproxy/{{ item }}.map\""},{"line_number":47,"context_line":"    mode: \"0640\""},{"line_number":48,"context_line":"    owner: haproxy"},{"line_number":49,"context_line":"    group: haproxy"},{"line_number":50,"context_line":"  with_items: \"{{ all_changed_results | map(attribute\u003d\u0027item\u0027) | flatten | selectattr(\u0027name\u0027, \u0027defined\u0027) | map(attribute\u003d\u0027name\u0027) | unique }}\""},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"- name: Regenerate HAProxy configuration"},{"line_number":53,"context_line":"  ansible.builtin.include_tasks: haproxy_assemble.yml"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"83f2557c_c1b1fb42","line":50,"range":{"start_line":44,"start_character":0,"end_line":50,"end_character":140},"updated":"2026-10-07 13:26:01.000000000","message":"oh, btw, this assemble can also result in failed config. It just needs a diferent register/block?","commit_id":"c5bc00bdf7906f85dc5ad7f0a914edb64cee4db8"},{"author":{"_account_id":32053,"name":"Denys Mishchenko","email":"denis@mischenko.org.ua","username":"arddennis"},"change_message_id":"523be3d06de4f8674eb59407c43450910f169ad0","unresolved":true,"context_lines":[{"line_number":41,"context_line":"- name: Regenerate maps"},{"line_number":42,"context_line":"  vars:"},{"line_number":43,"context_line":"    all_changed_results: \"{{ (map_create.results + map_delete.results) | select(\u0027changed\u0027) }}\""},{"line_number":44,"context_line":"  ansible.builtin.assemble:"},{"line_number":45,"context_line":"    src: \"/etc/haproxy/map.conf.d/{{ item }}\""},{"line_number":46,"context_line":"    dest: \"/etc/haproxy/{{ item }}.map\""},{"line_number":47,"context_line":"    mode: \"0640\""},{"line_number":48,"context_line":"    owner: haproxy"},{"line_number":49,"context_line":"    group: haproxy"},{"line_number":50,"context_line":"  with_items: \"{{ all_changed_results | map(attribute\u003d\u0027item\u0027) | flatten | selectattr(\u0027name\u0027, \u0027defined\u0027) | map(attribute\u003d\u0027name\u0027) | unique }}\""},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"- name: Regenerate HAProxy configuration"},{"line_number":53,"context_line":"  ansible.builtin.include_tasks: haproxy_assemble.yml"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"a2dc0957_71de866b","line":50,"range":{"start_line":44,"start_character":0,"end_line":50,"end_character":140},"in_reply_to":"83f2557c_c1b1fb42","updated":"2026-10-07 22:53:53.000000000","message":"yes, this needs separate rescue block. If it is ok, I can create assemble handler for map similar to implemented one in additional file.","commit_id":"c5bc00bdf7906f85dc5ad7f0a914edb64cee4db8"},{"author":{"_account_id":32053,"name":"Denys Mishchenko","email":"denis@mischenko.org.ua","username":"arddennis"},"change_message_id":"ac617b652c9ed84f43f3c82ec7391cf132628505","unresolved":true,"context_lines":[{"line_number":41,"context_line":"- name: Regenerate maps"},{"line_number":42,"context_line":"  vars:"},{"line_number":43,"context_line":"    all_changed_results: \"{{ (map_create.results + map_delete.results) | select(\u0027changed\u0027) }}\""},{"line_number":44,"context_line":"  ansible.builtin.assemble:"},{"line_number":45,"context_line":"    src: \"/etc/haproxy/map.conf.d/{{ item }}\""},{"line_number":46,"context_line":"    dest: \"/etc/haproxy/{{ item }}.map\""},{"line_number":47,"context_line":"    mode: \"0640\""},{"line_number":48,"context_line":"    owner: haproxy"},{"line_number":49,"context_line":"    group: haproxy"},{"line_number":50,"context_line":"  with_items: \"{{ all_changed_results | map(attribute\u003d\u0027item\u0027) | flatten | selectattr(\u0027name\u0027, \u0027defined\u0027) | map(attribute\u003d\u0027name\u0027) | unique }}\""},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"- name: Regenerate HAProxy configuration"},{"line_number":53,"context_line":"  ansible.builtin.include_tasks: haproxy_assemble.yml"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"fda7cd2d_363d6f09","line":50,"range":{"start_line":44,"start_character":0,"end_line":50,"end_character":140},"in_reply_to":"a2dc0957_71de866b","updated":"2026-10-09 07:14:14.000000000","message":"assemble validation for the map files becomes a kind of pointless as it doesn\u0027t lead to failed to start service. Incorrect records are being ignored by haproxy. \nActual validation can be done by parsing list of backends in haproxy.cfg file and checking if defined backends in the map files actually exist in the backends list. But map file format could be different based on the map type, so it looks to be overcomplicated to verify all cases and rollback in case of mistake. Doable, but we might need to write python module for ansible to do such test (not an easy to check all cases in bash). Doable, but it looks to be a separate case.","commit_id":"c5bc00bdf7906f85dc5ad7f0a914edb64cee4db8"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"a326381b228857965652d5e442157a8e55b788c0","unresolved":false,"context_lines":[{"line_number":41,"context_line":"- name: Regenerate maps"},{"line_number":42,"context_line":"  vars:"},{"line_number":43,"context_line":"    all_changed_results: \"{{ (map_create.results + map_delete.results) | select(\u0027changed\u0027) }}\""},{"line_number":44,"context_line":"  ansible.builtin.assemble:"},{"line_number":45,"context_line":"    src: \"/etc/haproxy/map.conf.d/{{ item }}\""},{"line_number":46,"context_line":"    dest: \"/etc/haproxy/{{ item }}.map\""},{"line_number":47,"context_line":"    mode: \"0640\""},{"line_number":48,"context_line":"    owner: haproxy"},{"line_number":49,"context_line":"    group: haproxy"},{"line_number":50,"context_line":"  with_items: \"{{ all_changed_results | map(attribute\u003d\u0027item\u0027) | flatten | selectattr(\u0027name\u0027, \u0027defined\u0027) | map(attribute\u003d\u0027name\u0027) | unique }}\""},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"- name: Regenerate HAProxy configuration"},{"line_number":53,"context_line":"  ansible.builtin.include_tasks: haproxy_assemble.yml"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"041d0ba3_d5ae3a46","line":50,"range":{"start_line":44,"start_character":0,"end_line":50,"end_character":140},"in_reply_to":"fda7cd2d_363d6f09","updated":"2026-10-20 15:20:32.000000000","message":"Done","commit_id":"c5bc00bdf7906f85dc5ad7f0a914edb64cee4db8"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"a6053ca2781118b9033601e85bf73c1b9134230a","unresolved":true,"context_lines":[{"line_number":51,"context_line":""},{"line_number":52,"context_line":"- name: Regenerate HAProxy configuration"},{"line_number":53,"context_line":"  ansible.builtin.include_tasks: haproxy_assemble.yml"},{"line_number":54,"context_line":"  listen: \"Regenerate HAProxy configuration\""},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"- name: Get package facts"},{"line_number":57,"context_line":"  ansible.builtin.package_facts:"}],"source_content_type":"text/x-yaml","patch_set":3,"id":"62bf512a_f0012893","line":54,"range":{"start_line":54,"start_character":0,"end_line":54,"end_character":44},"updated":"2026-10-20 17:03:20.000000000","message":"I am not sure how it behaves... But do we need to have listen when name is matching? Or we do because it\u0027s an include?","commit_id":"808795a951acb5e6c875ed4f7787cc46df18ac40"}],"tasks/haproxy_service_config.yml":[{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"cdfb197be42adc74aa6f2992ea85cd66f3638a65","unresolved":true,"context_lines":[{"line_number":68,"context_line":"    }}"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"# Create map entries when the service is enabled and an existing map fragment is not absent"},{"line_number":71,"context_line":"- name: Create HAProxy map files"},{"line_number":72,"context_line":"  vars:"},{"line_number":73,"context_line":"    map_file: \"/etc/haproxy/map.conf.d/{{ item.1.name }}/{{ item.1.order | default(\u002700\u0027) }}-{{ item.0.haproxy_service_name }}.map\""},{"line_number":74,"context_line":"  ansible.builtin.template:"},{"line_number":75,"context_line":"    src: map.j2"},{"line_number":76,"context_line":"    dest: \"{{ map_file }}\""},{"line_number":77,"context_line":"    owner: root"},{"line_number":78,"context_line":"    group: haproxy"},{"line_number":79,"context_line":"    mode: \"0640\""},{"line_number":80,"context_line":"  with_subelements:"},{"line_number":81,"context_line":"    - \"{{ haproxy_service_configs | selectattr(\u0027haproxy_map_entries\u0027, \u0027defined\u0027) }}\""},{"line_number":82,"context_line":"    - haproxy_map_entries"},{"line_number":83,"context_line":"  when:"},{"line_number":84,"context_line":"    - (item.0.haproxy_service_enabled | default(true)) | bool"},{"line_number":85,"context_line":"    - item.1.state | default(\u0027present\u0027) !\u003d \u0027absent\u0027"},{"line_number":86,"context_line":"  notify: Regenerate maps"},{"line_number":87,"context_line":"  register: map_create"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"# Remove map entries when the service is not enabled, the service is absent or the map is absent"},{"line_number":90,"context_line":"- name: Delete unused map entries"},{"line_number":91,"context_line":"  ansible.builtin.file:"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"a9cf3496_4319faac","line":88,"range":{"start_line":71,"start_character":0,"end_line":88,"end_character":0},"updated":"2026-10-07 13:48:33.000000000","message":"And it\u0027s this one.","commit_id":"c5bc00bdf7906f85dc5ad7f0a914edb64cee4db8"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"a6053ca2781118b9033601e85bf73c1b9134230a","unresolved":false,"context_lines":[{"line_number":68,"context_line":"    }}"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"# Create map entries when the service is enabled and an existing map fragment is not absent"},{"line_number":71,"context_line":"- name: Create HAProxy map files"},{"line_number":72,"context_line":"  vars:"},{"line_number":73,"context_line":"    map_file: \"/etc/haproxy/map.conf.d/{{ item.1.name }}/{{ item.1.order | default(\u002700\u0027) }}-{{ item.0.haproxy_service_name }}.map\""},{"line_number":74,"context_line":"  ansible.builtin.template:"},{"line_number":75,"context_line":"    src: map.j2"},{"line_number":76,"context_line":"    dest: \"{{ map_file }}\""},{"line_number":77,"context_line":"    owner: root"},{"line_number":78,"context_line":"    group: haproxy"},{"line_number":79,"context_line":"    mode: \"0640\""},{"line_number":80,"context_line":"  with_subelements:"},{"line_number":81,"context_line":"    - \"{{ haproxy_service_configs | selectattr(\u0027haproxy_map_entries\u0027, \u0027defined\u0027) }}\""},{"line_number":82,"context_line":"    - haproxy_map_entries"},{"line_number":83,"context_line":"  when:"},{"line_number":84,"context_line":"    - (item.0.haproxy_service_enabled | default(true)) | bool"},{"line_number":85,"context_line":"    - item.1.state | default(\u0027present\u0027) !\u003d \u0027absent\u0027"},{"line_number":86,"context_line":"  notify: Regenerate maps"},{"line_number":87,"context_line":"  register: map_create"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"# Remove map entries when the service is not enabled, the service is absent or the map is absent"},{"line_number":90,"context_line":"- name: Delete unused map entries"},{"line_number":91,"context_line":"  ansible.builtin.file:"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"8821d68f_67d1412a","line":88,"range":{"start_line":71,"start_character":0,"end_line":88,"end_character":0},"in_reply_to":"a9cf3496_4319faac","updated":"2026-10-20 17:03:20.000000000","message":"Done","commit_id":"c5bc00bdf7906f85dc5ad7f0a914edb64cee4db8"}]}
