ansible task using replace module runs ok but strings are not replaced - ansible

I am using a combination of the ansible find and replace modules to change string in some xml files. The task runs ok but the strings are not replaced.
Here is what the task looks like:
- name: Find common module config files
find:
paths: "/etc/app/common/"
patterns: "*.xml"
register: commonConfigs
- name: Set compress to false in common modules
become: yes
replace:
path: "{{item.path}}"
regexp: "<compress>true"
replace: "<compress>false"
with_items: "{{ commonConfigs.files }}"
I thought that the regexp might be the problem so I tried /<compress>true/g but that didn't help either.
I am pretty new to ansible so apologies if I confuse some terminologies here.
Thanks for any help
Edit:
Here is what part of the xml looks like
<appConfig>
<ui>
<compress>true</compress>
</ui>
<appConfig>

Whithout an example of your xml file, my guess is that your currently searched string does not actually start at the beginning of the line because of indentation.
Moreover, you should catpure the end of the line as well and write it back to make sure you don't loose anything:
regexp: "(\s+<compress>)true(.*)"
replace: "\1false\2"
Meanwhile, I would not rely on replace to make such changes in an xml file when there is an xml module you can use precisely for that.

Related

Ansible replace text in file

So ive been tasked with replaceing zabbix server. To do so i have to modify zabbix_agent file in all server and there are many. Tho in this job is the first time i see ansible so i need some help. And i am using ansible-playbook.
In zabbix_agentd.conf file there is the old zabbix conf:
HostMetadata=Linux
PidFile=/var/run/zabbix/zabbx_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
Server=zabbix.company.com
ServerActive=zabbix.company.com
HostnameItem=system.hostname
Include=/etc/zabbix_agentd.d/
Now i need to replace "Server" and "ServerActive" to "zabbix2.company.com"
I have tried various codes from this page to work for my needs but so far it has failed. No clue what im doing wrong
Try this one
- lineinfile:
path: /etc/zabbix_agentd.conf
regexp: '^\s*{{ key }}\s*=(.*)$'
line: '{{ key }}={{ value }}'
notify: reload zabix
loop:
- {key: 'Server', value: 'zabbix2.company.com'}
- {key: 'ServerActive', value: 'zabbix2.company.com'}
Notes
Path is required; probably /etc/zabbix_agentd.conf ?
It is not necessary to search the white-space \s* in regexp. However, it would match and fix potential spaces in the configuration.
Create and notify a handler reload zabix when anything changed. See Handlers: Running Operations On Change.
Take a look at Zabix modules.
I have manged to solve this issue using this code.
---
tasks:
- name: 'replace line'
lineinfile:
dest: /etc/zabbix/zabbix_agentd.conf
regexp: '^(.*)Server=zabbix.company.com(.*)$'
line: 'Server=zabbix2.company.com'
backrefs: yes

Replace string with hostname

I've been searching up and down for a way to replace a string in a file with the contents of ansible_hostname. Say I have something similar to this in a configuration file:
kern.* /syslog/SYSLOG_SERVER/kern.log
auth.* /syslog/SYSLOG_SERVER/auth.log
Is there an easy way in Ansible to replace all occurrences of SYSLOG_SERVER with the hostname of the server the configuration file is copied to? If anyone has an example or a link describing how to do this I would be super appreciative if you shared it.
You can use the replace module:
- replace:
dest: /path/to/configuration/file
regexp: SYSLOG_SERVER
replace: '{{ ansible_hostname }}'
backup: yes
backup parameter is optional, but since you will be experimenting at first, it is safer to leave it. You can leave it out once you have established the correct procedure.
If the file is already out on the destination server you can use the lineinfile module to make sure the contents are what you want.
If the file is distributed/updated as part of a playbook run you can use the template module to dynamically inject the destionation node's hostname as it gets copied to the destionation.

Log variables to a logfile on ansible host

I have a playbook that registers three variables. I want to produce a CSV report of those three variables on all hosts in my inventory.
This SO answer suggests to use:
- local_action: copy content={{ foo_result }} dest=/path/to/destination/file
But that does not append to the csv file.
Also, I have to manually compose by comma separators in this case.
Any ideas on how to log (append) variables to a local file?
If you are wanting to append a line to a file rather than replace it's contents then this is probably best suited to the lineinfile module and utilising the module's ability to insert a line at the end of the file.
The equivalent task to the copy one that you used would be something like:
- name: log foo_result to file
lineinfile:
line: "{{ foo_result }}"
insertafter: EOF
dest: /path/to/destination/file
delegate_to: 127.0.0.1
Note that I've used the long hand for delegating tasks locally rather than local_action. I personally feel that the syntax reads a lot clearer but you could easily use the following instead if you prefer the more compact syntax of local_action:
- local_action: lineinfile line={{ foo_result }} insertafter=EOF dest=/path/to/destination/file

