--- - name: Validate config file exists ansible.builtin.stat: path: "{{ config_file }}" register: config_check delegate_to: localhost connection: local - name: Fail if config missing ansible.builtin.fail: msg: "Configuration file {{ config_file }} not found!" when: not config_check.stat.exists - name: Ensure history directory exists ansible.builtin.file: path: "{{ config_dir }}" state: directory mode: '0750' owner: "{{ ansible_user_id | default(omit) }}" group: "{{ ansible_user_gid | default(omit) }}" delegate_to: localhost connection: local changed_when: false - name: Get current Patroni configuration ansible.builtin.uri: url: "http://{{ patroni_host }}:8008/config" method: GET return_content: yes status_code: 200 register: patroni_config changed_when: false - name: Save current config with timestamp ansible.builtin.copy: content: | # Original config from {{ ansible_date_time.iso8601 }} {{ patroni_config.content | from_json | to_nice_yaml }} dest: "{{ config_dir }}/{{ ansible_date_time.iso8601 | replace('T', '_') | replace(':', '-') | replace('+', '-UTC') }}-config.yaml" mode: '0640' owner: "{{ ansible_user_id | default(omit) }}" group: "{{ ansible_user_gid | default(omit) }}" delegate_to: localhost connection: local changed_when: false - name: Load configuration changes ansible.builtin.include_vars: file: "{{ config_file }}" name: config_changes delegate_to: localhost connection: local - name: Create merged configuration ansible.builtin.set_fact: new_config: "{{ patroni_config.content | from_json | combine(config_changes, recursive=True) }}" - name: Validate configuration changes ansible.builtin.command: cmd: | python3 -c ' import yaml, json, sys; try: yaml.safe_load(sys.stdin.read()) sys.exit(0) except Exception as e: print(f"Invalid YAML: {str(e)}") sys.exit(1)' stdin: "{{ new_config | to_nice_yaml }}" register: config_validation changed_when: false delegate_to: localhost connection: local - name: Save new config as last.yaml ansible.builtin.copy: content: | # Updated at {{ ansible_date_time.iso8601 }} {{ new_config | to_nice_yaml }} dest: "{{ config_dir }}/last.yaml" mode: '0640' owner: "{{ ansible_user_id | default(omit) }}" group: "{{ ansible_user_gid | default(omit) }}" delegate_to: localhost connection: local changed_when: false - name: Generate and display colored diff block: - name: Create temp files for diff ansible.builtin.shell: | cat > /tmp/old_config.yml << 'EOL' {{ patroni_config.content | from_json | to_nice_yaml }} EOL cat > /tmp/new_config.yml << 'EOL' {{ new_config | to_nice_yaml }} EOL delegate_to: localhost connection: local changed_when: false - name: Execute diff with colors ansible.builtin.command: > diff --color=always -u /tmp/old_config.yml /tmp/new_config.yml register: diff_result changed_when: diff_result.rc in [0,1] failed_when: diff_result.rc > 1 delegate_to: localhost connection: local - name: Cleanup temp files ansible.builtin.file: path: "/tmp/{{ item }}" state: absent loop: - old_config.yml - new_config.yml delegate_to: localhost connection: local changed_when: false - name: Display diff line by line ansible.builtin.debug: msg: "{{ item }}" loop: "{{ diff_result.stdout_lines }}" when: diff_result.stdout_lines | length > 0 loop_control: label: ""