aboutsummaryrefslogtreecommitdiffstats
path: root/packages-update.rsc
blob: 924a5d969f63fb893e21d1322d7b619fdf131497 (about) (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!rsc by RouterOS
# RouterOS script: packages-update
# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de>
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
#
# requires RouterOS, version=7.14
#
# download packages and reboot for installation
# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md

:global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }

:local ExitOK false;
:do {
  :local ScriptName [ :jobname ];

  :global DownloadPackage;
  :global Grep;
  :global LogPrint;
  :global ParseKeyValueStore;
  :global ScriptFromTerminal;
  :global ScriptLock;
  :global VersionToNum;

  :global PackagesUpdateDeferReboot;
  :global PackagesUpdateBackupFailure;

  :local Schedule do={
    :local ScriptName [ :tostr $1 ];

    :global GetRandomNumber;
    :global LogPrint;

    :global RebootForUpdate do={
      /system/reboot;
    }

    :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ];
    /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \
        on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \
        ":global RebootForUpdate; \$RebootForUpdate;");
    $LogPrint info $ScriptName ("Scheduled reboot for update at " . $StartTime . \
        " local time (" . [ /system/clock/get time-zone-name ] . ").");
    :return true;
  }

  :if ([ $ScriptLock $ScriptName ] = false) do={
    :set ExitOK true;
    :error false;
  }

  :local Update [ /system/package/update/get ];

  :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={
    $LogPrint warning $ScriptName ("Latest version is not known.");
    :set ExitOK true;
    :error false;
  }

  :if ($Update->"installed-version" = $Update->"latest-version") do={
    $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is already installed.");
    :set ExitOK true;
    :error true;
  }

  :local RunOrder ({});
  :foreach Script in=[ /system/script/find where source~("\n# provides: backup-script\\b") ] do={
    :local ScriptVal [ /system/script/get $Script ];
    :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: backup-script, ") ] ];

    :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name");
  }

  :foreach Order,Script in=$RunOrder do={
    :set PackagesUpdateBackupFailure false;
    :do {
      $LogPrint info $ScriptName ("Running backup script " . $Script . " before update.");
      /system/script/run $Script;
    } on-error={
      :set PackagesUpdateBackupFailure true;
    }

    :if ($PackagesUpdateBackupFailure = true) do={
      $LogPrint warning $ScriptName ("Running backup script " . $Script . " before update failed!");
      :if ([ $ScriptFromTerminal $ScriptName ] = true) do={
        :put "Do you want to continue anyway? [y/N]";
        :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
          $LogPrint info $ScriptName ("User requested to continue anyway.");
        } else={
          $LogPrint info $ScriptName ("Canceled update...");
          :set ExitOK true;
          :error false;
        }
      } else={
        $LogPrint warning $ScriptName ("Canceled non-interactive update.");
        :set ExitOK true;
        :error false;
      }
    }
  }

  :local NumInstalled [ $VersionToNum ($Update->"installed-version") ];
  :local NumLatest [ $VersionToNum ($Update->"latest-version") ];

  :local DoDowngrade false;
  :if ($NumInstalled > $NumLatest) do={
    :if ([ $ScriptFromTerminal $ScriptName ] = true) do={
      :put "Latest version is older than installed one. Want to downgrade? [y/N]";
      :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
        :set DoDowngrade true;
      } else={
        :put "Canceled...";
      }
    } else={
      $LogPrint warning $ScriptName ("Not installing downgrade automatically.");
      :set ExitOK true;
      :error false;
    }
  }

  :foreach Package in=[ /system/package/find where !bundle ] do={
    :local PkgName [ /system/package/get $Package name ];
    :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={
      $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted.");
      :set ExitOK true;
      :error false;
    }
  }

  :if ($DoDowngrade = true) do={
    $LogPrint info $ScriptName ("Rebooting for downgrade.");
    :delay 1s;
    /system/package/downgrade;
  }

  :if ([ $ScriptFromTerminal $ScriptName ] = true) do={
    :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]";
    :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={
      $Schedule $ScriptName;
      :set ExitOK true;
      :error true;
    }
  } else={
    :if ($PackagesUpdateDeferReboot = true) do={
      $Schedule $ScriptName;
      :set ExitOK true;
      :error true;
    }
  }

  $LogPrint info $ScriptName ("Rebooting for update.");
  :delay 1s;
  /system/reboot;
} on-error={
  :global ExitError; $ExitError $ExitOK [ :jobname ];
}