Read file on a Windows host in Ansible - ansible

Similar to the Get-Content command in PowerShell, I am looking for a way to read a file on a Windows target and save the file contents to a variable in Ansible. The documentation says that the ansible.builtin.file module is able to get file contents but this feature does not seem to be available for the win_file module.
The following pseudo-code should better explain what I'm trying to do:
- name: save file contents to variable
win_get_content:
path: C:\somefile.txt
register: file_contents

if "{{lookup('file', 'C:\somefile.txt') }}" is not functional in window, you could try:
- name: get content of file
win_shell: 'type C:\somefile.txt'
register: file_contents
- name: display content
debug:
msg: "{{ file_contents.stdout_lines }} "

You can do so using the module slurp.
It works on both windows and linux.
- name: Read file
ansible.builtin.slurp:
src: '<path/to/file>'
register: file
- name: Print file content
ansible.builtin.debug:
msg: "{{ file['content'] | b64decode }}"

Related

Copy json file from windows to linux in seperate awx jobs

I created a Worflow job in awx containing 2 jobs:
Job 1 is using the credentials of the windows server where we get the json file from. It reads the content and put it in a variable using set_stats
Job2 is using the credential of the server where to upload the json file. It reads the content of the variable set in the job 1 in the set_stats task and creates a json file with the content.
First job:
- name: get content
win_shell: 'type {{ file_dir }}{{ file_name }}'
register: content
- name: write content
debug:
msg: "{{ content.stdout_lines }} "
register: result
- set_fact:
this_local: "{{ content.stdout_lines }}"
- set_stats:
data:
test_stat: "{{ this_local }}"
- name: set hostname in a variable
set_stats:
data:
current_hostname: "{{ ansible_hostname }}"
per_host: no
Second job
- name: convert to json and copy the file to destination control node.
copy:
content: "{{ test_stat | to_json }}"
dest: "/tmp/{{ current_hostname }}.json"
How can I get the current_hostname, so that the the created json file is named <original_hostname>.json? In my case its concatenating the two hosts which I passed in the first job.
In my case its concatenating the two hosts which I passed in the first job
... which is precisely what you asked for since you used per_host: no as parameter to set_stats to gather the current_hostname stat globally for all host and that aggregate: yes is the default.
Anyhow, this is not exactly the intended use of set_stats and you are making this overly complicated IMO.
You don't need two jobs. In this particular case, you can delegate the write task to a linux host in the middle of a play dedicated to windows hosts (and one awx job can use several credentials).
Here is a pseudo untested playbook to give you the idea. You'll want to read the slurp module documentation which I used to replace your shell task to read the file (which is a bad practice).
Assuming your inventory looks something like:
---
windows_hosts:
hosts:
win1:
win2:
linux_hosts:
hosts:
json_file_target_server:
The playbook would look like:
- name: Gather jsons from win and write to linux target
hosts: windows_hosts
tasks:
- name: Get file content
slurp:
src: "{{ file_dir }}{{ file_name }}"
register: json_file
- name: Push json content to target linux
copy:
content: "{{ json_file.content | b64decode | to_json }}"
dest: "/tmp/{{ inventory_hostname }}.json"
delegate_to: json_file_target_server

Convert Ansible stat's mtime output to YYMMDD-HHMMSS

I'm trying to extract a file's last modified time in the format YYMMDD-HHMMSS (ex:210422-135018) using Ansible's stat module.
I'm getting the file's mtime in a playbook:
- name: stat
stat:
path: /path/to/file
register: file
- debug:
msg: "{{ file.stat.mtime }}"
Which returns the mtime in EPOCH format (ex: 1632916899.9357276)
I've tried following instructions in the Ansible docs, but could not get it to work.
Is there a simple way to do this via Ansible, or is it best to do it via the shell module?
Thanks!
UPDATE: Solved with help from comment below:
- name: stat
stat:
path: /path/to/file
register: file
- debug:
msg: "{{ '%Y%m%d-%H%M%S' | strftime(file.stat.mtime) }}"

Ansible: Is there a way to look into a file, split the content in the file based on a specific criteria & then copy that content to another file?

