I’ve been playing around with ansible a lot lately, and I noticed that while changing stuff from “installed and configured manually” to “installed and configured by ansible” I was running into quite a few configuration files that needed to be manually turned into templates. It can be quite tedious to replace values in a configuration file with placeholders and put all those placeholders in a .yml file with default values.
 Automating this is something I would have typically done in perl, but since I wanted to learn more about using regex in bash I decided to have a go at it in bash using regex and ${BASH_REMATCH}
The script takes a configuration file and spits out an ansible template, as well as the variable definitions you will need to add to your defaults/main.yml or vars/main.yml
The whole script is a bit to long to post here, but the interesting part is:
|  | 
if [[ ${line} =~ ^([^#][^\ ]+)[\ ]*[${Separator}][\ ]*([^\ ]+)$ ]] ; then
 
 VariableName="${Prefix}_${BASH_REMATCH[1]//-/_}" # create a name for this configuration variable
 
 VariableName="${VariableName,,}" # make lowercase
 
 sed -ri "s/^(${BASH_REMATCH[1]}[\ ]*[${Separator}][\ ]*).+$/\1{{ ${VariableName} }}/" "${Template}" # change the ansible template
 
 printf "%-40s %s\n" "${VariableName}:" "'${BASH_REMATCH[2]}'" # print variable info to stdout 
 fi | 
 
(You can download the full script here ansible_template.sh).
You can use regular expressions in a [[ ]] with =~ (e.g. if [[ “boot” =~ ^b ]]), and you can access the result of the regular expression by using ( ) to mark what parts of the result to store and access them via $BASH_REMATCH (comparable to how you would do it for other languages). Here I am parsing out anything that looks like a key=value from the configfile (with multiple possible separators) and storing the results in BASH_REMATCH[1] and BASH_REMATCH[2]
Usage of the script is pretty straightforward. you give it a prefix for the variable names (so you don’t end up with multiple roles all using a common variable name like “port”), and either a local or remote file to work with, and it spits out something like this:
| 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 
$ ./ansible_template.sh php webserver.somewhere.tld:/etc/php5/conf.d/xcache.ini
 
- name: Template
 
  template: src={{ item.local }} dest={{ item.remote }} owner={{ item.owner }} group={{ item.group }} mode={{ item.mode }}
 
  with_items:
 
    - { local: 'xcache.ini.j2', remote: '/etc/php5/conf.d/xcache.ini', owner: 'root', group: 'root', mode: '0644' }
   
php_zend_extension: '/usr/lib/php5/20090626/xcache.so'
 
php_xcache.admin.enable_auth: 'On'
 
php_xcache.admin.user: 'admin'
 
php_xcache.admin.pass: 'ea6299af10b40ba80236a0f015ed627d'
 
php_xcache.shm_scheme: 'mmap'
 
php_xcache.size: '16M'
 
php_xcache.count: '1'
 
php_xcache.slots: '8K'
 
php_xcache.ttl: '0'
 | 
 
There a tons of different configuration file formats out there so this script won’t work perfectly 100% of the time, but it does do quite well and reduces the manually copy&pasting to a minimum.
| 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 
$ cat xcache.ini.j2
 
; configuration for php Xcache module
   
[xcache-common]
 
zend_extension = {{ php_zend_extension }}
   
[xcache.admin]
 
xcache.admin.enable_auth = {{ php_xcache.admin.enable_auth }}
 
xcache.admin.user = "{{ php_xcache.admin.user }}"
 
xcache.admin.pass = "{{ php_xcache.admin.pass }}"
   
[xcache]
 
xcache.shm_scheme = "{{ php_xcache.shm_scheme }}"
 
xcache.size = {{ php_xcache.size }}
 
xcache.count = {{ php_xcache.count }}
 
xcache.slots = {{ php_xcache.slots }}
 
xcache.ttl = {{ php_xcache.ttl }}
 
...
 |