I need a way to update one entry in rsyslog.conf on RHEL 8/9/10 systems, using Ansible (I'm using 2.16). Unfortunately, the new rsyslog format uses multiline entries that are not easily manipulated with something like lineinfile.
Original (this is from RHEL 10 beta; RHEL 8 and 9 are similar but not identical):
module(load="imjournal" # provides access to the systemd journal
StateFile="imjournal.state") # File to store the position in the journal
Desired:
module(load="imjournal" # provides access to the systemd journal
StateFile="imjournal.state" # File to store the position in the journal
Ratelimit.Interval="300"
Ratelimit.Burst="30000")
It would be OK to lose the comments, or change the format of the module config, as long as the semantics are preserved. It is also acceptable to replace existing parameters with the factory defaults.
What I've looked at so far:
As a hint. Given the file for testing
shell> cat /tmp/rsyslog.conf
module(load="imjournal" # imjournal
StateFile="imjournal.state" # file
)
module(load="foo" # foo
StateFile="foo.state" # file
)
module(load="bar" # bar
StateFile="bar.state" # file
)
mark_files:
- path: /tmp/rsyslog.conf
markers:
- marker: imjournal
regex1: 'module\(load="imjournal"(.*)'
replace1: 'module(load="imjournal"'
regex2: \)
replace2: )
and execute the block
- name: Create markers
when: markers | d(false) | bool
block:
- name: Create BEGIN markers
replace:
path: "{{ item.0.path }}"
regexp: "{{ item.1.regex1 }}"
replace: |-
{{ '#' }} BEGIN ANSIBLE MANAGED BLOCK {{ item.1.marker }}
{{ item.1.replace1 }}
loop: "{{ mark_files | subelements('markers') }}"
- name: Create END markers
replace:
path: "{{ item.0.path }}"
regexp: '({{ item.1.regex1 }}[\s\S]*?){{ item.1.regex2 }}'
replace: |-
\g<1>{{ item.1.replace2 }}
{{ '#' }} END ANSIBLE MANAGED BLOCK {{ item.1.marker }}
loop: "{{ mark_files | subelements('markers') }}"
This creates the markers
shell> cat /tmp/rsyslog.conf
# BEGIN ANSIBLE MANAGED BLOCK imjournal
module(load="imjournal"
StateFile="imjournal.state" # file
)
# END ANSIBLE MANAGED BLOCK imjournal
module(load="foo" # foo
StateFile="foo.state" # file
)
module(load="bar" # bar
StateFile="bar.state" # file
)
update_files:
- path: /tmp/rsyslog.conf
markers:
- marker: imjournal
block: |
module(load="imjournal"
StateFile="imjournal.state"
Ratelimit.Interval="300"
Ratelimit.Burst="30000"
)
and execute the task
- name: Update files
when: update | d(false) | bool
blockinfile:
path: "{{ item.0.path }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.1.marker }}"
block: "{{ item.1.block }}"
loop: "{{ update_files | subelements('markers') }}"
This updates the files
shell> cat /tmp/rsyslog.conf
# BEGIN ANSIBLE MANAGED BLOCK imjournal
module(load="imjournal"
StateFile="imjournal.state"
Ratelimit.Interval="300"
Ratelimit.Burst="30000"
)
# END ANSIBLE MANAGED BLOCK imjournal
module(load="foo" # foo
StateFile="foo.state" # file
)
module(load="bar" # bar
StateFile="bar.state" # file
)
Notes:
The block that creates the markers is not idempotent. See example how to check the markers.
The regex2/replace2 attributes in the above example work with standalone closing parenthesis only. You'll have to modify this to your needs.
For more details see blockinfile markers.
Example of a complete playbook for testing
- hosts: localhost
vars:
mark_files:
- path: /tmp/rsyslog.conf
markers:
- marker: imjournal
regex1: 'module\(load="imjournal"(.*)'
replace1: 'module(load="imjournal"'
regex2: \)
replace2: )
update_files:
- path: /tmp/rsyslog.conf
markers:
- marker: imjournal
block: |
module(load="imjournal"
StateFile="imjournal.state"
Ratelimit.Interval="300"
Ratelimit.Burst="30000"
)
tasks:
- name: Create markers
when: markers | d(false) | bool
block:
- name: Create BEGIN markers
replace:
path: "{{ item.0.path }}"
regexp: "{{ item.1.regex1 }}"
replace: |-
{{ '#' }} BEGIN ANSIBLE MANAGED BLOCK {{ item.1.marker }}
{{ item.1.replace1 }}
loop: "{{ mark_files | subelements('markers') }}"
- name: Create END markers
replace:
path: "{{ item.0.path }}"
regexp: '({{ item.1.regex1 }}[\s\S]*?){{ item.1.regex2 }}'
replace: |-
\g<1>{{ item.1.replace2 }}
{{ '#' }} END ANSIBLE MANAGED BLOCK {{ item.1.marker }}
loop: "{{ mark_files | subelements('markers') }}"
- name: Update files
when: update | d(false) | bool
blockinfile:
path: "{{ item.0.path }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.1.marker }}"
block: "{{ item.1.block }}"
loop: "{{ update_files | subelements('markers') }}"