diff --git a/README.md b/README.md index fae6986..ffbc27e 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,7 @@ Available scripts * [Renew certificates and notify on expiration](doc/check-certificates.md) * [Notify about health state](doc/check-health.md) * [Notify on LTE firmware upgrade](doc/check-lte-firmware-upgrade.md) +* [Check perpetual license on CHR](doc/check-perpetual-license.md) * [Notify on RouterOS update](doc/check-routeros-update.md) * [Collect MAC addresses in wireless access list](doc/collect-wireless-mac.md) * [Use wireless network with daily psk](doc/daily-psk.md) diff --git a/check-perpetual-license.rsc b/check-perpetual-license.rsc new file mode 100644 index 0000000..9a3a3c7 --- /dev/null +++ b/check-perpetual-license.rsc @@ -0,0 +1,78 @@ +#!rsc by RouterOS +# RouterOS script: check-perpetual-license +# Copyright (c) 2025 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.15 +# +# check perpetual license on CHR +# https://rsc.eworm.de/doc/check-perpetual-license.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:local ExitOK false; +:do { + :local ScriptName [ :jobname ]; + + :global Identity; + :global SentCertificateNotification; + + :global LogPrint; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; + :error false; + } + + $WaitFullyConnected; + + :local License [ /system/license/get ]; + :if ([ :typeof ($License->"deadline-at") ] != "str") do={ + $LogPrint info $ScriptName ("This device does not have a perpetual license."); + :set ExitOK true; + :error true; + } + + :if ([ :len ($License->"next-renewal-at") ] = 0 && ($License->"limited-upgrades") = true) do={ + $LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!"); + :if ($SentCertificateNotification != "expired") do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "warning-sign" ] . "License expired!"); \ + message=("Your license expired on " . ($License->"deadline-at") . \ + ", can no longer update RouterOS on " . $Identity . "...") }); + :set SentCertificateNotification "expired"; + } + :set ExitOK true; + :error true; + } + + :if ([ :totime ($License->"deadline-at") ] - 3w < [ :timestamp ]) do={ + $LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!"); + :if ($SentCertificateNotification != "warning") do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "warning-sign" ] . "License about to expire!"); \ + message=("Your license failed to renew and is about to expire on " . \ + ($License->"deadline-at") . " on " . $Identity . "...") }); + :set SentCertificateNotification "warning"; + } + :set ExitOK true; + :error true; + } + + :if ([ :typeof $SentCertificateNotification ] = "str" && \ + [ :totime ($License->"deadline-at") ] - 4w > [ :timestamp ]) do={ + $LogPrint info $ScriptName ("Your license was successfully renewed."); + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "License renewed"); \ + message=("Your license was successfully renewed on " . $Identity . \ + ". It is now valid until " . ($License->"deadline-at") . ".") }); + :set SentCertificateNotification; + } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 1a5a930..361be34 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -22,7 +22,6 @@ :global SafeUpdateNeighborIdentity; :global SafeUpdatePatch; :global SafeUpdateUrl; - :global SentCertificateNotification; :global SentRouterosUpdateNotification; :global DeviceInfo; @@ -67,43 +66,6 @@ :error "A reboot for update is already scheduled."; } - :local License [ /system/license/get ]; - :if ([ :typeof ($License->"deadline-at") ] = "str") do={ - :if ([ :len ($License->"next-renewal-at") ] = 0 && ($License->"limited-upgrades") = true) do={ - $LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!"); - :if ($SentCertificateNotification != "expired") do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "warning-sign" ] . "License expired!"); \ - message=("Your license expired on " . ($License->"deadline-at") . \ - ", can no longer update RouterOS on " . $Identity . "...") }); - :set SentCertificateNotification "expired"; - } - :set ExitOK true; - :error false; - } - - :if ([ :totime ($License->"deadline-at") ] - 3w < [ :timestamp ]) do={ - $LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!"); - :if ($SentCertificateNotification != "warning") do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "warning-sign" ] . "License about to expire!"); \ - message=("Your license failed to renew and is about to expire on " . \ - ($License->"deadline-at") . " on " . $Identity . "...") }); - :set SentCertificateNotification "warning"; - } - } - - :if ([ :typeof $SentCertificateNotification ] = "str" && \ - [ :totime ($License->"deadline-at") ] - 4w > [ :timestamp ]) do={ - $LogPrint info $ScriptName ("Your license was successfully renewed."); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "License renewed"); \ - message=("Your license was successfully renewed on " . $Identity . \ - ". It is now valid until " . ($License->"deadline-at") . ".") }); - :set SentCertificateNotification; - } - } - $LogPrint debug $ScriptName ("Checking for updates..."); /system/package/update/check-for-updates without-paging as-value; :local Update [ /system/package/update/get ]; diff --git a/doc/check-perpetual-license.d/notification.avif b/doc/check-perpetual-license.d/notification.avif new file mode 100644 index 0000000..70ca603 Binary files /dev/null and b/doc/check-perpetual-license.d/notification.avif differ diff --git a/doc/check-perpetual-license.md b/doc/check-perpetual-license.md new file mode 100644 index 0000000..d444004 --- /dev/null +++ b/doc/check-perpetual-license.md @@ -0,0 +1,70 @@ +Check perpetual license on CHR +============================== + +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + +[⬅️ Go back to main README](../README.md) + +> ℹ️ **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. + +Description +----------- + +On *Cloud Hosted Router* (*CHR*) the licensing is perpetual: Buy once, use +forever - but it needs regular renewal. This script checks licensing state +and sends a notification to warn before expiration. + +### Sample notification + +![check-perpetual-license notification](check-perpetual-license.d/notification.avif) + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate check-perpetual-license; + +And add a scheduler for automatic update notification: + + /system/scheduler/add interval=1d name=check-perpetual-license on-event="/system/script/run check-perpetual-license;" start-time=startup; + +Configuration +------------- + +No extra configuration is required for this script, but notification +settings are required for +[e-mail](mod/notification-email.md), +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or +[telegram](mod/notification-telegram.md). + +Usage and invocation +-------------------- + +Be notified when run from scheduler or run it manually: + + /system/script/run check-perpetual-license; + +Tips & Tricks +------------- + +The script checks for full connectivity before acting, so scheduling at +startup is perfectly valid: + + /system/scheduler/add name=check-perpetual-license@startup on-event="/system/script/run check-perpetual-license;" start-time=startup; + +See also +-------- + +* [Notify on RouterOS update](check-routeros-update.md) + +--- +[⬅️ Go back to main README](../README.md) +[⬆️ Go back to top](#top) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 926b4aa..b6c716c 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -99,6 +99,7 @@ startup is perfectly valid: See also -------- +* [Check perpetual license on CHR](check-perpetual-license.md) * [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) * [Manage system update](packages-update.md) diff --git a/global-functions.rsc b/global-functions.rsc index 8ae7bb8..8ade79b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -15,7 +15,7 @@ # Git commit id & info, expected configuration version :global CommitId "unknown"; :global CommitInfo "unknown"; -:global ExpectedConfigVersion 135; +:global ExpectedConfigVersion 136; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 459326f..55b4165 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -60,6 +60,7 @@ 133="Updated the default configuration for 'fw-addr-lists', deprecated lists were removed, a collective list was added."; 134="Enhanced 'mod/notification-telegram' and 'telegram-chat' to support topics in groups."; 135="Introduced helper function '\$GetTelegramChatId' for 'mod/notification-telegram' which helps retrieve information."; + 136="Introduced script 'check-perpetual-license' to check for license state on CHR."; }; # Migration steps to be applied on script updates