Lineinfile matches one regex but not another

Working on creating a playbook to enforce CIS Benchmarks for Apache 2.4 on Red Hat Enterprise Linux 9. On control 5.1 it suggests adding “Options None” to the element. Config would look like this:

<Directory />
Options None
Other Directives
Etc
</Directory>

In example 1 below, it functions as I anticipate how adding a line with lineinfile would go. The next control suggests adding the same directive “Options None” to the document root directory element, with this as the end result:

<Directory “/var/www/html”>
Options None
Other directive
Etc
</Directory>

Example 2 shows my code and I am not getting the result that I expected. The major difference between example 1 and 2 insertafter regex is the quotation marks around the directory in example 2. I have tried different regex patterns trying to match it but I’m not having any luck. Am I missing something? I suppose in the end I can replace <Directory “/var/www/html”> with <Directory /var/www/html>, but I’d like to know what is causing the hang up here.

  • Version(s) of the relevant software tools, libraries, collections etc
    • Ansible Core: 2.14.5
    • Python 3.9
    • ansible.builtin.lineinfile

Example 1 - Working

  ansible.builtin.lineinfile:
    path: /etc/httpd/conf/httpd.conf
    line: "    Options None"
    state: present
    insertafter: <Directory />

Example 2 - Not working

  ansible.builtin.lineinfile:
    path: /etc/httpd/conf/httpd.conf
    line: "    Options None"
    state: present
    insertafter: <Directory "/var/www">

Hi, your regex in insertafter is correct, quotes can be used as quotes without any escaping. But there is a common misunderstanding about ansible.builtin.lineinfile module.

Simply, this module does nothing if the specified line already exists in the file. It does not matter where the line is placed, even if insertafter is specified.
The parameter insertafter is to indicate the place to insert line if no line is found.

Therefore, this module is not good choice for the tasks that insert the same line in multiple places.

I believe the line Options None always exists in the file on your second task, since the exact same line is added by the first task, or other directives in the same file already has the same options. I believe this is why your second task does nothing.

I don’t know your requirements in detail, but I suggest you to use ansible.builtin.copy or ansible.builtin.template instead.

4 Likes

100% agree. I continued to test yesterday after posting and just put in some gibberish for the fun of it and it appeared where I expected it to. I am thinking along the same lines that this task is better suited for something like a template as there are several lines where “Option None” in the configuration file is recommended by CIS. Appreciate the input.

Templating or copying Apache config files is the way to go — they are not valid SGML and I’m unaware of any parsers for them — I don’t think they can be generated any other way, however there is a danger that one can end up with a complicate template…

EDIT: there is an 23 year old CPAN parser but it is not complete:

Currently LogFormat and any other directive with embedded quotes, even if escaped, are not handled correctly… there is no configuration “inheritance”… the order of context blocks is not maintained…