[1/2] nodewatcher: split up

Submitted by Tim Niemeyer on Sept. 8, 2019, 3:18 p.m.

Details

Message ID 20190908151852.25677-1-tim@tn-x.org
State Superseded
Headers show

Commit Message

Tim Niemeyer Sept. 8, 2019, 3:18 p.m.
Signed-off-by: Tim Niemeyer <tim@tn-x.org>
---

 .../usr/lib/nodewatcher.d/30-batman-adv.sh    |  63 ++++
 .../usr/lib/nodewatcher.d/30-batman-adv.sh    |  60 ++++
 .../usr/lib/nodewatcher.d/20-interfaces.sh    |  74 +++++
 .../files/usr/lib/nodewatcher.d/50-clients.sh |  25 ++
 src/packages/fff/fff-nodewatcher/Makefile     |   2 +-
 .../files/etc/uci-defaults/93-fff-nodewatcher |   4 -
 .../usr/lib/nodewatcher.d/10-systemdata.sh    | 119 ++++++++
 .../files/usr/sbin/nodewatcher                | 281 ++----------------
 .../files/usr/lib/nodewatcher.d/60-airtime.sh |  27 ++
 9 files changed, 395 insertions(+), 260 deletions(-)
 create mode 100755 src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh
 create mode 100755 src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
 create mode 100755 src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
 create mode 100755 src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
 create mode 100755 src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
 create mode 100755 src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh

Patch hide | download patch | download mbox

