Community discussions

MikroTik App
 
User avatar
MrBonding
just joined
Topic Author
Posts: 10
Joined: Mon Jul 05, 2021 1:32 pm

Script to improve netwatch, dynamic variable solution?

Tue Sep 28, 2021 6:04 pm

I'm trying to build a script to improve netwatch ability to notify downs on some VPN connections, those VPN connections are from SIM routers so I'm getting a lot of false downs while using netwatch (they disconnect for a while sometimes).

My idea is to create a script run by the scheduler that ping's all the IP's on /ppp secret tab, if the IP is down then a global variable ( counter unique for that host) is increased by 1, and if the IP is up then the counter goes back to 0. At the end, there's an IF that checks if the counter is bigger than X and sends a notification. In my lack of understanding, I have not been able to implement that global "per-host variable" that I need. Since dynamic variables, or "variable in a variable" are not possible I'm stuck...

So far that's the script I've written.
:local pingip
:log info "Script"

:foreach id in=[/ppp secret find where profile=SIMRouters ] do={
 :global $id_counter
 :local name [/ppp secret get $id name]
 :local address [/ppp secret get $id remote-address]
 :set pingip [/ping $address count=1]
 :if ($pingip = 0) do={
  :log info "Fail PING on $address $name"
  THERE SHOULD BE THE COUNTER + 1 #PSEUDOCODE
  IF COUNTER > X NOTIFY #PSEUDOCODE
 } else={
  log info "Ping OK on $address $name"
  COUNTER = 0 #PSEUDOCODE
 }
}
I'm missing a lot of knowledge so any advice would be really apreciated.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script to improve netwatch, dynamic variable solution?  [SOLVED]

Tue Sep 28, 2021 7:47 pm

Just ask on MikroTik Forum...
:global arrayofvalues
:if ([:typeof $arrayofvalues] = "nothing") do={:set arrayofvalues [:toarray ""]}
/ppp secret
:foreach item in=[find where profile="SIMRouters"] do={
    :local pname  [get $item name]
    :local premip [get $item remote-address]
    :if ([:ping $premip count=1] != 1) do={
        :set ($arrayofvalues->$pname) (($arrayofvalues->$pname) + 1)
        :if (($arrayofvalues->$pname) = 5) do={
            :log error "Failed to PING 5 times on $premip $pname"
            # INSERT WARNING ROUTINE HERE
        }
    } else={
        :if (($arrayofvalues->$pname) >= 5) do={
            :log warning "PING succeeded again on $premip $pname"
            # INSERT UN-WARNING ROUTINE HERE
        }
        :set ($arrayofvalues->$pname) 0
    }
    :delay 1s
}

some suggestions:
do not use variable names than are like parameters (example name -> pname)
everytime use the ":" like on :log, :set, :if, :ping etc.

if the operation is single and is easy understandeable:

