How to check the OS version of host which in dynamically added to inventory - ansible

I'm trying to get server name as user input and if the server OS is RHEL7 it will proceed for further tasks. I'm trying with hostvars but it is not helping, kindly help me to find the OS version with when condition:
---
- name: Add hosts
hosts: localhost
vars:
- username: test
password: test
vars_prompt:
- name: server1
prompt: Server_1 IP or hostname
private: no
- name: server2
prompt: Server_2 IP or hostname
private: no
tasks:
- add_host:
name: "{{ server1 }}"
groups:
- cluster_nodes
- primary
- management
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- add_host:
name: "{{ server2 }}"
groups:
- cluster_nodes
- secondary
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- debug:
msg: "{{ hostvars['server1'].ansible_distribution_major_version }}"
When I execute the playbook, I'm getting below error:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['server1']\" is undefined\n\nThe error appears to be in '/var/lib/awx/projects/pacemaker_RHEL_7_ST/main_2.yml': line 33, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}

You need to gather_facts on the newly added host before you consume the variable. As an example, this will do it with automatic facts gathering.
---
- name: Add hosts
hosts: localhost
vars:
- username: test
password: test
vars_prompt:
- name: server1
prompt: Server_1 IP or hostname
private: no
- name: server2
prompt: Server_2 IP or hostname
private: no
tasks:
- add_host:
name: "{{ server1 }}"
groups:
- cluster_nodes
- primary
- management
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- add_host:
name: "{{ server2 }}"
groups:
- cluster_nodes
- secondary
ansible_user: "{{ username }}"
ansible_password: "{{ password}}"
- name: Gather facts for newly added targets
hosts: cluster_nodes
# gather_facts: true <= this is the default
- name: Do <whatever> targeting localhost again
hosts: localhost
gather_facts: false # already gathered in play1
tasks:
# Warning!! bad practice. Looping on a group usually
# shows you should have a play targeting that specific group
- debug:
msg: "OS version for {{ item }} is 7"
when: hostvars[item].ansible_distribution_major_version | int == 7
loop: "{{ groups['cluster_nodes'] }}"
If you don't want to rely on automatic gathering, you can manually play the setup module, e.g. for the second play:
- name: Gather facts for newly added targets
hosts: cluster_nodes
gather_facts: false
tasks:
- name: get facts from targets
setup:

Related

Ansible vars_prompt for host list into Import_playbook

I want to use a specific host / host list for an imported playbook which I get from a vars_prompt input. How can I do this? So far I wasn´t able to get this running.
I have two playbooks which I need to run separately and ios_check_routerports.yaml is the parent playbook:
ios_check_routerports.yaml
---
- hosts: '{{ branch_number }}'
connection: network_cli
gather_facts: False
any_errors_fatal: no
throttle: 75
vars_prompt:
- name: "branch_number"
prompt: "Which branch do you want to check?"
default: all
private: no
tasks:
- name: Check facts
ios_facts:
gather_subset: hardware
- name: Create directory
file:
path: /root/ansible/pb-outputs/ios_check_routerports/
state: directory
delegate_to: 127.0.0.1
- name: Run playbook
import_playbook: ios_check_routerports_main.yaml
ios_check_routerports_main.yaml
---
- hosts: '{{ branch_number }}'
connection: network_cli
gather_facts: False
any_errors_fatal: no
throttle: 75
tasks:
- name: Check default-gateway
ios_command:
commands: sh run | i default-gateway
register: default_gateway
I tried to set a fact for the var {{ branch_number }} like this:
ios_check_routerports.yaml
- set_fact:
devices: "{{ branch_number }}"
ios_check_routerports_main.yaml
---
- hosts: '{{ devices }}'
connection: network_cli
The playbook always runs into an error because the hosts var is not defined. What am I doing wrong here?
try this: no need to create a new variable devices but a dummy host
in ios_check_routerports.yaml add a task:
- name: Register dummy host with variable
add_host:
name: "DUMMY_HOST"
DEVICES: "{{ branch_number }}"
then :
- hosts: "{{ hostvars['DUMMY_HOST']['DEVICES'] }}"
connection: network_cli
as you create a new host, i suggest you to delete it if you havent need the variable branch_number so remove_host doesnt exit:
either you do a first task - meta: refresh_inventory
or you modify your host like this:
- hosts: "{{ hostvars['DUMMY_HOST']['DEVICES'] }},!DUMMY_HOST"