diff --git a/src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh b/src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh
new file mode 100755
index 0000000..c7fad80
--- /dev/null
+++ b/src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh
@@ -0,0 +1,63 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+debug() {
+    (>&2 echo "$1")
+}
+
+debug "$(date): Collecting information from batman advanced and its interfaces"
+#B.A.T.M.A.N. advanced
+if [ -f /sys/module/batman_adv/version ]; then
+    for iface in $(grep active /sys/class/net/*/batman_adv/iface_status); do
+        status=${iface#*:}
+        iface=${iface%/batman_adv/iface_status:active}
+        iface=${iface#/sys/class/net/}
+        BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
+    done
+
+    # Build a list of direct neighbors
+    batman_adv_originators=$(awk \
+        'BEGIN { FS=" "; i=0 } # set the delimiter to " "
+        /O/ { next } # ignore lines with O (will remove second line)
+        /B/ { next } # ignore line with B (will remove first line)
+        {   sub("\\(", "", $0) # remove parentheses
+            sub("\\)", "", $0)
+            sub("\\[", "", $0)
+            sub("\\]:", "", $0)
+            sub("  ", " ", $0)
+            o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
+            if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
+            {
+                printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
+                i++
+            }
+        }' /sys/kernel/debug/batman_adv/bat0/originators)
+
+    batman_adv_gateway_mode=$(batctl gw)
+
+    batman_adv_gateway_list=$(awk \
+        'BEGIN { FS=" "; i=0 }
+        /B.A.T.M.A.N./ { next }
+        /Gateway/ { next }
+        /No gateways/ { next }
+        {   sub("\\(", "", $0)
+            sub("\\)", "", $0)
+            sub("\\[ *", "", $0)
+            sub("\\]:", "", $0)
+            sub("=> ", "true ", $0)
+            sub("   ", "false ", $0)
+            printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
+            i++
+        }' /sys/kernel/debug/batman_adv/bat0/gateways)
+else
+    debug "$(date): No batman data .."
+    exit 1
+fi
+
+echo "<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
+echo "<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
+echo "<batman_adv_gateway_mode>$batman_adv_gateway_mode</batman_adv_gateway_mode>"
+echo "<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
+
+exit 0
diff --git a/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
new file mode 100755
index 0000000..b930130
--- /dev/null
+++ b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
@@ -0,0 +1,60 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+debug() {
+    (>&2 echo "$1")
+}
+
+debug "$(date): Collecting information from batman advanced and its interfaces"
+#B.A.T.M.A.N. advanced
+if [ -f /sys/module/batman_adv/version ]; then
+    for iface in $(grep active /sys/class/net/*/batman_adv/iface_status); do
+        status=${iface#*:}
+        iface=${iface%/batman_adv/iface_status:active}
+        iface=${iface#/sys/class/net/}
+        BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
+    done
+
+    # Build a list of direct neighbors
+    batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
+        'BEGIN { FS=" "; i=0 } # set the delimiter to " "
+        {   sub("\\(", "", $0) # remove parentheses
+            sub("\\)", "", $0)
+            sub("\\[", "", $0)
+            sub("\\]", "", $0)
+            sub("\\*", "", $0)
+            sub("  ", " ", $0)
+            o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
+            if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
+            {
+                printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
+                i++
+            }
+        }')
+
+    batman_adv_gateway_mode=$(/usr/sbin/batctl gw)
+
+    batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
+        'BEGIN { FS=" "; i=0 }
+        /No gateways/ { next }
+        {   sub("\\(", "", $0)
+            sub("\\)", "", $0)
+            sub("\\[ *", "", $0)
+            sub("\\]:", "", $0)
+            sub("\\* ", "true ", $0)
+            sub("  ", "false ", $0)
+            printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
+            i++
+        }')
+else
+    debug "$(date): No batman data .."
+    exit 1
+fi
+
+echo "<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
+echo "<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
+echo "<batman_adv_gateway_mode>$batman_adv_gateway_mode</batman_adv_gateway_mode>"
+echo "<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
+
+exit 0
diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
new file mode 100755
index 0000000..d999c9f
--- /dev/null
+++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
@@ -0,0 +1,74 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+IFACEBLACKLIST="lo ifb0"
+IPWHITELIST="br-mesh"
+
+debug() {
+    (>&2 echo "$1")
+}
+
+inArray() {
+    local value
+    for value in $1; do
+        if [ "$value" = "$2" ]; then
+            return 0
+        fi
+    done
+    return 1
+}
+
+debug "$(date): Collecting information from network interfaces"
+
+#Get interfaces
+interface_data=""
+#Loop interfaces
+#for entry in $IFACES; do
+for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
+    ifpath=${filename%/operstate*}
+    iface=${ifpath#/sys/class/net/}
+    if inArray "$IFACEBLACKLIST" "$iface"; then
+        continue
+    fi
+
+    #Get interface data for whitelisted interfaces
+    # shellcheck disable=SC2016
+    awkscript='
+        /ether/ { printf "<mac_addr>"$2"</mac_addr>" }
+        /mtu/ { printf "<mtu>"$5"</mtu>" }'
+    if inArray "$IPWHITELIST" "$iface"; then
+        # shellcheck disable=SC2016
+        awkscript=$awkscript'
+            /inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
+            /inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
+            /inet6/ && /scope link/ { printf "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
+    fi
+    addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
+
+    traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
+    traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
+
+    interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
+
+    interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
+        /Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
+        /Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
+        /ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
+        /Freq/{ split($3, f, " "); printf "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
+        /Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
+    ')
+
+    interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
+        /ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
+        /type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
+        /channel/{ split($0, c, " "); printf "<wlan_channel>"c[2]"</wlan_channel>" }
+        /width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf "<wlan_width>"w[2]"</wlan_width>" }
+    ')
+
+    interface_data=$interface_data"</$iface>"
+done
+
+echo "<interface_data>$interface_data</interface_data>"
+
+exit 0
diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
new file mode 100755
index 0000000..426dd57
--- /dev/null
+++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
@@ -0,0 +1,25 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+MESH_INTERFACE=br-mesh
+
+debug() {
+    (>&2 echo "$1")
+}
+
+debug "$(date): Collecting information about conected clients"
+#CLIENTS
+client_count=0
+dataclient=""
+CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
+for clientif in ${CLIENT_INTERFACES}; do
+    local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
+    client_count=$((client_count + cc))
+    dataclient="$dataclient<$clientif>$cc</$clientif>"
+done
+
+echo "<client_count>$client_count</client_count>"
+echo "<clients>$dataclient</clients>"
+
+exit 0
diff --git a/src/packages/fff/fff-nodewatcher/Makefile b/src/packages/fff/fff-nodewatcher/Makefile
index a5551e0..4e670d7 100644
--- a/src/packages/fff/fff-nodewatcher/Makefile
+++ b/src/packages/fff/fff-nodewatcher/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fff-nodewatcher
-PKG_RELEASE:=53
+PKG_VERSION:=54
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
 
diff --git a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
index 4e56435..0fc2e90 100644
--- a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
+++ b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
@@ -8,10 +8,6 @@  uci batch <<EOF
   set nodewatcher.@script[0].logfile='/var/log/nodewatcher.log'
   set nodewatcher.@script[0].data_file='/tmp/crawldata/node.data'
   set nodewatcher.@script[0].status_text_file='/tmp/status.txt'
-  add nodewatcher network
-  set nodewatcher.@network[0].mesh_interface='br-mesh'
-  set nodewatcher.@network[0].iface_blacklist='lo ifb0'
-  set nodewatcher.@network[0].ip_whitelist='br-mesh'
 EOF
 uci commit
 
diff --git a/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
new file mode 100755
index 0000000..f404286
--- /dev/null
+++ b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
@@ -0,0 +1,119 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+SCRIPT_STATUS_FILE=$(uci -q get nodewatcher.@script[0].status_text_file)
+SCRIPT_VERSION="54"
+
+debug() {
+    (>&2 echo "$1")
+}
+
+#Get system data from other locations
+debug "$(date): Collecting basic system status data"
+hostname="$(cat /proc/sys/kernel/hostname)"
+mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
+[ "$hostname" = "OpenWrt" ] && hostname="$mac"
+[ "$hostname" = "FFF" ] && hostname="$mac"
+description="$(uci -q get fff.system.description)"
+if [ -n "$description" ]; then
+    description="<description><![CDATA[$description]]></description>"
+fi
+latitude="$(uci -q get fff.system.latitude)"
+longitude="$(uci -q get fff.system.longitude)"
+if [ -n "$longitude" -a -n "$latitude" ]; then
+    geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
+fi
+position_comment="$(uci -q get fff.system.position_comment)"
+if [ -n "$position_comment" ]; then
+    position_comment="<position_comment><![CDATA[$position_comment]]></position_comment>"
+fi
+contact="$(uci -q get fff.system.contact)"
+if [ -n "$contact" ]; then
+    contact="<contact>$contact</contact>"
+fi
+uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>" }' /proc/uptime)
+
+memory=$(awk '
+    /^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
+    /^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
+    /^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
+    /^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
+' /proc/meminfo)
+cpu=$(awk -F': ' '
+    /model/ { printf "<cpu>"$2"</cpu>" }
+    /system type/ { printf "<chipset>"$2"</chipset>" }
+    /platform/ { printf "<chipset>"$2"</chipset>" }
+' /proc/cpuinfo)
+model="<model>$(cat /var/sysinfo/model)</model>"
+local_time="$(date +%s)"
+load=$(awk '{ printf "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
+
+debug "$(date): Collecting version information"
+
+batman_adv_version=$(cat /sys/module/batman_adv/version)
+kernel_version=$(uname -r)
+if [ -x /usr/bin/fastd ]; then
+    fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2 }')</fastd_version>"
+fi
+nodewatcher_version=$SCRIPT_VERSION
+
+if [ -f "$SCRIPT_STATUS_FILE" ]; then
+    status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
+fi
+
+# Checks if fastd is running
+if pidof fastd >/dev/null ; then
+    vpn_active="<vpn_active>1</vpn_active>"
+else
+    vpn_active="<vpn_active>0</vpn_active>"
+fi
+
+# example for /etc/openwrt_release:
+#DISTRIB_ID="OpenWrt"
+#DISTRIB_RELEASE="Attitude Adjustment"
+#DISTRIB_REVISION="r35298"
+#DISTRIB_CODENAME="attitude_adjustment"
+#DISTRIB_TARGET="atheros/generic"
+#DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
+. /etc/openwrt_release
+distname=$DISTRIB_ID
+distversion=$DISTRIB_RELEASE
+
+# example for /etc/firmware_release:
+#FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
+#BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
+#OPENWRT_CORE_REVISION="35298"
+#OPENWRT_FEEDS_PACKAGES_REVISION="35298"
+. /etc/firmware_release
+
+SYSTEM_DATA="<status>online</status>"
+SYSTEM_DATA=$SYSTEM_DATA"$status_text"
+SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
+SYSTEM_DATA=$SYSTEM_DATA"${description}"
+SYSTEM_DATA=$SYSTEM_DATA"${geo}"
+SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
+SYSTEM_DATA=$SYSTEM_DATA"${contact}"
+SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get "system.@system[0].hood")</hood>"
+SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get "system.@system[0].hoodid")</hoodid>"
+SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
+SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
+SYSTEM_DATA=$SYSTEM_DATA"$cpu"
+SYSTEM_DATA=$SYSTEM_DATA"$model"
+SYSTEM_DATA=$SYSTEM_DATA"$memory"
+SYSTEM_DATA=$SYSTEM_DATA"$load"
+SYSTEM_DATA=$SYSTEM_DATA"$uptime"
+SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
+SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_version</batman_advanced_version>"
+SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_version>"
+SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
+SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version</nodewatcher_version>"
+SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</firmware_version>"
+SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_revision>"
+SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_REVISION</openwrt_core_revision>"
+SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWRT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
+SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
+
+echo "<system_data>$SYSTEM_DATA</system_data>"
+
+exit 0
diff --git a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
index 90509ba..2137898 100755
--- a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
+++ b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
@@ -12,28 +12,18 @@  if ! lock -n "$lockfile"; then
 fi
 trap "lock -u \"$lockfile\"" INT TERM EXIT
 
-SCRIPT_VERSION="53"
-
 #Get the configuration from the uci configuration file
 #If it does not exists, then get it from a normal bash file with variables.
-if [ -f /etc/config/nodewatcher ];then
-    SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
-    SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
-    SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
-    MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
-    IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
-    IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
-    SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
-else
-    . "$(dirname "$0")/nodewatcher_config"
-fi
+SCRIPT_ERROR_LEVEL=$(uci -q get nodewatcher.@script[0].error_level)
+SCRIPT_LOGFILE=$(uci -q get nodewatcher.@script[0].logfile)
+SCRIPT_DATA_FILE=$(uci -q get nodewatcher.@script[0].data_file)
 
 if [ "$SCRIPT_ERROR_LEVEL" -gt "1" ]; then
-    err() {
+    debug() {
         echo "$1" >> "$SCRIPT_LOGFILE"
     }
 else
-    err() {
+    debug() {
         :
     }
 fi
@@ -43,258 +33,39 @@  delete_log() {
     if [ -f "$SCRIPT_LOGFILE" ]; then
         if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
             sed -i '1,60d' "$SCRIPT_LOGFILE"
-            err "$(date): Logfile has been made smaller"
+            debug "$(date): Logfile has been made smaller"
         fi
     fi
 }
 
-inArray() {
-    local value
-    for value in $1; do
-        if [ "$value" = "$2" ]; then
-            return 0
-        fi
-    done
-    return 1
+run_with_timeout () { 
+    time=2
+
+    # Run in a subshell to avoid job control messages
+    (
+        "$@" &
+        child=$!
+        # Avoid default notification in non-interactive shell for SIGTERM
+        trap -- "" TERM
+        ( sleep $time; kill $child 2> /dev/null ) &
+        wait $child
+    )
 }
 
 #This method generates the crawl data XML file that is being fetched by netmon
 #and provided by a small local httpd
 crawl() {
-    #Get system data from other locations
-    err "$(date): Collecting basic system status data"
-    hostname="$(cat /proc/sys/kernel/hostname)"
-    mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
-    [ "$hostname" = "OpenWrt" ] && hostname="$mac"
-    [ "$hostname" = "FFF" ] && hostname="$mac"
-    description="$(uci -q get fff.system.description)"
-    if [ -n "$description" ]; then
-        description="<description><![CDATA[$description]]></description>"
-    fi
-    latitude="$(uci -q get fff.system.latitude)"
-    longitude="$(uci -q get fff.system.longitude)"
-    if [ -n "$longitude" -a -n "$latitude" ]; then
-        geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
-    fi
-    position_comment="$(uci -q get fff.system.position_comment)"
-    if [ -n "$position_comment" ]; then
-        position_comment="<position_comment><![CDATA[$position_comment]]></position_comment>"
-    fi
-    contact="$(uci -q get fff.system.contact)"
-    if [ -n "$contact" ]; then
-        contact="<contact>$contact</contact>"
-    fi
-    uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>" }' /proc/uptime)
-
-    memory=$(awk '
-        /^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
-        /^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
-        /^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
-        /^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
-    ' /proc/meminfo)
-    cpu=$(awk -F': ' '
-        /model/ { printf "<cpu>"$2"</cpu>" }
-        /system type/ { printf "<chipset>"$2"</chipset>" }
-        /platform/ { printf "<chipset>"$2"</chipset>" }
-    ' /proc/cpuinfo)
-    model="<model>$(cat /var/sysinfo/model)</model>"
-    local_time="$(date +%s)"
-    load=$(awk '{ printf "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
-
-    err "$(date): Collecting version information"
-
-    batman_adv_version=$(cat /sys/module/batman_adv/version)
-    kernel_version=$(uname -r)
-    if [ -x /usr/bin/fastd ]; then
-        fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2 }')</fastd_version>"
-    fi
-    nodewatcher_version=$SCRIPT_VERSION
-
-    if [ -f "$SCRIPT_STATUS_FILE" ]; then
-        status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
-    fi
-
-    # Checks if fastd is running
-    if pidof fastd >/dev/null ; then
-        vpn_active="<vpn_active>1</vpn_active>"
-    else
-        vpn_active="<vpn_active>0</vpn_active>"
-    fi
-
-    # example for /etc/openwrt_release:
-    #DISTRIB_ID="OpenWrt"
-    #DISTRIB_RELEASE="Attitude Adjustment"
-    #DISTRIB_REVISION="r35298"
-    #DISTRIB_CODENAME="attitude_adjustment"
-    #DISTRIB_TARGET="atheros/generic"
-    #DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
-    . /etc/openwrt_release
-    distname=$DISTRIB_ID
-    distversion=$DISTRIB_RELEASE
-
-    # example for /etc/firmware_release:
-    #FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
-    #BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
-    #OPENWRT_CORE_REVISION="35298"
-    #OPENWRT_FEEDS_PACKAGES_REVISION="35298"
-    . /etc/firmware_release
-
-    SYSTEM_DATA="<status>online</status>"
-    SYSTEM_DATA=$SYSTEM_DATA"$status_text"
-    SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
-    SYSTEM_DATA=$SYSTEM_DATA"${description}"
-    SYSTEM_DATA=$SYSTEM_DATA"${geo}"
-    SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
-    SYSTEM_DATA=$SYSTEM_DATA"${contact}"
-    SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get "system.@system[0].hood")</hood>"
-    SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get "system.@system[0].hoodid")</hoodid>"
-    SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
-    SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
-    SYSTEM_DATA=$SYSTEM_DATA"$cpu"
-    SYSTEM_DATA=$SYSTEM_DATA"$model"
-    SYSTEM_DATA=$SYSTEM_DATA"$memory"
-    SYSTEM_DATA=$SYSTEM_DATA"$load"
-    SYSTEM_DATA=$SYSTEM_DATA"$uptime"
-    SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
-    SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_version</batman_advanced_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
-    SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version</nodewatcher_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</firmware_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_revision>"
-    SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_REVISION</openwrt_core_revision>"
-    SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWRT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
-    SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
+    debug "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
 
-    err "$(date): Collecting information from network interfaces"
-
-    #Get interfaces
-    interface_data=""
-    #Loop interfaces
-    #for entry in $IFACES; do
-    for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
-        ifpath=${filename%/operstate*}
-        iface=${ifpath#/sys/class/net/}
-        if inArray "$IFACEBLACKLIST" "$iface"; then
-            continue
-        fi
+    DATA="<?xml version='1.0' standalone='yes'?><data>"
 
-        #Get interface data for whitelisted interfaces
-        # shellcheck disable=SC2016
-        awkscript='
-            /ether/ { printf "<mac_addr>"$2"</mac_addr>" }
-            /mtu/ { printf "<mtu>"$5"</mtu>" }'
-        if inArray "$IPWHITELIST" "$iface"; then
-            # shellcheck disable=SC2016
-            awkscript=$awkscript'
-                /inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
-                /inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
-                /inet6/ && /scope link/ { printf "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
+    for f in /usr/lib/nodewatcher.d/*.sh; do
+        tmp=$(run_with_timeout "$f")
+        if [ $? ]; then
+            DATA=$DATA"$tmp"
         fi
-        addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
-
-        traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
-        traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
-
-        interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
-
-        interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
-            /Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
-            /Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
-            /ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
-            /Freq/{ split($3, f, " "); printf "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
-            /Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
-        ')
-
-        interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
-            /ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
-            /type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
-            /channel/{ split($0, c, " "); printf "<wlan_channel>"c[2]"</wlan_channel>" }
-            /width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf "<wlan_width>"w[2]"</wlan_width>" }
-        ')
-
-        interface_data=$interface_data"</$iface>"
     done
 
-    err "$(date): Collecting information from batman advanced and its interfaces"
-    #B.A.T.M.A.N. advanced
-    if [ -f /sys/module/batman_adv/version ]; then
-        for iface in $(grep active /sys/class/net/*/batman_adv/iface_status); do
-            status=${iface#*:}
-            iface=${iface%/batman_adv/iface_status:active}
-            iface=${iface#/sys/class/net/}
-            BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
-        done
-
-        # Build a list of direct neighbors
-        batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
-            'BEGIN { FS=" "; i=0 } # set the delimiter to " "
-            {   sub("\\(", "", $0) # remove parentheses
-                sub("\\)", "", $0)
-                sub("\\[", "", $0)
-                sub("\\]", "", $0)
-                sub("\\*", "", $0)
-                sub("  ", " ", $0)
-                o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
-                if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
-                {
-                    printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
-                    i++
-                }
-            }')
-
-        batman_adv_gateway_mode=$(/usr/sbin/batctl gw)
-
-        batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
-            'BEGIN { FS=" "; i=0 }
-            /No gateways/ { next }
-            {   sub("\\(", "", $0)
-                sub("\\)", "", $0)
-                sub("\\[ *", "", $0)
-                sub("\\]:", "", $0)
-                sub("\\* ", "true ", $0)
-                sub("  ", "false ", $0)
-                printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
-                i++
-            }')
-    fi
-    err "$(date): Collecting information about conected clients"
-    #CLIENTS
-    client_count=0
-    dataclient=""
-    CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
-    for clientif in ${CLIENT_INTERFACES}; do
-        local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
-        client_count=$((client_count + cc))
-        dataclient="$dataclient<$clientif>$cc</$clientif>"
-    done
-
-    dataair=""
-    w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
-    if [ -n "$w2dump" ] ; then
-        w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
-        w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
-        dataair="$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtime2>"
-    fi
-    w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
-    if [ -n "$w5dump" ] ; then
-        w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
-        w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
-        dataair="$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtime5>"
-    fi
-
-    err "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
-
-    DATA="<?xml version='1.0' standalone='yes'?><data>"
-    DATA=$DATA"<system_data>$SYSTEM_DATA</system_data>"
-    DATA=$DATA"<interface_data>$interface_data</interface_data>"
-    DATA=$DATA"<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
-    DATA=$DATA"<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
-    DATA=$DATA"<batman_adv_gateway_mode>$batman_adv_gateway_mode</batman_adv_gateway_mode>"
-    DATA=$DATA"<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
-    DATA=$DATA"<client_count>$client_count</client_count>"
-    DATA=$DATA"<clients>$dataclient</clients>"
-    DATA=$DATA"$dataair"
     DATA=$DATA"</data>"
 
     #write data to xml file that provides the data on httpd
@@ -306,11 +77,11 @@  crawl() {
 LANG=C
 
 #Prüft ob das logfile zu groß geworden ist
-err "$(date): Check logfile"
+debug "$(date): Check logfile"
 delete_log
 
 #Erzeugt die statusdaten
-err "$(date): Generate actual status data"
+debug "$(date): Generate actual status data"
 crawl
 
 exit 0
diff --git a/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
new file mode 100755
index 0000000..37eae02
--- /dev/null
+++ b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
@@ -0,0 +1,27 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+debug() {
+    (>&2 echo "$1")
+}
+
+debug "$(date): Collecting information about used airtime"
+
+dataair=""
+w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
+if [ -n "$w2dump" ] ; then
+    w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
+    w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
+    dataair="$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtime2>"
+fi
+w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
+if [ -n "$w5dump" ] ; then
+    w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
+    w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
+    dataair="$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtime5>"
+fi
+
+echo "$dataair"
+
+exit 0

Comments

Fabian Blaese Sept. 8, 2019, 8:21 p.m.
Hey Tim,

super Sache, danke für die Arbeit!

Noch ein bisschen Senf inline:

On 08.09.19 17:18, Tim Niemeyer wrote:
> diff --git a/src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh b/src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh
> new file mode 100755
> index 0000000..c7fad80
> --- /dev/null
> +++ b/src/packages/fff/fff-batman-adv-legacy/files/usr/lib/nodewatcher.d/30-batman-adv.sh
> @@ -0,0 +1,63 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +debug() {
> +    (>&2 echo "$1")
Möchte man das $(date) vielleicht noch mit in diese Funktion nehmen?
Generell würde ich das vielleicht auch in die Commit Message schreiben, dass Funktionsnamen geändert wurden.

> diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
> new file mode 100755
> index 0000000..d999c9f
> --- /dev/null
> +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
> @@ -0,0 +1,74 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +IFACEBLACKLIST="lo ifb0"
> +IPWHITELIST="br-mesh"
Hat es einen Grund, warum die Listen nicht mehr in der uci-Konfiguration stehen?
Falls ja: -> Commitmessage

Ich fand die Konfigurierbarkeit eigentlich recht angenehm, so konnte man selbst entscheiden, ob man die IPs von Interfaces im Monitoring haben möchte.

> diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> new file mode 100755
> index 0000000..426dd57
> --- /dev/null
> +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> @@ -0,0 +1,25 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +MESH_INTERFACE=br-mesh
Siehe oben, nicht mehr konfigurierbar.

> diff --git a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> index 90509ba..2137898 100755
> --- a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> +++ b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> @@ -12,28 +12,18 @@ if ! lock -n "$lockfile"; then
>  fi
>  trap "lock -u \"$lockfile\"" INT TERM EXIT
>  
> -SCRIPT_VERSION="53"
> -
>  #Get the configuration from the uci configuration file
>  #If it does not exists, then get it from a normal bash file with variables.
> -if [ -f /etc/config/nodewatcher ];then
> -    SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
> -    SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
> -    SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
> -    MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
> -    IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
> -    IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
> -    SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
> -else
> -    . "$(dirname "$0")/nodewatcher_config"
> -fi
Es gab mal Bestrebungen den nodewatcher auch unter nicht-OpenWRT lauffähig zu machen.
Daher kommt vermutlich auch dieser Test.

Möchte man das weiter verfolgen? Gute Frage eigentlich, wie man das gut machen kann, da der Nodewatcher jetzt über mehrere Packages verteilt ist..

Ansonsten:
Reviewed-by: Fabian Bläse <fabian@blaese.de>
Adrian Schmutzler Oct. 7, 2019, 6:21 p.m.
Hallo Tim,

gefällt mir gut. Ein paar Kommentare:
- Die 20-interfaces.sh enthält auch WiFi Zeug. Man könnte die theoretisch nach fff-wireless schieben, aber so richtig richtig wäre das auch nicht. Aber lieber hat fff-wireless eine Abhängigkeit von fff-network als umgekehrt.
- batman-adv-legacy wurde entfernt, der File fällt weg
- Generell müsste nochmal rebased werden, ein paar kleine Änderungen im nodewatcher fehlen
- Die run_with_timeout Funktion muss ich mir noch mal in Ruhe ankucken. Macht der wirklich pro Skript dann einen sleep 2?
- Eine ausführliche Commit Message wäre in der Tat schön
- Beim Durchschauen sind mir diverse Sachen aufgefallen, die man dringend mal ordentlich machen sollte. Finde es aber gut, dass jetzt erstmal nur Copy/Paste gemacht wurde. Danach kann man ja irgendwann mal aufräumen.
- Auf Fabian Kommentare antworte ich separat.
- Das mit der separaten SCRIPT_VERSION stört mich, v.a. wenn die jetzt noch tiefer versteckt wird. Vll. hat hier jemand noch eine bestechende Idee...

Ich denke, viel mehr lässt sich erstmal nicht rausholen.

Beste Grüße

Adrian
Adrian Schmutzler Oct. 7, 2019, 6:33 p.m.
Hallo,

Kommentare zu den Kommentaren unten:

> > +debug() { 
> > +    (>&2 echo "$1") 
> Möchte man das $(date) vielleicht noch mit in diese Funktion nehmen? 

Fände ich gut.

> > +IFACEBLACKLIST="lo ifb0" 
> > +IPWHITELIST="br-mesh" 
> Hat es einen Grund, warum die Listen nicht mehr in der uci-Konfiguration stehen? 
> Falls ja: -> Commitmessage 
> Ich fand die Konfigurierbarkeit eigentlich recht angenehm, so konnte man selbst entscheiden, ob man die IPs von Interfaces im Monitoring haben möchte.

Ich habe das tatsächlich nie benutzt, insofern habe ich kein Problem mit dem hardcoden. Wenn man das in uci haben möchte, kann man das aber auch ohne weiteres durch ein zusätzliches uci-default im jeweiligen Paket lösen.
Für den konkreten Fall würde ich die hardgecodeten Variablen erstmal behalten und dann mit einem separaten Patch wieder uci einführen, sonst doktern wir ewig an dem Patch rum.
BTW: Die nodewatcher config ist nicht mal updatefest, oder? Könnte man auch mal ändern.

> > +MESH_INTERFACE=br-mesh 

> Siehe oben, nicht mehr konfigurierbar. 

Hier finde ich ein uci setting nicht wirklich gerechtfertigt. Wer das ändert, baut relativ viel an der Firmware um, da kann man dann auch den Wert im Skript hier ändern.

Wie auch oben festgestellt würde ich das aber ohnehin für diesen Patch belassen.

> > -if [ -f /etc/config/nodewatcher ];then 
> > -    SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level) 
> > -    SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile) 
> > -    SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file) 
> > -    MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface) 
> > -    IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist) 
> > -    IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist) 
> > -    SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file) 
> > -else 
> > -    . "$(dirname "$0")/nodewatcher_config" 
> > -fi 
> Es gab mal Bestrebungen den nodewatcher auch unter nicht-OpenWRT lauffähig zu machen. 
> Daher kommt vermutlich auch dieser Test. 
> Möchte man das weiter verfolgen? Gute Frage eigentlich, wie man das gut machen kann, da der Nodewatcher jetzt über mehrere Packages verteilt ist..

Nun ja, die Frage ist, ob dieser alternative Nodewatcher mit in die Firmware eingebaut werden muss. Ich finde: Nein.

Ich denke, hierfür muss es eigene _separate_ Skripte geben, die dann auch besser auf die jeweiligen Bedürfnisse abgestimmt sind (so wie es ja auch im Moment ist).
Ich war eigentlich froh, dass dieser Sonderfall gleich mit rausgeflogen ist.

Für meinen Geschmack wurde hier für die aktuelle Situation genau an den richtigen Stellen geändert oder belassen.

Grüße

Adrian
Adrian Schmutzler Oct. 7, 2019, 7:18 p.m.
Hallo nochmal,

ich habe mir das run_with_timeout nochmal genauer angesehen.

Ich denke, ich verstehe jetzt einigermaßen, was es tut. Dementsprechend sind die 2 sec. keine Wartezeit, sondern die Zeit, nach der ein Teilskript abgeschossen wird?

Das würde dann bedeuten, dass der nodewatcher die Daten aus diesem Skript nicht bekommt und daher ein unvollständiges XML baut.
Meiner Meinung nach sollte dann der ganze nodewatcher ein exit 1 machen, anstatt einen unvollständigen Datensatz rauszuschicken.

+    for f in /usr/lib/nodewatcher.d/*.sh; do
+        tmp=$(run_with_timeout "$f")
+        if [ $? ]; then
+            DATA=$DATA"$tmp"

Was genau legt hier den Wert von $? fest? Die Zuweisung? Ist der Status-Code dann != 0, wenn tmp leer ist? Oder run_with_timeout?
Macht es ggf. mehr Sinn, hier mit [ -n "$tmp" ] zu prüfen? Hat das echo einen buffer, sodass ein blöder kill in der Funktion eine halbe Ausgabe erzeugen kann (dann müsste man den Status-Code von kill auswerten ...)?
Wahrscheinlich reicht es aber aus, einfach ein "else exit 1" hinzuzufügen.

Ich fände es außerdem super, wenn man in der Funktion run_with_timeout _jede_ Zeile kommentieren könnte, damit das auch ein Nicht-Pro versteht, wenn er es in zwei Jahren mal durchliest.

War jetzt zwar viel Text von mir, sollte aber recht unanstrengend zu beantworten sein.

Grüße

Adrian
Robert Langhammer Oct. 7, 2019, 9:22 p.m.
Hi Adrian,

Am 07.10.19 um 21:18 schrieb Adrian Schmutzler:
> Hallo nochmal,
>
> ich habe mir das run_with_timeout nochmal genauer angesehen.
>
> Ich denke, ich verstehe jetzt einigermaßen, was es tut. Dementsprechend sind die 2 sec. keine Wartezeit, sondern die Zeit, nach der ein Teilskript abgeschossen wird?
>
> Das würde dann bedeuten, dass der nodewatcher die Daten aus diesem Skript nicht bekommt und daher ein unvollständiges XML baut.
> Meiner Meinung nach sollte dann der ganze nodewatcher ein exit 1 machen, anstatt einen unvollständigen Datensatz rauszuschicken.
>
> +    for f in /usr/lib/nodewatcher.d/*.sh; do
> +        tmp=$(run_with_timeout "$f")
> +        if [ $? ]; then
> +            DATA=$DATA"$tmp"

[ $? ] ist IMMER true, da immer exsistent! Ich denke da wurde nur der
Test auf 0 vergessen: if [ $? = 0 ]

In $? ist in diesem Fall der Exitstatus der Subshell.

Gruß Robert

>
> Was genau legt hier den Wert von $? fest? Die Zuweisung? Ist der Status-Code dann != 0, wenn tmp leer ist? Oder run_with_timeout?
> Macht es ggf. mehr Sinn, hier mit [ -n "$tmp" ] zu prüfen? Hat das echo einen buffer, sodass ein blöder kill in der Funktion eine halbe Ausgabe erzeugen kann (dann müsste man den Status-Code von kill auswerten ...)?
> Wahrscheinlich reicht es aber aus, einfach ein "else exit 1" hinzuzufügen.
>
> Ich fände es außerdem super, wenn man in der Funktion run_with_timeout _jede_ Zeile kommentieren könnte, damit das auch ein Nicht-Pro versteht, wenn er es in zwei Jahren mal durchliest.
>
> War jetzt zwar viel Text von mir, sollte aber recht unanstrengend zu beantworten sein.
>
> Grüße
>
> Adrian
Adrian Schmutzler Oct. 7, 2019, 11:29 p.m.
Hallo Robert,

> > +    for f in /usr/lib/nodewatcher.d/*.sh; do 
> > +        tmp=$(run_with_timeout "$f") 
> > +        if [ $? ]; then 
> > +            DATA=$DATA"$tmp" 
> [ $? ] ist IMMER true, da immer exsistent! Ich denke da wurde nur der 
> Test auf 0 vergessen: if [ $? = 0 ] 
> In $? ist in diesem Fall der Exitstatus der Subshell. 

Da müsste man dann überlegen, was den Exitstatus der Subshell determiniert.

Klingt für mich sehr danach, als ob man einfach [ -n "$tmp" ] prüfen sollte.

Grüße

Adrian
Robert Langhammer Oct. 8, 2019, 9:48 p.m.
Hi Adrian,

Am 08.10.19 um 01:29 schrieb mail@adrianschmutzler.de:
> Hallo Robert,
>
>>> +    for f in /usr/lib/nodewatcher.d/*.sh; do 
>>> +        tmp=$(run_with_timeout "$f") 
>>> +        if [ $? ]; then 
>>> +            DATA=$DATA"$tmp" 
>> [ $? ] ist IMMER true, da immer exsistent! Ich denke da wurde nur der 
>> Test auf 0 vergessen: if [ $? = 0 ] 
>> In $? ist in diesem Fall der Exitstatus der Subshell. 
> Da müsste man dann überlegen, was den Exitstatus der Subshell determiniert.
>
> Klingt für mich sehr danach, als ob man einfach [ -n "$tmp" ] prüfen sollte.

Nein, das ist schon richtig so. Wenn der Timer zuschlägt und das Skript
noch nicht fertig ist, steht zerhacktes in $tmp. Wir bekommen dann
$?=143 (SIGTERM) und man kann das Ganze mit if [ $? = 0 ] verwerfen.

Wichtig ist auch vernünftiges Fehlerhandling in den Skripten. Ein exit 1
landet hier in $?.

@Tim: sehe ich das richtig so?

Viele Grüße
Robert

>
> Grüße
>
> Adrian
Adrian Schmutzler Oct. 9, 2019, 12:22 p.m.
Hallo Robert,

>>> In $? ist in diesem Fall der Exitstatus der Subshell. 
>> Da müsste man dann überlegen, was den Exitstatus der Subshell determiniert. 
>> 
>> Klingt für mich sehr danach, als ob man einfach [ -n "$tmp" ] prüfen sollte. 
> Nein, das ist schon richtig so. Wenn der Timer zuschlägt und das Skript 
> noch nicht fertig ist, steht zerhacktes in $tmp. Wir bekommen dann 
> $?=143 (SIGTERM) und man kann das Ganze mit if [ $? = 0 ] verwerfen. 
> Wichtig ist auch vernünftiges Fehlerhandling in den Skripten. Ein exit 1 
> landet hier in $?. 

Okay, das spricht gegen -n.

Ich bin mir nur nicht sicher, ob bei dem ganzen asynchronen Prozessgedöns dann auch der richtige exit status "der letzte" ist.
Ich habe das daher mal getestet und es scheint aber wunderbar zu funktionieren.

Allerdings habe ich hier ein anderes Problem:

Wenn ich das echo von run_with_timeout abfange, braucht er die gesamte wait time:
z.B. tmp=$(run_with_timeout false)
blockiert die Konsole entsprechend.

Wenn ich run_with_timeout direkt aufrufe, ist er sofort fertig, z.B.
run_with_timeout false

Output und Status-Code werden in beiden Fällen korrekt verarbeitet.

Hat da jemand eine Idee?

Grüße

Adrian
Robert Langhammer Oct. 10, 2019, 10:19 a.m.
Hi Adrian, s. unten

Am 09.10.19 um 14:22 schrieb Adrian Schmutzler:
> Hallo Robert,
>
>>>> In $? ist in diesem Fall der Exitstatus der Subshell. 
>>> Da müsste man dann überlegen, was den Exitstatus der Subshell determiniert. 
>>>
>>> Klingt für mich sehr danach, als ob man einfach [ -n "$tmp" ] prüfen sollte. 
>> Nein, das ist schon richtig so. Wenn der Timer zuschlägt und das Skript 
>> noch nicht fertig ist, steht zerhacktes in $tmp. Wir bekommen dann 
>> $?=143 (SIGTERM) und man kann das Ganze mit if [ $? = 0 ] verwerfen. 
>> Wichtig ist auch vernünftiges Fehlerhandling in den Skripten. Ein exit 1 
>> landet hier in $?. 
> Okay, das spricht gegen -n.
>
> Ich bin mir nur nicht sicher, ob bei dem ganzen asynchronen Prozessgedöns dann auch der richtige exit status "der letzte" ist.
> Ich habe das daher mal getestet und es scheint aber wunderbar zu funktionieren.
>
> Allerdings habe ich hier ein anderes Problem:
>
> Wenn ich das echo von run_with_timeout abfange, braucht er die gesamte wait time:
> z.B. tmp=$(run_with_timeout false)
> blockiert die Konsole entsprechend.
>
> Wenn ich run_with_timeout direkt aufrufe, ist er sofort fertig, z.B.
> run_with_timeout false
>
> Output und Status-Code werden in beiden Fällen korrekt verarbeitet.
>
> Hat da jemand eine Idee?

Ja, das liegt an der Zuweisung tmp=$(xxx). Die erfolgt erst wenn die
Subshell fertig ist. Da gehört auch das sleep dazu auch wenn das mit &
als bg-Job gestartet wird.

Mit Variablen kann man das auch nicht lösen. Der Export funktioniert nur
in eine Richtung und ist eigentlich nur ein Kopieren der Variable in die
Subshell.

Es gibt nur eine Möglichkeit das zu umgehen. Man schreibt in der
Subshell die Daten auf die Platte und holt die in der äußeren Shell
wieder rein. Da muss man dann abwägen ob man das will. Die Shell ist
halt  nur eine Skriptsprache.

In diesem Fall spielt die Zeit keine all zu große Rolle. Und ich würde
nicht in eine Datei schreiben. Auch der Vorteil vom Timeout überwiegt
meiner Ansicht nach und sollte drin bleiben.

Ich würde das so lassen. Nur der Test [ $? = 0 ]  muss noch rein.

Viele Grüße
Robert


>
> Grüße
>
> Adrian
Adrian Schmutzler Oct. 10, 2019, 10:31 a.m.
Hallo Robert,

 

also ganz ehrlich finde ich es nicht erstrebenswert, für jede Datei in nodewatcher.d x Sekunden zu warten.

 

Da wäre es dann vll. sinnvoller, einfach alle Dateien normal auszuführen und das ganze nodewatcher-Skript dann nach einer Zeit y abzuschießen.

Folgt man meinem Vorschlag bei einer einzelnen Datei die fehlschlägt alle nodewatcher-Daten zu verwerfen sollte dies effektiv zum gleichen Ergebnis führen, aber im Normalfall schneller sein.

 

Grüße

 

Adrian
Adrian Schmutzler Oct. 10, 2019, 10:46 a.m.
Hallo nochmal,

im Prinzip ist die ganze run_with_timeout Funktion ja ein Zusatzfeature.

Spricht etwas dagegen, erstmal die Aufteilung des nodewatchers umzusetzen und dabei die nodewatcher.d Dateien einfach direkt auszuführen?
Dies würde im Wesentlichen das Gleiche tun wie der nodewatcher jetzt. Dann könnte man den großen Teil des Patches relativ schnell einbauen und würde danach nur noch über die Ausgestaltung der Funktion run_with_timeout diskutieren.

Man würde dann zunächst einfach

tmp=$("$f")
if [ -n "$f" ]; then
   ...

verwenden.

Man müsste dann nur noch:
- klären, ob man 20-interfaces.sh nach network oder wireless tut
- Die Commit-Message schön machen
- Sich bezüglich uci vs. hardcode aus Fabian E-Mail einigen (mMn könnte man das zunächst wie im Patch lassen und danach ggf. wieder in einem separaten Patch uci einbauen/diskutieren)
- Rebasen

@Tim: Hast du Lust, das nochmal zu rebasen/die Commit Message zu schreiben oder soll ich das machen.

Grüße

Adrian
Robert Langhammer Oct. 19, 2019, 7:23 p.m.
HI,

was machen wir denn jetzt damit?

run_with_timeout: also ich finde die 2 Sekunden nicht schlimm. Der
Timeout "schützt" das Sysytem vor einer hängenden Funktion. Das ist
schon ein gewisser Vorteil.

uci: Es wäre zwar schön einen Plattform unabhängigen nodewatcher zu
haben, ich glaube allerdings, dass sich keiner finden wird das hin
bastelt. Ist auch nicht ganz trivial. Ich würde vorschlagen, hier eine
Openwrt Variante mit uci zu machen. Ein "Gerippe", das man sich dann auf
einer anderen Kiste anpasst, könnte man zusätzlich noch irgendwie anbieten.

20-interfaces.sh: Spielt das überhaupt eine Rolle?

Viele Grüße
Robert

Am 10.10.19 um 12:46 schrieb Adrian Schmutzler:
> Hallo nochmal,
>
> im Prinzip ist die ganze run_with_timeout Funktion ja ein Zusatzfeature.
>
> Spricht etwas dagegen, erstmal die Aufteilung des nodewatchers umzusetzen und dabei die nodewatcher.d Dateien einfach direkt auszuführen?
> Dies würde im Wesentlichen das Gleiche tun wie der nodewatcher jetzt. Dann könnte man den großen Teil des Patches relativ schnell einbauen und würde danach nur noch über die Ausgestaltung der Funktion run_with_timeout diskutieren.
>
> Man würde dann zunächst einfach
>
> tmp=$("$f")
> if [ -n "$f" ]; then
>    ...
>
> verwenden.
>
> Man müsste dann nur noch:
> - klären, ob man 20-interfaces.sh nach network oder wireless tut
> - Die Commit-Message schön machen
> - Sich bezüglich uci vs. hardcode aus Fabian E-Mail einigen (mMn könnte man das zunächst wie im Patch lassen und danach ggf. wieder in einem separaten Patch uci einbauen/diskutieren)
> - Rebasen
>
> @Tim: Hast du Lust, das nochmal zu rebasen/die Commit Message zu schreiben oder soll ich das machen.
>
> Grüße
>
> Adrian
>
Adrian Schmutzler Oct. 21, 2019, 9:58 a.m.
Hallo Robert,

> run_with_timeout: also ich finde die 2 Sekunden nicht schlimm. Der 
> Timeout "schützt" das Sysytem vor einer hängenden Funktion. Das ist 
> schon ein gewisser Vorteil. 

Wir haben ja dann 6 oder 7 Mal 2 Sekunden.

Zudem hat dieses Konzept den Nachteil, dass man bei den schnellen nodewatcher.d Skripten zwei Sekunden warten muss, während bei den langsamen ggf. 2 Sekunden zu kurz sind, und diese öfters kaputt gehen.

Hätte die Lösung "funktioniert", sodass die Wartezeit nicht immer läuft, hätte ich eine längere Zeit in Richtung 5 Sekunden vorgeschlagen.

Das Hängen des Ganzen könnte man auch einfach implementieren, indem man die Skripte "normal" called oder sourced, und dann einfach für den ganzen nodewatcher ein timeout von z.B. 30 Sekunden setzt.

Ich bin ohnehin dringend dafür, dass bei Scheitern eines nodewatcher.d Teils der ganze Datensatz verworfen wird, wodurch ein spezifisches Auswerten des Erfolgs der Teilskripte hinfällig wird.

> uci: Es wäre zwar schön einen Plattform unabhängigen nodewatcher zu 
> haben, ich glaube allerdings, dass sich keiner finden wird das hin 
> bastelt. Ist auch nicht ganz trivial. Ich würde vorschlagen, hier eine 
> Openwrt Variante mit uci zu machen. Ein "Gerippe", das man sich dann auf 
> einer anderen Kiste anpasst, könnte man zusätzlich noch irgendwie anbieten. 

Das deckt sich glaube ich mit meiner zuvor geäußerten Meinung.

> 20-interfaces.sh: Spielt das überhaupt eine Rolle? 

Nur für ein sauberes Trennen der dependencies. Praktisch relevant ist das erstmal nicht, deshalb kann man das auch erstmal nicht anfassen. Sauber trennen kann man es mit der aktuellen xml Struktur ohnehin nicht, man muss sich also für die weniger falsche Lösung entscheiden.

Generell noch:

Je mehr ich darüber nachdenke, desto mehr bin dafür, den Umbau erst NACH dem Release einzubauen. Einen nodewatcher-Umbau will ich ausführlich getestet haben, bevor er in eine Firmware hineinkommt, die dann vll. wieder ein Jahr lang ohne Nachfolger rumfliegt. Ich bin sehr für diesen Umbau, aber ich habe auch keine Lust, danach ggf. lang am Monitoring nachsitzen zu müssen.

Grüße

Adrian