I have two interfaces in machine(linux). One interface has been addressed and second is down without any IP.
Now I would like to get the interface name matched with IP what I provide as value in ansible.
I was trying something like this:
- name: interface name from provides IP
set_fact:
interface_name="{{ item }}"
with_items:
- "{{ ansible_interfaces | map('replace', '-','_') | list }}"
when: hostvars[ansible_fqdn]['ansible_'~item]['ipv4']['address'] == PROVIDED_IP
It works good when all interfaces have IP address but problem is when one interface has no IP then I have error:
'dict object' has no attribute 'ipv4'
Is possible to get interface name without getting errors?
You can do this using jinja:
- name: Get interface name from provided IP
set_fact:
interface_name: "{{ ansible_interfaces | map('regex_replace', '^', 'ansible_') | map('extract', vars) | selectattr('ipv4.address', 'match', '192\\.168\\.16\\.200') | map(attribute='device') | first }}"
{{ ansible_interfaces | map('regex_replace', '^', 'ansible_') | map('extract', vars) gets you a list of interfaces, where each interface is a dictionary with information about the interface. You can then filter and map the list to get what you need.
try this playbook, just set the IP you want to search for:
- hosts: localhost
gather_facts: true
vars:
desired_interface_name: ""
target_interface_name: "192.168.16.200"
tasks:
- name: parse interfaces
set_fact:
desired_interface_name="{{ item }}"
when: hostvars[inventory_hostname]['ansible_{{item}}']['ipv4']['address'] == target_interface_name
with_items:
- "{{ ansible_interfaces }}"
- name: print result
debug:
var: desired_interface_name
Related
Newbie ansible user here.
I'm trying to print output of ps into csv file but somehow its printing on next column rather than next row.
This is my playbook xml:
- name: Write running process into a csv file
hosts: servers
gather_facts: yes
vars:
output_path: "./reports/"
filename: "process_{{ date }}.csv"
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
lineinfile:
dest: "{{ output_path }}/{{ filename }}"
line:
PID,Started,CPU,Memory,User,Process
create: yes
state: present
delegate_to: localhost
- name: CSV - Get ps cpu
ansible.builtin.shell:
ps -e -o %p, -o lstart -o ,%C, -o %mem -o user, -o %c --no-header
register: ps
- name: CSV - Write into csv file
lineinfile:
insertafter: EOF
dest: "{{ output_path }}/{{ filename }}"
line: "{inventory_hostname}},{{ps.stdout_lines}}"
loop: "{{ ps.stdout_lines }}"
delegate_to: localhost
- name: CSV - Blank lines removal
lineinfile:
path: "./{{ output_path }}/{{ filename }}"
state: absent
regex: '^\s*$'
delegate_to: localhost
current output is like
Example of desired output :
... but somehow its printing on next column rather than next row ... current output is like ...
This is because within your task "CSV - Write into CSV file" you are printing out all stdout_lines for each iteration steps instead of one, the line for the iteration step only.
To print out line by line one could use an approach like
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: CSV - Get ps cpu
shell:
cmd: ps -e -o %p, -o lstart -o ,%C, -o %mem -o user, -o %c --no-header
register: ps
- name: Show 'stdout_lines' one line per iteration for CSV
debug:
msg: "{{ inventory_hostname }}, {{ ps.stdout_lines[item | int] }}"
loop: "{{ range(0, ps.stdout_lines | length) | list }}"
I want to use hostnames of a group in ansible inventory in a template bash script file.
This is my inventory:
[group_srv]
srv1.co.company
srv2.co.company
srv3.co.company
This is that I wrote in script.sh.j2
for i in '{{ groups['group_srv'][0:3].split('.')[0] | join(' ') }}' ; do
echo $i
done
This is my desired output, but I cannot use split() and join() together.
for i in 'srv1' 'srv2' 'srv3'; do
echo $i
done
Any help is appreciated.
Ansible provides a magic variable containing the short name for each server in your inventory (i.e. the first string before the first dot): inventory_hostname_short
You can access all servers vars in an other magic var: hostvars
You can use the map filter to:
extract values for a list of keys inside a dict (e.g. the relevant hosts for your group in hostvars)
select a single key in a list of dictionaries (e.g. the short inventory name in each extracted server vars).
Those two operations can actually be done at once at extraction time.
Putting it all together:
for i in '{{ groups['group_srv'] | map('extract', hostvars) | map(attribute='inventory_hostname_short') | join("' '") }}' ; do
echo $i
done
Which can be shortened as
for i in '{{ groups['group_srv'] | map('extract', hostvars, 'inventory_hostname_short') | join("' '") }}' ; do
echo $i
done
The declaration below does the job
short_0_3: "{{ groups.group_srv[0:3]|
map('split', '.')|
map('first')|
join(' ') }}"
The next option is the extraction of the variable inventory_hostname_short
short_0_3: "{{ groups.group_srv[0:3]|
map('extract', hostvars, 'inventory_hostname_short')|
join(' ') }}"
Both options give
short_0_3: srv1 srv2 srv3
Example of a complete playbook for testing
- hosts: all
gather_facts: false
vars:
short_0_3: "{{ groups.group_srv[0:3]|
map('split', '.')|
map('first')|
join(' ') }}"
tasks:
- block:
- shell: "for i in {{ short_0_3 }}; do echo $i; done"
register: out
- debug:
var: out.stdout_lines
delegate_to: localhost
run_once: true
shell> cat hosts
[group_srv]
srv1.co.company
srv2.co.company
srv3.co.company
srv4.co.company
srv5.co.company
In Jinja2 loop you can use filters.
{% if not loop.last %} {% endif %} adds a white space after every element except the last one.
for i in {% for host in groups['group_srv'] %}'{{ host.split('.')[0] }}'{% if not loop.last %} {% endif %}{% endfor %} ; do
echo $i
done
Result:
for i in 'test-001' 'test-002' ; do
echo $i
done
I'm trying to use the nsupdate module to update records but I'm having mixed success. While the records do get added, I'm getting the zone appended at the end of the value.
For example:
I want a cname called mycname.domain1.com pointed to shawarmas.domain2.com. After I run the playbook I end up with an entry that looks like this:
mycname.domain1.com. 5 IN CNAME shawarmas.domain2.com.domain1.com
Is there something wrong in my playbook that is causing this?
Playbook:
---
- hosts: myserver
tasks:
- debug:
msg: "{{ value }}"
- name: "Add record to escapia zone"
nsupdate:
key_name: "ddns"
key_secret: "******"
server: "dnsserver"
record: "{{ record }}"
type: "{{ type }}"
value: "{{ value }}"
ttl: 5
Run Command:
ansible-playbook -i inv -e "record=record-test.example.com.
type=CNAME value=test.different.com" exampledns.yml -v
Ansible output:
changed: [myserver] => changed=true
dns_rc: 0
dns_rc_str: NOERROR
record:
record: record-test.example.com.
ttl: 5
type: CNAME
value:
- test.different.com
zone: example.com.
DNS result:
;; ANSWER SECTION:
record-test.example.com. 5 IN CNAME test.different.com.example.com
Usually, you need to append a . to the end of the value to make it full qualified. Without the . it is unqualified and appending the zone.
Try with:
ansible-playbook -i inv -e "record=record-test.example.com. type=CNAME value=test.different.com." exampledns.yml -v
I want to hard code 2 different values based on variable stdout in a single play.If a service is running then i want to hard code value as good else bad.How to use this logic in ansible?
I can able to hard code one value based on status result.
---
- hosts: localhost
connection: local
gather_facts: false
vars:
tasks:
- name: load var from file
include_vars:
file: /tmp/var.json
name: imported_var
- name: Checking mysqld status
shell: service mysqld status
register: mysqld_stat
- name: Checking mysqld status
shell: service httpd status
register: httpd_stat
- name: append more key/values
set_fact:
imported_var: "{{ imported_var| default([]) | combine({ 'mysqld_status': 'good' })}}"
when: mysqld_stat.rc == 0
- name: append more key/values
set_fact:
imported_var: "{{ imported_var| default([]) | combine({ 'httpd_status': 'good' })}}"
when: httpd_stat.rc == 0
- name: write var to file
copy:
content: "{{ imported_var | to_nice_json }}"
dest: /tmp/final.json
I want to hard code mysqld_status : Good if mysqld_stat.rc == 0 or mysqld-status: Bad if mysqld_stat.rc != 0.Is it possible to achieve in single play.(i.e) in single command
There are many of ways of approaching this problem. You could just add a second set_fact that runs when mysqld_stat.rc != 0. In the following example, only one of the two set_fact tasks will run:
- name: append more key/values
set_fact:
imported_var: "{{ imported_var| default({}) | combine({ 'mysqld_status': 'good' })}}"
when: mysqld_stat.rc == 0
- name: append more key/values
set_fact:
imported_var: "{{ imported_var| default({}) | combine({ 'mysqld_status': 'bad' })}}"
when: mysqld_stat.rc != 0
You could instead use Ansible's ternary filter:
- name: append more key/values
set_fact:
imported_var: "{{ imported_var| default({}) | combine({ 'mysqld_status': (mysqld_stat.rc == 0)|ternary('good', 'bad') })}}"
I have multiple tasks depend from the value of variable1. I want to check if the value is in {{ variable1 }} but I get an error:
- name: do something when the value in variable1
command: <command>
when: "'value' in {{ variable1 }}"
I'm using ansible 2.0.2
If variable1 is a string, and you are searching for a substring in it, this should work:
when: '"value" in variable1'
if variable1 is an array or dict instead, in will search for the exact string as one of its items.
None of the above answers worked for me in ansible 2.3.0.0, but the following does:
when: variable1 | search("value")
In ansible 2.9 this is deprecated in favor of using ~ concatenation for variable replacement:
when: "variable1.find('v=' ~ value) == -1"
http://jinja.pocoo.org/docs/dev/templates/#other-operators
Other options:
when: "inventory_hostname in groups[sync_source]"
From Ansible 2.5
when: variable1 is search("value")
For negative scenarios
when: not variable1 is search("value")
Some of the answers no longer work as explained.
Currently here is something that works for me in ansible 2.6.x
when: register_var.stdout is search('some_string')
This works for me in Ansible 2.9:
variable1 = www.example.com.
variable2 = www.example.org.
when: ".com" in variable1
and for not:
when: not ".com" in variable2
This example uses regex_search to perform a substring search.
- name: make conditional variable
command: "file -s /dev/xvdf"
register: fsm_out
- name: makefs
command: touch "/tmp/condition_satisfied"
when: fsm_out.stdout | regex_search(' data')
ansible version: 2.4.3.0
In Ansible version 2.9.2:
If your variable variable1 is declared:
when: "'value' in variable1"
If you registered variable1 then:
when: "'value' in variable1.stdout"
use this
when: "{{ 'value' in variable1}}"
instead of
when: "'value' in {{variable1}}"
Also for string comparison you can use
when: "{{ variable1 == 'value' }}"
I used
failed_when: not(promtool_version.stdout.find('1.5.2') != -1)
means - failed only when the previously registered variable "promtool_version" doesn't contains string '1.5.2'.