Сбор конфигурации сетевого оборудования и хранение их в SVN

Не так давно, в связи с расширением штата сетевых администраторов, роста числа оборудования в сети и круга задач, возлагаемых на это оборудование, возникло желание отслеживать изменение его конфигурации, и хранить историю этих изменений.
Очевидным решением стало хранение конфигурации в системе управления версиями. Выбор пал на Subversion, так же известную как SVN.
На установке и настройке репозитория останавливаться не буду, так как этому посвящено много страниц в интернете и ничего нестандартного в этом нету. Здесь опишу свой способ сбора конфигурации с оборудования и учет изменений.

Для начала создадим рабочую копию нашего репозитория, куда и будут скриптом на perl собираться конфиги.
svn checkout svn://svn.reposerver.ru/configs /configs

Приступим к написанию скрипта. Скрипт писался с учетом нескольких особенностей.
  • простое добавление/удаление устройств в списке проверяемых
  • мультивендорная сеть
  • уведомление об изменениях почтой
  • уведомление об ошибках подключения почтой

Инициализация переменных:
#!/usr/bin/perl -w 

use Net::Appliance::Session;
use Net::SCP::Expect;
use Switch;
use Fcntl ':flock'; 

exit(1) unless &lock("lockfile"); 

my $date = `/bin/date`;
my $flag=0; ### флаг наличия изменений
my $path="/configs"; ###путь к рабочей копии
my $cfg = "/configs/switches.cfg"; ### файл списка оборудования
my $error = "\n"; ### переменная сообщений об ошибке.

Сделаем update и получим номер текущей ревизии. Он нам пригодится для сравнения версий.
$_=`/usr/local/bin/svn update $path`;
s/At revision (\d+)./$1/;
$prev_rev = $_;

Функции лока/анлока. Позволяют запускать только одну копию скрипта.
sub lock($) {
	open(LK,">$_[0]") or return 0;
	flock(LK,LOCK_EX|LOCK_NB);
}
sub unlock($) {
        unlink($_[0]);
	flock(LK,LOCK_UN);
	close(LK);
} 

Далее читаем конфигурационный файл. Файл должен представлять из себя набор строчек. Каждая строчка содержит адрес железки и ее тип, разделенные двоеточием:
switch1:e
switch2:cat
router1:c
router2:j

open (CFG, "$cfg") || die "Cant open file $cfg: $!";
while (<CFG>) {
	next if /^\#/; ###Пропускаем комментарии в конфиге
        next if /^\s*$/; ###Пропускаем пустые строки в конфиге
	chomp;
	my @host = split /:/,$_;
	switch($host[1]) {
		case "cat" {
			`/usr/bin/touch $path/$host[0]`;
			&cat_telnet($host[0]);
			&str_remove ($host[0]);
		}
		case "c" {
			`/usr/bin/touch $path/$host[0]`;
			&cat_telnet($host[0]);
			&str_remove ($host[0]);
		}
		case "e" {
			 `/usr/bin/touch $path/$host[0]`;
		    	&extreme_telnet($host[0]);
		    	&str_remove ($host[0]);
		}
		case "j" {
		    &juni_scp($host[0]);
		}
	}

Здесь мы для каждой строчки конфига создаем файл с конфигурацией (на случай если его небыло) и вызываем набор функций в зависимости от типа устройства. Функции расмотрим позже, скажу лишь, что после их выполнения у нас будет новый собраный с устройства конфиг. Проверяем есть ли изменения в конфиге. Если есть — коммитим и устанавливаем флаг наличия изменений в 1. Если добавился новый хост, также добавляем его в репозиторий. При выставленном флаге – пишем письмо.
my $svnst = `/usr/local/bin/svn status $path/$host[0]`;
    	if ($svnst =~ /^M/) { ### Если файл был модифицирован
		$flag=1;
		`/usr/local/bin/svn commit -m "$date" $path/$host[0]`;	
	}
if ($svnst =~/^\?/) { ### Если добавился новый файл
		`/usr/local/bin/svn add $path/$host[0]`;
		`/usr/local/bin/svn commit -m "Add new host at $date" $path/$host[0]`;
	}
}
close CFG;
if ($flag==1) {
	&diff_mail();
}

