forked from svlsResearch/ha-mikrotik
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HA_init.rsc
620 lines (620 loc) · 31.2 KB
/
HA_init.rsc
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
:do {
/system script
remove [find name=ha_checkchanges_new]
add name=ha_checkchanges_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":if ([:len [/system script job find where script=\"ha_checkchanges\"]] > 1) do={:error \"already running checkchanges\"; }\
\n:global isMaster\
\n:global isStandbyInSync\
\n:global haPassword\
\n:global haAddressOther\
\n:global haCheckLastCheckTS \"\$[/system clock get date] \$[/system clock get time] \$[/system clock get time-zone-name]\"\
\n:global haCheckStandbyVer\
\n:global haCheckMasterVer\
\n:do {\
\n :if (\$isMaster) do={\
\n /file print file=HA_get-version.txt; /file set [find name=\"HA_get-version.txt\"] contents=\":global haConfigVer\\n[:put \\\"XXX \\\$haConfigVer YYYY\\\"]\\n\"\
\n /tool fetch upload=yes src-path=HA_get-version.txt dst-path=HA_get-version.auto.rsc address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n /file remove [find name=\"HA_standby-haConfigVer.txt\"]\
\n /tool fetch upload=no src-path=HA_get-version.auto.log dst-path=HA_standby-haConfigVer.txt address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n :local haCheckStandbyVerTmp [/file get [find name=\"HA_standby-haConfigVer.txt\"] contents]\
\n :local xxxOffset [:find \$haCheckStandbyVerTmp \"XXX \"]\
\n :local yyyOffset [:find \$haCheckStandbyVerTmp \" YYYY\"]\
\n #Safety check that auto is running.\
\n :if (([:typeof \$xxxOffset] = \"nil\") || ([:typeof \$yyyOffset] = \"nil\")) do={\
\n :put \"ha_checkchanges: unable to find xxx/yyy! is auto working on this platform? xxxOffset: \$xxxOffset yyyOffset: \$yyyOffset\"\
\n :error \"ha_checkchanges: unable to find xxx/yyy! is auto working on this platform? xxxOffset: \$xxxOffset yyyOffset: \$yyyOffset \$haCheckStandbyVerTmp\"\
\n }\
\n :global haCheckStandbyVer [:pick \$haCheckStandbyVerTmp (\$xxxOffset+4) \$yyyOffset]\
\n :global haMasterConfigVer\
\n [/system script run [find name=\"ha_setconfigver\"]]\
\n :global haCheckMasterVer \$haMasterConfigVer\
\n /file remove [find name=\"HA_standby-haConfigVer.txt\"]\
\n :put \"MASTER VERSION: ! \$haCheckMasterVer !\"\
\n :put \"STANDB VERSION: ! \$haCheckStandbyVer !\"\
\n :if (\$haCheckStandbyVer != \$haCheckMasterVer) do={\
\n :put \"NEED TO PUSH\"\
\n :global isStandbyInSync false\
\n /system script run [find name=\"ha_pushbackup\"]\
\n } else={\
\n :global isStandbyInSync true\
\n :put \"GOOD\"\
\n }\
\n }\
\n} on-error={\
\n :put \"GOT ERROR\"\
\n :global isStandbyInSync false\
\n}\
\n"
remove [find name=ha_config_new]
add name=ha_config_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source="/system script run [find name=\"ha_config_base\"]\
\n:global haNetwork \"169.254.23.0\"\
\n:global haNetmask \"255.255.255.0\"\
\n:global haNetmaskBits \"24\"\
\n:global haAddressA \"169.254.23.1\"\
\n:global haAddressB \"169.254.23.2\"\
\n:global haAddressVRRP \"169.254.23.10\"\
\n"
remove [find name=ha_functions_new]
add name=ha_functions_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":global HADebug do={\
\n :put \$1\
\n /log warning \$1\
\n}\
\n\
\n:global HAPushStandby do={\
\n /system script run [find name=\"ha_pushbackup\"]\
\n}\
\n\
\n:global HASyncStandby do={\
\n /system script run [find name=\"ha_checkchanges\"]\
\n}\
\n\
\n:global HAInstall do={\
\n #\$HAInstall interface=\"ether8\" macA=\"E1:81:8C:35:13:8C\" macB=\"E1:81:8C:35:10:08\" password=\"a25d89ba41236c40726ff9e7ffee1d202992f61c\"\
\n :if ([:typeof \$interface] = \"nothing\") do={:error \"interface missing\"};\
\n :if ([:typeof \$macA] = \"nothing\") do={:error \"macA missing\"};\
\n :if ([:typeof \$macB] = \"nothing\") do={:error \"macB missing\"};\
\n :if ([:typeof \$password] = \"nothing\") do={:error \"password missing\"};\
\n /system script remove [find name=ha_config_base]\
\n /system script add name=ha_config_base owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=\":global haPassword \\\"\$password\\\"\\\
\n \\n:global haInterface \\\"\$interface\\\"\\\
\n \\n:global haMacA \\\"\$macA\\\"\\\
\n \\n:global haMacB \\\"\$macB\\\"\\\
\n \\n:global haPreferMac \\\"\\\"\"\
\n /system script run [find name=\"ha_install\"]\
\n}\
\n\
\n:global HASwitchRole do={\
\n /system script run [find name=\"ha_switchrole\"]\
\n}\
\n\
\n:global HALoopPushStandby do={\
\n /system script run [find name=\"ha_loop_push_standby\"]\
\n}\
\n"
remove [find name=ha_install_new]
add name=ha_install_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source="/system script run [find name=\"ha_config\"]\
\n:global haPassword\
\n:global haInterface\
\n:global haMacA\
\n:global haMacB\
\n:global haNetmaskBits\
\n:global haAddressOther\
\n:global isMaster\
\n:global haMacOther\
\n\
\n:if ([:len [/interface find where default-name=\"\$haInterface\" name=\"\$haInterface\"]] != 1) do={\
\n :error \"Unable to find interface named \$haInterface with default-name that matches name. Make sure you don't rename these interfaces, leave default-name as-is.\"\
\n}\
\n\
\n:local mac [[/interface ethernet get [find default-name=\"\$haInterface\"] orig-mac-address]]\
\n:if (\$mac != \$haMacA and \$mac != \$haMacB) do={\
\n :error \"Interface \$haInterface MAC \$mac does not match (A=\$haMacA or B=\$haMacB) - please check config\\r\\nUse orig-mac address!\"\
\n}\
\n\
\n:local pingMac \$haMacA\
\n:if (\$mac = \$haMacA) do={\
\n :set pingMac \$haMacB\
\n}\
\n\
\n:put \$mac\
\n:put \$pingMac\
\n\
\n:if ([/ping \$pingMac count=1] = 0) do={\
\n :error \"Are you sure the other device is configured properly? I am unable to ping MAC \$pingMac\"\
\n}\
\n\
\n:if ([:len [/ip address find where interface=\"\$haInterface\" and comment!=\"HA_AUTO\"]] > 0) do={\
\n :error \"Interface \$haInterface has IP addresses. HA should completely own the interface and it cannot be used by anything else. Please correct\"\
\n}\
\n\
\n:if ([:len [/file find name=HA_backup_beforeHA.backup]] = 0) do={\
\n system backup save name=HA_backup_beforeHA dont-encrypt=yes\
\n /export file=HA_backup_beforeHA.rsc\
\n}\
\n\
\n:if (!\$isMaster) do={\
\n :put \"I am not master - running ha_startup first\"\
\n :global haAllowBootstrap\
\n :set haAllowBootstrap true\
\n /system script run \"ha_startup\"\
\n} else={\
\n :put \"I am already master! Skipping my own bootstrap...\"\
\n}\
\n\
\n:put \"###\"\
\n:put \"#Maybe try: /tool mac-telnet \$haMacOther\"\
\n:put \"###PASTE THIS ON THE OTHER DEVICE - YOUR CONFIG WILL BE RESET AND LOST!!!###\"\
\n:put \":global mac [[/interface ethernet get [find default-name=\\\"\$haInterface\\\"] orig-mac-address]]\"\
\n:put \":if (\\\$mac != \\\"\$haMacA\\\" and \\\$mac != \\\"\$haMacB\\\") do={\"\
\n:put \" :error \\\"Interface \$haInterface MAC \\\$mac does not match (A=\$haMacA or B=\$haMacB) - please check config\\\\r\\\\nUse orig-mac address!\\\"\"\
\n:put \"}\"\
\n#Try to backup the local device before HA, just in case.\
\n:put \":if ([:len [/file find name=HA_backup_beforeHA.backup]] = 0) do={\"\
\n:put \" /system backup save name=HA_backup_beforeHA dont-encrypt=yes\"\
\n:put \" /export file=HA_backup_beforeHA.rsc\"\
\n:put \"}\"\
\n#Oh this is ridicullous, we can't create a file that doesn't end in .txt any other way. Use export to create a rsc file extension.\
\n:put \"/export file=HA_bootstrap.rsc\"\
\n#Seems to be a race condition between the export and the visibility, delay a bit.\
\n:put \"/delay 2\"\
\n:put \"/file print file=HA_bootstrap.rsc\"\
\n#Need delays here similar to ha_startup, sometimes the interfaces arent ready when this runs.\
\n:put \"/file set [find name=HA_bootstrap.rsc] contents=\\\":local haBootstrapOK false; :while (!\\\\\\\$haBootstrapOK) do={:do { /ip address add address=\\\\\\\"\$haAddressOther/\$haNetmaskBits\\\\\\\" interface=\$haInterface; /user add name=ha group=full password=\\\\\\\"\$haPassword\\\\\\\"; :set haBootstrapOK true;} on-error={/log warning \\\\\\\"ha_startup: 0.0 B bootstrap failed...waiting\\\\\\\"; :delay 5};}\\\"\"\
\n:put \"/system reset-configuration no-defaults=yes keep-users=no skip-backup=yes run-after-reset=HA_bootstrap.rsc\"\
\n:put \"###END OF PASTE FOR OTHER DEVICE###\"\
\n:put \"###\"\
\n"
remove [find name=ha_loop_push_standby_new]
add name=ha_loop_push_standby_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source="#Debugging stress test tool for new RouterOS testing\
\n###Helper note for testing (disable automatic schedule, import, loop push):\
\n# /system scheduler disable [find name=\"ha_checkchanges\"]; /system scheduler disable [find name=\"ha_auto_pushbackup\"]; \$HALoopPushStandby\
\n###\
\n:for pushCount from=1 to=10000 do={\
\n :put \"\$pushCount pushing\"\
\n /system script run [find name=\"ha_pushbackup\"]\
\n :put \"\$pushCount push done\"\
\n :delay 200\
\n /system script run [find name=\"ha_checkchanges\"]\
\n :put \"\$pushCount sync ok\"\
\n :delay 10\
\n}\
\n"
remove [find name=ha_onbackup_new]
add name=ha_onbackup_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":global isMaster false\
\n:global haNetmaskBits\
\n:global haInterface\
\n/interface ethernet disable [find default-name!=\"\$haInterface\"]\
\n:execute \"ha_setidentity\"\
\n:do { :local k [/system script find name=\"on_backup\"]; if ([:len \$k] = 1) do={ /system script run \$k } } on-error={ :put \"on_backup failed\" }\
\n"
remove [find name=ha_onmaster_new]
add name=ha_onmaster_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":global isMaster true\
\n:global haNetmaskBits\
\n:global haInterface\
\n/interface ethernet enable [find]\
\n:execute \"ha_setidentity\"\
\n:do { :local k [/system script find name=\"on_master\"]; if ([:len \$k] = 1) do={ /system script run \$k } } on-error={ :put \"on_master failed\" }\
\n"
remove [find name=ha_pushbackup_new]
add name=ha_pushbackup_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":if ([:len [/system script job find where script=\"ha_pushbackup\"]] > 1) do={:error \"already running pushbackup\"; }\
\n:global haPassword\
\n:global isMaster\
\n:global haAddressOther\
\n:if (!\$isMaster) do={\
\n :error \"NOT MASTER\"\
\n} else={\
\n #Really? this is the only way to create directories?\
\n :local mkdirCode \":do { /ip smb shares add comment=HA_AUTO name=mkdir disabled=yes directory=/skins } on-error={}\"\
\n\
\n :foreach k in=[/file find type=\"directory\"] do={\
\n :local xferfile [/file get \$k name]\
\n if ([:pick \"\$xferfile\" 0 3] != \"HA_\") do={\
\n :set mkdirCode \"\$mkdirCode\\r\\n/ip smb shares set [find comment=HA_AUTO] directory=\\\"\$xferfile\\\"\"\
\n }\
\n }\
\n\
\n :set mkdirCode \"\$mkdirCode\\r\\n/ip smb shares remove [find comment=HA_AUTO]\\r\\n\"\
\n #eh - good chance to keep files in sync, just delete everything, we will reupload. is this going to reduce life of nvram?\
\n :local purgeFilesCode \":foreach k in=[/file find type!=\\\"directory\\\"] do={ :local xferfile [/file get \\\$k name]; if ([:pick \\\"\\\$xferfile\\\" 0 3] != \\\"HA_\\\") do={ :put \\\"removing \\\$xferfile\\\"; /file remove \\\$k; } }\"\
\n :set mkdirCode \"\$purgeFilesCode;\\r\\n/delay 2;\\r\\n\$mkdirCode\"\
\n\
\n /file print file=HA_mkdirs.txt\
\n /file set [find name=\"HA_mkdirs.txt\"] contents=\$mkdirCode\
\n :put \"mkdirCode: \$mkdirCode end_mkDirCode\"\
\n /tool fetch upload=yes src-path=HA_mkdirs.txt dst-path=HA_mkdirs.auto.rsc address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n \
\n :foreach k in=[/file find type!=\"directory\"] do={\
\n :local xferfile [/file get \$k name]\
\n if ([:pick \"\$xferfile\" 0 3] != \"HA_\") do={\
\n :put \"Transferring: \$xferfile\"\
\n :do {\
\n /tool fetch upload=yes src-path=\$xferfile dst-path=\$xferfile address=\$haAddressOther user=ha password=\$haPassword mode=ftp\
\n } on-error={\
\n :put \"Failed to transfer \$xferfile\"\
\n }\
\n }\
\n }\
\n\
\n :if ([:len [/file find name=HA_dsa]] <= 0) do={ \
\n /ip ssh export-host-key key-file-prefix=\"HA\"\
\n }\
\n\
\n /tool fetch upload=yes src-path=HA_dsa dst-path=HA_dsa address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n /tool fetch upload=yes src-path=HA_rsa dst-path=HA_rsa address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n\
\n\
\n :global haMasterConfigVer\
\n [/system script run [find name=\"ha_setconfigver\"]]\
\n /file print file=HA_run-after-hastartup.txt\
\n /file set [find name=HA_run-after-hastartup.txt] contents=\":global haConfigVer \\\"\$haMasterConfigVer\\\"\"\
\n /tool fetch upload=yes src-path=HA_run-after-hastartup.txt dst-path=HA_run-after-hastartup.rsc address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n\
\n /export file=HA_b2s.rsc\
\n /system backup save name=HA_b2s.backup password=p\
\n /tool fetch upload=yes src-path=HA_b2s.rsc dst-path=HA_b2s.rsc address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n /tool fetch upload=yes src-path=HA_b2s.backup dst-path=HA_b2s.backup address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n /file print file=HA_restore-backup.rsc; /file set [find name=\"HA_restore-backup.rsc.txt\"] contents=\"/system backup load name=HA_b2s.backup password=p\"\
\n :do {\
\n /tool fetch upload=yes src-path=HA_restore-backup.rsc.txt dst-path=HA_restore-backup.auto.rsc address=\$haAddressOther user=ha password=\$haPassword mode=ftp \
\n } on-error={\
\n :put \"OK - status failed is OK from last fetch, standby is rebooting.\"\
\n }\
\n}\
\n"
remove [find name=ha_report_startup_new]
add name=ha_report_startup_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source="#Attempt to kick the timing clients into a forced update so we get accurate timestamps to syslog on the report.\
\n:do {/ip cloud force-update} on-error={};\
\n:if ([/system ntp client get enabled]) do={\
\n /system ntp client set enabled=no\
\n :delay 16\
\n /system ntp client set enabled=yes\
\n}\
\n\
\n:delay 65\
\n\
\n:local badCount [:len [/log find where message~\"ha_startup.*(FAILED)\"]]\
\n:local goodCount [:len [/log find where message~\"ha_startup.*(DONE)\"]]\
\n:local delay1Count [:len [/log find where message~\"ha_startup.*(delaying1)\"]]\
\n:local delay2Count [:len [/log find where message~\"ha_startup.*(delaying2)\"]]\
\n:local uptime [/system resource get uptime]\
\n:local routerVersion [/system resource get version]\
\n:local firmwareVersion [/system routerboard get current-firmware]\
\n\
\n:global isMaster\
\n:global haStartupHasRun\
\n:global haStartupHAVersion\
\n:global haInitTries\
\n:global haPreferMac\
\n/log info \"ha_startup: ha_report_startup debug version=\$routerVersion firmware=\$firmwareVersion badC=\$badCount goodC=\$goodCount delay1C=\$delay1Count delay2C=\$delay2Count uptime=\$uptime isMaster=\$isMaster haPreferMac=\$haPreferMac haInitTries=\$haInitTries haStartupHasRun=\$haStartupHasRun haStartupHAVersion=\$haStartupHAVersion\"\
\n:execute \"/log print\" file=\"HA_boot_log.txt\"\
\n\
\n#Debugging helper for spinning reboots of the standby - you probably don't want to mess with this.\
\n:if (false) do={\
\n :if (\$isMaster) do={\
\n #Just because we are master doesnt mean we really are, we could have a failed startup but it is too risky to do anything else.\
\n :put \"I am master - do nothing\"\
\n } else={\
\n :if (\$goodCount = 1) do={\
\n :put \"REBOOT\"\
\n /system reboot\
\n } else={\
\n :put \"STAY\"\
\n #Disable all interfaces if they havent already, so the primary doesnt sneak in and we lose the failed state.\
\n /interface ethernet disable [find]\
\n }\
\n }\
\n}\
\n"
remove [find name=ha_setconfigver_new]
add name=ha_setconfigver_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":local verHistory [:tostr [:pick [/system history print detail as-value] 1]]\
\n:local verCertificate [:tostr [/certificate find]]\
\n:local verFile [:tostr [/file find name~\"^[^H][^A][^_]\"]]\
\n:local haVer \"history=\$verHistory file=\$verFile certificate=\$verCertificate\"\
\n:global haMasterConfigVer \$haVer\
\n"
remove [find name=ha_setidentity_new]
add name=ha_setidentity_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":global haIdentity\
\n:global isMaster\
\n:local sysIdentity [/system identity get name]\
\n:local haPos [:find \$sysIdentity \"_HA_\" 0]\
\nif (\$haPos > 0) do={\
\n :set sysIdentity [:pick \$sysIdentity 0 \$haPos]\
\n}\
\n:if (\$isMaster) do={\
\n /system identity set name=\"\$sysIdentity_HA_\$haIdentity_ACTIVE\"\
\n} else={\
\n /system identity set name=\"\$sysIdentity_HA_\$haIdentity_STANDBY\"\
\n}\
\n"
remove [find name=ha_startup_new]
add name=ha_startup_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source="#:do {\
\n#Prevent double running of the startup. Is there a bug in the scheduler? It seems that sometimes our start-time=startup ha_startup\
\n#fires again on newer versions of RouterOS.\
\n:global haAllowBootstrap\
\n:global haStartupHasRun\
\n:global uptime [/system resource get uptime]\
\n:if (!\$haAllowBootstrap && ([:typeof \$haStartupHasRun] != \"nothing\" || uptime > 2m)) do={\
\n /log warning \"ha_startup: ERROR ATTEMPTED TO RUN AGAIN!!! \$haStartupHasRun \$uptime\"\
\n :error \"ha_startup: ERROR ATTEMPTED TO RUN AGAIN!!! \$haStartupHasRun \$uptime\"\
\n} else={\
\n:set haStartupHasRun [/system resource get uptime]\
\n:set haAllowBootstrap false\
\n:execute \"/interface print detail\" file=\"HA_boot_interface_print.txt\"\
\n/log warning \"ha_startup: START\"\
\n/system script run [find name=ha_functions]\
\n/log warning \"ha_startup: 0.1\"\
\n/system script run [find name=\"ha_config\"]\
\n/log warning \"ha_startup: 0.2\"\
\n:global haInterface\
\n#Sometimes the hardware isn't initialized by the time we get here. Wait until we can see the interface.\
\n#https://github.com/svlsResearch/ha-mikrotik/issues/1\
\n:while ([:len [/interface find where name=\"\$haInterface\"]] != 1) do={\
\n /log error \"ha_startup: delaying1 for hardware...cant find \$haInterface\"\
\n :delay .1\
\n}\
\n/log warning \"ha_startup: 0.3\"\
\n/interface ethernet disable [find]\
\n:global haStartupHAVersion \"0.7test14 - 8cc3b3dee70854ad2676fc2b73922b07d8c64019\"\
\n:global isStandbyInSync false\
\n:global isMaster false\
\n:global haPassword\
\n:global haMacA\
\n:global haMacB\
\n:global haAddressA\
\n:global haAddressB\
\n:global haAddressVRRP\
\n:global haNetmask\
\n:global haNetmaskBits\
\n:global haNetwork\
\n:global haMacOther\
\n:global haMacMe\
\n:global haAddressOther\
\n:global haAddressMe\
\n:global haPreferMac\
\n\
\n/log warning \"ha_startup: version \$haStartupHAVersion\"\
\n\
\n/log warning \"ha_startup: 1 \$haInterface\"\
\n/system scheduler remove [find comment=\"HA_AUTO\"]\
\n\
\n#Pause on-error just in case we error out before the spin loop - hope 5 seconds is enough.\
\n/system scheduler add comment=HA_AUTO name=ha_startup on-event=\":do {:global haInterface; /system script run [find name=ha_startup]; } on-error={ :delay 5; /interface ethernet disable [find default-name!=\\\"\\\$haInterface\\\"]; /log error \\\"ha_startup: FAILED - DISABLED ALL INTERFACES\\\" }\" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=Jan/01/1970 start-time=startup\
\n/system scheduler add comment=HA_AUTO name=ha_report_startup on-event=\"ha_report_startup\" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=Jan/01/1970 start-time=startup\
\n\
\n/log warning \"ha_startup: 2\"\
\n\
\n#Spin this initialization code until we succeed. Sometimes RouterOS gives us an error when we try to find an interface\
\n#that is in some sort of transient state, unclear why.\
\n#https://github.com/svlsResearch/ha-mikrotik/issues/7\
\n:global haTmpMac \"\"\
\n:global haTmpMaxInitTries 100\
\n:global haInitTries 0\
\n#Used to be backwards compatible with pre-bridge config.\
\n:global haInterfaceLogical\
\n:while (\$haTmpMac = \"\" && \$haInitTries <= \$haTmpMaxInitTries) do={\
\n :do {\
\n :set haInitTries (\$haInitTries+1)\
\n #Reset the MAC on the single HA interface - if they are connected via a switch, they need to be unique.\
\n /interface ethernet reset-mac-address [find default-name=\"\$haInterface\"]\
\n /ip address remove [find interface=\"\$haInterface\"]\
\n /ip address remove [find comment=\"HA_AUTO\"]\
\n /interface bridge port remove [find comment=\"HA_AUTO\"]\
\n /interface bridge remove [find comment=\"HA_AUTO\"]\
\n /interface vrrp remove [find name=\"HA_VRRP\"]\
\n /ip address remove [find interface=\"HA_VRRP\"]\
\n /ip firewall filter remove [find comment=\"HA_AUTO\"]\
\n /ip service set [find name=\"ftp\"] disabled=yes\
\n /interface ethernet enable [find default-name=\"\$haInterface\"] \
\n /log warning \"ha_startup: 2.1 \$haInitTries\"\
\n /interface ethernet get [find default-name=\"\$haInterface\"] orig-mac-address\
\n /log warning \"ha_startup: 2.2 \$haInitTries\"\
\n :set haTmpMac [[/interface ethernet get [find default-name=\"\$haInterface\"] orig-mac-address]]\
\n /log warning \"ha_startup: 2.3\"\
\n /interface bridge add name=\"bridge-\$haInterface\" protocol-mode=none fast-forward=yes comment=\"HA_AUTO\"\
\n /interface bridge port add bridge=\"bridge-\$haInterface\" interface=\"\$haInterface\" comment=\"HA_AUTO\"\
\n :set haInterfaceLogical \"bridge-\$haInterface\"\
\n /log warning \"ha_startup: 3 \$haTmpMac \$haInitTries\"\
\n } on-error={\
\n /log error \"ha_startup: delaying2 for hardware...\$haInitTries\"\
\n :delay 1\
\n }\
\n}\
\n\
\n/log warning \"ha_startup: 3.1 \$haTmpMac \$haInitTries\"\
\n\
\n:local mac \"\$haTmpMac\"\
\n\
\n:if (\"\$mac\" = \"\$haMacA\") do={\
\n :global haIdentity \"A\"\
\n /log warning \"I AM A\"\
\n /ip address add interface=\"bridge-\$haInterface\" address=\$haAddressA netmask=\$haNetmask comment=\"HA_AUTO\"\
\n :global haAddressMe \$haAddressA\
\n :global haAddressOther \$haAddressB\
\n :global haMacMe \$haMacA\
\n :global haMacOther \$haMacB\
\n} else={\
\n :if (\"\$mac\" = \"\$haMacB\") do={\
\n :global haIdentity \"B\"\
\n /log warning \"I AM B\"\
\n /ip address add interface=\"bridge-\$haInterface\" address=\$haAddressB netmask=\$haNetmask comment=\"HA_AUTO\"\
\n :global haAddressMe \$haAddressB\
\n :global haAddressOther \$haAddressA\
\n :global haMacMe \$haMacB\
\n :global haMacOther \$haMacA\
\n } else={\
\n #This is a very strange bug...maybe just in the CCR? Sometimes when the unit comes up, ethernet interfaces sometimes have swapped positions?\
\n #A reboot clears this error - it is very odd, I don't know if it is a race condition in hardware initialization or something.\
\n #I'm not sure this covers ALL cases, since it only checks the MAC of the one interface our HA runs over. It might not right now :(\
\n #Do we need to track all MACs to make sure they are in the right order? This seems like a general problem with the platform but I don't understand the extent of it.\
\n #Am I causing this?\
\n :global haIdentity \"UKNOWN\"\
\n /log warning \"I AM UNKNOWN - WRONG MAC\"\
\n /delay 15\
\n :execute \"/system reboot\"\
\n /delay 1000\
\n }\
\n}\
\n\
\n:local vrrpPriority 100\
\n\
\n:if (\"\$haMacMe\" = \"\$haPreferMac\") do={\
\n :set vrrpPriority 150\
\n /log warning \"ha_startup: 3.5 haPreferMac=\$haPreferMac is me! new vrrpPriority=\$vrrpPriority\"\
\n}\
\n\
\n/ip route remove [find comment=\"HA_AUTO\"]\
\n/ip route add gateway=\$haAddressOther distance=250 comment=HA_AUTO\
\n\
\n/log warning \"ha_startup: 4\"\
\n\
\n#If firewall is empty, place-before=0 won't work. Add first rule.\
\n:if ([:len [/ip firewall filter find]] = 0) do={\
\n /log warning \"ha_startup: 4.1\"\
\n /ip firewall filter add chain=output action=accept out-interface=\"bridge-\$haInterface\" comment=\"HA_AUTO\"\
\n /ip firewall filter add chain=input action=accept in-interface=\"bridge-\$haInterface\" comment=\"HA_AUTO\"\
\n} else={\
\n /log warning \"ha_startup: 4.2\"\
\n /ip firewall filter add chain=output action=accept out-interface=\"bridge-\$haInterface\" comment=\"HA_AUTO\" place-before=0\
\n /ip firewall filter add chain=input action=accept in-interface=\"bridge-\$haInterface\" comment=\"HA_AUTO\" place-before=0\
\n}\
\n/log warning \"ha_startup: 4.3\"\
\n\
\n/log warning \"ha_startup: 5\"\
\n/interface vrrp add interface=\"bridge-\$haInterface\" version=3 interval=1 priority=\"\$vrrpPriority\" name=HA_VRRP on-backup=\"ha_onbackup\" on-master=\"ha_onmaster\" disabled=yes\
\n/ip address add address=\$haAddressVRRP netmask=255.255.255.255 interface=HA_VRRP comment=\"HA_AUTO\"\
\n\
\n/log warning \"ha_startup: 6\"\
\n/system scheduler add comment=HA_AUTO interval=10m name=ha_exportcurrent on-event=\"/export file=\\\"HA_current.rsc\\\"\" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=Jan/01/1970 start-time=00:05:00\
\n/system scheduler add interval=10m name=ha_checkchanges on-event=ha_checkchanges policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=Jan/01/1970 start-time=00:10:00 comment=HA_AUTO\
\n#Still need this - things like DHCP leases dont cause a system config change, we want to backup periodically.\
\n/system scheduler add comment=HA_AUTO interval=24h name=ha_auto_pushbackup on-event=ha_pushbackup policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=Jan/01/1970 start-time=05:00:00\
\n/log warning \"ha_startup: 7\"\
\n:if ([:len [/file find name=\"HA_dsa\"]] = 1) do={\
\n /ip ssh import-host-key private-key-file=HA_rsa\
\n}\
\n:if ([:len [/file find name=\"HA_rsa\"]] = 1) do={\
\n /ip ssh import-host-key private-key-file=HA_rsa\
\n}\
\n/user remove [find comment=HA_AUTO]\
\n/user add address=\"\$haNetwork/\$haNetmaskBits\" comment=HA_AUTO group=full name=ha password=\"\$haPassword\"\
\n/log warning \"ha_startup: 8\"\
\n\
\n#So you dont get annoyed with constant beeping - try catch because this may fail on some platforms (x86).\
\n:do {/system routerboard settings set silent-boot=yes} on-error={};\
\n\
\n:foreach service in=[:toarray \"ftp\"] do={\
\n :local serviceAddresses \"\"\
\n :foreach k in=[/ip service get [find name=\$service] address] do={\
\n :if (\$k != \"\$haAddressA/32\" and \$k != \"\$haAddressB/32\" and \$k != \"\$haAddressVRRP/32\") do={\
\n :set serviceAddresses \"\$serviceAddresses,\$k\"\
\n }\
\n }\
\n :set serviceAddresses \"\$serviceAddresses,\$haAddressA,\$haAddressB,\$haAddressVRRP\"\
\n /ip service set [find name=\$service] address=[:toarray \$serviceAddresses]\
\n}\
\n\
\n:if ([:len [/file find where name=\"HA_run-after-hastartup.rsc\"]] > 0) do={\
\n /import HA_run-after-hastartup.rsc\
\n}\
\n/delay 5\
\n#We need FTP to do our HA work\
\n/ip service set [find name=\"ftp\"] disabled=no\
\n\
\n/log warning \"ha_startup: 9\"\
\n/interface vrrp set [find interface=\"bridge-\$haInterface\"] disabled=no\
\n/log warning \"ha_startup: 9.1\"\
\n\
\n/log warning \"ha_startup: DONE\"\
\n:put \"ha_startup: DONE\"\
\n\
\n#} on-error={\
\n# /log warning \"ha_startup: FAILED got error! disabling all interfaces!\"\
\n# /interface ethernet disable [find]\
\n#}\
\n\
\n:do { :local k [/system script find name=\"on_startup\"]; if ([:len \$k] = 1) do={ /system script run \$k } } on-error={ :put \"on_startup failed\" }\
\n}\
\n"
remove [find name=ha_switchrole_new]
add name=ha_switchrole_new owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":global isMaster\
\n:global haAddressOther\
\n:global haInterface\
\n:global haInterfaceLogical\
\n:global haPreferMac\
\n\
\n:local haPingInterface\
\n:if ([:typeof \$haInterfaceLogical] = \"nothing\") do={\
\n :set haPingInterface \"\$haInterface\"\
\n} else={\
\n :set haPingInterface \"\$haInterfaceLogical\"\
\n}\
\n\
\n:put \"Using ping interface \$haPingInterface\"\
\n\
\n:if (([:typeof \$haPreferMac] != \"nothing\") && (\$haPreferMac != \"\")) do={\
\n :put \"You are using haPreferMac (\$haPreferMac) - switch role does not make sense.\"\
\n return 0\
\n}\
\n\
\n:if (\$isMaster) do={\
\n :put \"I am master - switching role\"\
\n /system script run [find name=\"ha_pushbackup\"]\
\n :delay 5\
\n :local haWaitCount 0\
\n while ([/ping \$haAddressOther count=1 interface=\$haPingInterface ttl=1] = 0) do={\
\n :set haWaitCount (\$haWaitCount+1)\
\n :put \"Still waiting for standby \$haWaitCount...\"\
\n :delay 1\
\n }\
\n :put \"Standby available \$haWaitCount...delaying 5s\"\
\n /delay 5\
\n :if (\$isMaster && [/ping \$haAddressOther count=1 interface=\$haPingInterface ttl=1] >= 1) do={\
\n :put \"REBOOTING MYSELF\"\
\n :execute \"/system reboot\"\
\n } else={\
\n :put \"NOT REBOOTING MYSELF! SLAVE IS NOT UP OR I AM NOT MASTER!\"\
\n }\
\n} else={\
\n :put \"I am NOT master - nothing to do\"\
\n}\
\n"
remove [find name=ha_checkchanges_old]
remove [find name=ha_checkchanges]
set name=ha_checkchanges [find name=ha_checkchanges_new]
remove [find name=ha_config_old]
remove [find name=ha_config]
set name=ha_config [find name=ha_config_new]
remove [find name=ha_functions_old]
remove [find name=ha_functions]
set name=ha_functions [find name=ha_functions_new]
remove [find name=ha_install_old]
remove [find name=ha_install]
set name=ha_install [find name=ha_install_new]
remove [find name=ha_loop_push_standby_old]
remove [find name=ha_loop_push_standby]
set name=ha_loop_push_standby [find name=ha_loop_push_standby_new]
remove [find name=ha_onbackup_old]
remove [find name=ha_onbackup]
set name=ha_onbackup [find name=ha_onbackup_new]
remove [find name=ha_onmaster_old]
remove [find name=ha_onmaster]
set name=ha_onmaster [find name=ha_onmaster_new]
remove [find name=ha_pushbackup_old]
remove [find name=ha_pushbackup]
set name=ha_pushbackup [find name=ha_pushbackup_new]
remove [find name=ha_report_startup_old]
remove [find name=ha_report_startup]
set name=ha_report_startup [find name=ha_report_startup_new]
remove [find name=ha_setconfigver_old]
remove [find name=ha_setconfigver]
set name=ha_setconfigver [find name=ha_setconfigver_new]
remove [find name=ha_setidentity_old]
remove [find name=ha_setidentity]
set name=ha_setidentity [find name=ha_setidentity_new]
remove [find name=ha_startup_old]
remove [find name=ha_startup]
set name=ha_startup [find name=ha_startup_new]
remove [find name=ha_switchrole_old]
remove [find name=ha_switchrole]
set name=ha_switchrole [find name=ha_switchrole_new]
/system script run [find name=ha_functions]
}