apinger: add rrd graph support
authorJaymin Patel <jem.patel@gmail.com>
Mon, 10 Apr 2023 18:26:43 +0000 (21:26 +0300)
committerHannu Nyman <hannu.nyman@iki.fi>
Mon, 10 Apr 2023 18:26:43 +0000 (21:26 +0300)
- add package apinger-rrd for RRD graphs
- add RPC to get an overview and update graphs
- fix interface hotplug to restart apinger instance
- add patch to split alarms list in the status

Signed-off-by: Jaymin Patel <jem.patel@gmail.com>
(cherry picked from commit 4281b7639c79ece68b50031f37ee8c693f32b4ef)

net/apinger/Makefile
net/apinger/files/apinger.init
net/apinger/files/apinger.rpc [new file with mode: 0644]
net/apinger/files/graphs.sh [new file with mode: 0644]
net/apinger/files/iface.hotplug
net/apinger/patches/060-format-alarm-list.patch [new file with mode: 0644]

index c0b232d15875155f9e5f45434e6003fe3c926bba..e449e8fe926d3b2171b9f4ebd7ae533164279390 100644 (file)
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=apinger
 PKG_SOURCE_DATE:=2015-04-09
 PKG_SOURCE_VERSION:=78eb328721ba1a10571c19df95acddcb5f0c17c8
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=3
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL:=https://github.com/Jajcus/apinger
@@ -65,7 +65,27 @@ define Package/apinger/install
        $(INSTALL_DATA) ./files/user.hotplug $(1)/etc/hotplug.d/apinger/01-user
        $(INSTALL_DIR) $(1)/etc/hotplug.d/iface
        $(INSTALL_DATA) ./files/iface.hotplug $(1)/etc/hotplug.d/iface/25-apinger
+       $(INSTALL_DIR) $(1)/usr/libexec/rpcd
+       $(INSTALL_BIN) ./files/apinger.rpc $(1)/usr/libexec/rpcd/apinger
+endef
+
+define Package/apinger-rrd
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+apinger +rrdtool1 +rrdcgi1
+  TITLE:=Apinger RRD Graphs
+  URL:=https://github.com/Jajcus/apinger
+endef
+
+define Package/apinger-rrd/description
+       Generate RRD Graphs from Apinger Data
+endef
+
+define Package/apinger-rrd/install
+       $(INSTALL_DIR) $(1)/usr/libexec/apinger/rpc
+       $(INSTALL_DATA) ./files/graphs.sh $(1)/usr/libexec/apinger/rpc
 endef
 
 $(eval $(call BuildPackage,apinger))
+$(eval $(call BuildPackage,apinger-rrd))
 
index 51999880cc7b06e661c5d00e9f3ea1673e4fce27..7a287c03b5d51b084524029b6eef447844bad990 100644 (file)
@@ -3,6 +3,8 @@
 
 START=80
 USE_PROCD=1
+BIN=/usr/sbin/apinger
+APINGER_RRD=/apinger/rrd
 
 . /lib/functions/network.sh
 
