I am having an ansible script. It calls other scripts using include module.
I need to get the current file name in a variable.
For ex:
- include: Run-Config889.yml
Inside Run-Config889.yml, i need to get the file name Run-Config889.yml in a variable.
Whether any built-in variable is there to find the current file name? if so what it is?
You can get the current playbook file name with :
---
- hosts: 127.0.0.1
connection: local
gather_facts: no
vars:
playbook_absoluteName: "{{ (lookup('file', '/proc/self/cmdline') | regex_replace('\u0000',' ')).split() | select('match','^.*[.]ya?ml$') | list | first }}"
playbook_baseName: "{{ playbook_absoluteName | basename }}"
tasks:
- debug:
var: item
loop:
- "{{ playbook_absoluteName }}"
- "{{ playbook_baseName }}"
...
This was inspired by this blog article, with minor/cosmetics improvements.
Don't know about any built-in variable but there are 2 options I can think of.
Option 1
You can pass variables to included files like so:
main.yml
---
- include: Run-Config889.yml file_name_variable="Run-Config889.yml"
Option 2
Set the variable in any of the vars files used by the play. All defined variables in a play are inherited by subsequent include statements.
sample-vars.yml
---
file_name_variable: "Run-Config889.yml"
Using the variable.
Run-Config889.yml
---
- name: Display variable
debug:
msg: File name {{ file_name_variable }}
Related
I have an ansible playbook as follows:
---
- name: test variables
hosts: all
tasks:
- name: test
command: echo {{ ansible_role_dir }}
register: result
- name: show result
debug:
msg="{{ result.stdout }}"
#roles: #line12
# - "{{ ansible_role_dir }}/testrole" #line13
the variable ansible_role_dir is defined under group_vars/all.yaml.
if I run the playbook which comments out the line12 and line13, it shows the result of variable correctly. Obviously it knows where the variable ansible_role_dir is defined. But if I uncomment line12 and line13, it shows error ERROR! 'ansible_role_dir' is undefined. Why it does not know where the ansible_role_dir is defined this time?
Ansible does not like jinja tags without quotes. try this:
---
- name: test variables
hosts: all
tasks:
- name: test
command: "echo {{ ansible_role_dir }}"
register: result
- name: show result
debug:
msg="{{ result.stdout }}"
#roles: #line12
# - "{{ ansible_role_dir }}/testrole" #line13
EDIT:
sorry, i think i misread the question.
have you tried putting in the real path instead of the var, just to see if it works? usually role paths are given in ansible's config, i never saw them run with a direct path
How can I print variables declared only at group_vars, host_vars without ansible facts?
such code is good:
- name: "Ansible | List all known variables and facts"
debug:
var: hostvars[inventory_hostname]
But I don't need host IPs,disks, etc.
I mean to check all my variables one more time before continue to execute Play.
There are 3 categories of variables: ansible facts, special variables, and user's variables. Remove both ansible facts and special variables from hostvars and what is left are user's variables. The list of the ansible facts is available in the variables ansible_facts. The list of the special variables must be created (I think).
Create a list of special variables
If you run the playbook below you'll see the list of the special variables and user's variables
- hosts: localhost
tasks:
- debug:
msg: "{{ hostvars[inventory_hostname]|
difference(ansible_facts) }}"
Eliminate the user's vars and put the list of the special variables into a file. For example
shell> cat special_vars.yml
special_vars:
- ansible_python_interpreter
- ansible_connection
- inventory_hostname
...
This list of special variables might be not complete and will serve the purpose of this host only.
Remove ansible facts and special variables from hostvars
- hosts: localhost
vars_files:
- special_vars.yml
tasks:
- set_fact:
user_var1: AAA
- debug:
msg: "{{ hostvars[inventory_hostname]|
difference(ansible_facts)
difference(special_vars) }}"
gives the list of user's variables only
msg:
- user_var1
The user's variables will include also the configuration variables set by the user (e.g. connection variables: ansible_user or priviledge escalation: ansible_become).
Name-space
A better practice is to "name-space" variables. For example
- hosts: localhost
vars:
prj51_var1: AAA
prj51_var2: BBB
tasks:
- debug:
msg: "{{ item }}: {{ query('vars', item)|first }}"
loop: "{{ query('varnames', 'prj51_.+$') }}"
gives
msg: 'prj51_var1: AAA'
msg: 'prj51_var2: BBB'
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 }}"
In my ansible vars file, I have a variable that will sometimes be set and other times I want to dynamically set it. For example, I have an RPM that I want to install. I can manually store the location in a variable, or if I don't have a particular one in mind, I want to pull the latest from Jenkins. My question is, how can I check if the variable is not defined or empty, and if so, just use the default from Jenkins (already stored in a var)?
Here is what I have in mind:
...code which gets host_vars[jenkins_rpm]
- hosts: "{{ host }}"
tasks:
- name: Set Facts
set_fact:
jenkins_rpm: "{{ hostvars['localhost']['jenkins_rpm'] }}"
- name: If my_rpm is empty or not defined, just use the jenkins_rpm
set_fact: my_rpm=jenkins_rpm
when: !my_rpm | my_rpm == ""
There is default filter for that:
- set_fact:
my_rpm: "{{ my_rpm | default(jenkins_rpm) }}"
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.