ansiblersyslog

Ansible: update rsyslog.conf multiline entry


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:


Solution

  • 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:


    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') }}"