Ansible - Append variable in line - ansible

I want to append attribute to a file, instead of replacing or setting it on a new line.
Content of file:
PATH = "/a/path"
The variable which attributes has to append in the file:
"{{ key.values() | map(attribute='hi') | list | join(' ') }}"
The output of the variable is:
/hi1 /hi2 /hi3
Trying to append with lineinfile, but the parameter insertafter places the attributes on a new line, instead of the same line.
- lineinfile:
dest: /file
state: present
insertafter: 'PATH = "'
line: "{{ mounts.values() | map(attribute='mountpoint') | list | join(' ') }}"
Expected result:
PATH = "/a/path /hi1 /h2 /hi3"
Actual result:
PATH = "/a/path"
/hi1 /hi2 /hi3
Receiving syntax errors if I use the method described here: Ansible: insert a single word on an existing line in a file
Which module should I use for this particular use case?
Using Ansible v2.1.2.0
edit
The backrefs option gives the same result, which is not expected:
- lineinfile:
dest: /file
backrefs: yes
regexp: 'PATH = "'
line: "{{ key.values() | map(attribute='hi') | list | join(' ') }}"

Thanks for helping #Mir.
Final solution:
- lineinfile:
dest: /file
backrefs: yes
regexp: '(^PATH\s+\=\s+)(?:")([\w+\s/]+)(?<!{{ hi }})(?:")'
line: '\1"\2 {{ hi }}"'
Where hi is the variable.

Lineinfile module has the backrefs option that goes in pair with the regexp option and allows you to match an existing line and change only parts of it.
Something like (not tested)
- lineinfile:
[...]
regexp: ^PATH = "(.*)"$
line: PATH="\1 {{ your_variable_here}}"
backrefs: yes
Is probably what you need.

Related

Add text end of specific line

I have a /etc/rhsm/rhsm.conf file with this block:
[rhsm]
# Content base URL:
baseurl=https://satellite.bcnconsulting.com
I want to check whether the line from baseurl ends with /pulp/repos or not. In case it doesn't add it to the end of the line.
The end result should be:
[rhsm]
# Content base URL:
baseurl=https://satellite.bcnconsulting.com/pulp/repos
For now I have,
- name: Check if baseurl in rhsm.conf is correct
shell: "grep -nr baseurl /etc/rhsm/rhsm.conf | grep -nr /pulp /etc/rhsm/rhsm.conf"
ignore_errors: yes
register: result
- name: If it has not the /pulp/repos ending add it
lineinfile:
path: /etc/rhsm/rhsm.conf
line: '/pulp/repos'
regexp: 'baseurl'
when: result.stdout == ""
But this is just removing the line and writing /pulp/repos.
How can I accomplish to put it just after the last letter of the line?
That is the problem regex "backreferences" are designed to solve
- name: If it has not the /pulp/repos ending add it
lineinfile:
path: /etc/rhsm/rhsm.conf
line: '\1/pulp/repos'
regexp: '^(baseurl=https://satellite.bcnconsulting.com)$'
backrefs: yes
when: result.stdout == ""

Ansible: Lineinfile with items in front of the other in same line

I want to know if it's possible to insert two or more items in the same line with module lineinfile or other modules.
Like that example:
- name: Insert content in the File
lineinfile:
dest: /tmp/file.txt
line: 'Groups = {{ item }}'
create: yes
with_items:
- "{{ group_ad }}"
group_ad:
- LINUX
- DBA
In the file stay that after executing the playbook:
Groups = LINUX
Groups = DBA
But I want to stay like below:
Groups = LINUX, DBA
Who I make that?
You're iterating over the list, but you want to add the list. So it's easier to use join here
- name: Insert content in the File
lineinfile:
dest: /tmp/file.txt
line: 'Groups = {{ group_ad | join(', ') }}'
create: yes

Add a string inside a configuration file through ansible

