tempfile module using fixed name - ansible

Can I create temp file with a fixed name with the tempfile module?
- name: Create temporary file
tempfile:
state: file
suffix: 2023-2-2
prefix: app_010
register: tempfile_1
delegate_to: localhost
- name: debug
debug:
msg: "{{ tempfile_1.path }}"
The result is
ok: [localhost] => {
"msg": "/tmp/app_010zvhvpiqr2023-2-2"
}
tempfile creates a random file name, but, I would like to give it a hardcoded name.
I want to read the temporary file from another playbook, so, should I use regex to find a file that starts with app_010 and finishes with 2023-2-2?

The entire point of tempfile is to create unpredictable temporary files with a random component, because using a predictable name in a world-writable directory like /tmp has security implications.
If you want a predictable, hardcoded name, just use the file module.

Related

ansible-playbook gather information from a file

I want to read a file by ansible and find specific thing and store all of them in a file in my localhost
for example there is /tmp/test file in all host and I want to grep specific thing in this file and store all of them in my home.
What should I do?
There might be many ways to accomplish this. The choice of Ansible modules (or even tools) can vary.
One approach is (using only Ansible):
Slurp the remote file
Write new file with filtered content
Fetch the file to Control machine
Example:
- hosts: remote_host
tasks:
# Slurp the file
- name: Get contents of file
slurp:
src: /tmp/test
register: testfile
# Filter the contents to new file
- name: Save contents to a variable for looping
set_fact:
testfile_contents: "{{ testfile.content | b64decode }}"
- name: Write a filtered file
lineinfile:
path: /tmp/filtered_test
line: "{{ item }}"
create: yes
when: "'TEXT_YOU_WANT' in item"
with_items: "{{ testfile_contents.split('\n') }}"
# Fetch the file
- name: Fetch the filtered file
fetch:
src: /tmp/filtered_test
dest: /tmp/
This will fetch the file to /tmp/<ANSIBLE_HOSTNAME>/tmp/filtered_test.
You can use the Ansible fetch module to download files from the remote system to your local system. You can then do the processing locally, as shown in this Ansible cli example:
REMOTE=[YOUR_REMOTE_SERVER]; \
ansible -m fetch -a "src=/tmp/test dest=/tmp/ansiblefetch/" $REMOTE && \
grep "[WHAT_YOU_ARE_INTERESTED_IN]" /tmp/ansiblefetch/$REMOTE/tmp/test > /home/user/ansible_files/$REMOTE
This snippet runs the ad-hoc version of Ansible, calling the module fetch with the source folder (on the remote) and the destination folder (locally) as arguments. Fetch copies the file into a folder [SRC]/[REMOTE_NAME]/[DEST], from which we then grep what we are interested in, and output that in the /home/user/ansible_files/$REMOTE.

Write slurped variable to a remote file in Ansible

I'm trying to figure out how one would copy or write the contents of a slurped variable to a remote (preferable) file. If this is not possible, what's the cleanest way to do it in steps?
I have something like this:
- name: Load r user public key
slurp:
src: *path*
register: slurped_r_key
- name: Decode r key
set_fact:
r_content: "{{ slurped_r_key.content | b64decode }}"
I want to get the contents of {{ r_content }} into a file in the remote machines that are part of an inventory group. If I cannot do that directly, what's the best way? Should I copy the contents to a local file and then scp the file over to the remote machines?
Thanks in advance!
To copy the variable to a file you can try as below:
- name: copy
copy:
content: "{{r_content}}"
dest: /tmp/testing

Ansible, save variable content to new file

I'm trying to create an Ansible task to save the content of a variable to a new file.
Using Ansible 2.5.13 and Python 2.7.5.
I've tried already to copy the content of the variable to a destination path where the file should be created...
- name: Save alert rule example file to Prometheus
copy:
content: "{{ alert_rule_config }}"
dest: /opt/compose/prom/alert_rule.yml
Tried also to create the file before copying the content of the variable
- name: Create alert rule file
file:
path: /opt/compose/prom/alert_rule.yml
state: touch
- name: Save alert rule example file to Prometheus
copy:
content: "{{ alert_rule_config }}"
dest: /opt/compose/prom/alert_rule.yml
Tried to wrap the destination path in quotes...
But no matter what a directory /opt/compose/prom/alert_rule.yml/ is created!
The content of the variable is something like
alert_rule_config:
groups:
- name: debug-metrics
rules:
- alert: DebugAlert
expr: test_expression
I expect the file to be created (because it does not exist) and the content of the variable to be saved to the newly created file but the task fails with
FAILED! => {"changed": false, "msg": "can not use content with a dir as dest"}
I want to avoid issuing a command and would prefer to use an Ansible module.
You need to create the target directory instead of the target file, or you will get Destination directory /opt/compose/prom does not exist in the first option or Error, could not touch target: [Errno 2] No such file or directory: '/opt/compose/prom/alert_rule.yml' in the second option.
- name: Create alert rule containing directory
file:
path: /opt/compose/prom/
state: directory
- name: Save alert rule example file to Prometheus
copy:
content: "{{ alert_rule_config }}"
dest: /opt/compose/prom/alert_rule.yml
But as #Calum Halpin says, if during your tests you did an error and created a directory /opt/compose/prom/alert_rule.yml/, you need to remove it before.
This will happen if a directory /opt/compose/prom/alert_rule.yml already exists when your tasks are run.
To remove it as part of your tasks add
- file:
path: /opt/compose/prom/alert_rule.yml
state: absent
ahead of your other tasks.

