В прошлой статье я рассказал о возможном способе снимать централизованные резервные копии конфигураций с маршрутизаторов MikroTik. Казалось бы на этом можно и успокоиться, но для некоторых филиалов руководство требует сиюминутного восстановления работы в случае выхода из строя любого участка сети. Первое, что приходит в голову — само собой, нужно иметь рядом две одинаковые железки. Однако вторая логичная мысль — использовать VRRP не подходит в силу ряда причин, одна из которых использование IPSec. Значит нужно снова шаманить костыль и синхронизировать конфигурацию в полуручном режиме, то есть скриптоваться.
Логика
1. Подключаемся по ssh к активному маршрутизатору и меняем адрес физического интерфейса, через который подключен подогретый маршрутизатор на 10.0.0.1/24
2. Используя проброс порта фаерволом, подключаемся по ssh к подогретому маршрутизатору через активный
3. Сверяем серийный номер, чтобы удостовериться что подключились на самом деле к подогретому маршрутизатору, дабы не угрохать активный
4. Забираем бэкап по ftp с активного маршрутизатора и перезагружаем подогретый
5. Подключаемся по ssh к активному маршрутизатору и возвращаем изначальный адрес физического интерфейса на 10.0.0.2/24, через который подключен подогретый маршрутизатор
Манипуляции с изменением адреса мне нужны по той причине, что раз в день я снимаю бэкап со всех маршрутизаторов. Далее когда я буду заливать бэкап на подогретый маршрутизатор, мне до него необходимо будет как-то добраться, для этого у него уже будет настроен адрес 10.0.0.2/24, а на активном я временно выставлю адрес 10.0.0.1/24, этот IP в бэкапах никогда фигурировать не будет. Таким образом мы добиваемся идентичности конфигураций.
Подключаем подогретую железку
… так, как показано на картинке, а именно — не суть важно как в вашем случае вы подключите интернет и локалку, важно лишь то, чтобы интерфейсы, которыми мы соединим активный и подогретый роутеры, были одинаковыми. Дальше будет понятно почему.
Настроим интерфейсы идентичным образом — да да, ничего криминального в этом нет.
/add address=10.0.0.2/24 comment=backup disabled=no interface=ether10 network=10.0.0.0
Еще нам понадобится SSH на борту обоих железок:
/set ssh address="" disabled=no port=2222
Пусть будет нестандартный порт, т.к. стандартный мало ли для чего может еще понадобиться.
Сделаем также проброс порта:
/ip firewall nat add action=dst-nat chain=dstnat comment="dst-nat to knock-to hotbackup" disabled=no dst-port=2422 protocol=tcp to-addresses=10.0.0.2 to-ports=2222
/ip firewall nat add action=src-nat chain=srcnat comment="to knock-to hotbackup we either need to change source address from ssh being connected" disabled=no dst-address=10.0.0.2 dst-port=2222 protocol=tcp to-addresses=10.0.0.1
Именно так, вторым правилом меняя source address, ведь на резервном маршрутизаторе уже будет какой-то default gateway и он будет пытаться ответить через него, а нам надо в обратку, через активный маршрутизатор.
Кроме этого нужен FTP, но мы его прикроем от посторонних:
/set ftp address=10.0.0.0/24 disabled=no port=21
На этом подготовительная работа закончена, рисуем скрипт.
Скрипт
Уже есть заготовленная болванка из предыдущего опыта, нужно лишь добавить некоторые штрихи:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# for SSH
import paramiko
from paramiko import SSHClient
from paramiko import AutoAddPolicy
# for versioning
import datetime
# for file operations
import os
# for sleep
import time
# for strip()
import string
# versioning
Version = datetime.date.today()
print "n" + str(Version)
# credentials array
arrCreds = (
("R0", "11.22.33.44", "user0", "password0", "serial0"),
("R1", "1.1.1.1", "user1", "password1", "serial1"),
("R2", "2.2.2.2", "user2", "password2", "serial2"),
)
# FTPD IP
FtpdIP = "10.0.0.1/24"
BackupIP = "10.0.0.2/24"
# keep backups for 4 weeks
backtime = datetime.timedelta(weeks=-4)
sshCli = SSHClient()
sshCli.set_missing_host_key_policy(AutoAddPolicy())
LogFile = "/var/log/remotes/scripts/scripts1.log"
paramiko.util.log_to_file(LogFile, level=10)
print "header done"
# loop adresses inside given network
for (site, host, user, Password, SerialNumberA) in arrCreds:
print datetime.datetime.now()
print "n" + host
# define operations
ChangeBackupIfAddr = '/ip address set [/ip address find address="' + BackupIP + '"] address="' + FtpdIP + '"'
SSHToBackup = "/system ssh address=" + BackupIP.replace('/24', '') + " port=2222 user=" + user + "n"
GetSerial = ':put [system routerboard get value-name=serial-number]'
GetBackupFromFtp = "/tool fetch address=" + FtpdIP.replace('/24', '') + " mode=ftp src-path=" + site + "_" + host + "_" + str(Version) + ".backup" + " user=" + user + " password=" + Password
ApplyBackup = "/system backup load name=" + site + "_" + host + "_" + str(Version) + ".backup"
ChangeBackupIfAddrA = '/ip address set [/ip address find address="' + FtpdIP + '"] address="' + BackupIP + '"'
# try for not to fail the whole script on one error
try:
print "connecting to active router.." + site + "_" + host + "@" + user + ":" + Password
sshCli.connect(str(host), port=2222, username=str(user), password=str(Password))
time.sleep(2)
print "..done"
print "changing backup interface IP address form 10.0.0.2/24 to 10.0.0.1/24.. " + ChangeBackupIfAddr
sshCli.exec_command(ChangeBackupIfAddr)
print "..done"
print "connecting to hotbackup router.. "
sshCli.connect(str(host), port=2422, username=str(user), password=str(Password))
time.sleep(2)
print "..done"
# we need to check if we're not still on active router
print "checking router serial number.. " + GetSerial
stdin, stdout, stderr = sshCli.exec_command(GetSerial)
type(stdin)
SerialNumberCurrent = stdout.read()
SerialNumberCurrent = SerialNumberCurrent.strip()
print "SNA=" + SerialNumberCurrent
# if SerialNumber == Active router SN, so we are still on active router and must stop script
if SerialNumberCurrent == SerialNumberA:
print "we are still on active device, aborting host processing"
continue
else:
print "successfully connected to hotbackup device, going on futher host processing"
print "downloading backup from active router ftp.. /" + GetBackupFromFtp
sshCli.exec_command(GetBackupFromFtp)
time.sleep(2)
print "..backup downloaded from active router"
print "apply backup on HotBackup.. /" + ApplyBackup
sshCli.exec_command(ApplyBackup)
# and say yes
sshCli.exec_command("y")
time.sleep(2)
print "..done"
print "connecting to active router.. "
sshCli.connect(str(host), port=2222, username=str(user), password=str(Password))
time.sleep(2)
print "..done"
print "giving backup interface address 10.0.0.2/24.."
sshCli.exec_command(ChangeBackupIfAddrA)
time.sleep(2)
print "..done"
except:
print "Error connecting to host", host
Когда сломается активный маршрутизатор, нужно будет просто руками переткнуть все провода в подогретый маршрутизатор — у себя я проверил, работает.
Минусы
— схема работы такова, что будет маслать встроенную флешку при каждом выполнении, тем самым уменьшая её lifetime, поэтому я бы не советовал выполнять такую операцию чаще, чем один раз в неделю
— способ будет работать только с железом одинаковой модели и одинаковой версии прошивки, в противном случае может сместиться нумерация интерфейсов
— это тот еще костыль и нужно это понимать
Респект читательу just_wow за дельный совет по организации массива с учетными данными.
Автор: diver66