From 5f46ef7635f27f6180898815cebd954617790b37 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 23 Mar 2020 12:21:38 +0100 Subject: completely replace script-updates with $ScriptInstallUpdate --- INITIAL-COMMANDS.md | 2 +- README.md | 8 +-- global-config | 2 +- global-config-overlay | 4 +- global-config.changes | 3 +- global-functions | 136 ++++++++++++++++++++++++++++++++++++++++++++++++-- script-updates | 132 +----------------------------------------------- 7 files changed, 142 insertions(+), 145 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index d7625c0..2f2b7b1 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -19,7 +19,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :error "Something is wrong with your certificates!"; } / file remove "letsencrypt.pem"; - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } / system script { run global-config; run global-config-overlay; run global-functions; } diff --git a/README.md b/README.md index 15b33ab..52d5a1b 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ crap and a good example how to *not* do it. Now let's download the main scripts and add them in configuration on the fly. - [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } + [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } The configuration needs to be tweaked for your needs. Make sure not to send your mails to `mail@example.com`! Edit `global-config-overlay`, copy @@ -101,11 +101,7 @@ And finally load configuration and functions and add the scheduler. Updating scripts ---------------- -To update existing scripts just run `script-updates`. - - [admin@MikroTik] > / system script run script-updates - -Calling function `$ScriptInstallUpdate` does the same. +To update existing scripts just run function `$ScriptInstallUpdate`. [admin@MikroTik] > $ScriptInstallUpdate diff --git a/global-config b/global-config index 46c07b8..1ad8393 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 13; +:global GlobalConfigVersion 14; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index b6a983f..90740cd 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -7,9 +7,9 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 13; +:global GlobalConfigVersion 14; -# The global-config script is updated by script-updates, +# The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. :global ScriptUpdatesIgnore { "global-config-overlay" diff --git a/global-config.changes b/global-config.changes index 6df7cfd..38c23a4 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,7 +1,7 @@ # RouterOS global-config changes # Copyright (c) 2019-2020 Christian Hesse -# Changes for global-config to be added to notification on script-updates +# Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { 1="moved variables from 'global-config' to 'global-functions' for independence"; 2="variable names became CamelCase to work around scripting issues"; @@ -16,4 +16,5 @@ 11="introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; 12="removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; 13="configuration for script 'bridge-port-to-default' changed with new syntax in comment"; + 14="dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; }; diff --git a/global-functions b/global-functions index 3187036..1aa64d2 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 13; +:global ExpectedConfigVersion 14; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -378,13 +378,143 @@ :set ScriptInstallUpdate do={ :local Scripts [ :toarray $1 ]; + :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=$Scripts do={ :if ([ / system script print count-only where name=$Script ] = 0) do={ - :log info ("Adding new script: " . $Script); + $LogPrintExit info ("Adding new script: " . $Script) false; / system script add name=$Script source="#!rsc"; } } - / system script run script-updates; + + :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 && \ + !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ + $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ + "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") 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; + } } # lock script against multiple invocation diff --git a/script-updates b/script-updates index 38165c9..7604cb4 100644 --- a/script-updates +++ b/script-updates @@ -1,136 +1,6 @@ #!rsc # RouterOS script: script-updates -# Copyright (c) 2013-2020 Christian Hesse -# -# 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 && \ - !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ - $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ - "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") 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; -} +$LogPrintExit warning "This script has been replaced by function '\$ScriptInstallUpdate'." true; -- cgit v1.2.3-54-g00ecf