Gather Ip Addresses for Inventory servers and deploy snmp - ansible

I'm working on a deployment project for SNMP on a larger list of servers. The idea is for the script to utilise the inventory file where servers are listed in the following format
# AMRS
[AMRS_CENTRAL]
server1
server2
server3
[AMRS_EASTERN]
server4
server5
server6
I want to run an ansible playbook on all those hosts and get their MGMT IP address which I would then use to input into the snmpd.conf file along with 127.0.0.1.
So far I've come up with below but I'm not sure how to get the set_fact to gather the IPs of the servers.
---
- name: Gather Facts
hosts: all
gather_facts: yes
tasks:
- name: set_fact (target_ip) ..
set_fact:
target_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
- name: Write this the target IP to a file
copy:
content: "{{ target_ip }}"
dest: /home/AABB/deployment/ansible/playbooks/snmpd/host-vars.ini
- name: Install a list of packages for snmpd
yum:
name:
- net-snmp-utils
- net-snmp-devel
- net-snmp
state: present
- name: "disable and stop snmpd.service"
service:
name: snmpd.service
enabled: no
state: stopped
- name: Write this target IP to a file
lineinfile:
path: /etc/snmp/snmpd.conf
insertafter: "# manual page."
line: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }},127.0.0.1"
firstmatch: yes
state: present
- name: line insert
lineinfile:
path: /etc/snmp/snmpd.conf
insertbefore: BOF
line: "{{ item }}"
with_items:
- 'rwcommunity private 127.0.0.2'
- 'rocommunity public 127.0.0.1'
- 'rwcommunity private 10.129.165.50'
- 'rocommunity public 10.129.165.50'
- name: add text to the end of file
blockinfile:
state: present
insertafter: EOF
path: /etc/snmp/snmpd.conf
marker: "<!-- add services ANSIBLE MANAGED BLOCK -->"
block: |
#Traps To Sink
trapsink 10.129.165.50 public
#Event MIBS
iquerySecName User123
rouser User123
#Generate Traps on UCD error conditions
defaultMonitors yes
#Generate traps on linkUp/Down
linkUpDownNotifications yes
#LINKDOWN/LINKUP Configurations 1 Second Generate alert
notificationEvent linkUpTrap linkUp ifIndex ifAdminStatus ifOperStatus
notificationEvent linkDownTrap linkDown ifIndex ifAdminStatus ifOperStatus
monitor -r 1 -e linkUpTrap "Generate linkUp" ifOperStatus != 2
- name: "enable and start snmpd.service"
service:
name: snmpd.service
enabled: yes
state: started

Related

Create Local File With Ansible Template From Variables