@@ -36,7 +38,7 @@ append_target() {
        local target=$1
        local interface address probe_interval srcip
        local avg_delay_samples avg_loss_samples avg_loss_delay_samples 
-       local alarm_down alarm_delay alarm_loss alarms
+       local alarm_down alarm_delay alarm_loss alarms rrd
 
        config_get interface              "$target" interface wan
        [ "$interface" != "$instance" ] && return 0
@@ -49,6 +51,7 @@ append_target() {
        config_get alarm_down             "$target" alarm_down
        config_get alarm_delay            "$target" alarm_delay
        config_get alarm_loss             "$target" alarm_loss
+       config_get_bool rrd               "$target" rrd 0
 
        [ -z "$address" ] && return 0
 
@@ -69,6 +72,7 @@ append_target() {
        [ -n "$avg_loss_samples" ]        && append_config_line "avg_loss_samples ${avg_loss_samples}"
        [ -n "$avg_loss_delay_samples" ]  && append_config_line "avg_loss_delay_samples ${avg_loss_delay_samples}"
        [ -n "$alarms" ]                  && append_config_line "alarms override ${alarms}"
+       [ "$rrd" = "1" ]                  && append_config_line "rrd file \"$APINGER_RRD/apinger-target-$target.rrd\""
 
        close_config_block
        write_config_block
@@ -125,13 +129,14 @@ append_alarm_loss() {
 }
 
 init_apinger_config() {
-       local debug status_interval instance
+       local debug status_interval rrd_interval instance
        instance=$1
 
        config_get_bool debug             apinger debug 0
        config_get      status_interval   apinger status_interval 1
+       config_get      rrd_interval      apinger rrd_interval 30
 
-       [ "$debug" == "1" ] && debug=on || debug=off
+       [ "$debug" = "1" ] && debug=on || debug=off
 
        set_config_file
        set_status_file
@@ -141,6 +146,8 @@ user "root"
 group "root"
 debug ${debug}
 
+rrd interval ${rrd_interval}s
+
 status {
        scriptformat on
        file "$STATUS_FILE"
@@ -185,9 +192,8 @@ start_instance() {
        config_foreach append_target target
 
        procd_open_instance "$instance"
-       procd_set_param command /usr/sbin/apinger -f -c $CONFIG_FILE
+       procd_set_param command $BIN -f -c $CONFIG_FILE
        procd_set_param stderr 1
-       procd_set_param stdout 1
        procd_close_instance
 }
 
@@ -196,6 +202,8 @@ start_service() {
 
        config_load apinger
 
+       [ ! -d "$APINGER_RRD" ] && mkdir -p "$APINGER_RRD"
+
        if [ -n "$instance" ]; then
                start_instance "$instance"
        else
diff --git a/net/apinger/files/apinger.rpc b/net/apinger/files/apinger.rpc
new file mode 100644 (file)
index 0000000..0be6e16
--- /dev/null
@@ -0,0 +1,117 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+RPC_SCRIPTS=/usr/libexec/apinger/rpc
+
+[ -d $RPC_SCRIPTS ] && include $RPC_SCRIPTS
+
+__function__() {
+    type "$1" > /dev/null 2>&1
+}
+
+foreach_extra() {
+       local file obj
+
+       [ ! -d $RPC_SCRIPTS ] && return
+       
+       for file in $RPC_SCRIPTS/*; do
+               obj="${file##*/}"
+               $1 "${obj%%.*}"
+       done
+}
+
+apinger_status() {
+       interface_list() {
+               append iface_list $1
+       }
+       config_load apinger
+       config_foreach interface_list interface
+
+       json_init
+       json_add_array targets
+
+       for iface in $iface_list; do
+               local status_file="/var/run/apinger-$iface.status"
+
+               if [ -f "$status_file" ]; then
+                       _IFS="$IFS"
+                       IFS="|"
+                       while read -r address srcip target received sent timestamp latency loss alarm; do
+                               json_add_object targets
+                               json_add_string interface "$iface"
+                               json_add_string target "$target"
+                               json_add_string address "$address"
+                               json_add_string srcip "$srcip"
+                               json_add_int sent "$sent"
+                               json_add_int received "$received"
+                               json_add_string latency "$latency"
+                               json_add_string loss "$loss"
+                               json_add_string alarm "$alarm"
+                               json_add_int timestamp "$timestamp"
+                               json_close_object
+                       done < "$status_file"
+                       IFS="$_IFS"
+               fi
+       done
+
+       json_close_array
+       json_dump
+}
+
+call_extra() {
+       if __function__ "$1"; then
+               $1
+       else
+               json_init
+               json_add_string error "invalid call $1"
+               json_dump
+       fi
+}
+
+call_method() {
+       case "$1" in
+               status)
+                       apinger_status
+                       ;;
+               *)
+                       call_extra $1
+                       ;;
+       esac
+}
+
+list_extra() {
+       if __function__ "${1}_help"; then
+               ${1}_help
+       else
+               json_add_object "$1"
+               json_close_object
+       fi
+}
+
+list_methods() {
+       local file
+
+       json_init
+
+       json_add_object status
+       json_close_object
+
+       foreach_extra list_extra ${1}
+
+       json_dump
+} 
+
+main () {
+       case "$1" in
+               list)
+                       list_methods
+                       ;;
+               call)
+                       call_method $2
+                       ;;
+       esac
+}
+
+main "$@"
diff --git a/net/apinger/files/graphs.sh b/net/apinger/files/graphs.sh
new file mode 100644 (file)
index 0000000..442dfbe
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+APINGER="/usr/sbin/apinger"
+RRDCGI="/www/cgi-bin/apinger"
+GRAPH_DIR="/apinger/graphs"
+WWW_LOCATION="/www${GRAPH_DIR}"
+
+update_interface_graphs() {
+       local iface cfg cmd
+
+       iface=$1
+       cfg=/var/run/apinger-$iface.conf
+
+       [ ! -f $cfg ] && return
+
+       cmd="$APINGER -c $cfg -g $WWW_LOCATION -l $GRAPH_DIR"
+
+       if [ -x $RRDCGI ]; then
+               $cmd 2>/dev/null | sed -e '/\(HTML\|TITLE\|H1\|H2\|by\|^#\)/d' >> $RRDCGI
+       else
+               $cmd 2>/dev/null | sed -e '/\(HTML\|TITLE\|H1\|H2\|by\)/d' > $RRDCGI
+               chmod 755 $RRDCGI
+       fi
+}
+
+update_graphs() {
+       [ ! -d $WWW_LOCATION ] && mkdir -p $WWW_LOCATION
+       [ -e $RRDCGI ] && rm -f $RRDCGI
+
+       config_load apinger
+       config_foreach update_interface_graphs interface
+
+       json_init
+       json_add_string rrdcgi "$RRDCGI"
+       json_dump
+}
+
+graphs_help() {
+       json_add_object update_graphs
+       json_close_object
+}
index 6c1930f935600b630db52485770b76e45565b791..f97de0ae9033c5c01b5bf4b0d3ace9d36226e7a2 100644 (file)
@@ -6,7 +6,7 @@
        [ "$(uci_get apinger $INTERFACE)" == "interface" ] || exit 0
 
        [ "$ACTION" = "ifup" ] && {
-               /etc/init.d/apinger $INTERFACE restart
+               /etc/init.d/apinger restart $INTERFACE
        }
 
 }
diff --git a/net/apinger/patches/060-format-alarm-list.patch b/net/apinger/patches/060-format-alarm-list.patch
new file mode 100644 (file)
index 0000000..815202f
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/src/apinger.c
++++ b/src/apinger.c
+@@ -860,6 +860,9 @@ char *buf1,*buf2;
+                               a=al->alarm;
+                               if(config->status_format){
+                                       fprintf(f,"%s",a->name);
++                                      if(al->next){
++                                              fprintf(f,",");
++                                      }
+                               }
+                               else{
+                                       fprintf(f," \"%s\"",a->name);