Using Ansible blockinfile module multiple times in the same file

Once again, I struggled using Ansible module: blockinfile to change multiple sections of the same file. It's time to write somewhere how to achieve it.

I'm using Grafana config file as example. This file contains different sections separated by a header in the form of  [section_name]. I need to edit sections: server, database, analytics, security and user.

Edit only on section is simple:

---
- name: test
  hosts: localhost
  connection: local
  tasks:
      -   name: setup grafana
          blockinfile:
              path: /etc/grafana/grafana.ini
              marker: "# {mark} ANSIBLE MANAGED BLOCK - grafana role"
              insertafter: '\[server\]'
              block: |
                 http_addr = 127.0.0.1
                 root_url = https://grafana.acme.dev
                 enable_gzip = true
 

As expected, the result is:

[server]
# BEGIN ANSIBLE MANAGED BLOCK - grafana role
http_addr = 127.0.0.1
root_url = https://grafana.acme.dev
enable_gzip = true
# END ANSIBLE MANAGED BLOCK - grafana role
 

To edit multiple sections, I'm using var and loop.

---
- name: test
  hosts: localhost
  connection: local
  vars:
      grafana_config:
          -   insertafter: '\[server\]'
              block: |
                  http_addr = 127.0.0.1
                  root_url = https://grafana.acme.dev
                  enable_gzip = true
          -   insertafter: '\[database\]'
              block: |
                  type = mysql
                  host = 127.0.0.1:3306
                  name = grafana
                  user = grafana
                  password = secret_me
          -   insertafter: '\[analytics\]'
              block: |
                  reporting_enabled = false
                  check_for_updates = false
          -   insertafter: '\[security\]'
              block: |
                  admin_user = user1
                  admin_password = secret
                  secret_key = s3d5fs6d54ds6
                  disable_gravatar = true
                  cookie_secure = true
                  cookie_samesite = lax
          -   insertafter: '\[users\]'
              block: |
                  allow_sign_up = false
  tasks:
      -   name: configure grafana
          blockinfile:
              path: /etc/grafana/grafana.ini
              marker: "# {mark} ANSIBLE MANAGED BLOCK - grafana role"
              insertafter: "{{ item.insertafter }}"
              block: "{{ item.block }}"
          loop: "{{ grafana_config }}"
          when:
              - item|lower != 'none'
 

Everything looks good but the result is unexpected. Each block is replaced by the next one inside the marker and only the last stay in the file and in the wrong section.

[server]
# BEGIN ANSIBLE MANAGED BLOCK - grafana role
allow_sign_up = false
# END ANSIBLE MANAGED BLOCK - grafana role
 

It's annoying, to solve this I found out I need to have a dedicated marker by section. The new task looks like this:

---
- name: test
  hosts: localhost
  connection: local
  vars:
      grafana_config:
          -   insertafter: '\[server\]'
              section: server
              block: |
                  http_addr = 127.0.0.1
                  root_url = https://grafana.acme.dev
                  enable_gzip = true
          -   insertafter: '\[database\]'
              section: database
              block: |
                  type = mysql
                  host = 127.0.0.1:3306
                  name = grafana
                  user = grafana
                  password = secret_me
          -   insertafter: '\[analytics\]'
              section: analytics
              block: |
                  reporting_enabled = false
                  check_for_updates = false
          -   insertafter: '\[security\]'
              section: security
              block: |
                  admin_user = user1
                  admin_password = secret
                  secret_key = s3d5fs6d54ds6
                  disable_gravatar = true
                  cookie_secure = true
                  cookie_samesite = lax
          -   insertafter: '\[users\]'
              section: users
              block: |
                  allow_sign_up = false
  tasks:
      -   name: configure grafana
          blockinfile:
              path: /etc/grafana/grafana.ini
              marker: "# {mark} ANSIBLE MANAGED BLOCK - {{ item.section }} - grafana role"
              insertafter: "{{ item.insertafter }}"
              block: "{{ item.block }}"
          loop: "{{ grafana_config }}"
          when:
              - item|lower != 'none'
 

This time I got the expected result, having one block for each section I want to change. I hope this tips will help someone to achieve his goal faster than I did.





Add a comment