Automated Network Monitoring: Adding Servers to LibreNMS with Ansible

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:

  1. Install and configure SNMP
  2. Set up necessary firewall rules
  3. Add the server to LibreNMS
  4. 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