#!rsc # RouterOS script: script-updates # Copyright (c) 2013-2020 Christian Hesse <mail@eworm.de> # # update installed scripts from file or url :global ExpectedConfigVersion; :global GlobalConfigVersion; :global Identity; :global IDonate; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesFetch; :global ScriptUpdatesIgnore; :global ScriptUpdatesUrlSuffix; :global SentConfigChangesNotification; :global LogPrintExit; :global SendNotification; :foreach Script in=[ / system script find where source~"^#!rsc" or source="" ] do={ :local Ignore 0; :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; :local SourceNew; :if ([ :len $ScriptFile ] > 0) do={ :set SourceNew [ / file get $ScriptFile content ]; / file remove $ScriptFile; } :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ / system scheduler get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ " and its scheduler " . $SchedulerVal->"name" . "!") false; } :if ($SchedulerVal->"name" != "global-scripts" && \ $SchedulerVal->"start-time" = "startup" && \ $SchedulerVal->"interval" = 0s && \ [ :pick ($SchedulerVal->"on-event") 0 7 ] != ":delay ") do={ $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ "without interval. Add delay to make sure the configuration is available!") false; } } :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ :if ($IgnoreLoop = $ScriptVal->"name") do={ :set Ignore 1; } } :if ($Ignore = 0) do={ $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . $ScriptVal->"name" . $ScriptUpdatesUrlSuffix) \ output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } } on-error={ $LogPrintExit warning ("Failed fetching " . $ScriptVal->"name") false; } } } :if ([ :len $SourceNew ] > 0) do={ :if ([ :pick $SourceNew 0 5 ] = "#!rsc") do={ :if ($SourceNew != $ScriptVal->"source") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); $LogPrintExit info ("Updating script: " . $ScriptVal->"name") false; / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config" && \ [ / system script print count-only where name="global-config-overlay" ] > 0) do={ / system script { run global-config; run global-config-overlay; } } :if ($ScriptVal->"name" = "global-functions") do={ / system script run global-functions; } } else={ $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; } } else={ $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; } } else={ $LogPrintExit debug ("No update for script " . $ScriptVal->"name" . ".") false; } } :if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :local ChangeLogCode; :local ConfigScript "global-config"; :if ([ /system script print count-only where name="global-config-overlay" ] > 0) do={ :set ConfigScript "global-config-overlay"; } :local NotificationMessage ("Current configuration on " . $Identity . \ " is out of date. Please update " . $ConfigScript . ", then increase " . \ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); $LogPrintExit debug ("Fetching changelog.") false; :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); [ :parse $ChangeLogCode ]; :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ :set NotificationMessage ($NotificationMessage . \ "\n * " . $GlobalConfigChanges->[ :tostr $I ]); } :set GlobalConfigChanges; } on-error={ $LogPrintExit warning ("Failed fetching changes!") false; :set NotificationMessage ($NotificationMessage . \ "\n\nChanges are not available."); } :if ($IDonate != true) do={ :set NotificationMessage ($NotificationMessage . \ "\n\n==== donation hint ====\n" . \ "This project is developed in private spare time and usage is " . \ "free of charge for you. If you like the scripts and think this is " . \ "of value for you or your business please consider a donation:\n" . \ "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); } $SendNotification "Configuration warning!" $NotificationMessage; :set SentConfigChangesNotification $ExpectedConfigVersion; }