Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

watchcat: add support for "change status" trigger #26057

Open
lars18th opened this issue Feb 26, 2025 · 2 comments
Open

watchcat: add support for "change status" trigger #26057

lars18th opened this issue Feb 26, 2025 · 2 comments

Comments

@lars18th
Copy link

Hi,

When using the "script" mode with Watchcat I need to execute the script not (only) when the ping fails, but when the ping "changes the status". One use case to understand the problem:

  • Using Wireguard (or any other VPN tunnel) you want to execute the script when the pings fails. This could be done now.
  • But also you want to execute the script when the ping returns to the OK status. This can't be done now.

The idea is to add support for "up" and "down" status. Then the script will be executed when then OK->FAIL event appears (and not at every FAIL), and another time when FAIL->OK (and just one time).

And in case this can't be implemented, I suggest for the "script" mode to add support for TWO different scripts: one for FAIL and one for OK. Or also with only one script add a new option that calls it after every check adding a new parameter indicating the return code of the ping.

I hope you want to implement this.

@lars18th
Copy link
Author

Hi to all,

I've created a dirty patch to support this functionality. Here is the patch:

--- /tmp/watchcat.sh.org        2025-02-26 19:11:46.822650864 +0100
+++ /usr/bin/watchcat.sh        2025-02-26 21:09:39.000000000 +0100
@@ -89,7 +89,7 @@

 watchcat_run_script() {
        logger -p daemon.info -t "watchcat[$$]" "Running script \"$1\" for network interface: \"$2\"."
-       "$1" "$2"
+       "$1" "$2" "$3"
 }

 watchcat_restart_all_network() {
@@ -118,6 +118,9 @@
        time_lastcheck="$time_now"
        time_lastcheck_withinternet="$time_now"

+       status_enabled=1
+       status_last="-1"
+
        ping_size="$(get_ping_size "$ping_size")"

        ping_family="$(get_ping_family_flag "$address_family")"
@@ -133,6 +136,7 @@
                time_now="$(cat /proc/uptime)"
                time_now="${time_now%%.*}"
                time_lastcheck="$time_now"
+               status_trigger=0

                for host in $ping_hosts; do
                        if [ "$iface" != "" ]; then
@@ -147,11 +151,26 @@
                                )"
                        fi

+                       if [ "$status_enabled" -ne 0 ] && [ "$script" != "" ] && [ "$status_last" -ne "$ping_result" ]; then
+               #               logger -p daemon.info -t "watchcat[$$]" "Old STATUS \"$status_last\" to New STATUS \"$ping_result\" for ping"
+                               status_trigger=1
+                       fi
                        if [ "$ping_result" -eq 0 ]; then
                                time_lastcheck_withinternet="$time_now"
+                               if [ "$status_trigger" -ne 0 ]; then
+                                       logger -p daemon.info -t "watchcat[$$]" "Can reach $host via \"$iface\". Running script now"
+                               fi
+                               status_last="$ping_result"
                        else
                                if [ "$script" != "" ]; then
-                                       logger -p daemon.info -t "watchcat[$$]" "Could not reach $host via \"$iface\" for \"$((time_now - time_lastcheck_withinternet))\" seconds. Running script after reaching \"$failure_period\" seconds"
+                                       if [ "$status_enabled" -eq 0 ] || [ "$status_trigger" -ne 0 ]; then
+                                               logger -p daemon.info -t "watchcat[$$]" "Could not reach $host via \"$iface\" for \"$((time_now - time_lastcheck_withinternet))\" seconds. Running script after reaching \"$failure_period\" seconds"
+                                       fi
+                                       if [ "$status_enabled" -ne 0 ] && [ "$((time_now - time_lastcheck_withinternet))" -lt "$failure_period" ]; then
+                                               status_trigger=0
+                                       else
+                                               status_last="$ping_result"
+                                       fi
                                elif [ "$iface" != "" ]; then
                                        logger -p daemon.info -t "watchcat[$$]" "Could not reach $host via \"$iface\" for \"$((time_now - time_lastcheck_withinternet))\" seconds. Restarting \"$iface\" after reaching \"$failure_period\" seconds"
                                else
@@ -160,9 +179,13 @@
                        fi
                done

-               [ "$((time_now - time_lastcheck_withinternet))" -ge "$failure_period" ] && {
+               [ "$((time_now - time_lastcheck_withinternet))" -ge "$failure_period" ] && [ "$status_enabled" -eq 0 ] || [ "$status_trigger" -ne 0 ] && {
                        if [ "$script" != "" ]; then
-                               watchcat_run_script "$script" "$iface"
+                               if [ "$status_enabled" -eq 0 ]; then
+                                       watchcat_run_script "$script" "$iface"
+                               else
+                                       watchcat_run_script "$script" "$iface" "$status_last"
+                               fi
                        else
                                if [ "$mm_iface_name" != "" ]; then
                                        watchcat_restart_modemmanager_iface "$mm_iface_name" "$mm_iface_unlock_bands"

Within this patch the status_enabled variable is responsible for selecting the current or new behavior. The idea is to read it from the args. But here it is hard-coded. Also, this only works for scripts, and does not change any other current behavior.

This could be useful to change the POWER LED based on status of Wireguard/VPN/Tunnel. Here my config:

  • In the LED configuration I use the kernel Heartbeat interval, without the invert blinking.
  • So, when the tunnel is OFF the standard blink indicates only the running activity.
  • I use the script /etc/watchcat.user.sh called from the Watchcat to change the status.
  • The Watchcat configuration is to the ping to the remote end of the tunnel every 5s with a period of 10s.
  • Using my patch the script is called ONLY when the status changes.
  • The content of the /etc/watchcat.user.sh:
#!/bin/sh
if [ "$2" -eq "0" ]; then
        logger -p daemon.info -t "watchcat.user.sh[$$]" "$0 $1 $2 $3 LED ENABLED!"
        echo 1 > /sys/class/leds/green:power/invert
else
        logger -p daemon.info -t "watchcat.user.sh[$$]" "$0 $1 $2 $3 LED DISABLED!"
        echo 0 > /sys/class/leds/green:power/invert
fi

I hope someone of you will like to clean and complete this patch and merge it.
Feel free to use it.
Regards.

@lars18th
Copy link
Author

Hi,

More interesting configuration for Wireguard (or VPN/SSH-Tunnel/etc):

  • Using my proposed patch, you can configure the LED using the netdev trigger for the tunnel interface (wg0) and configure the trigger mode with TX & RX.
  • With Watchcat then you can configure to ping the other end of the tunnel (for Wireguard it's the peer address).
  • And use this user script:
#!/bin/sh
if [ "$2" -eq "0" ]; then
        echo 1 > /sys/class/leds/green:power/link
else
        echo 0 > /sys/class/leds/green:power/link
fi

The behaviour is then:

  • When the tunnel is stablished, the LED is ON and blinks with activity (like a switch led).
  • When the tunnel is not working (the ping fails), then the LED is OFF and it blinks with activity (aka the testing ping).

This is a very visual method to physically check the VPN status.

If anyone wants to help to complete the patch and create a PR (I can't sign for openwrt patches), please comment here. I have improved the code a bit. And now I know how to add full uci support for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant