Commit e690c8f3 authored by Jan Koester's avatar Jan Koester
Browse files

Initial import of snmpdd

snmpdd sends the state of the system as SNMP notifications (SNMPv2c or
v1 traps, over libnetplus UDP) to network management stations: every
interval a report of what storaged knows (RAID arrays, LVM volume
groups, SMART with the ATA attributes, self-tests, NVMe health),
syslite's services and mount units and the mounted file systems; at
once a new SMART warning, a failed self-test, a service that fails or
comes back and every status change. SNMPDD-MIB (tools/mkmib.py)
describes them.

Configured with snmpdd.yaml (libconfplus) and a settings file
(tinyxml2) that snmpdd writes on SetSettings -- over sysbus as the
service "snmpdd", webctl's SNMP page is its client.

Co-Authored-By: default avatarClaude Opus 5.5 <noreply@anthropic.com>
parents
Loading
Loading
Loading
Loading

.gitignore

0 → 100644
+3 −0
Changes for .gitignore: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
build/
*.o
*.d

CMakeLists.txt

0 → 100644
+54 −0
Changes for CMakeLists.txt: 54 added lines, 0 removed lines.
Original line number Diff line number Diff line
cmake_minimum_required(VERSION 3.16)
project(snmpdd VERSION 0.1.0 LANGUAGES CXX)

# snmpdd: sends the state of the system as SNMP notifications (traps,
# SNMPv2c or v1) to network management stations, every interval and on
# events. It collects over sysbus what storaged knows (RAID arrays, LVM
# volume groups, SMART) and syslite's services and mount units, and how
# full the mounted file systems are; mibs/SNMPDD-MIB.txt describes the
# notifications. It is configured over sysbus as the service "snmpdd"
# (include/snmpdd/api.h) -- webctl's SNMP page is its client.
#
#   snmpdd        the daemon (root)
#   snmpdd.yaml   enterprise OID, limits, where the settings are
#                  (libconfplus)
#   settings file  targets, interval, what is reported (tinyxml2),
#                  written by snmpdd on SetSettings

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()

include(GNUInstallDirs)

find_package(sysbus REQUIRED)
find_package(libnetplus REQUIRED)
find_package(libconfplus REQUIRED)
find_package(tinyxml2 REQUIRED)

set(SNMPDD_SYSCONFDIR "/etc/snmpdd" CACHE PATH "configuration directory")
set(SNMPDD_MIBDIR "${CMAKE_INSTALL_FULL_DATADIR}/snmp/mibs" CACHE PATH "MIB directory")

# needs storaged/api.h (storaged-dev)
add_executable(snmpdd
    src/main.cpp
    src/config.cpp
    src/collect.cpp
    src/sender.cpp
    src/snmp.cpp
)
target_include_directories(snmpdd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_compile_definitions(snmpdd PRIVATE
    SNMPDD_CONFIG="${SNMPDD_SYSCONFDIR}/snmpdd.yaml"
    SNMPDD_SETTINGS="${SNMPDD_SYSCONFDIR}/settings.xml"
)
target_link_libraries(snmpdd PRIVATE sysbus::sysbus netplus::netplus confplus::confplus tinyxml2::tinyxml2)

install(TARGETS snmpdd RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
install(DIRECTORY include/snmpdd DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES dist/snmpdd.yaml DESTINATION ${SNMPDD_SYSCONFDIR})
install(FILES mibs/SNMPDD-MIB.txt DESTINATION ${SNMPDD_MIBDIR})
set(SNMPDD_UNITDIR "/etc/syslite/services" CACHE PATH "syslite unit directory")
install(FILES dist/snmpdd.service DESTINATION ${SNMPDD_UNITDIR})

dist/snmpdd.service

0 → 100644
+10 −0
Changes for dist/snmpdd.service: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
[Unit]
Description=snmpdd: SNMP notifications of storage and service state

[Service]
Type=simple
ExecStart=/usr/sbin/snmpdd
Restart=always

[Install]
WantedBy=multi-user.target

dist/snmpdd.yaml

0 → 100644
+16 −0
Changes for dist/snmpdd.yaml: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
# snmpdd configuration (read with libconfplus at start and on SIGHUP).
# Every key is optional; the values below are the defaults. Targets,
# interval and what is reported are settings, changed in webctl (SNMP).
snmpdd:
  # the settings file, written by snmpdd itself (mode 0600: communities)
  settings: /etc/snmpdd/settings.xml
  # the root of SNMPDD-MIB: put your own private enterprise number
  # (https://www.iana.org/assignments/enterprise-numbers) here and in
  # the MIB's MODULE-IDENTITY
  enterprise: 1.3.6.1.4.1.99999
  # the largest notification in bytes; longer reports are split
  # (1472: one Ethernet frame without fragments)
  max_message: 1472
  # seconds statvfs() of all mounted file systems may take together (a
  # dead NFS server doesn't answer)
  statvfs_timeout: 5

include/snmpdd/api.h

0 → 100644
+76 −0
Changes for include/snmpdd/api.h: 76 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*******************************************************************************
Copyright (c) 2026, Jan Koester jan.koester@gmx.net
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

/* snmpdd on sysbus: the service "snmpdd", reached with
 * sysbus::Client::callService(snmpdd::Service, method, fields). Every
 * method needs root (the settings hold the communities). Error messages
 * are in English, or in German if the call has a field "lang" starting
 * with "de". Flags are yes|no.
 *
 * snmpdd collects, every interval, what storaged knows about RAID
 * arrays, LVM volume groups and SMART, the state of syslite's services
 * and mount units and how full the mounted file systems are, and sends
 * it as SNMP notifications (traps, SNMPv2c or v1) to every target. Event
 * notifications go out at once: a new SMART warning (storaged), a failed
 * self-test, a unit that fails or comes back (syslite), an item whose
 * status changed since the last report (a disk getting too warm, an
 * attribute that starts failing, ...). The objects and notifications are in
 * mibs/SNMPDD-MIB.txt, under the enterprise OID of snmpdd.yaml.
 *
 * Settings (written to the settings file, see snmpdd.yaml):
 *   GetSettings -> enabled, interval (seconds), events, report_raid,
 *       report_lvm, report_filesystems, report_disks, report_services,
 *       report_smart_attributes (ATA attributes of every disk),
 *       fs_warning, fs_critical (% used), temp_warning, temp_critical
 *       (°C of a disk), service (repeated: the services
 *       reported; none: all), enterprise (read only); then per target:
 *       target (host), port, version (2c|1), community
 *   SetSettings {the same, without enterprise} replaces all of them
 *
 * Status:
 *   GetStatus -> enabled, interval, last_report (unix time, 0: never),
 *       next_report (0: off), sent (notifications since start), status
 *       (ok|warning|critical|unknown: the worst item of the last report),
 *       problem? (repeated: what couldn't be collected); then per
 *       target: target (host:port), sent, error?
 *   SendReport -> sent (notifications) -- collects and sends now; an
 *       error if no target could be reached */

#pragma once

namespace snmpdd {

constexpr const char *Service = "snmpdd";

namespace method {
constexpr const char *GetSettings = "GetSettings";
constexpr const char *SetSettings = "SetSettings";
constexpr const char *GetStatus = "GetStatus";
constexpr const char *SendReport = "SendReport";
} // namespace method

} // namespace snmpdd
Loading