I'm new to Ansible & I've been trying to read the content of a file, split it based on a specific criteria & then I want to copy that content or return that content.
for example, a file sample.txt contains:
userid= "abc"
I want to read the content in sample.txt & split whereever there's a '=' sign, so that I can extract the creds (userid & abc) & then use it further.
I'm dropping drafts of the code snippets I've tried.
---
- name: extracting creds
hosts: servers
tasks:
- name: read secure value
lineinfile:
path: /home/usr/Desktop/sample.txt
register: creds
debug:
msg: "{{ creds.split('=') }}"
Another code I tried:
---
- name: Creds
hosts: servers
vars:
test: /home/usr/Desktop/sample.txt
tasks:
- debug:
msg: "{{lookup('file', test).split('=') }}"
None of them works :( What shall be followed to get it done?
You can also try the following approach to read the contents from file and split them.
---
- hosts: localhost
tasks:
- name: add host
add_host:
hostname: "{{ server1 }}"
groups: host1
- hosts: host1
become: yes
tasks:
- name: Fetch the sample file
slurp:
src: /tmp/sample.txt
register: var1
- name: extract content for matching pattern
set_fact:
sample_var1: "{{ var1['content'] | b64decode | regex_findall ('(.+=.+)', multiline=True, ignorecase=True) }}"
- debug:
msg: "{{ item.split('=')[1] }}"
loop: "{{ sample_var1 }}"
According to ansible doc, this is what lineinfile does. So, if you want to modify some content from one file and write to another file then this module wouldn't help.
This module ensures a particular line is in a file, or replace an
existing line using a back-referenced regular expression. This is
primarily useful when you want to change a single line in a file
only.
lookup on the other hand works on control machine. Judging by the code you have added, may be you were trying to use the file on target host. So, lookup wouldn't help either.
If the file is available on local/control host then read file, split content and copy to another file on the control machine and then copy the final file to the target host using copy module. Here is a sample that reads a file from control host and split every line using = as a separator.
- hosts: localhost
tasks:
- debug:
msg: "{{ item.split('=') }}"
with_lines: "cat /home/usr/Desktop/sample.txt"
If the file is on remote/managed host then you can use something like below:
- hosts: servers
tasks:
- command: "cat /home/usr/Desktop/sample.txt"
register: content
- debug:
msg: "{{ item.split('=') }}"
loop: "{{ content.stdout_lines }}"

Ansible: Write multiple lines to a file using local_action or another method

I am using the command:
local_action: copy content="The installation failed" dest=~/ansible/ansible_log.txt
However, when I do it again:
local_action: copy content="Contact me for assistance" dest=~/ansible/ansible_log.txt
It overwrites the old text with the new text. What I want to do is append to the file instead of replacing the previous text.
I tried adding in a /n to the end of the original string to no avail.
What about the lineinfile module:
local_action:
module: lineinfile
dest: "~/ansible/ansible_log.txt"
line: "The installation failed"
create: yes
local_action:
module: lineinfile
dest: "~/ansible/ansible_log.txt"
line: "Contact me for assistance"
Tried multiple posts and this is that finally helped what I wanted to do. Collect various facts and finally output it to a local file for review. Posting it out here, hoping to help someone starting on ansbile :)
---
- name: "Collect host OS Version information for the host"
vars:
- output_path: "/tmp"
- filename: "osinfo_{{date}}.csv"
vars_prompt:
- name: input_hostname
prompt: What is the set of hosts you want connect ?
private: no
hosts: "{{ input_hostname }}"
tasks:
- name: CSV Generate output filename
set_fact: date="{{lookup('pipe','date +%Y%m%d_%H%M%S')}}"
run_once: true
- name: CSV - Create file and set the header
local_action: copy content="Hostname,SID,OSVersion,KernelVersion\n" dest="{{output_path}}/{{filename }}"
run_once: true
- name: OS Version info for {{ input_hostname }} hosts
set_fact:
csv_tmp: >
{{ inventory_hostname }},{{SID}},{{ ansible_distribution_version }},{{ ansible_kernel }}
- name: CSV - Write information into .csv file
local_action:
module: lineinfile
dest: "{{output_path}}/{{filename }}"
line: "{{csv_tmp}}"
- name: CSV - Blank lines removal
local_action:
module: lineinfile
dest: "{{output_path}}/{{filename }}"
state: absent
regex: '^\s*$'

Ansible: Set variable to file content

I'm using the ec2 module with ansible-playbook I want to set a variable to the contents of a file. Here's how I'm currently doing it.
Var with the filename
shell task to cat the file
use the result of the cat to pass to the ec2 module.
Example contents of my playbook.
vars:
amazon_linux_ami: "ami-fb8e9292"
user_data_file: "base-ami-userdata.sh"
tasks:
- name: user_data_contents
shell: cat {{ user_data_file }}
register: user_data_action
- name: launch ec2-instance
local_action:
...
user_data: "{{ user_data_action.stdout }}"
I assume there's a much easier way to do this, but I couldn't find it while searching Ansible docs.
You can use lookups in Ansible in order to get the contents of a file, e.g.
user_data: "{{ lookup('file', user_data_file) }}"
Caveat: This lookup will work with local files, not remote files.
Here's a complete example from the docs:
- hosts: all
vars:
contents: "{{ lookup('file', '/etc/foo.txt') }}"
tasks:
- debug: msg="the value of foo.txt is {{ contents }}"
You can use the slurp module to fetch a file from the remote host: (Thanks to #mlissner for suggesting it)
vars:
amazon_linux_ami: "ami-fb8e9292"
user_data_file: "base-ami-userdata.sh"
tasks:
- name: Load data
slurp:
src: "{{ user_data_file }}"
register: slurped_user_data
- name: Decode data and store as fact # You can skip this if you want to use the right hand side directly...
set_fact:
user_data: "{{ slurped_user_data.content | b64decode }}"
You can use fetch module to copy files from remote hosts to local, and lookup module to read the content of fetched files.
lookup only works on localhost. If you want to retrieve variables from a variables file you made remotely use include_vars: {{ varfile }} . Contents of {{ varfile }} should be a dictionary of the form {"key":"value"}, you will find ansible gives you trouble if you include a space after the colon.

Resources