3

I am starting to look into using ansible for maintaining a set of servers. I have ran into a difficulty with lineinfile. I am setting up rsyslog and want to make sure a few lines are in the /etc/rsyslog.conf:

  - name: set up rsyslog
    lineinfile:
       dest: /etc/rsyslog.conf
       line: '{{ item }}'
    with_items:
       - "*.* @@rsysserver.example.com:514"
       - "*.info;mail.none;authpriv.none;cron.none;user.none      /var/log/messages"
       - "user.*                                                  -/var/log/user_messages"

This works fine on a new box, but my problem is that some of the servers have been hand-maintained for a while and that means that the amount of whitespace in the lines may differ, so if there should be a line like user.* -/var/log/user_messages ansible will add on the last item in the rule above.

I could make three different rules like

    lineinfile:
       dest: /etc/rsyslog.conf
       line: user.*                                                  -/var/log/user_messages
       regexp: 'user.\*\s+-/var/log/user_messages'
       state: present

should work, but then I need to write three different rules to add the three lines to /etc/syslog.conf.

Is there any way I can set up one rule to maintain the file but use different regexes for each of the lines I want to add?

2 Answers2

1

Write a rule or script that removes the lines first, then use your "set up rsyslog" task to add it back in. Once all the files are fixed and consistent you can remove the rule or script that was removing the line.

Alternatively, have you considered managing the entire /etc/rsyslog.conf file with Ansible instead of trying to add/remove/update individual lines from the file? This is how I would do it if possible.

tbenz9
  • 7,095
1

Systemic, more robust, and the idempotent way would be declaring the selector and action separately, and use it both in regexp and line. For example

- name: set up rsyslog
  lineinfile:
    dest: rsyslog.conf
    regexp: '^\s*{{ item.selector|regex_escape() }}\s+{{ item.action|regex_escape() }}\s*$'
    line: '{{ item.selector }} {{ item.action }}'
  loop:
    - selector: '*.*'
      action: '@@rsysserver.example.com:514'
    - selector: '*.info;mail.none;authpriv.none;cron.none;user.none'
      action: '/var/log/messages'
    - selector: 'user.*'
      action: '-/var/log/user_messages'

gives

shell> cat rsyslog.conf 
*.* @@rsysserver.example.com:514
*.info;mail.none;authpriv.none;cron.none;user.none /var/log/messages
user.* -/var/log/user_messages

Use backrefs if you want to keep the spacing between the selector and action. For example, the task below

- name: set up rsyslog
  lineinfile:
    dest: rsyslog.conf
    backrefs: true
    regexp: '^\s*{{ item.selector|regex_escape() }} (\s*){{ item.action|regex_escape() }}\s*$'
    line: '{{ item.selector }} \1{{ item.action }}'
  loop:
    - selector: '*.*'
      action: '@@rsysserver.example.com:514'
    - selector: '*.info;mail.none;authpriv.none;cron.none;user.none'
      action: '/var/log/messages'
    - selector: 'user.*'
      action: '-/var/log/user_messages'

will keep this file unchanged

shell> cat rsyslog.conf
*.*                                                @@rsysserver.example.com:514
*.info;mail.none;authpriv.none;cron.none;user.none /var/log/messages
user.*                                             -/var/log/user_messages

Unfortunately, new lines won't be added. Quoting from backrefs

if the regexp does not match anywhere in the file, the file will be left unchanged

See format to try more sophisticated formatting.

  • 1
    I'm getting "page not found" when selecting the "format" link shared by Vladimir near the end of his excellent answer, thus I would just like to share for others that link appears to be the current URL. – JeremyCanfield Sep 22 '21 at 12:11