aboutsummaryrefslogtreecommitdiffstats
path: root/script-updates
blob: 38165c93b17dc391b0d0b2ab310499e518d872c8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!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 && \
         !(($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;
}