I am in need of adding a new string to one of the configuration file. I have to add say "mycustomimage" with a "," in "images =". So in short, my required output is images= previousimage,mycustomimage
View of mycnf.conf
id=1
images=previousimage
For this, I tried this code
---
- hosts: test_server
- name: Add new string after "," in images
lineinfile:
path: /home/mycnf.conf
regexp: 'images='
insertafter: '^,'
line: mycustomimage
Expected output
id= 1
images=previousimage,mycustomimage
But its not working for me. Any thoughts?
Thanks in advance!
Sid
This will help
- name: replace line
lineinfile:
path: myfile.txt
regexp: "^image="
line: 'image=previousimage,customimage'
From your example
You know the final line you want to have in the file is images=previousimage,mycustomimage
You want to add this line in place of an already existing image=.* line if it exists and does not match the final one.
The following will do the job
- name: Replace line if needed
lineinfile:
path: /home/mycnf.conf
regex: images=.*
line: images=previousimage,mycustomimage
Note: If for any reason there is no matching line in your file for the regex, the line will be added at the end of the file.
Assuming that previousimage is not known you can do two things:
1.Get this line using grep, register to a variable and add the line
- name: get line
shell: grep "^image=" /config/file.something
register: current_image
- name: update image
lineinfile:
path: /config/file.something
regexp: '^image='
line: "{{ current_image.stdout }},{{ new_image | default('customimage') }}"
2.Create a template for this configuration file and render it every time the playbook run and a change is detected:
- set_fact:
images: <list of images retrieved by lookup or static>
- name: update config.something
template:
src: my_template.j2
dest: /config/file.something
The template will look like this:
id={{ id }}
images={{ images | join(",") }}
We'll assume you don't know what previousimage is, that you may have several previous images, and you want to append mycustomimage, and you want the playbook to be idempotent:
---
- hosts: all
connection: ssh
become: no
gather_facts: no
vars:
image_name: mycustomimage
tasks:
- lineinfile:
path: testfile.txt
regexp: '^images=(.*(?<!{{ image_name }}))'
line: '\1,{{ image_name }}'
backrefs: yes
So let's explain the regexp: ^images= you can figure out yourself!
The first parenthesis starts the backref block, and it's going to suck up everything to the end of the line: .*
Then, it looks back at what it just sucked in, and makes sure {{ image_name }} is not at the end: (?<!{{ image_name }})
Finally, we close the backref block with ).

Ansible uncomment line and change string value

I've got a line in a config file as follows:
# value = False
I know you can use lineinfile to remove the '#' as follows:
- name: Uncomment parameters
lineinfile:
dest: app.conf
regexp: (?i)^\s*#\s*({{ item }}.*)
line: \1
backrefs: yes
with_items:
- value
I was wonder if there was a way to also change the 'False' to 'True' in the same task or would that require another task? (using replace most likely?)
Sure, unless there is some other logic you want added?
- name: Uncomment parameters
lineinfile:
dest: app.conf
regexp: (?i)^\s*#\s*{{ item }}.*
line: "{{ item }} = True"
backrefs: yes
with_items:
- value

Ansible: Insert line if not exists