How do I save an ansible variable into a temporary file that is automatically removed at the end of playbook execution?

In order to perform some operations locally (not on the remote machine), I need to put the content of an ansible variable inside a temporary file.
Please note that I am looking for a solution that takes care of generating the temporary file to a location where it can be written (no hardcoded names) and also that takes care of the removal of the file as we do not want to leave things behind.
You should be able to use the tempfile module, followed by either the copy or template modules. Like so:
- hosts: localhost
tasks:
# Create a file named ansible.{random}.config
- tempfile:
state: file
suffix: config
register: temp_config
# Render template content to it
- template:
src: templates/configfile.j2
dest: "{{ temp_config.path }}"
vars:
username: admin
Or if you're running it in a role:
- tempfile:
state: file
suffix: config
register: temp_config
- copy:
content: "{{ lookup('template', 'configfile.j2') }}"
dest: "{{ temp_config.path }}"
vars:
username: admin
Then just pass temp_config.path to whatever module you need to pass the file to.
It's not a great solution, but the alternative is writing a custom module to do it in one step.
Rather than do it with a file, why not just use the environment? This wan you can easily work with the variable and it will be alive through the ansible session and you can easily retrieve it in any steps or outside of them.
Although using the shell/application environment is probably, if you specifically want to use a file to store variable data you could do something like this
- hosts: server1
tasks:
- shell: cat /etc/file.txt
register: some_data
- local_action: copy dest=/tmp/foo.txt content="{{some_data.stdout}}"
- hosts: localhost
tasks:
- set_fact: some_data="{{ lookup('file', '/tmp/foo.txt') }}"
- debug: var=some_data
As for your requirement to give the file a unique name and clean it up at the end of the play. I'll leave that implementation to you

Using variables for file name and file contents in lineinfile module

I am trying to read the contents of a file, store these in a variable and then insert them into another file if they don't already exist.
So, how I'm attempting to go about this is as follows:
# Create a variable that represents the path to the file that you want to read from
ssh_public_key_file: '../../jenkins_master/files/{{ hostvars[inventory_hostname]["environment"] }}/id_rsa.pub'
# Create a variable that represents the contents of this file:
ssh_public_key: "{{ lookup('file', '{{ ssh_public_key_file }}') }}"
I then use these variables in my Ansible playbook as follows:
- name: Install SSH authorized key
lineinfile: create=yes dest=~/.ssh/authorized_keys line=" {{ ssh_public_key }}" mode=0644
However, when I try and run the playbook, I get the following error message:
could not locate file in lookup: {{ ssh_public_key_file }}
Can anyone recommend a solution or suggest what I may have done wrong?
Thanks,
Seán
You have to change the line to:
# Create a variable that represents the contents of this file:
ssh_public_key: "{{ lookup('file', ssh_public_key_file) }}"
If you need to concatenate variables and strings you can do it like this:
# Example with two variables
ssh_public_key: "{{ lookup('file', var_1+var_2) }}"
# Example with string and variable
ssh_public_key: "{{ lookup('file', '~/config/'+var_1) }}"
. .
First I would make sure that your ssh_public_key_file variable is set up properly. If you add a task like the following what does it show?
- name: display variable
debug: var=ssh_public_key_file
If the output looks something like this then the variable isn't defined properly (eg. the "environment" fact doesn't exist for the host):
ok: [localhost] => {
"ssh_public_key_file": "../../jenkins_master/files/{{ hostvars[inventory_hostname][\"environment\"] }}/id_rsa.pub"
}
However if everything is defined properly then your output should show the variables replaced with their correct values:
ok: [localhost] => {
"ssh_public_key_file": "../../jenkins_master/files/foo/id_rsa.pub"
}
Once you've verified that then I would do the same thing with your ssh_public_key variable. Just output its value using the debug module. It should display as the contents of the public key file.
One other thing I would strongly suggest is to avoid using lineinfile altogether. Since you're working with SSH keys I would recommend you use the authorized_key module instead. It's a much cleaner way of managing authorized_keys files.

Resources