I'm running an ansible playbook against a number of ec2 instances to check if a directory exists.
---
- hosts: all
become: true
tasks:
- name: Check if foo is installed
stat:
path:
/etc/foo
register: path
- debug: msg="{{path.stat.exists}}"
And I would like to generate a localfile that lists the private IP addresses of the ec2 instances and states whether or not the directory foo does exist.
I can get the private IP addresses of the instances with this task
- name: Get info from remote
shell: curl http://169.254.169.254/latest/meta-data/local-ipv4
register: bar
- debug: msg="{{bar.stdout}}"
How do I create a local file with content
IP address: 10.100.0.151 directory foo - false
IP address: 10.100.0.152 directory foo - true
I've tried adding a block for this as such
- hosts: localhost
become: false
vars:
installed: "{{bar.stdout}}"
status: "{{path.stat.exists}}"
local_file: "./Report.txt"
tasks:
- name: Create local file with info
copy:
dest: "{{ local_file }}"
content: |
"IP address {{ installed }} foo - {{ status }}"
But it doesn't look like I can read values of variables from earlier steps.
What am I doing wrong please?
A similar question has been answered here.
Basically what you want is to reference it through the host var variable.
This should work.
- hosts: localhost
become: false
vars:
local_file: "./Report.txt"
tasks:
- name: Create local file with info
lineinfile:
path: "{{ local_file }}"
line:
"IP Address: {{ hostvars[item]['bar'].stdout }} - Installed: {{ hostvars[item]['path'].stat.exists }}"
with_items: "{{ query('inventory_hostnames', 'all') }}"
And this should populate your local ./Report.txt file, with the info you need.
I've used the ec2_metadata_facts module to get the IP address us ingansible_ec2_local_ipv4
I've also created the directory /tmp/testdir on the second host.
- hosts: test_hosts
gather_facts: no
vars:
directory_name: /tmp/testdir
tasks:
- ec2_metadata_facts:
- name: check if directory '{{ directory_name }}' exsists
stat:
path: "{{ directory_name }}"
register: path
# I make the outputfile empty
# because the module lineinfile(as I know) can't overwrite a file
# but appends line to the old content
- name: create empty output file
copy:
content: ""
dest: outputfile
delegate_to: localhost
- name: write output to outputfile
lineinfile:
dest: outputfile
line: "IP Address: {{ ansible_ec2_local_ipv4 }} {{ directory_name }} - {{ path.stat.exists }}"
state: present
with_items: "{{ groups.all }}"
# with_items: "{{ ansible_play_hosts }}" can also be used here
delegate_to: localhost
The outputfile looks like:
IP Address: xxx.xx.x.133 /tmp/testdir - False
IP Address: xxx.xx.x.45 /tmp/testdir - True

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

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:

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

saving variables from playbook run to ansible host local file

I'm sort of trying to build an inventory file from an ansible playbook run.
I'm trying to list out all the kvm hosts and the guests running on them, by running both service libvirtd status and if successful, virsh list --all, and to store the values in a file on the ansible host.
Ive tried a few different playbook structures but none have been successful in writing the file (using local_action wrote the ansible_hostname from just one host).
Please can someone guide me on what I'm doing wrong?
This is what I'm running:
- name: Determine KVM hosts
hosts: all
become: yes
#gather_facts: false
tasks:
- name: Check if libvirtd service exists
shell: "service libvirtd status"
register: libvirtd_status
failed_when: not(libvirtd_status.rc == 0)
ignore_errors: true
- name: List KVM guests
shell: "virsh list --all"
register: list_vms
when: libvirtd_status.rc == 0
ignore_errors: true
- name: Write hostname to file
lineinfile:
path: /tmp/libvirtd_hosts
line: "{{ ansible_hostname }} kvm guests: "
create: true
#local_action: copy content="{{ item.value }}" dest="/tmp/libvirtd_hosts"
with_items:
- variable: ansible_hostname
value: "{{ ansible_hostname }}"
- variable: list_vms
value: "{{ list_vms }}"
when: libvirtd_status.rc == 0 or list_vms.rc == 0
Was able to cobble something that's mostly working:
- name: Check if libvirtd service exists
shell: "service libvirtd status"
register: libvirtd_status
failed_when: libvirtd_status.rc not in [0, 1]
- name: List KVM guests
#shell: "virsh list --all"
virt:
command: list_vms
register: all_vms
when: libvirtd_status.rc == 0
---
- name: List all KVM hosts
hosts: production, admin_hosts, kvm_hosts
become: yes
tasks:
- name: create file
file:
dest: /tmp/libvirtd_hosts
state: touch
delegate_to: localhost
- name: Copy VMs list
include_tasks: run_libvirtd_commands.yaml
- name: saving cumulative result
lineinfile:
line: '{{ ansible_hostname }} has {{ all_vms }}'
dest: /tmp/libvirtd_hosts
insertafter: EOF
delegate_to: localhost
when: groups["list_vms"] is defined and (groups["list_vms"] | length > 0)
Now if only I could clean up the output to filter out false positives (machines that don't have libvirtd status, and have an empty/no list of VMs, because the above doesn't really work.
But at least there is output from all the KVM hosts!

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 }}"

Resources