Ansible how to remove groups value by key

I am having a play where i will collect available host names before running a task, i am using this for a purpose,
My play code:
--
- name: check reachable side A hosts
hosts: ????ha???
connection: local
gather_facts: no
roles:
- Juniper.junos
vars:
credentials:
host: "{{ loopback_v4 }}"
username: "test"
ssh_keyfile: "/id_rsa"
port: "{{ port }}"
timeout: 60
tasks:
- block:
- name: "Check netconf connectivity with switches"
juniper_junos_ping:
provider: "{{ credentials }}"
dest: "{{ loopback_v4 }}"
- name: Add devices with connectivity to the "reachable" group
group_by:
key: "reachable_other_pairs"
rescue:
- debug: msg="Cannot ping to {{inventory_hostname}}. Skipping OS Install"
When i print this using
- debug:
msg: "group: {{ groups['reachable_other_pairs'] }}"
i am getting below result
"this group : ['testha1', 'testha2', 'testha3']",
Now if again call the same play with different hosts grouping with the same key i am getting the new host names appending to the existing values, like below
- name: check reachable side B hosts
hosts: ????hb???
connection: local
gather_facts: no
roles:
- Juniper.junos
vars:
credentials:
host: "{{ loopback_v4 }}"
username: "test"
ssh_keyfile: "/id_rsa"
port: "{{ port }}"
timeout: 60
tasks:
- block:
- name: "Check netconf connectivity with switches"
juniper_junos_ping:
provider: "{{ credentials }}"
dest: "{{ loopback_v4 }}"
- name: Add devices with connectivity to the "reachable" group
group_by:
key: "reachable_other_pairs"
rescue:
- debug: msg="Cannot ping to {{inventory_hostname}}. Skipping OS Install"
if i print the reachable_other_pairs i am getting below results
"msg": " new group: ['testhb1', 'testhb2', 'testhb3', 'testha1', 'testha2', 'testha3']"
All i want is only first 3 entries ['testhb1', 'testhb2', 'testhb3']
Can some one let me know how to achieve this?
Add this as as task just before your block. It will refresh your inventory and clean up all groups that are not in there:
- meta: refresh_inventory

How to use variable in different playbook?

How to use a variable in a different playbook? (ansible 2.7.10)
username.yml
- hosts: host
vars_prompt:
- name: username
prompt: 'Username...'
private: no
tasks:
- name: Show username
debug:
msg: "{{username}}"
- import_playbook: dns.yml
dns.yml
- hosts: DNS
tasks:
- name: Mesaj
debug:
msg: "{{username}}"
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'username' is undefined
The scope of a variable declared by vars_prompt is the play. Use set_fact to share such variable in the whole playbook.
The set_fact module takes key=value pairs as variables to set in the playbook scope.
- hosts: host
vars_prompt:
- name: username
prompt: 'Username...'
private: no
tasks:
- name: Show username
debug:
msg: "{{ username }}"
- set_fact:
username: "{{ username }}"
In the second play (dns.yml) use hostvars to reference the variables cached by host in the first play.
- hosts: DNS
tasks:
- name: Mesaj
debug:
msg: "{{ hostvars['host'].username }}"
Without disturbing the dns.yml playbook. So, you can pass -e username=myuser and execute it separately if needed.
username.yml
Adding set fact with different variable name (uname) and passing it to the playbook (dns.yml)
- hosts: localhost
vars_prompt:
- name: username
prompt: 'Username...'
private: no
tasks:
- name: Show username
debug:
msg: "{{username}}"
- name: Set fact
set_fact:
uname: "{{ username }}"
- import_playbook: dns.yml
vars:
username: "{{ uname }}"
dns.yml
No change to this playbook.
- hosts: DNS
tasks:
- name: Mesaj
debug:
msg: "{{username}}"

How add hosts from user's input in a ansible playbook?