Основной скрипт закончен. Далее набор функций.
Для функции сбора конфига ввиду мультивендорности, было решено использовать более или менее универсальный механизм – коннект на свитч и команда просмотра конфигурации.
sub cat_telnet {
	(my $host1)=@_;
	$try = 5;
	$update='false';
	while ($try>0) {
		my $s = Net::Appliance::Session->new(
			Host => $host1,
			Transport => 'Telnet',
			Timeout => 50,
			Source => '/configs/nas-pb.yml',
			Platform=> 'IOS'
		);
		eval {
			$s->do_login();
			$s->connect(
				Name => 'username',
				Password => 'pass',
			);
			my @temp = $s->cmd('show run');
		};
		if ($#temp>5) {
			$s->close;
			$update='true';
			last;
		}
		$try=$try-1 ;
		if ($try==0) {
			$error = $error.»Some error occure while getting config from «. $host1. «\n»;
			$flag=1;
		}
		$s->close;
	}
	if ($update eq 'true'){
		open (CFG1, «>$path/$host1») || die «Cant open file $path/$host1: $!»;
		print CFG1 @temp;
		close CFG1;
	}
}

Методы подключения и передачи команд выполняются в контексте eval, чтобы скрипт не вылетал если будут проблеммы с подключением. На всякий случай дается пять попыток подключения. Далее либо записываем сообщение об ошибке,(флаг выставляем, для того чтобы ошибка ушла почтой) либо записываем полученый массив в файл. Проверка длины масива сделана потому, что некоторые устройства переодически возвращают сообщения вида: «невозможно выдать конфигурацию, попробуйте позже», когда они очень чем-то заняты, что бы такое сообщение не записывалось в файл, потому как явной ошибки подключения нет, но конфига тоже нет. Можно конечно парсить вывод на предмет ключевых слов, но данная проверка проще и универсальней.
Для нового типа устройства добавляется новая функция в которой можно описать собственную логику работы с данным типом. Например Juniper:
sub juni_scp {
	(my $host1)=@_;
	$try = 5;
	$update = 'false';
	while ($try>0) {
		my $s = Net::SCP::Expect->new(
			user=>'username',
			password=>'pass',
			auto_yes=>1
		);
		eval {
			my @temp= $s->scp("$host1:/config/juniper.conf.gz","$path/$host1.gz" );
		};
		if ($#temp eq "0") {
			$update='true';
			last;
		}
		$try=$try-1 ;
		if ($try==0) {
			$error = $error."Some error occure while getting config from ". $host1. "\n";
			$flag=1;
		}
	}
	if ($update eq 'true'){
		`/usr/bin/gunzip -f $path/$host1.gz`;
	}
}

В данном примере вместо telnet конфиг скачивается по scp. На устройстве создана учетка для доступа в шелл с ограниченными правами.

В процессе тестов выяснилось, что иногда попадаются строчки в конфиге, которые постоянно меняются, но не несут важной смысловой нагрузки. Например ntp clock-period в Cisco, или Extreme любит добавлять звездочку в приглашение, если есть несохраненные изменения. Была добавлена функция вырезания таких строчек, что бы игнорировать их и учитывать только важные изменения:
sub str_remove {
	(my $host)=@_;
	open (F,"$path/$host") ; 
	my @f = <F>; 
	close F; 
	open (F, ">$path/$host"); 
	foreach $str (@f) { 
   		print F $str if ( $str !~ /^ntp clock-period/  and $str !~ /^Current configuration/ and $str !~ /^Slot-/ and $str !~ /^\* Slot-/ and $str !~ /^\*/); 
	} 
	close F;  
}

После прохода всех устройств из нашего списка, если где-то был выставлен флаг необходимости почтового сообщения, то отправляем письмо в которое включаем список изменений, и переменную с ошибками. Список изменений получаем стандартным svn diff, указывая предыдущий номер ревизии.
sub diff_mail {
	@mail = `/usr/local/bin/svn diff $path -r $prev_rev`;
	open (MAIL, "| /usr/sbin/sendmail user@mydomain.ru, user2@mydomain.ru ")  || die " $!";
	print MAIL <<EOF;
From: Config Checker
Subject: Config Update

@mail
$error

EOF
	close MAIL;
}

В конце удаляем локфайл
&unlock("lockfile");

