I’m trying to use Ansible’s lineinfile
module to add a new parameter to an existing log_format
directive in an nginx configuration file. However, I’m encountering difficulties in getting the module to work as expected.
Here’s my nginx configuration file excerpt:
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
I want it to change it to:
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
And here’s the Ansible task I’m using:
- name: Add string between groups of regex in nginx.conf
ansible.builtin.lineinfile:
path: nginx.conf
backrefs: yes
regexp: '(log_format[^;]*?)(;)'
line: '1 my_string 2'
Despite trying different regex
patterns and configurations, the file remains unchanged, and Ansible simply returns ok
without making any changes. I’ve validated the regex using online tools like regex101, and it appears to match the desired portion of the file accurately.
PS: I have tried other regex too, but none of them seem to work. Eg:
(log_formats*S*;)
(log_formats*S*;)
2
Answers
In such a case it is recommended to simplify the Use Case as much as possible. You may consider
template
module – Template a file out to a target host a feasible option?copy
module – Copy files to remote locations a feasible option?log_format
be managed as block viablockinfile
module – Insert/update/remove a text block surrounded by marker linesand so on …
In example, if the line order does not matter, a minimal playbook
will result into an output of
and a file content of
The problem is that you try to match a string spanning multiple lines.
When the
logformat entry is on a single line, it would work. Lineinfile is not suitable for tackling this task (as the name suggests).
From the ansible documentation:
Because of the one line character of the module, your regexp simply does not match.
If you want to use lineInFile for this task, you should change your insert strategy by inserting your string somewhere on the first line, if this is an acceptable and working solution.