Is it possible to use inline templates?

I need to create a single file with the contents of a single fact in Ansible. I'm currently doing something like this:
- template: src=templates/git_commit.j2 dest=/path/to/REVISION
My template file looks like this:
{{ git_commit }}
Obviously, it'd make a lot more sense to just do something like this:
- inline_template: content={{ git_revision }} dest=/path/to/REVISION
Puppet offers something similar. Is there a way to do this in Ansible?
Another option to the lineinfile module (as given by udondan's answer) would be to use the copy module and specify the content rather than a source local to the Ansible host.
An example task would look something like:
- name: Copy commit ref to file
copy:
content: "{{ git_commit }}"
dest: /path/to/REVISION
I personally prefer this to lineinfile as for me lineinfile should be for making slight changes to files that are already there where as copy is for making sure a file is in a place and looking exactly like you want it to. It also has the benefit of coping with multiple lines.
In reality though I'd be tempted to make this a template task and just have a the template file be:
"{{ git_commit }}"
Which gets created by this task:
- name: Copy commit ref to file
template:
src: path/to/template
dest: /path/to/REVISION
It's cleaner and it's using modules for exactly what they are meant for.
Yes, in that simple case it is possible with the lineinfile module.
- lineinfile:
dest=/path/to/REVISION
line="{{ git_commit }}"
regexp=".*"
create=yes
The lineinfile module usually is used to ensure that a specific line is contained inside a file. The create=yes option will crete the file if it does not exist. The regexp=.* option makes sure you do not add content to the file if git_commit changes, because it would by default simply make sure the new content is added to the file and not replace the previous content.
This only works since you only have one line in your file. If you'd had more lines this obviously would not work with this module.
This issue seems to be resolved. However, if the template file was more than one variable, i.e. a json file, it is possible to use copy module with content parameter, with a lookup, i.e.:
# playbook.yml
---
- name: deploy inline template
copy:
content: '{{ lookup("template", "inlinetemplate.yml.j2") }}'
dest: /var/tmp/inlinetempl.yml
# inlinetemplate.yml.j2
---
- name: {{ somevar }}
abc: def
If you need insert the template to the exist file, you can insert through the lineinfile module.
- name: Insert jinja2 template to the file
lineinfile:
path: /path/file.conf
insertafter: "after this line"
line: "{{ lookup('template', 'template.conf.j2') }}"

Using ansible, what is the best way to add a line to an existing file that depends on the value of a variable passed by --extra-vars?

I have a numerical config (e.g., number of milliseconds for some config) that needs to be set in a standard system file. I don't want to keep the whole config file in version control since it's part of a standard install. Is there a way to add a line to a file and have some variable replacement text in the line that can depend on a specified variable (e.g., passed via command line when the playbook is run using --extra-vars.
For example, something like the following (my best effort so far):
- name: Set ring delay
lineinfile:
dest: /etc/cassandra/cassandra-env.sh
state: present
regexp: 'JVM_OPTS="$JVM_OPTS -Dcassandra.ring_delay_ms=.*"'
line: 'JVM_OPTS="$JVM_OPTS -Dcassandra.ring_delay_ms=${ring_delay}"'
backrefs: yes
when: ring_delay is defined
where the playbook is executed with ansible-playbook -e "ring_delay=10000"
The above example works fine if I don't have variable value for the config (e.g., I just hard code line: 'JVM_OPTS="$JVM_OPTS -Dcassandra.ring_delay_ms=10000"', but I would like to be able to specify the value manually from the command line when I run the playbook. Is there a good way to do this? Ideally, rerunning the playbook would overwrite the ring_delay with the new value
EDIT: From this link, It appears that the ${ring_delay} notation I used above is not a feature of ansible, though there are a couple of examples on the web that suggest there is some related functionality for string replacement. The docs refer to "named backreferences", but I'm not sure what those are.
The proper syntax for interpolation is '{{ var }}'. The '${ var }' syntax has been deprecated for some time now.
Changing your task like below should do it :
- name: Set ring delay
lineinfile:
dest: /etc/cassandra/cassandra-env.sh
state: present
regexp: 'JVM_OPTS="$JVM_OPTS -Dcassandra.ring_delay_ms=.*"'
line: 'JVM_OPTS="$JVM_OPTS -Dcassandra.ring_delay_ms={{ring_delay}}"'
when: ring_delay is defined
You don't need backrefs here since there are no catching groups in the regexp.
Good luck.

Resources