:set pingip [/ping $address count=1]
:if ($pingip = 0) do={

better:

:if ([/ping $address count=1] = 0) do={



Commented version just for teaching

teaching code

# if exist I want use this variable
:global arrayofvalues

# if it is not already defined, I defined it as empty Array
:if ([:typeof $arrayofvalues] = "nothing") do={:set arrayofvalues [:toarray ""]}

# I work only on that section
/ppp secret

# select all items that have SIMRouters as profile
:foreach item in=[find where profile="SIMRouters"] do={
    :local pname  [get $item name]
    :local premip [get $item remote-address]
    :if ([:ping $premip count=1] != 1) do={
# if the ping fail, use the "username" as variable name and set it to "previous value + 1" (nothing + 1 = 1, no matter to set it first to 0)
        :set ($arrayofvalues->$pname) (($arrayofvalues->$pname) + 1)

# I want be warned only one time, when the fail reach 5 times only
# no matter is the 6th, 7th, 8th time, I want receive only one warning
        :if (($arrayofvalues->$pname) = 5) do={
            :log error "Failed to PING 5 times on $premip $pname"
            # INSERT WARNING ROUTINE HERE
        }
    } else={

# if I have been warned, I want be un-warned because the link work again
# if before have failed only 4 thimes, and now is working, I do not want any warn (because I receive warning only the 5th time...)
        :if (($arrayofvalues->$pname) >= 5) do={
            :log warning "PING succeeded again on $premip $pname"
            # INSERT UN-WARNING ROUTINE HERE
        }
# if ping successfully set / reset the variable to 0
        :set ($arrayofvalues->$pname) 0
    }

# prevent ping and CPU "storm"
    :delay 1s
}
Last edited by rextended on Sat Oct 02, 2021 10:46 am, edited 4 times in total.
 
User avatar
eworm
Forum Guru
Forum Guru
Posts: 1070
Joined: Wed Oct 22, 2014 9:23 am
Location: Oberhausen, Germany
Contact:

Re: Script to improve netwatch, dynamic variable solution?

Tue Sep 28, 2021 11:12 pm

You may be interested in my script Notify on host up and down...
 
User avatar
SiB
Forum Guru
Forum Guru
Posts: 1888
Joined: Sun Jan 06, 2013 11:19 pm
Location: Poland

Re: Script to improve netwatch, dynamic variable solution?

Wed Sep 29, 2021 3:51 am

rextended write
Commented version just for teaching
Perfect base for create better netwatch.
I start my own with idea of :local arrayofoperators {"WAN1 Orange GW"=192.168.1.1 ; "WAN2 ITSA GW"=192.168.2.2 } ... but this is OT here.

What when we receive that:
put [typeof [ping 192.168.1.1 count=1]]
Columns: SEQ, HOST, SIZE, TTL, TIME, STATUS
SEQ HOST SIZE TTL TIME STATUS
0 37.109.59.29 84 64 1ms497us net unreachable

nil
Probably better when main ([:ping $premip count=1] = 1) do={put "Only OK"} else={put "All timeout and nil results and other like no buffer space :D"}

EDIT: sorry, normal ros return 0 but my 7.1rc4 have bug what I describe it here: viewtopic.php?f=1&t=178704&p=882822#p882822 ; workaround: count=3
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script to improve netwatch, dynamic variable solution?

Wed Sep 29, 2021 11:06 am

I accept the hint, RouterOS 7 or not,
without move too much things, simply from "] = 0)" to "] != 1)"

:lol:

PS: don't get into the bad habit of omitting ":" before all the items where it should be put...
put [typeof [ping 192.168.1.1 count=1]]
# --->>
:put [:typeof [:ping 192.168.1.1 count=1]]
 
User avatar
SiB
Forum Guru
Forum Guru
Posts: 1888
Joined: Sun Jan 06, 2013 11:19 pm
Location: Poland

Re: Script to improve netwatch, dynamic variable solution?

Wed Sep 29, 2021 11:51 am

without move too much things, simply from "] = 0)" to "] != 1)"
Thanks for teaching approach :)

:put [:typeof [:ping 1.1.1.1 count=1]]
return nil at 7.1rc4 what is bug of course and a !=1 not help because even ping is OK then this nil exist and we have falsepossitive :).
if ( [:ping 1.1.1.1 count=1] != 1 ) do={put FailPing } else={put WorkingPing}
0 1.1.1.1 56 58 21ms998us
FailPing
PS. My WAN NetWatch works not and even have own up/down-scripts. This is perfect thread

in BUG environment simple logic like !=1 not work :) counter=3 works and we wait for rc5
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script to improve netwatch, dynamic variable solution?

Wed Sep 29, 2021 11:55 am

P.P.S: about the "!=" and ":"... the suggestions are for the syntax, not for fix the broken 7.1rc4 :(


I do not want omit that the "original" question/idea is from @MrBonding
I just added my way to save "declared-later" variables...
 
User avatar
MrBonding
just joined
Topic Author
Posts: 10
Joined: Mon Jul 05, 2021 1:32 pm

Re: Script to improve netwatch, dynamic variable solution?

Sat Oct 02, 2021 10:12 am

Many, many thanks to you all especially for the brilliant response of @rextended, not only works flawlessly but also you've taken you time to explain and give really good advice about the script, I'm truly happy for your help. I do know now a little bit more about ROS thanks to you :)

Many thanks!

Who is online

Users browsing this forum: No registered users and 14 guests