ansible lineinfile regex multiline

16,351

Solution 1

I managed to do exactly this by slightly improving @mattyoung-redhatmatt's answer. As it turns out, the replace module handles multi line regular expressions and backreferences just fine:

- name: AllowOverride all
  replace:
    dest=/etc/apache2/apache2.conf
    regexp='(<[dD]irectory /var/www/>[^<]*)AllowOverride None'
    replace='\1AllowOverride All'
    backup=yes
  sudo: yes
  notify:
    - restart apache

Solution 2

I tried and I tried to use blockinfile for this and I did not want to use a full template. I ended up using ansible's replace module and practicing a little regex on regex.com:

- hosts: all
  tasks:
    - name: Update apache2.conf
      replace: dest=/etc/apache2/apache2.conf
        regexp='<Directory /var/www/>\n\tOptions Indexes FollowSymLinks\n\tAllowOverride None'
        replace='<Directory /var/www/>\n\tOptions Indexes FollowSymLinks\n\tAllowOverride All'
        backup=yes
      notify:
        - restart apache2
  handlers:
    - name: restart apache2
      service: name=apache2 state=restarted

Solution 3

Ansible's lineinfile module does precisely just that, it deals with single lines in files and has no support for multiple lines.

This leaves you with a couple of options to tackle this problem instead.

As with most tricky things around lineinfile you might be best replacing this with a template instead.

Alternatively you could try using the blockinfile role to first remove (state=absent) the following block:

        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted

after <Directory /var/www/> and then inserting (state=present) the following block:

        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted

after <Directory /var/www/>.

Share:
16,351
Fatimah Wulandari
Author by

Fatimah Wulandari

Updated on August 10, 2022

Comments

  • Fatimah Wulandari
    Fatimah Wulandari over 1 year

    I'm trying to edit apache.conf using Ansible. Here's part of my conf:

    # Sets the default security model of the Apache2 HTTPD server. It does
    # not allow access to the root filesystem outside of /usr/share and /var/www.
    # The former is used by web applications packaged in Debian,
    # the latter may be used for local directories served by the web server. If
    # your system is serving content from a sub-directory in /srv you must allow
    # access here, or in any related virtual host.
    <Directory />
            Options FollowSymLinks
            AllowOverride None
            Require all denied
    </Directory>
    
    <Directory /usr/share>
            AllowOverride None
            Require all granted
    </Directory>
    
    <Directory /var/www/>
            Options Indexes FollowSymLinks
            AllowOverride None
            Require all granted
    </Directory>
    
    #<Directory /srv/>
    #       Options Indexes FollowSymLinks
            AllowOverride All
    #       Require all granted
    #</Directory>
    

    I want to change this block

    <Directory /var/www/>
                Options Indexes FollowSymLinks
                AllowOverride None
                Require all granted
        </Directory>
    

    into

    <Directory /var/www/>
                Options Indexes FollowSymLinks
                AllowOverride All
                Require all granted
        </Directory>
    

    set AllowOverride from None to All. I'm using this ansible task

    - name: change htaccess support
      lineinfile:
        dest: /etc/apache2/apache2.conf
        regexp: '\s<Directory /var/www/>\n\sOptions Indexes FollowSymLinks\n\sAllowOverride'
        line: "AllowOverride All"
      tags:
        - test
    

    However, AllowOverride All always added to the end of file. What's the correct regex pattern to do this jobs. I don't use ansible template cuz I only change one line.

  • Fatimah Wulandari
    Fatimah Wulandari over 8 years
    thank you. but I decide to use copy module to recplace file.
  • rsjethani
    rsjethani about 7 years
    replace's multi line understanding will break if you use .* instead of [^<]* in your expression. The '.*' is a very common expression and here replace will not work. The reason: by default '.' matches any characters except a new line: docs.python.org/2/library/re.html#re.DOTALL. But yes best answer so far :)
  • oneindelijk
    oneindelijk almost 6 years
    I'm trying to match a multiline entry to use for the insertafter parameter, which I suppose ist just a regexp with a different function ? I'm actually trying to us blockinfile to add a DNS zone in the /etc/named.conf which should come after the whole Zone "." IN {}; block. I'm trying now with .*, but if that doesn't capture the newlines, I will try your approach. Thanks