2020-09-18 09:00:27 +00:00
|
|
|
#!rsc by RouterOS
|
2018-07-05 13:29:26 +00:00
|
|
|
# RouterOS script: check-routeros-update
|
2023-01-02 22:33:49 +00:00
|
|
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
2020-06-19 20:17:42 +00:00
|
|
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
2018-07-05 13:29:26 +00:00
|
|
|
#
|
2019-05-23 10:16:34 +00:00
|
|
|
# check for RouterOS update, send notification and/or install
|
2020-03-27 20:42:19 +00:00
|
|
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md
|
2018-07-05 13:29:26 +00:00
|
|
|
|
2021-02-22 14:14:10 +00:00
|
|
|
:local 0 "check-routeros-update";
|
2021-02-18 13:52:47 +00:00
|
|
|
:global GlobalFunctionsReady;
|
|
|
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
|
|
|
global: variable names are CamelCase
___ _ ___ __
/ _ )(_)__ _ / _/__ _/ /_
/ _ / / _ `/ / _/ _ `/ __/
/____/_/\_, / /_/ \_,_/\__/
_ __ /___/ _ __
| | / /___ __________ (_)___ ____ _/ /
| | /| / / __ `/ ___/ __ \/ / __ \/ __ `/ /
| |/ |/ / /_/ / / / / / / / / / / /_/ /_/
|__/|__/\__,_/_/ /_/ /_/_/_/ /_/\__, (_)
/____/
RouterOS has some odd behavior when it comes to variable names. Let's
have a look at the interfaces:
[admin@MikroTik] > / interface print where name=en1
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
That looks ok. Now we use a script:
{ :local interface "en1";
/ interface print where name=$interface; }
And the result...
[admin@MikroTik] > { :local interface "en1";
{... / interface print where name=$interface; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
... still looks ok.
We make a little modification to the script:
{ :local name "en1";
/ interface print where name=$name; }
And the result:
[admin@MikroTik] > { :local name "en1";
{... / interface print where name=$name; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
1 S en2 ether 1500 1598
2 S en3 ether 1500 1598
3 S en4 ether 1500 1598
4 S en5 ether 1500 1598
5 R br-local bridge 1500 1598
Ups! The filter has no effect!
That happens whenever the variable name ($name) matches the property
name (name=).
And another modification:
{ :local type "en1";
/ interface print where name=$type; }
And the result:
[admin@MikroTik] > { :local type "en1";
{... / interface print where name=$type; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
Ups! Nothing?
Even if the variable name ($type) matches whatever property name (type=)
things go wrong.
The answer from MikroTik support (in Ticket#2019010222000454):
> This is how scripting works in RouterOS and we will not fix it.
To get around this we use variable names in CamelCase. Let's hope
Mikrotik never ever introduces property names in CamelCase...
*fingers crossed*
2019-01-03 16:45:43 +00:00
|
|
|
:global Identity;
|
2020-11-01 20:48:03 +00:00
|
|
|
:global SafeUpdateNeighbor;
|
2021-06-28 16:00:25 +00:00
|
|
|
:global SafeUpdateOnCap;
|
2020-07-06 22:21:47 +00:00
|
|
|
:global SafeUpdatePatch;
|
2020-11-01 20:48:03 +00:00
|
|
|
:global SafeUpdateUrl;
|
global: variable names are CamelCase
___ _ ___ __
/ _ )(_)__ _ / _/__ _/ /_
/ _ / / _ `/ / _/ _ `/ __/
/____/_/\_, / /_/ \_,_/\__/
_ __ /___/ _ __
| | / /___ __________ (_)___ ____ _/ /
| | /| / / __ `/ ___/ __ \/ / __ \/ __ `/ /
| |/ |/ / /_/ / / / / / / / / / / /_/ /_/
|__/|__/\__,_/_/ /_/ /_/_/_/ /_/\__, (_)
/____/
RouterOS has some odd behavior when it comes to variable names. Let's
have a look at the interfaces:
[admin@MikroTik] > / interface print where name=en1
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
That looks ok. Now we use a script:
{ :local interface "en1";
/ interface print where name=$interface; }
And the result...
[admin@MikroTik] > { :local interface "en1";
{... / interface print where name=$interface; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
... still looks ok.
We make a little modification to the script:
{ :local name "en1";
/ interface print where name=$name; }
And the result:
[admin@MikroTik] > { :local name "en1";
{... / interface print where name=$name; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
1 S en2 ether 1500 1598
2 S en3 ether 1500 1598
3 S en4 ether 1500 1598
4 S en5 ether 1500 1598
5 R br-local bridge 1500 1598
Ups! The filter has no effect!
That happens whenever the variable name ($name) matches the property
name (name=).
And another modification:
{ :local type "en1";
/ interface print where name=$type; }
And the result:
[admin@MikroTik] > { :local type "en1";
{... / interface print where name=$type; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
Ups! Nothing?
Even if the variable name ($type) matches whatever property name (type=)
things go wrong.
The answer from MikroTik support (in Ticket#2019010222000454):
> This is how scripting works in RouterOS and we will not fix it.
To get around this we use variable names in CamelCase. Let's hope
Mikrotik never ever introduces property names in CamelCase...
*fingers crossed*
2019-01-03 16:45:43 +00:00
|
|
|
:global SentRouterosUpdateNotification;
|
2018-07-05 13:29:26 +00:00
|
|
|
|
2019-09-12 11:45:44 +00:00
|
|
|
:global DeviceInfo;
|
2021-02-22 14:14:10 +00:00
|
|
|
:global LogPrintExit2;
|
2019-12-03 21:07:29 +00:00
|
|
|
:global ScriptFromTerminal;
|
2021-12-07 14:40:14 +00:00
|
|
|
:global ScriptLock;
|
2021-04-27 18:51:04 +00:00
|
|
|
:global SendNotification2;
|
2020-07-17 06:07:12 +00:00
|
|
|
:global SymbolForNotification;
|
2020-07-06 22:21:47 +00:00
|
|
|
:global VersionToNum;
|
2021-02-18 22:14:46 +00:00
|
|
|
:global WaitFullyConnected;
|
2018-10-09 13:53:27 +00:00
|
|
|
|
2019-07-24 08:59:53 +00:00
|
|
|
:local DoUpdate do={
|
2022-05-10 12:45:58 +00:00
|
|
|
:if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={
|
|
|
|
/system/script/run packages-update;
|
2019-02-21 17:03:51 +00:00
|
|
|
} else={
|
2022-05-10 12:45:58 +00:00
|
|
|
/system/package/update/install without-paging;
|
2019-02-21 17:03:51 +00:00
|
|
|
}
|
|
|
|
:error "Waiting for system to reboot.";
|
|
|
|
}
|
|
|
|
|
2021-12-07 14:40:14 +00:00
|
|
|
$ScriptLock $0;
|
|
|
|
|
2021-02-18 22:14:46 +00:00
|
|
|
$WaitFullyConnected;
|
|
|
|
|
2022-07-11 08:38:01 +00:00
|
|
|
:if ([ /interface/wireless/cap/get enabled ] = true && \
|
|
|
|
[ /caps-man/manager/get enabled ] = false && \
|
|
|
|
$SafeUpdateOnCap != true) do={
|
|
|
|
$LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true;
|
2018-07-05 13:29:26 +00:00
|
|
|
}
|
|
|
|
|
2022-05-10 12:45:58 +00:00
|
|
|
:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={
|
2020-01-16 15:11:50 +00:00
|
|
|
:error "A reboot for update is already scheduled.";
|
|
|
|
}
|
|
|
|
|
2021-04-26 14:33:41 +00:00
|
|
|
$LogPrintExit2 debug $0 ("Checking for updates...") false;
|
2022-05-10 12:45:58 +00:00
|
|
|
/system/package/update/check-for-updates without-paging as-value;
|
|
|
|
:local Update [ /system/package/update/get ];
|
2018-08-30 06:18:17 +00:00
|
|
|
|
2021-04-27 06:57:05 +00:00
|
|
|
:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={
|
2021-04-26 14:33:41 +00:00
|
|
|
$LogPrintExit2 info $0 ("System is already up to date.") true;
|
|
|
|
}
|
|
|
|
|
2020-07-07 06:55:49 +00:00
|
|
|
:local NumInstalled [ $VersionToNum ($Update->"installed-version") ];
|
|
|
|
:local NumLatest [ $VersionToNum ($Update->"latest-version") ];
|
2020-11-26 22:02:15 +00:00
|
|
|
:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree");
|
2020-07-06 22:21:47 +00:00
|
|
|
|
2022-07-18 21:46:49 +00:00
|
|
|
:if ($NumLatest < 117505792) do={
|
|
|
|
$LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true;
|
|
|
|
}
|
|
|
|
|
2020-07-07 06:55:49 +00:00
|
|
|
:if ($NumInstalled < $NumLatest) do={
|
|
|
|
:if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false;
|
2021-04-27 19:53:28 +00:00
|
|
|
$SendNotification2 ({ origin=$0; \
|
|
|
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
2021-04-27 18:51:04 +00:00
|
|
|
message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \
|
|
|
|
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
2020-07-06 22:21:47 +00:00
|
|
|
$DoUpdate;
|
|
|
|
}
|
|
|
|
|
2022-05-10 12:45:58 +00:00
|
|
|
:if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \
|
2020-11-01 20:48:03 +00:00
|
|
|
version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false;
|
2021-04-27 19:53:28 +00:00
|
|
|
$SendNotification2 ({ origin=$0; \
|
|
|
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
2021-04-27 18:51:04 +00:00
|
|
|
message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \
|
|
|
|
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
2020-11-01 20:48:03 +00:00
|
|
|
$DoUpdate;
|
|
|
|
}
|
|
|
|
|
global: variable names are CamelCase
___ _ ___ __
/ _ )(_)__ _ / _/__ _/ /_
/ _ / / _ `/ / _/ _ `/ __/
/____/_/\_, / /_/ \_,_/\__/
_ __ /___/ _ __
| | / /___ __________ (_)___ ____ _/ /
| | /| / / __ `/ ___/ __ \/ / __ \/ __ `/ /
| |/ |/ / /_/ / / / / / / / / / / /_/ /_/
|__/|__/\__,_/_/ /_/ /_/_/_/ /_/\__, (_)
/____/
RouterOS has some odd behavior when it comes to variable names. Let's
have a look at the interfaces:
[admin@MikroTik] > / interface print where name=en1
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
That looks ok. Now we use a script:
{ :local interface "en1";
/ interface print where name=$interface; }
And the result...
[admin@MikroTik] > { :local interface "en1";
{... / interface print where name=$interface; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
... still looks ok.
We make a little modification to the script:
{ :local name "en1";
/ interface print where name=$name; }
And the result:
[admin@MikroTik] > { :local name "en1";
{... / interface print where name=$name; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
0 RS en1 ether 1500 1598
1 S en2 ether 1500 1598
2 S en3 ether 1500 1598
3 S en4 ether 1500 1598
4 S en5 ether 1500 1598
5 R br-local bridge 1500 1598
Ups! The filter has no effect!
That happens whenever the variable name ($name) matches the property
name (name=).
And another modification:
{ :local type "en1";
/ interface print where name=$type; }
And the result:
[admin@MikroTik] > { :local type "en1";
{... / interface print where name=$type; }
Flags: D - dynamic, X - disabled, R - running, S - slave
# NAME TYPE ACTUAL-MTU L2MTU
Ups! Nothing?
Even if the variable name ($type) matches whatever property name (type=)
things go wrong.
The answer from MikroTik support (in Ticket#2019010222000454):
> This is how scripting works in RouterOS and we will not fix it.
To get around this we use variable names in CamelCase. Let's hope
Mikrotik never ever introduces property names in CamelCase...
*fingers crossed*
2019-01-03 16:45:43 +00:00
|
|
|
:if ([ :len $SafeUpdateUrl ] > 0) do={
|
|
|
|
:local Result;
|
2019-01-02 09:45:20 +00:00
|
|
|
:do {
|
2022-05-10 12:45:58 +00:00
|
|
|
:set Result [ /tool/fetch check-certificate=yes-without-crl \
|
2019-07-24 08:59:53 +00:00
|
|
|
($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \
|
|
|
|
"&latest=" . $Update->"latest-version") output=user as-value ];
|
2019-01-02 09:45:20 +00:00
|
|
|
} on-error={
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false;
|
2019-01-02 09:45:20 +00:00
|
|
|
}
|
2019-07-24 08:59:53 +00:00
|
|
|
:if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false;
|
2021-04-27 19:53:28 +00:00
|
|
|
$SendNotification2 ({ origin=$0; \
|
|
|
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
2021-04-27 18:51:04 +00:00
|
|
|
message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \
|
|
|
|
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
2019-07-24 08:59:53 +00:00
|
|
|
$DoUpdate;
|
2019-02-21 17:03:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-22 19:01:43 +00:00
|
|
|
:if ([ $ScriptFromTerminal $0 ] = true) do={
|
2019-07-24 08:59:53 +00:00
|
|
|
:put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]");
|
2022-05-10 12:45:58 +00:00
|
|
|
:if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
|
2019-07-24 08:59:53 +00:00
|
|
|
$DoUpdate;
|
2019-02-21 17:03:51 +00:00
|
|
|
} else={
|
|
|
|
:put "Canceled...";
|
2018-08-30 09:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-24 08:59:53 +00:00
|
|
|
:if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \
|
2020-03-05 08:08:57 +00:00
|
|
|
$Update->"latest-version" . ".") true;
|
2018-08-30 09:26:47 +00:00
|
|
|
}
|
|
|
|
|
2021-04-27 19:53:28 +00:00
|
|
|
$SendNotification2 ({ origin=$0; \
|
|
|
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
2021-04-27 18:51:04 +00:00
|
|
|
message=("A new RouterOS version " . ($Update->"latest-version") . \
|
2020-04-07 14:13:44 +00:00
|
|
|
" is available for " . $Identity . ".\n\n" . \
|
2021-04-27 18:51:04 +00:00
|
|
|
[ $DeviceInfo ]); link=$Link; silent=true });
|
2019-07-24 08:59:53 +00:00
|
|
|
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
2018-07-05 13:29:26 +00:00
|
|
|
}
|
2020-07-07 06:55:49 +00:00
|
|
|
|
|
|
|
:if ($NumInstalled > $NumLatest) do={
|
2020-07-07 07:05:06 +00:00
|
|
|
:if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \
|
2020-07-07 07:05:06 +00:00
|
|
|
$Update->"latest-version" . ".") true;
|
|
|
|
}
|
|
|
|
|
2021-04-27 19:53:28 +00:00
|
|
|
$SendNotification2 ({ origin=$0; \
|
|
|
|
subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \
|
2021-04-27 18:51:04 +00:00
|
|
|
message=("A different RouterOS version " . ($Update->"latest-version") . \
|
2020-07-07 06:55:49 +00:00
|
|
|
" is available for " . $Identity . ", but it is a downgrade.\n\n" . \
|
2021-04-27 18:51:04 +00:00
|
|
|
[ $DeviceInfo ]); link=$Link; silent=true });
|
2021-02-22 14:14:10 +00:00
|
|
|
$LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \
|
2020-07-07 07:04:40 +00:00
|
|
|
" is available for downgrade.") false;
|
2020-07-07 06:55:49 +00:00
|
|
|
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
|
|
|
}
|