I'm trying insert a line in a property file using ansible.
I want to add some property if it does not exist, but not replace it if such property already exists in the file.
I add to my ansible role
- name: add couchbase host to properties
lineinfile: dest=/database.properties regexp="^couchbase.host" line="couchbase.host=127.0.0.1"
But this replaces the property value back to 127.0.0.1 if it exists already in the file.
What I'm doing wrong?
The lineinfile module ensures the line as defined in line is present in the file and the line is identified by your regexp. So no matter what value your setting already has, it will be overridden by your new line.
If you don't want to override the line you first need to test the content and then apply that condition to the lineinfile module. There is no module for testing the content of a file so you probably need to run grep with a shell command and check the .stdout for content. Something like this (untested):
- name: Test for line
shell: grep -c "^couchbase.host" /database.properties || true
register: test_grep
And then apply the condition to your lineinfile task:
- name: add couchbase host to properties
lineinfile:
dest: /database.properties
line: couchbase.host=127.0.0.1
when: test_grep.stdout == "0"
The regexp then can be removed since you already made sure the line doesn't exist so it never would match.
But maybe you're doing things back to front. Where does that line in the file come from? When you manage your system with Ansible there should be no other mechanisms in place which interfere with the same config files. Maybe you can work around this by adding a default value to your role?
This is possible by simply using lineinfile and check_mode:
- name: Check if couchbase.host is already defined
lineinfile:
state: absent
path: "/database.properties"
regexp: "^couchbase.host="
check_mode: true
changed_when: false # This just makes things look prettier in the logs
register: check
- name: Define couchbase.host if undefined
lineinfile:
state: present
path: "/database.properties"
line: "couchbase.host=127.0.0.1"
when: check.found == 0
This is the only way I was able to get this to work.
- name: checking for host
shell: cat /database.properties | grep couchbase.host | wc -l
register: test_grep
- debug: msg="{{test_grep.stdout}}"
- name: adding license server
lineinfile: dest=/database.properties line="couchbase.host=127.0.0.1"
when: test_grep.stdout == "0"
By a long way of "Trials and errors" I come to this:
- name: check existence of line in the target file
command: grep -Fxq "ip addr add {{ item }}/32 dev lo label lo:{{ app | default('app') }}" /etc/rc.local
changed_when: false
failed_when: false
register: ip_test
with_items:
- "{{ list_of_ips }}"
- name: add autostart command
lineinfile: dest=/etc/rc.local
line="ip addr add {{ item.item }}/32 dev lo label lo:{{ app | default('app') }}"
insertbefore="exit 0"
state=present
when: item.rc == 1
with_items:
- "{{ ip_test.results }}"
Looks like it does not work if you use backrefs.
Following sample does not add a line
- name: add hosts file entry
lineinfile:
path: "/etc/hosts"
regexp: "foohost"
line: "10.10.10.10 foohost"
state: present
backrefs: yes
After removing backrefs I got my line added to the file
- name: add hosts file entry
lineinfile:
path: "/etc/hosts"
regexp: "foohost"
line: "10.10.10.10 foohost"
state: present
Same idea as presented here : https://stackoverflow.com/a/40890850/7231194
Steps are:
Try to replace the line.
If replace mod change it, restore
If replace mod doesn't change, add the line
Example
# Vars
- name: Set parameters
set_fact:
ipAddress : "127.0.0.1"
lineSearched : "couchbase.host={{ ipAddress }}"
lineModified : "couchbase.host={{ ipAddress }} hello"
# Tasks
- name: Try to replace the line
replace:
dest : /dir/file
replace : '{{ lineModified }} '
regexp : '{{ lineSearched }}$'
backup : yes
register : checkIfLineIsHere
# If the line not is here, I add it
- name: Add line
lineinfile:
state : present
dest : /dir/file
line : '{{ lineSearched }}'
regexp : ''
insertafter: EOF
when: checkIfLineIsHere.changed == false
# If the line is here, I still want this line in the file, Then restore it
- name: Restore the searched line.
lineinfile:
state : present
dest : /dir/file
line : '{{ lineSearched }}'
regexp : '{{ lineModified }}$'
when: checkIfLineIsHere.changed
Ok, here is mine naive solution... probably not a cross-platform and native Ansible (I've just started to use this tool and still learn it), but definitely shorter:
- name: Update /path/to/some/file
shell: grep -q 'regex' /path/to/some/file && echo exists || echo 'text-to-append' >> /path/to/some/file
register: result
changed_when: result.stdout.find('exists') == -1
We have tried the below and it worked well. our scenario need to entry "compress" in syslog file if it does not exist.
- name: Checking compress entry present if not add entry
lineinfile:
path: /etc/logrotate.d/syslog
regexp: " compress"
state: present
insertafter: " missingok"
line: " compress"
- name: add couchbase.host to properties, works like add or replace
lineinfile:
path: /database.properties
regexp: '^couchbase.host=(?!(127.0.0.1))\b'
line: 'couchbase.host=127.0.0.1'
This code will replace any line ^couchbase.host=* except couchbase.host=127.0.0.1 or will add new line if it does not exist
- name: add couchbase.host to properties, works like add or replace
lineinfile:
state: present
dest: /database.properties
regexp: '^couchbase.host'
line: 'couchbase.host=127.0.0.1'

Resources