I need to add a host from the user's input. Now I'm trying to use the ansible in-memory inventory, add_host module and prompt to add the target host to execute the remaining tasks. This is the content of my playbook:
Deploy.yml
- name: Adding the host server
hosts: localhost
- vars_prompt:
- name: "Server IP"
prompt: "Server"
private: no
- name: "Username (default: Ubuntu)"
prompt: "User"
default: "Ubuntu"
private: no
- name: "Password"
prompt: "Passwd"
private: yes
encrypt: "sha512_crypt"
- name: "Identity file path"
prompt: "IdFile"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
when: Passwd is defined
- hosts: "{{ Server }}"
tasks:
- name: Copy the script file to the server
copy:
src: script.sh
dest: "{{ ansible_env.HOME }}/folder/"
mode: 755
force: yes
attr:
- +x
When I run this playbook with this command $ ansible-playbook Deploy.yml, The output is:
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Adding the host server] ***********************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
Server: <server-ip>
User [Ubuntu]:
Passwd:
IdFile: <path/to/id/file>
ERROR! the field 'hosts' is required but was not set
I don't know why it throws this error:
ERROR! the field 'hosts' is required but was not set
How can I do what I need to do?
UPDATE:
It still not working. This is the content of my playbook:
Deploy.yml
- name: Adding the host server
hosts: localhost
vars_prompt:
- name: "Server"
prompt: "Server IP"
private: no
- name: "User"
prompt: "Username"
default: "Ubuntu"
private: no
- name: "Passwd"
prompt: "Password"
private: yes
encrypt: "sha512_crypt"
- name: "IdFile"
prompt: "Identity file path"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
when: IdFile is undefined
- hosts: "{{ Server }}"
tasks:
- name: Copy the script file to the server
copy:
src: script.sh
dest: "{{ ansible_env.HOME }}/folder/"
mode: 755
force: yes
attr:
- +x
When I run this playbook with this command $ ansible-playbook Deploy.yml, The output is:
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Adding the host server] ***********************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
Server IP: <server-ip>
Username [Ubuntu]:
Password:
Identity file path: <path/to/id/file>
ERROR! the field 'hosts' is required but was not set
I don't know why it throws this error:
ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'Server' is undefined
Here is a flowchart of how the playbook should works:
+------------------+ +---------------+ +-----------------+
|Use ansible to run| |Get host IP fom| |Get ssh User from|
| this playbook +---->+ user's input +---->+ user's input |
+------------------+ +---------------+ +--------+--------+
|
v
+------------+--------+
|Get ssh password from|
| user's input |
+------------+--------+
|
v
+---------------+ *************************
|Add a host with| Yes | Did the user inputted |
v----------+ password +<---+| a password? |
+----------------+ +---------------+ ***************+*********
||Run some tasks|| |No
||in recently || v
||added host || +---------------+ +------------+--------+
+----------------+ |Add a host with| |Get ssh identity file|
^----------+ identity file +<------+ from user's input |
+---------------+ +---------------------+
Ok I've updated my answer to suit the changes in your question, with the original answer left for historic reasons.
To solve the substitution error you are seeing, which results in an empty host list in your second play, I would instead use an inventory group.
There are also two other syntax errors in the second play
The file mode needs to be octal (i.e. 0700)
The attribute is invalid. My assumption is you are trying to make the file executable, so fix the file mode and remove the attribute.
Here is an updated playbook:
- name: Adding the host server
hosts: localhost
vars_prompt:
- name: "Server"
prompt: "Server IP"
private: no
- name: "User"
prompt: "Username"
default: "Ubuntu"
private: no
- name: "Passwd"
prompt: "Password"
private: yes
encrypt: "sha512_crypt"
- name: "IdFile"
prompt: "Identity file path"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
group: added_hosts
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
group: added_hosts
when: IdFile is undefined
- hosts: added_hosts
tasks:
- name: Copy the script file to the server
copy:
src: script.sh
dest: "{{ ansible_env.HOME }}/folder/"
mode: 0755
force: yes
=== OLD ANSWER ===
User input is stored in the whatever variable you are using for the name attribute in each of the variable prompts.
You need to switch around your name and prompt values under vars_prompt
There are also YAML formatting issues
For example:
- vars_prompt:
- name: "Server IP"
prompt: "Server"
private: no
should be:
vars_prompt:
- name: "server"
prompt: "Server IP"
private: no
Then you can refer to the {{ server }} variable in your tasks
Your ansible script is having a problem.
vars_prompt:
remove - from vars_prompt line it will work properly.
I tried in my local server the same script is working properly.
- name: Adding the host server
hosts: localhost
vars_prompt:
- name: "Server"
prompt: "Server IP"
private: no
- name: "User"
prompt: "Username"
default: "Ubuntu"
private: no
- name: "Passwd"
prompt: "Password"
private: yes
encrypt: "sha512_crypt"
- name: "IdFile"
prompt: "Identity file path"
private: no
when: Passwd is undefined
tasks:
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_private_key_file: "{{ IdFile }}"
when: IdFile is defined
- name: Add host server
add_host:
name: "{{ Server }}"
ansible_ssh_user: "{{ User }}"
ansible_ssh_pass: "{{ Passwd }}"
when: Passwd is defined
- name: Create a file
shell: touch newfile
delegate_to: "{{ Server }}"
In the last task update to your task and run it.
- name: Create a file
shell: touch newfile
delegate_to: "{{ Server }}"

