Automated Network Monitoring: Adding Servers to LibreNMS with Ansible #
Adding servers to LibreNMS by hand is tedious, and should be done by automation. In this post, I’ll show you how I’ve automated the entire process of configuring SNMP and adding servers to LibreNMS using Ansible.
The Workflow #
Basically what the playbook does is:
- Install and configure SNMP
- Set up necessary firewall rules
- Add the server to LibreNMS
- Add it to the correct device group.
The Playbook #
Step 1: Installing SNMP Components #
- name: Ensure snmp is installed
ansible.builtin.dnf:
name:
- net-snmp
- net-snmp-utils
state: present
The net-snmp package is needed for the SNMP daemon.
Step 2: LibreNMS Agent Integration #
- name: Ensure /usr/bin/distro exists
ansible.builtin.get_url:
url: https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/distro
dest: /usr/bin/distro
mode: '0755'
force: true
This downloads the LibreNMS distribution detection script, which provides the OS’ logo in the GUI.
Step 3: SNMP Configuration #
- name: Ensure correct snmpd.conf
ansible.builtin.copy:
content: |
com2sec readonly default {{ librenms_community_string }}
group MyROGroup v2c readonly
view all included .1 80
access MyROGroup "" any noauth exact all none none
extend distro /usr/bin/distro
syslocation home.arpa
dest: /etc/snmp/snmpd.conf
mode: '0600'
The SNMP configuration includes:
- Community string: Uses
{{ librenms_community_string }}variable (stored securely in Ansible Vault) - Extended information: Links the distro script for additional data
Step 4: Firewall Configuration #
- name: Ensure snmp is allowed in firewall
ansible.posix.firewalld:
zone: public
service: snmp
permanent: true
state: enabled
immediate: true
This opens UDP port 161 for SNMP.
Step 5: Service Management #
- name: Ensure snmpd service is enabled and running
ansible.builtin.systemd:
name: snmpd
state: started
enabled: true
Ensures the service is up and running.
The LibreNMS API Integration #
Here’s how we can add the host(s) to LibreNMS by using the REST API:
Checking for Existing Devices #
- name: Check if device exists in LibreNMS
ansible.builtin.uri:
url: "{{ librenms_api_url }}/devices"
method: GET
headers:
X-Auth-Token: "{{ librenms_api_token }}"
register: existing_devices
First, we query the LibreNMS API to get a list of all existing devices. This prevents duplicate entries.
Conditional Device Addition #
- name: Add server to LibreNMS if missing
when: >
not inventory_hostname in existing_devices.json.devices
| map(attribute='hostname') | list
block:
The conditional logic checks if the current server’s hostname exists in the device list. If not, we proceed with the addition process.
Adding the Device #
- name: Add server(s) to LibreNMS
ansible.builtin.uri:
url: "{{ librenms_api_url }}/devices"
method: POST
headers:
X-Auth-Token: "{{ librenms_api_token }}"
body:
hostname: "{{ inventory_hostname }}"
version: v2c
community: "{{ librenms_snmp_token }}"
body_format: json
register: device_result
changed_when: true
This API call creates the device in LibreNMS with.
Automatic Device Group Assignment #
- name: Get default device group
ansible.builtin.uri:
url: "{{ librenms_api_url }}/devicegroups"
method: GET
headers:
X-Auth-Token: "{{ librenms_api_token }}"
register: device_group_result
- name: Add server(s) to default device group
ansible.builtin.uri:
url: >
{{ librenms_api_url }}/devicegroups/{{
device_group_result.json.groups[0].name | urlencode }}/devices
method: POST
headers:
X-Auth-Token: "{{ librenms_api_token }}"
body:
devices: >
["{{ device_result.json.devices[0].device_id | default(0) }}"]
body_format: json
changed_when: true
Finally, we automatically assign the new device to the default device group (I only have one group).
Complete Playbook #
Click to expand the full playbook
---
- name: SNMP
hosts: all
become: true
gather_facts: true
vars_files:
- "../group_vars/all/vault.yml"
tasks:
- name: Ensure snmp is installed
ansible.builtin.dnf:
name:
- net-snmp
- net-snmp-utils
state: present
- name: Ensure /usr/bin/distro exists
ansible.builtin.get_url:
url: https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/distro
dest: /usr/bin/distro
mode: '0755'
force: true
- name: Ensure correct snmpd.conf
ansible.builtin.copy:
content: |
com2sec readonly default {{ librenms_community_string }}
group MyROGroup v2c readonly
view all included .1 80
access MyROGroup "" any noauth exact all none none
extend distro /usr/bin/distro
syslocation home.arpa
dest: /etc/snmp/snmpd.conf
mode: '0600'
- name: Ensure snmp is allowed in firewall
ansible.posix.firewalld:
zone: public
service: snmp
permanent: true
state: enabled
immediate: true
- name: Ensure snmpd service is enabled and running
ansible.builtin.systemd:
name: snmpd
state: started
enabled: true
- name: Check if device exists in LibreNMS
ansible.builtin.uri:
url: >
{{ librenms_api_url }}/devices
method: GET
headers:
X-Auth-Token: "{{ librenms_api_token }}"
register: existing_devices
- name: Add server to LibreNMS if missing
when: >
not inventory_hostname in existing_devices.json.devices
| map(attribute='hostname') | list
block:
- name: Add server(s) to LibreNMS
ansible.builtin.uri:
url: "{{ librenms_api_url }}/devices"
method: POST
headers:
X-Auth-Token: "{{ librenms_api_token }}"
body:
hostname: "{{ inventory_hostname }}"
version: v2c
community: "{{ librenms_community_string }}"
body_format: json
register: device_result
changed_when: true
- name: Get default device group
ansible.builtin.uri:
url: "{{ librenms_api_url }}/devicegroups"
method: GET
headers:
X-Auth-Token: "{{ librenms_api_token }}"
register: device_group_result
- name: Add server(s) to default device group
ansible.builtin.uri:
url: >
{{ librenms_api_url }}/devicegroups/{{
device_group_result.json.groups[0].name
| urlencode }}/devices
method: POST
headers:
X-Auth-Token: "{{ librenms_api_token }}"
body:
devices: >
["{{ device_result.json.devices[0].device_id
| default(0) }}"]
body_format: json
changed_when: true