Андрей Бирюков
Делаем резервное копирование конфигураций активного сетевого оборудования
Конфигурации активного сетевого оборудования, также как и данные, используемые различными приложениями, нуждаются в резервном копировании. Предлагаем вам пример сценария для резервного копирования, написанный на языке Perl.
На сегодняшний день резервное копирование данных стало неотъемлемой частью ежедневных задач, выполняемых системными администраторами. И это неудивительно, так как убытки, которые компания может понести в случае потери данных или вынужденного простоя, зачастую намного больше стоимости оборудования, используемого для хранения данных. Существует масса различных программных продуктов, позволяющих осуществлять автоматическое резервное копирование данных практически в любом формате, от «снимка» состояния операционной системы до бэкапа баз данных. Однако все многообразие применимо лишь к программным решениям. С аппаратными решениями, в частности, с активным сетевым оборудованием, дело обстоит немного сложнее. Конечно, многие могут возразить, что энергонезависимая память маршрутизаторов и коммутаторов более устойчива к сбоям в энергосети и что вполне достаточно, скажем, раз в месяц делать вручную копию рабочей конфигурации своего оборудования и сохранять ее на TFTP-сервер [1].
Однако в случае динамически изменяющейся конфигурации сети такой подход будет, мягко говоря, не слишком хорош. Например, на маршрутизаторах телекоммуникационной компании, где настройки интерфейсов, статические маршруты или access-list могут меняться ежедневно. Осуществлять резервное копирование вручную в такой сети очень сложно, особенно если количество маршрутизаторов и коммутаторов больше пяти. В такой ситуации нам необходимо осуществлять ежедневное, автоматическое резервное копирование рабочих конфигураций активного сетевого оборудования. Для решения поставленной задачи мы воспользуемся небольшим сценарием на языке Perl, который будет запускаться по расписанию, удаленно подключаться к каждому маршрутизатору или коммутатору по протоколу Telnet или SSH и копировать рабочую конфигурацию на TFTP-сервер. Для примера в статье будут использоваться команды Cisco IOS, хотя ничто не мешает вам использовать активное сетевое оборудование других фирм, предварительно настроив на нем удаленный доступ через Telnet или SSH.
Реализация
Итак, приступим к программной реализации. В качестве операционной системы используется FreeBSD, хотя с тем же успехом можно все описанное далее реализовать и на Linux-клонах. За основу нашего сценария, используемого для выполнения удаленных команд, возьмем пример кода с сайта CPAN.org [2]. Данный ресурс содержит массу примеров кода на языке Perl и будет весьма полезен при написании собственных сценариев. Если на вашем сервере нет модуля Telnet.pm, то его можно скачать по адресу http://search.cpan.org/CPAN/authors/id/J/JR/JROGERS/Net-Telnet-3.03.tar.gz и установить в соответствии с находящейся в архиве инструкцией. При отсутствии данного модуля вы просто получите сообщение об ошибке при выполнении сценария. Сценарий, устанавливающий соединение по протоколу Telnet, выглядит следующим образом:
Листинг 1. Сценарий, устанавливающий соединение по протоколу Telnet
#!/usr/bin/perl
use Net::Telnet ();
$t = new Net::Telnet ;
$hostname="10.0.1.11";
$t->open($hostname);
$t->waitfor('/login:.*$/');
$t->print("user");
$t->waitfor('/Password:.*$/');
$t->print("password");
В этом сценарии мы сначала устанавливаем соединение с заданным узлом, затем ожидаем приглашения ввести имя пользователя. Получив его, указываем user (пользователь, под именем которого мы подключаемся к маршрутизатору), потом ждем приглашения ввести пароль и вводим password (пароль данного пользователя). Принцип работы нашего сценария прост и понятен, мы дожидаемся появления определенной строки и, получив ее, отправляем в ответ команду или данные на удаленный узел.
Однако прежде чем двигаться дальше, нам необходимо определиться с тем, что нужно сделать на удаленном активном сетевом оборудовании. Пусть нам необходимо скопировать рабочую конфигурацию маршрутизатора Cisco Router 2620 на TFTP-сервер. Выглядеть это должно примерно так:
Router>
Router>enable
Router#copy running-config tftp
Address or name of remote host []?10.0.1.2
Destination filename []?config080106
!!!!!!
21519 bytes copied in 1.056 secs (20045 bytes/sec)
|
Другой вариант резервного копирования для маршрутизаторов Cisco – это полный дамп конфигурации, находящейся в флеш-памяти маршрутизатора. Для этого необходимо вначале узнать полное имя файла конфигурации. Получить список файлов, находящихся в флеш-памяти можно с помощью команды «show flash». На рис. 1 показан результат действия данной команды. Выделен файл, который нам необходимо скопировать.
Рисунок 1. Резервное копирование дампа конфигурации
Однако, как видно из данного рисунка, размер дампа конфигурации существенно превышает размер простой копии рабочей конфигурации, которая делалась в первом примере. Это может иметь значение при использовании каналов с небольшой пропускной способностью или если на TFTP-сервере мало свободного места. В такой ситуации имеет смысл делать, к примеру, раз в неделю копию дампа и ежедневно копию рабочей конфигурации, аналогично полному и разностному резервному копированию.
Таким образом, для решения поставленной задачи нам необходимо написать сценарий, корректно выполняющий данный диалог сервера и маршрутизатора. Остается только добавить обработку исключений, на случай если возникнут ошибки, а также отправку администратору письма о том, что резервное копирование успешно осуществлено. Для того чтобы perl-сценарий мог отправлять почтовые сообщения, необходимо наличие модуля sendmail, который в случае отсутствия можно также найти на CPAN.org.
Листинг 2. Отправка почтовых сообщений
use Mail::Sendmail;
%mail = ( To => 'admin@test.local', # кому письмо
From => 'ciscobackup@test.local', # от кого
Message => "Backup was finished with result:".$result, # текст сообщения
SMTP => 'smtp.mail.ru' # SMTP рестранслятор
);
sendmail(%mail) or die $Mail::Sendmail::error;
Приведем полный текст данного сценария.
Листинг 3. Полный текст сценария
use Net::Telnet ();
use Mail::Sendmail;
$t = new Net::Telnet ;
$hostname=”10.0.1.11”;
$t->open($hostname);
$t->waitfor('/login:.*$/')
or die "bad login: ", $t->lastline;
$t->print("user");
$t->waitfor('/Password:.*$/')
or die "bad password: ", $t->lastline;
$t->print("password");
$t->waitfor('/Router>:.*$/')
or die "No router user mode: ", $t->lastline;
$t->print("enable");
$t->waitfor('/login:.*$/')
or die "bad login: ", $t->lastline;
$t->print("user");
$t->waitfor('/Password:.*$/')
or die "bad password: ", $t->lastline;
$t->print("password");
$t->waitfor('/Router#:.*$/')
or die "No router privilege mode: ", $t->lastline;
$t->print("copy running-config tftp");
$t->waitfor('/Address or name of remote host:.*$/');
or die "Wrong copy format $t->lastline;
$t->print("10.0.1.2");
$t->waitfor('/Destination filename:.*$/');
($sec, $min, $hour, $day, $mon, $year)=gmtime(time);
$filename=”config”.$hour.$min.$sec.$day.$mon.$year;
$t->print($filename);
$result=$t->getline;
$t->waitfor('/Router#:.*$/');
$t->print("logout");
%mail = ( To => 'admin@test.local',
From => 'ciscobackup@test.local',
Message => "Backup was finished with result:".$result,
SMTP => 'smtp.mail.ru'
);
sendmail(%mail) or die $Mail::Sendmail::error;
Пользователям, не слишком искушенным в программировании на Perl, следует обратить внимание на ряд технических моментов. Прежде всего для запуска сценария необходимы права на выполнение для данного пользователя. Также сценарий можно запускать с помощью команды «perl имя_сценария», однако в случае, если первой строкой в тексте идет путь к интерпретатору Perl (например #!/usr/bin/perl, как в Листинге 1), то тогда можно запускать как обычный файл сценария, то есть ./имя_сценария (аналогично chmod +x), но второй вариант также удобен при использовании веб-интерфейса. Узнать путь к интерпретатору Perl можно с помощью команды «which perl».
Наш сценарий соединяется с удаленным устройством по протоколу Telnet, затем выполняет заданный набор команд, сохраняет рабочую конфигурацию в файле с именем, содержащим полную дату создания файла, и потом отправляет администратору письмо с результатами выполнения сценария. Для отправки почты данным сценарием достаточно, чтобы был указан SMTP-сервер на котором для данного IP-адреса разрешена ретрансляция почты. В качестве показателя результата выступает строка, которую возвращает удаленное устройство после попытки сохранить конфигурацию на TFTP-сервер.
В случае ошибки результирующая строка может выглядеть вот так:
Error opening tftp://10.0.12/config080106 |
Получение такой строки в письме с результатами свидетельствует о том, что на удаленном устройстве все команды отработали корректно, но по каким-то причинам TFTP-сервер недоступен.
В последнее время многие модели активного сетевого оборудования снабжаются поддержкой удаленного доступа с помощью протокола ssh. Данный протокол позволяет устанавливать защищенное соединение с удаленным узлом. В силу специфики протокола ssh perl-сценарий, устанавливающий удаленное соединение, будет иметь более сложный вид. В частности, как видно из Листинга 4, при соединении используются псевдотерминалы, которые образуют пары ttyp3 и ptyp3, где pty... – это хозяин или управляющий терминал, а tty... – подчиненный.
Листинг 4. Сценарий с подключением по протоколу SSH
my ($pty, $ssh, @lines);
my $host = "10.0.1.2";
my $user = "user";
my $password = "password";
my $prompt = '/ $/';
$pty = &spawn("ssh", "-l", $user, $host); # spawn() defined below
use Net::Telnet ();
use Mail::Sendmail;
$ssh = new Net::Telnet (-fhopen => $pty,
-prompt => $prompt,
-telnetmode => 0,
-cmd_remove_mode => 1,
-output_record_separator => "\r");
## Соединение с удаленным узлом
$ssh->waitfor(-match => '/password: ?$/i',
-errmode => "return")
or die "problem connecting to host: ", $ssh->lastline;
$ssh->print($password);
$ssh->waitfor(-match => $ssh->prompt,
-errmode => "return")
or die "login failed: ", $ssh->lastline;
## Отправляем команды и обрабатываем ответы
$ssh->waitfor(-match => '/ Router#: $/i',
-errmode => "return")
or die " Wrong copy format ", $ssh->lastline;
$ssh->cmd("copy running-config tftp");
$ssh->waitfor(-match => '/ Address or name of remote host: $/i',
-errmode => "return")
or die " Wrong copy format ", $ssh->lastline;
$ssh->print(“10.0.1.2”);
$ssh->waitfor(-match => '/ Destination filename: $/i',
-errmode => "return")
or die " Wrong copy format ", $ssh->lastline;
($sec, $min, $hour, $day, $mon, $year)=gmtime(time);
$filename=”config”.$hour.$min.$sec.$day.$mon.$year;
$ssh->print($filename);
$result=$t->lastline;
$ssh->waitfor(-match => '/ Router#: $/i',
-errmode => "return")
or die " Wrong copy format ", $ssh->lastline;
$ssh->cmd("logout");
%mail = ( To => 'admin@test.local',
From => 'ciscobackup@test.local',
Message => "Backup was finished with result:".$result,
SMTP => 'smtp.mail.ru'
);
sendmail(%mail) or die $Mail::Sendmail::error;
exit;
} # end main program
sub spawn {
my(@cmd) = @_;
my($pid, $pty, $tty, $tty_fd);
use IO::Pty ();
$pty = new IO::Pty
or die $!;
unless ($pid = fork) { # child process
die "problem spawning program: $!\n" unless defined $pid;
use POSIX ();
POSIX::setsid
or die "setsid failed: $!";
$tty = $pty->slave;
$tty_fd = $tty->fileno;
close $pty;
open STDIN, "<&$tty_fd" or die $!;
open STDOUT, ">&$tty_fd" or die $!;
open STDERR, ">&STDOUT" or die $!;
close $tty;
exec @cmd
or die "problem executing $cmd[0]\n";
}
$pty;
В завершении данной темы хотелось бы отметить, что эти сценарии также можно использовать и для выполнения других задач на удаленных устройствах. Например, если нам необходимо выполнить обратное действие, заменить рабочую конфигурацию на ее копию с TFTP-сервера, но мы не можем это сделать в рабочее время в связи с загруженностью сети, то наш сценарий выполнит задачу в нужное время. Для этого достаточно указать команду «copy tftp running-config».
Итак, мы написали сценарии, которые позволяют выполнить команды на удаленных сетевых устройствах. Однако для решения поставленной задачи необходимо также правильно настроить службы операционной системы, которые требуются для корректной работы автоматической системы резервного копирования.
Автоматизируем выполнение
Прежде всего нам потребуется TFTP-сервер. Я не буду описывать процесс установки и настройки данной службы, так как все это уже хорошо описано в [1].
Следующим этапом будет настройка утилиты cron. Данная утилита входит в состав UNIX-систем и позволяет выполнять автоматически различные задачи по расписанию. Формат данных, который использует cron, довольно прост.
Поля:
- Минута – от 0 до 59.
- Час – от 0 до 23.
- Дата –от 1 до 31.
- Месяц – от 1 до 31 или от Jan до Dec.
- День недели – от 0 до 6 или от Sun до Sat.
- Команда – выполняемая команда (в нашем случае это буде файл сценария).
Для большей ясности приведем пару примеров:
30 2 * * perl /tmp/telnet.pl
Сценарий telnet.pl, находящийся в каталоге tmp, будет выполняться каждый день в 2 часа 30 минут. Поле «день недели» не используется, вместо него указан лишний пробел.
50 18 1,15 * perl /tmp/ssh.pl
В данном случае сценарий будет выполняться в 18:50 1го и 15-го числа каждого месяца.
Для того чтобы добавить строку настроек для запуска сценария в таблицу cron, нужно воспользоваться следующей командой «crontab -е USER -l», где USER – это пользователь, от имени которого выполняется данная команда.
Для того чтобы удалить ненужную запись из таблиц, нужно воспользоваться командой «crontab -u USER -r». А для простого просмотра таблиц можно воспользоваться командой «crontab -u USER -l». Вообще, текстовый файл с настройками таблиц cron можно найти в каталоге /var/cron/tabs, однако редактировать его вручную не рекомендуется. Резервное копирование оптимально делать один раз в сутки. Файл конфигурации в среднем занимает около 100 Кб, так что ежедневные копии конфигураций не займут много места.
Заключение
Итак, мы написали сценарии и настроили их автоматическое выполнение. В статье сознательно не затрагивались аспекты, связанные с настройкой удаленного доступа на маршрутизаторе или коммутаторе, так как это слишком обширная тема, требующая отдельной статьи.
Литература, ссылки:
- Супрунов С. FreeBSD TIPS: Работаем с TFTP. – Журнал «Системный администратор», № 7, июль, 2005 г. – 39-41с (http://www.samag.ru/cgi-bin/go.pl?q=articles;n=07.2005;a=08).
- CPAN.org. – ресурс содержит большое количество примеров различных сценариев и библиотек Perl.
- Родерик Смит. Полный справочник по FreeBSD.