Devops 101: How to deal with regexes in Ansible's YAML
My last post on this blog was almost a year ago. Yes, I haven’t been very talkative this year, even though I said in the previous post that I was starting a new series. I’m sorry. It’s been a very… weird year.
So, to make it up to you, today, I’ll give you a little tip on how to correctly handle regexes
in YAML. This may prove particularly useful with Ansible’s lineinfile
module.
The situation
Using Ansible, you may quickly find yourself in a situation where you need to modify a
configuration file. Like every sensible Ansible user, you will use Ansible’s
lineinfile
.
It turns out that some of the lines you try to replace contain characters that have
a special meaning in Python’s regex language. Like [
or .
. So you’ll need to escape them.
And you’ll bang your head on the wall because YAML has a special way of handling escaping.
The solution
YAML has 2 types of strings. Double-quoted strings: "this is a YAML string"
and
single-quoted strings: 'this is also a string in YAML'
. But they’re not strictly equivalent.
In double-quoted strings, escape sequences using \
are interpreted by the YAML parser and
only certain characters can be escaped. Namely: \\
, \"
to produce litteral double-quotes and
litteral backspaces, \b
, \f
, \n
, \r
and \t
to produce various blank characters and \u
to produce unicode characters. Any other escaped characters will produce an error.
In single-quoted characters, on the other hand, escape sequences using \
don’t mean anything
special to YAML. So you can use \[
to escape regex special characters.
The single-quote character exception
So far, there’s nothing particularly tricky in what I just explained. It’s certainly easy to
miss, but if you carefully ready lineinfile
’s documentation, all example use single-quoted
strings so you may be fine.
But you may wonder: “hey, what if the line I’m trying to replace contains a litteral single-quote?”. Something like:
nginx['listen_addresses']
in Gitlab’s configuration.
You may try to escape them but remember: escape sequence aren’t interpreted in YAML’s single-quoted string so this will still result in an error.
The correct way to insert a litteral single-quote in YAML’s single-quoted strings is to double it:
lineinfile:
regexp: 'nginx\[''listen_addresses''\]'
And that’s it!
This was a relatively short article, compared to what I usually write, but many of my Ansible students stumble over this tricky situation. So I thought it might be useful to others…