Merge pull request #2941 from hojuruku/p_mini_snmpd
mini_snmpd: new upstream/package maintainer, new version, init procd multi instance support with uci validation & network interface monitoring.
This commit is contained in:
commit
9f9e9aa891
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# Copyright (C) 2009-2016 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mini_snmpd
|
||||
PKG_VERSION:=1.4-rc1
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Luke McKee <hojuruku@gmail.com>
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
PKG_LICENSE_FILES:=COPYING
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/troglobit/mini-snmpd.git
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=203d92e60ed09466d6676c6ad20ad6cb2ce08a5d
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
|
||||
PKG_FIXUP:=autoreconf
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_INSTALL:=1
|
||||
# As warned by upstream maintainer and binutils
|
||||
# however compiler warnings can be ignored until next binutils release
|
||||
# https://github.com/wongsyrone/openwrt-1/issues/67
|
||||
# PKG_SSP:=0
|
||||
# PKG_RELRO:=0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/mini_snmpd
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=A tiny SNMP server for embedded systems
|
||||
URL:=http://troglobit.github.io/mini-snmpd.html
|
||||
# uncomment if you just want the binary, not the init script
|
||||
# openwrt requires init script runtime dependencies be defined for make menuconfig
|
||||
# (e.g busybox sysntpd)
|
||||
DEPENDS:=+jsonfilter +ubus +procd +ubox
|
||||
endef
|
||||
|
||||
CONFIGURE_ARGS+= \
|
||||
$(if $(CONFIG_IPV6),,--disable-ipv6)
|
||||
|
||||
# Configure weirdness - Disabled by default, explicitately disabling turns feature on!
|
||||
# --disable-debug \
|
||||
# --disable-demo - Upstream Github Issue #4 Fixed 20160707
|
||||
|
||||
define Package/mini_snmpd/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/bin/mini_snmpd $(1)/usr/bin/
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/mini_snmpd.config $(1)/etc/config/mini_snmpd
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/mini_snmpd.init $(1)/etc/init.d/mini_snmpd
|
||||
endef
|
||||
|
||||
define Package/mini_snmpd/conffiles
|
||||
/etc/config/mini_snmpd
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,mini_snmpd))
|
|
@ -0,0 +1,26 @@
|
|||
# you may add more than the 'default' mini_snmpd instances provided they all bind to different ports/interfaces
|
||||
# to get around max 4 interface or mountpoint limit constrained by mini_snmpd's mib
|
||||
config mini_snmpd 'default'
|
||||
option enabled 1
|
||||
option ipv6 0
|
||||
# Verbose flag given to mini_snmpd, extra verbose is only possible with compile time config flags
|
||||
option debug 0
|
||||
# Turn on community authentication (snmp agent must use community name)
|
||||
option auth 0
|
||||
option community 'public'
|
||||
option contact 'OpenWRT router <openwrt@openwrt.org>'
|
||||
option location 'Undisclosed'
|
||||
# to listen on all interfaces you need to set option listen_interface ''
|
||||
option listen_interface 'lan'
|
||||
#option udp_port '161'
|
||||
#option tcp_port '161'
|
||||
#option vendor_oid ''
|
||||
option mib_timeout 1
|
||||
# enable basic disk usage statistics on specified mountpoint
|
||||
list disks '/overlay'
|
||||
list disks '/tmp'
|
||||
# enable basic network statistics on specified interface
|
||||
# 4 interfaces maximum per instance, as named in /etc/config/network and luci
|
||||
# not physical device names
|
||||
list interfaces 'lan'
|
||||
list interfaces 'wan'
|
|
@ -0,0 +1,240 @@
|
|||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2009-2016 OpenWrt.org
|
||||
# Copyright (C) 2016 Luke McKee <hojuruku@gmail.com>
|
||||
# Procd init script reference: http://wiki.prplfoundation.org/wiki/Procd_reference
|
||||
|
||||
START=98
|
||||
USE_PROCD=1
|
||||
PROG=/usr/bin/mini_snmpd
|
||||
NAME=mini_snmpd
|
||||
|
||||
_log() {
|
||||
logger -p daemon.info -t mini_snmpd "$@"
|
||||
}
|
||||
|
||||
_err() {
|
||||
logger -p daemon.err -t mini_snmpd "$@"
|
||||
}
|
||||
|
||||
|
||||
# mini_snmpd 1.3+ now starts later in the game. Expects filesystems monitored to be already mounted, or wont pass args to mini_snmpd
|
||||
# and at least configuration entry for network physical interface defined in /etc/config/network
|
||||
# It handles network interfaces not yet present (e.g. ppp) but will statfs() the root/wrong filesystem if device not mounted
|
||||
# Tip: complex scripts run faster without in openwrt if you stop busybox forking and searching for applets. Faster bootups
|
||||
# CONFIG_BUSYBOX_CONFIG_FEATURE_SH_NOFORK
|
||||
# CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS
|
||||
# BUSYBOX_CONFIG_ASH_OPTIMIZE_FOR_SIZE [=n]
|
||||
# CONFIG_BUSYBOX_CONFIG_ASH_CMDCMD
|
||||
|
||||
mini_snmpd_validation="enabled:bool:0 \
|
||||
ipv6:bool:0 \
|
||||
debug:bool:0 \
|
||||
auth:bool:1 \
|
||||
community:rangelength(1,32):public \
|
||||
contact:maxlength(255) \
|
||||
location:maxlength(255) \
|
||||
listen_interface:uciname \
|
||||
udp_port:port \
|
||||
tcp_port:port \
|
||||
vendor_oid:string \
|
||||
mib_timeout:and(min(1),uinteger) \
|
||||
disks:list(directory) \
|
||||
interfaces:list(uciname) \
|
||||
respawn_threshold:uinteger respawn_timeout:uinteger respawn_retry:uinteger"
|
||||
# busybox ash has no array variable support, when put validations in a string be careful to have no spaces in each validate constraint
|
||||
# this makes it very difficult to use the 'or(uciname, "all")' test, so listen_interface '' or undefined now meands bind to "all".
|
||||
# this is the sarafice you have to make to avoid typing it all in twice in this script so we can give feedback to user on what's misconfigered
|
||||
# in syslog
|
||||
|
||||
append_disk() {
|
||||
local disk="$1" disk_count
|
||||
[ -z $disk_count ] && disk_count=0
|
||||
if grep -qF "$disk" /proc/mounts ; then
|
||||
# check the fileystem is mountpoint, and directory search permissions available for statfs()
|
||||
# presence as a directory -d test done is already done by uci_validate_section()
|
||||
[ -x "$disk" ] || {
|
||||
_err "$cfg: mountpoint $disk for snmp monitoring EACCES error. Check permissions, ignoring"
|
||||
return 1
|
||||
}
|
||||
if [ $disk_count -lt 4 ] ; then
|
||||
append disks_arg "$disk" ','
|
||||
disk_count=$((disk_count++))
|
||||
else
|
||||
_err "$cfg: more than 4 mountpoints defined in uci. Disc $disk ignored."
|
||||
fi
|
||||
else
|
||||
_err "$cfg: mountpoint $disk for snmp monitoring not mounted, ignoring."
|
||||
fi
|
||||
}
|
||||
|
||||
append_interface() {
|
||||
local name="$1" netdev netdev_count
|
||||
[ -z $netdev_count ] && netdev_count=0
|
||||
# for the purposes of snmp monitoring it doesn't need to be up, it just needs to exist in /proc/net/dev
|
||||
netdev=$(ubus -S call network.interface dump|jsonfilter -e "@.interface[@.interface=\"$name\"].device")
|
||||
if [ -n "$netdev" ] && grep -qF "$netdev" /proc/net/dev ]; then
|
||||
[ $netdev_count -ge 4 ] && {
|
||||
_err "$cfg: too many network interfaces configured, ignoring $name"
|
||||
return
|
||||
}
|
||||
netdev_count=$((netdev_count++))
|
||||
if [ -n "$interfaces_arg" ]; then
|
||||
append interfaces_arg "$netdev" ','
|
||||
else
|
||||
append interfaces_arg "$netdev"
|
||||
fi
|
||||
else
|
||||
_err "$cfg: physical interface for network $name not found in uci or kernel so not monitoring"
|
||||
fi
|
||||
}
|
||||
|
||||
append_arg() {
|
||||
local var="$2"
|
||||
local opt="$1"
|
||||
[ -n "$var" ] && procd_append_param command $opt "$var"
|
||||
}
|
||||
|
||||
watch_interfaces() {
|
||||
local cfg="$1"
|
||||
local enabled listen_interface # listen_interface_up
|
||||
config_get_bool enabled "$cfg" "enabled" '1'
|
||||
[ "$enabled" -gt 0 ] || return 0
|
||||
config_get listen_interface "$cfg" listen_interface
|
||||
# listen_interface_up=$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.interface=\"$listen_interface\"].up")
|
||||
# If the interface is up & instance is running we'll watch at the instance level and only restart that instance if it's bound interface changes
|
||||
# Regardless of ubus knowing about an interface (in the case it's not yet configured)
|
||||
[ -n "$listen_interface" ] && trigger_interfaces="${listen_interface} ${trigger_interfaces} "
|
||||
}
|
||||
|
||||
validate_mini_snmpd_section() {
|
||||
# validate a mini_snmpd instance in uci config file mini_snmpd
|
||||
# http://luci.subsignal.org/trac/wiki/Documentation/Datatypes ubox/validate/validate.c
|
||||
uci_validate_section mini_snmpd mini_snmpd "${1}" $mini_snmpd_validation
|
||||
}
|
||||
|
||||
|
||||
service_triggers() {
|
||||
config_load 'mini_snmpd'
|
||||
procd_open_trigger
|
||||
procd_add_config_trigger "config.change" "mini_snmpd" /etc/init.d/mini_snmpd reload
|
||||
config_foreach watch_interfaces 'mini_snmpd'
|
||||
# this only watches interfaces for which there is no running instance due to interface down / not in ubus
|
||||
# hence start not reload, this trigger will not affect running instances as another start will not change their procd command arguments
|
||||
# or stop the already running process
|
||||
[ -n "$trigger_interfaces" ] & {
|
||||
for n in $trigger_interfaces ; do
|
||||
procd_add_interface_trigger "interface.*" $n /etc/init.d/mini_snmpd start
|
||||
done
|
||||
}
|
||||
procd_close_trigger
|
||||
procd_add_validation validate_mini_snmpd_section
|
||||
}
|
||||
|
||||
|
||||
start_instance() {
|
||||
local cfg validation_failed validation_err disks_arg interfaces_arg
|
||||
cfg="$1"
|
||||
#uci_validate_section should unset undefined variables from other instances
|
||||
#however defining uci variables as local will scope them to this instance
|
||||
#"local variables are also visible to functions called by the parent function" so it's good practice
|
||||
local enabled ipv6 debug auth community contact location listen_interface \
|
||||
udp_port tcp_port vendor_oid mib_timeout
|
||||
local disks="" interfaces=""
|
||||
validate_mini_snmpd_section "$cfg" 2>/dev/null || validation_failed=1
|
||||
[ "$enabled" == 1 ] || {
|
||||
_log "instance:$cfg disabled not starting"
|
||||
return 1
|
||||
}
|
||||
|
||||
local listen_interface_json listen_interface_ip listen_interface_device listen_interface_up ubus_exit ubus_err
|
||||
[ -n "$listen_interface" ] && {
|
||||
listen_interface_json=$(ubus -S call network.interface.$listen_interface status)
|
||||
ubus_exit=$?
|
||||
[ $ubus_exit = 4 ] && {
|
||||
_err "$cfg: listen_interface $listen_interface not properly configured in ubus network.interface.* not starting this instance "
|
||||
return 1
|
||||
}
|
||||
[ $ubus_exit = 255 -a -z "$listen_interface_json" ] && {
|
||||
_log "$cfg: ubusd not yet up, will try to start mini_snmpd shorlty when procd detects $listen_interface comes up"
|
||||
return 1
|
||||
}
|
||||
[ -z "$listen_interface_json" ] && {
|
||||
ubus_err=`ubus call network.interface.$listen_interface status 2>&1 >/dev/null`
|
||||
_err "$cfg: unknown ubus error. exit: $ubus_exit errormsg: $ubus_err "
|
||||
return 1
|
||||
}
|
||||
listen_interface_up=$(jsonfilter -s "$listen_interface_json" -e '@.up')
|
||||
if [ "$ipv6" = 1 ]; then
|
||||
listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv6-address'][0].address")
|
||||
else
|
||||
listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv4-address'][0].address")
|
||||
fi
|
||||
[ -n "$listen_interface_ip" -a "$listen_interface_up" = 'true' ] || {
|
||||
_log "$cfg:listen interface $listen_interface not up yet / not configured properly"
|
||||
_log "$cfg:procd will try again when interface state changes"
|
||||
return 1
|
||||
}
|
||||
listen_interface_device=$(jsonfilter -s "$listen_interface_json" -e '@.l3_device')
|
||||
}
|
||||
|
||||
[ $validation_failed ] && {
|
||||
_err "validation of $NAME configuration for $cfg instance failed, all tests should be within constraints"
|
||||
_err "please edit the configuration values below using [l]uci "
|
||||
validation_err=`/sbin/validate_data mini_snmpd mini_snmpd "$cfg" $mini_snmpd_validation 2>&1 | sed '/with\ false$/!d;s/validates\ as\ /needs\ to\ be\ /;s/with\ false//' `
|
||||
_err "${validation_err}"
|
||||
return 1
|
||||
}
|
||||
config_list_foreach "$cfg" 'disks' append_disk
|
||||
config_list_foreach "$cfg" 'interfaces' append_interface
|
||||
# test if variables are unset or zero length
|
||||
[ -z "${disks_arg:+1}" -a -z "${interfaces_arg:+1}" ] && {
|
||||
_err "$cfg: you haven't sucessfully configured any mountpoints or disks for this instance, not starting"
|
||||
return 1
|
||||
}
|
||||
|
||||
procd_open_instance
|
||||
|
||||
procd_set_param command "$PROG" -n
|
||||
procd_set_param stdout "1"
|
||||
procd_set_param stderr "1"
|
||||
# don't the like default respawn values? you can override through uci.
|
||||
# vars left as global so you only need to do it in the first mini_snmpd instance
|
||||
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-10} ${respawn_retry:-1}
|
||||
# this monitors ubus changes
|
||||
[ -n "$listen_interface" ] && {
|
||||
#procd_open_trigger
|
||||
#procd_add_interface_trigger "interface.*" $listen_interface /etc/init.d/mini_snmpd reload
|
||||
#procd_close_trigger
|
||||
procd_add_reload_interface_trigger $listen_interface #or use shorthand of above
|
||||
}
|
||||
# this re-starts the daemon if a properly configured network interface is changed whilst it is already running
|
||||
# igmpproxy has this as well as "procd_set_param netdev"
|
||||
|
||||
append_arg "-c" "$community"
|
||||
append_arg "-L" "${location}"
|
||||
append_arg "-C" "${contact}"
|
||||
append_arg "-p" $udp_port
|
||||
append_arg "-P" $tcp_port
|
||||
append_arg "-V" "${vendor_oid}"
|
||||
append_arg "-t" $mib_timeout
|
||||
|
||||
[ "$ipv6" = 1 ] && procd_append_param command "-6"
|
||||
[ "$debug" = 1 ] && procd_append_param command "-v"
|
||||
# uci_validate_section() aka /sbin/validate_data can only cast default values not defined in /etc/config/* to string
|
||||
# e.g. ="1" however it sets bools defined in /etc/config/* to =1 / =0
|
||||
[ "$auth" = 1 -o "$auth" = "1" ] && procd_append_param command "-a"
|
||||
[ -n "$disks_arg" ] && procd_append_param command "-d $disks_arg"
|
||||
[ -n "$interfaces_arg" ] && procd_append_param command "-i $interfaces_arg"
|
||||
[ -n "$listen_interface_device" ] && {
|
||||
procd_append_param command "-I" "$listen_interface_device"
|
||||
# and this monitors the hardware device for changes outside of ubus - just a guess
|
||||
procd_set_param netdev $listen_interface_device
|
||||
}
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load 'mini_snmpd'
|
||||
config_foreach start_instance 'mini_snmpd'
|
||||
}
|
||||
|
Loading…
Reference in New Issue