Данный скрипт запускается по крону несколько раз в день. Все внесенные изменения приходят на почту и в любой момент можно любым SVN клиентом подключаться наблюдать за изменениями, сравнивать версии, откатываться и т.д.
Оговорюсь, что я не гуру перлового программирования, и все замечания и советы будут с благодарностью приняты.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 24

    +2
    Давненько зрела мысль написать нечто подобное, но руки всегда не доходили, равно как и разбираться в автоматизированных систем сбора конфига с устройств.

    Спасибо за статью.

    Касательно критики — не очень удачная функция diff_mail, лучше используйте какие-нибудь модули для отправки почты, скажем, Mime::Lite или Mime::Entity.

    Также не понял зачем вы с каталистов забираете конфиг как show run, а не show startup-config.
    Ну и конечно лучшим, на мой взгляд решением, было бы хранить конфиги на tftp сервере, и в svn забирать их уже оттуда. Это и проще с точки зрения скрипта (меньше ошибок при работе с файловой системой, нежели с сетевыми устройствами, не будет таких исключительных ситуаций, как устройство недоступно, конфиг содержит левые строчки и тп).

      +1
      Спасибо за советы. Модули обязательно изучу и постараюсь применить.
      Касательно sh run — sh start — просто задача забирать именно текущий рабочий конфиг. Как показала практика: если кто-нибудь из инженеров забывал сохранять конфигурацию(бывало и такое), то после непредвиденной перезагрузки устройства у всех в почте было видно, что конфигурация изменилась (т.к. startup отличался от run ) и конфигурация приводилось в нормальное состояние до того как пользователи, которых это коснулось, успевали замечать.
      Изначально, я как раз и хотел сделать без логина на свичи, а, например с Cisco, по snmp просить ее слить свой конфиг по tftp. Но при таком подходе я не могу отследить процесс скачавания конфига. И ингода выходило, что скрипт пытается сравнить еще недокачанный конфиг. Синхронизировать этот процесс я не придумал как.
        0
        а если конфиг был сделан криво, что привело к частичной неработоспособности железки, а система его подобрала?.. иногда быстрее залить бэкап, а он кривой
          0
          Заливаем предыдущую ривизию. Конфиг же не затерается поверх новым, а хранится вся история изменений, соответственно мы можем откатиться до любой даты.
            0
            угу. сглупил, каюсь
        +2
        Сразу могу сказать что забор конфигов по tftp не лучшая идея, потому как tftp протокол не самый хороший выбор на длинном канале с ошибками. У меня на этом протоколе на моих скриптах были конфиги, которые категорически недокачивались.

        Я выбрал протокол ftp. Почему не scp? Потому что из-за какой-то, уже не помню какой баги, scp на базе sshv2 с циски не ходили. Надо на цисках всех было включать ssh v1.

        А еще подводный камень, в ios в окрестности 12.4.20T ошибка, такая, чтобы ftp не работает.

        В итоге в моем скрипте сначала идет попытка передачи конфига по ftp, если проблема, переключаемся на scp. А я уж позаботился о том, что на хостах с проблемой в ftp стоял ssh v1.

        И еще, Net::Appliance::Session у меня на FreeBSD не заработал, как и все прочее SSH из под perl-а. Удивительно хорошо и надежно работает Net::Telnet::Cisco, но канал не защищенный, не подходит.

        В итоге свои скрипты я написал на базе Expect-a.

        Можно было еще использовать snmp для скидывания конфига (чтобы не лезть на консоль), но Cisco ASA не позволяет этого, а ASA мне была важна.

        Вот такие небольшие заметки.
        +1
        А почему выбор пал на svn?
          +1
          Обратите внимание на rancid, а еще лучше на Notch и co.
          • UFO just landed and posted this here
              +3
              Опять велосипеды :)))

              www.nocproject.org

              redmine.nocproject.org/wiki/noc/Configuration_Management

              Configuration Management Configuration Management deals with network equipment and services configuration.
              Primary tasks are:
              Router/switches config backup
              Store configs under version control system
              Maintain a full history of configuration changes
              Provide web access to configs with rich set of analytic tools
              Restore part or full config to device in case of failure or staff mistake
              To ease equipment replacement
              Network services configs are stored too, including DNS Zones
                +2
                Ничего плохого в таких «велосипедах» нет. Именно на них «молодняк» набирается опыта, «набивает руку», и изучает новые(для себя) технологии. И к тому же, если была поставлена задача «просто собирать конфиги», без дополнительных функций, то данный скрипт выполняет её в совершенстве. А внедрять мощную многофункциональную систему вроде «NOC Project», для данной задачи, это все равно что «покупать газель для перевозки ящика пива», не помню где, но натыкался на термин «информационное потреблядство» который очень хорошо подходит к данной ситуации.

                Сам не так давно реализовывал подобное, а началось все как раз с того что руководство решило внедрять Cisco LMS. После подробного анализа пришли к выводу, что кроме бэкапа конфигов нам пока ничего не надо. Скрипт собирающий конфиги через SNMP был написан буквально за один день. В результате потребности удовлетворены, и организация сэкономила чуть меньше миллиона.

                P.S. Автору респект, сам давно хотел допилить свое «творение» для работы с SVN, но руки пока не доходят.
                  +1
                  Это где вы «совершенство» увидели? То что поддерживается несколько несчастных железок? ;)

                  Плохо делать велосипеды, плохо.

                  Вместо того чтобы писать нужные модули к тому же NOC или чему-то подобному (и заодно изучать как правильно программировать / писать такие системы), люди учатся делать кривые поделки, которые (вот это уже реально опасно) потом экcплуатируются промышленно и на которые все надеются в критических ситуациях.

                    0
                    Это где вы «совершенство» увидели? То что поддерживается несколько несчастных железок? ;)

                    В сравнении с моей «поделкой» которая просто два раза вдень раскидывает всем коммутаторам snmp- команду скинуть конфиг, этот скрипт гораздо лутше. Если вы про реализацию, то думаю «отшлифует» когда- нибудь, возможно, если руки дойдут:)

                    Вместо того чтобы писать нужные модули к тому же NOC или чему-то подобному (и заодно изучать как правильно программировать / писать такие системы), люди учатся делать кривые поделки, которые (вот это уже реально опасно) потом экcплуатируются промышленно и на которые все надеются в критических ситуациях.


                    внедрять мощную многофункциональную систему вроде «NOC Project», для данной задачи, это все равно что «покупать газель для перевозки ящика пива»

                      0
                      ну да, ну да.

                      а если вам надо маленький сервер сделать — то напишете свою ОС, ибо ставить линукс — это как покупать газель, да?

                      все «внедрение» NOC'а — ну минут 15-20 максимум (поставить да скормить адреса / пароли железок)
                      — но нет-же, надо плодить кучу самописной ерунды.

                      вообще IT начальству за такое надо жестко бить по ручкам подчиненным — ибо если (а когда-то это точно произойдет) «вася пупкин» который наваял это уволится (уйдет в другую контору, заболеет, и тд и тп), то другим разбираться в том как это все сделано — радость еще та, фактически человек самовольничает и подставляет компанию / бизнес.
                        0
                        ну да, ну да.

                        а если вам надо маленький сервер сделать — то напишете свою ОС, ибо ставить линукс — это как покупать газель, да?

                        все «внедрение» NOC'а — ну минут 15-20 максимум (поставить да скормить адреса / пароли железок)
                        — но нет-же, надо плодить кучу самописной ерунды.


                        Ну зачем же так утрировать:)
                        Человек совместил «приятное с полезным»- написал сам скрипт, и решил проблему для комании. ПУсть учится и развивается. А про NOC: если вам надо сделать небольшую текствую заметку вы наверное Word открываете?;)

                        вообще IT начальству за такое надо жестко бить по ручкам подчиненным — ибо если (а когда-то это точно произойдет) «вася пупкин» который наваял это уволится (уйдет в другую контору, заболеет, и тд и тп), то другим разбираться в том как это все сделано — радость еще та, фактически человек самовольничает и подставляет компанию / бизнес.


                        Не бить по рукам, заставить сделать статью во внутреней wiki, или написать простенькую инструкцию с описание что как работает, где находится и к чему привязанно.

                          0
                          Возможно это действительно велосипед, но зато я могу его модернизировать и дополнять как угодно, при том что критичность сбора конфига невысокая, и едва ли нанесет ощутимый ущерб, если вдруг что, а из SVN они уж точно никуда не денутся

                          За ссылки спасибо. Скорее всего NOC поставлю в другом своем проекте, где как раз необходимо иметь веб доступ для не очень подкованных коллег.
                            0
                            все «внедрение» NOC'а — ну минут 15-20 максимум (поставить да скормить адреса / пароли железок)
                            — но нет-же, надо плодить кучу самописной ерунды.


                            На первых порах NOC была далеко не простая штука, и что бы поставить и заставить работать нужно было приложить не мало усилий. Ковырял его пару недель, так внятной работы и не добился — поставил rancid, до сих пор использую. Возможно сейчас что-то изменилось.
                    0
                    Кстати, действительно, чем не угодил RANCID? Нужны веские основания для написания чего-то своего, если есть что-то такое же, только готовое. Все-таки готовый программный продукт, это не просто код, но и чужой опыт и чужая работа над ошибками. По закону подлости ошибки в своем скрипте проявятся как раз во время аварии :)
                      0
                      Помимо сбора и хранения конфигурации, для некоторого специфичного оборудования производится ее анализ и заполнение базы данных, для последующих манипуляций с этими данными. Т.е. есть еще набор узко специфичных задач, которые делает скрипт
                        0
                        В таком случае, подозреваю, что ваши узкоспециальные задачи весьма широко распространены :)
                        Настоятельно рекомендую все-таки посмотреть на NOC, в частности на Map/Reduce Tasks (http://redmine.nocproject.org/boards/3/topics/1084?r=1094#message-1094).
                          0
                          Уже присматриваюсь к этому проекту. Спасибо.
                            0
                            Дима — его автор :P

                              +1
                              Проект открытый и активно развивается. Если есть энтузиазм и свежие идеи, предлагаю поучавствовать. Основное обсуждение ведется на IRC (#nocproject.org @ irc.freenode.net)
                        +1
                        Писал недавно похожий велосипед, но с возможностью хранить комментарии к каждой из строк: github.com/unicast/conkeep

                        Only users with full accounts can post comments. Log in, please.