In ansible how to add a block of text at end of a file with a blank line before the marker?

Viewed 8614

I have a playbook as shown below:

- hosts: localhost
  tasks:
    - name: update a file
      blockinfile:
        dest: /tmp/test
        block: |
          line 1
          line 2

Upon running the playbook, the file /tmp/test becomes:

a # this is the end line of the original file
# BEGIN ANSIBLE MANAGED BLOCK
line 1
line 2
# END ANSIBLE MANAGED BLOCK

I would like to add a blank line (newline) before the marker "# BEGIN ANSIBLE MANAGED BLOCK" for visual effect, what is the easiest way to do it? Preferably within the task, but any idea is welcome. If I redefine the marker, it will affect both the "BEGIN" and "END" marker.

3 Answers

Use lineinfile. For example

- hosts: localhost
  tasks:
    - name: update a file
      blockinfile:
        dest: /tmp/test
        block: |
          line 1
          line 2
    - name: insert empty line before the marker
      lineinfile:
        dest: /tmp/test
        insertbefore: '^# BEGIN ANSIBLE MANAGED BLOCK$'
        line: ''

Unfortunately insertbefore doesn't work with more blocks. template module might be needed if you insist on empty lines among blocks.

Try the playbook below. Unfortunately, EOF doesn't work as expected

shell> cat manage-block.yml
- name: "insert {{ my_marker }} in {{ my_dest }}"
  blockinfile:
    dest: "{{ my_dest }}"
    marker: "# {mark} ANSIBLE MANAGED BLOCK {{ my_marker }}"
    block: "{{ my_block }}"
- name: "insert empty line before {{ my_marker }}"
  lineinfile:
    dest: "{{ my_dest }}"
    insertbefore: '^# BEGIN ANSIBLE MANAGED BLOCK {{ my_marker }}'
    line: 'empty line'
  when: ansible_loop.first
- name: "insert empty line after EOF"
  lineinfile:
    dest: "{{ my_dest }}"
    insertafter: EOF
    line: 'empty line'
- hosts: localhost
  vars:
    my_blocks:
      /tmp/test:
        - my_marker: block001
          my_block: |
            line 1
            line 2
        - my_marker: block002
          my_block: |
            line 3
            line 4
  tasks:
    - include_tasks: manage-block.yml
      with_subelements:
        - "{{ my_blocks|dict2items }}"
        - value
      loop_control:
          extended: true
      vars:
        my_dest: "{{ item.0.key }}"
        my_marker: "{{ item.1.my_marker }}"
        my_block: "{{ item.1.my_block }}"

If you are on Ansible 2.5 or above, you could alter the marker, marker_begin and marker_end.

Here is an example playbook:

- hosts: all
  gather_facts: no

  tasks:
    - blockinfile:
        dest: /tmp/test
        marker: '{mark} ANSIBLE MANAGED BLOCK'
        marker_begin: '\n# BEGIN' 
        marker_end: '# END'
        block: |
          line 1
          line 2

This yields the recap:

PLAY [all] ********************************************************************************************************

TASK [blockinfile] ************************************************************************************************
changed: [localhost]

PLAY RECAP ********************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

And the file /tmp/test ends up being:

a
 
# BEGIN ANSIBLE MANAGED BLOCK
line 1
line 2
# END ANSIBLE MANAGED BLOCK

The following adds an empty line before a pattern, and it is idempotent and does not add at the end of file when pattern is not present.

- hosts: localhost
  gather_facts: no
  tasks:
    - name: update a file
      replace:
        dest: /tmp/foobar
        regexp: '(?smx) (?<!\n\n) ^ (foobar)$'
        replace: "\n\\1"
Related