How to transfer variables to include playbook?

i have playbook, which have include. Also have var_prompt "name_VM" and i need transfer variable in include playbook "new-vm.yml", but i have error:
TASK [hostname]
**************************************************************** fatal: [192.168.250.102]: FAILED! => {"failed": true, "msg": "the
field 'args' has an invalid value, which appears to include a variable
that is undefined. The error was: {{ name_VM }}: 'name_VM' is
undefined\n\nThe error appears to have been in
'/etc/ansible/playbooks/tasks/new-vm.yml': line 7, column 7, but
may\nbe elsewhere in the file depending on the exact syntax
problem.\n\nThe offending line appears to be:\n\n pre_tasks:\n -
hostname:\n ^ here\n"}
How to transfer variables in pre_tasks include playbook?
Main playbook:
- hosts: localhost
gather_facts: false
connection: local
become: true
vars_files:
- ../roles/vm-create/vars/am-default.yml
vars_prompt:
- name: "name_VM"
prompt: "VM name:"
private: no
default: "vm001"
- name: "size_hard"
prompt: "Size hard disk (Gb)"
private: no
default: "16"
- name: "size_memory"
prompt: "Size memory (Mb)"
private: no
default: "2048"
- name: "count_CPU"
prompt: "Count CPU:"
private: no
default: "2"
roles:
- vm-create
tasks:
- include: tasks/check-ip.yml
- include: tasks/new-vm.yml
new-vm playbook:
- hosts: temp
vars:
ldap_server: ldap://ldap.example.com
agent_server: zabbix.aexample.com
pre_tasks:
- hostname:
name: "{{ name_vm }}"
roles:
- { role: zabbix-agent, tags: [ 'zabbix' ] }
- { role: ldap-client, tags: [ 'ldap' ] }
- { role: motd, tags: [ 'motd' ] }
tasks:
- telegram:
token: 'bot12345:XXXXXX'
chat_id: XXXXX
msg: "New VM {{ ansible_hostname }} ({{ ansible_all_ipv4_addresses }}) is created and has been configured."
tags:
- telegram
check_ip.yml in which i add host:
- vsphere_guest:
vcenter_hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
guest: "{{ name_VM }}"
vmware_guest_facts: yes
validate_certs: no
register: vsphere_facts
until: vsphere_facts.ansible_facts.hw_eth0.ipaddresses[0] | match("192.168.250.")
retries: 6
delay: 10
- name: Ensure virtual machine is in the dynamic inventory
add_host:
name: "{{ vsphere_facts.ansible_facts.hw_eth0.ipaddresses[0] }}"
ansible_user: root
ansible_ssh_pass: pass
groups: temp
In your case name_VM is play-bound and will not be visible from second play.
You need to assign a fact to temp host (I guess you use add_host somewhere inside vm-create role; so just add name_vm: "{{ name_VM }}" host fact there).
Then in second play you can access {{ name_vm }} host fact.
Update: example, based on question edit.
- name: Ensure virtual machine is in the dynamic inventory
add_host:
name: "{{ vsphere_facts.ansible_facts.hw_eth0.ipaddresses[0] }}"
name_vm: "{{ name_VM }}"
ansible_user: root
ansible_ssh_pass: pass
groups: temp

Resources