5

Following this answer, I want to make a copy of OpenSSL's configuration, with a specific set of changes. The original file is out of my control, so I can't make it a template.

At the moment I have:

  - name: Make a copy
    copy:
      src: original.cnf
      dest: copy.cnf
      force: no
  - name: Modify
    ini_file:
      path: copy.cnf
      section: ...
      option: ...
      value: ...

This sequence of changes is idempotent, but if the original file changes, the change won't be propagated to the copy. If I change this to force: yes, then original changes will be propagated, but the changes will be performed every time the playbook is run. This is problematic, since I need to restart dependent services in the case of changes, but obviously this must not happen every time.

Is there a way to maintain a copy in such a way that the target file is modified if and only if it's needed?

Petr
  • 581
  • 1
  • 5
  • 16

2 Answers2

2
- block:
  name: These two are changed every time as modifications are not in original.cnf
  - name: Make a temporary copy
    copy:
      src: original.cnf
      dest: temp.cnf
      force: yes
  - name: Modify temporary copy
    ini_file:
      path: temp.cnf
      section: ...
      option: ...
      value: ...

- block:
  name: With same original.cnf and same modifications, the result will be already installed
  - name: Idempotent copy into place
    register: openssl_config_install
    copy:
      src: temp.cnf
      dest: copy.cnf
      force: yes


- assert:
    that:
      - openssl_config_install is not changed
John Mahowald
  • 32,050
  • 2
  • 19
  • 34
  • Nice idea! While it still applies the changes the first block unconditionally, the second block is applied only if there is a change. Also it could be useful to use the [tempfile](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/tempfile_module.html) in the first block. – Petr Jan 04 '21 at 08:30
  • The first block only exists because of your requirement to use the original unmodified and also install future changes. I prefer template in one step, even if it means maintaining a lightly modified copy of the original. – John Mahowald Jan 05 '21 at 20:25
2

Based on John's answer, I ended up with the following playbook fragment. The important part is changed_when: False, which makes sure that only the step that modifies the target config file copy is counted as a change.

- name: Create OpenSSL config copy
  block:
  - name: Create temporary file for the config's copy
    tempfile:
    register: tempfile
    changed_when: False
  - name: Copy openssl.cnf to the temporary file
    copy:
      src: "{{ openssl_cnf_source }}"
      dest: "{{ tempfile.path }}"
      mode: 0644  # Without this the next `copy` task can have issues reading the file.
    changed_when: False
  - name: Modify openssl.cnf in the temporary file
    ini_file:
      path: "{{ tempfile.path }}"
      section: ...
      option: ...
      value: ...
    changed_when: False
  - name: Copy the temporary file to the target OpenSSL config
    copy:
      src: "{{ tempfile.path }}"
      dest: "{{ openssl_cnf_copy }}"
      mode: 0644
      owner: ...
    notify:
      - ...
  - name: Delete the temporary file
    file:
      path: "{{ tempfile.path }}"
      state: absent
    changed_when: False
Petr
  • 581
  • 1
  • 5
  • 16