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.
Related
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.
Context
I have an Ansible template that creates a configuration file. Most variables used by this template come from some stable source, such as variables defined in the playbook. However one variable contains a secret key which somehow needs to be generated if it does not already exist.
I want Ansible to generate the key on an as-needed basis. I do not want the key to be stored on the OS running Ansible, like is done with the password module. And naturally I want idempotence.
I currently have a working solution but I'm not happy with it, hence my question here. My current solution uses an extra file which is include by the configuration file created by my template. This is possible as it is a PHP file. I have a task using the shell module that generates the secret when this extra file does not exist, and then another that then creates it using the registered variable.
- name: Generate secret key
shell: openssl rand -hex 32
register: secret_key_command
when: not SecretKey.stat.exists
- name: Create SecretKey.php
template:
src: "SecretKey.php.j2"
dest: "{{ some_dir }}/SecretKey.php"
when: not SecretKey.stat.exists
Surely there is a less contrived way to do this?
Question
Is there a nice way to have a variable that gets generated only once in an Ansible template?
I am not sure, but I understood correctly, we want to generate your template if it doesn't already exists. So you can just do as follow:
- name: Create SecretKey.php
template:
src: "SecretKey.php.j2"
dest: "{{ some_dir }}/SecretKey.php"
force: no
force: no tells to don't overwrite a file if it already exists. No need to do extra check.
Hei guys,
After a few days of struggling, I've decided to write my issue here.
I have an ansible(2.7) task that that has a single variable, which points to a host var that uses the file lookup plugin.
Thing is that this works, for one host, but I have 6 hosts, where a value inside the lookup file should be different for each of the hosts.
Can you pass a variable inside the file that is looked up?
I'm new to ansible and don't master it fully.
Has someone encountered this before?
Task:
- name: Copy the file to its directory
template:
src: file.conf
dest: /path/to/file
vars:
file_contents: "{{file_configuration}}"
-----
hostvar file:
file_configuration:
- "{{lookup('file', './path/to/file') | from_yaml}}"
----
file that is looked up:
name: {{ value that should be different per host }}
driver:
long_name: unchanged value.
You should have 6 host_vars files, one for each host. In that host_var file, set your desired value.
Ansible documentation is here
E.g.
https://imgur.com/a/JCbnNBT
Content of host1.yml
---
my_value: something
Content of host2.yml
---
my_value: else
Ansible automagicly sees the host_var folder. It looks in that folder and searches for files which exactly match a host in the play.
So ensure your host_var/filename.yml matches the hostname in your play!
If there is a match, then it'll use that .yml file for that specific host.
The documentation for file operations does not seem to mention a module which would allow me to create a file with one line. The closest is lineinfile but this module also inserts markers (so a minimum of three lines).
The line will be generated from variables so I do not want to use a local file transferred to the target.
Is there such a module? Or should I run a shell command such as
command: echo {{ myvariable }} > the_file_to_create
to generate it?
You can do it easily with copy module using force=no to create a new empty file only when the file does not yet exist (if the file exists, it's content is preserved)
- name: Copy the content
copy:
content: "{{ myvariable }}"
dest: /location/of/the/file
force: no
Hope that might help you.
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.