Многие хранят шаблоны конфигураций сетевых устройств (прим. да и не только сетевых) в обычных текстовых файлах. И когда приходит время настраивать новое оборудование, достают эти файлики и начинают в них что-то менять. Повседневные типовые операционные задачи не являются исключением и бой с этими задачами обычно ведётся с помощью фалов-шаблонов конфигураций. Безусловно, есть приложения по управлению сетью, но увы их используют далеко не все, потому что многим они не по карману или задачи по конфигурированию оборудования выполняются достаточно редко, в связи с чем обосновать покупку такого ПО очень сложно. Хочу предложить Вам решение по реализации генератора конфигураций на базе HTML/JS, а так же небольшой DIY набор для быстрого старта.

Некоторые админы пишут генераторы конфигураций на Bash/Python, а затем обучают подающего надежды паренька из техподдержки пользоваться этими «самописными приблудами». Далее передают всю рутину и типовые задачи на первую линию поддержки. Проблема здесь только в том, что зачастую, приложение представляет из себя черный экран с мигающим курсором и предложением ввести данные строго по порядку и без ошибок. Соответственно далее эти данные будут использоваться для создания конфигурации или набора команд.

Компания, в которой я работаю, не исключение, и у нас так же хватает рутинных задач, которые хотелось бы упростить и автоматизировать. Было принято решение сделать кроссплатформенный генератор конфигураций Cisco с GUI. Естественно взгляд упал на веб-технологии, но перспектива поднимать веб-сервер (по крайней мере на начальном этапе) не очень радовала. Нашлись умные люди, которые подсказали, что всё это можно реализовать локально на стеке технологий HTML/JS, что я в итоге и сделал. Некоторые части приложения возможно выглядят не очень элегантно (в частности хранение шаблонов), но есть и неоспоримые плюсы, HTML и JS знают почти все, а если трудности и возникнут, то их всегда поможет решить гигантское сообщество. И так, к делу.

Архитектурно, генератор представляет собой веб-страничку написанную на HTML. Шаблоны конфигураций хранятся в файлах JS в виде текстовых переменных. Данные заносятся в веб-форму и на их основе происходит создание конфигурации. Давайте разберем как это происходит на конкретном примере.

Для начала давайте поставим задачу по созданию набора команд для конфигурации VLAN и его IP адреса. Для создания шаблона я взял такой кусок конфигурации.

interface Vlan555
description === LAN ===
ip nat inside
ip virtual-reassembly in
ip address 10.47.3.1 255.255.255.0
ip tcp adjust-mss 1442
exit


Есть простая веб страничка, которая содержит поля ввода информации generator.html:
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>Config generator</title>
		<!-- ШАБЛОН УСТРОЙСТВА -->
		<script src="config_tempalte.js"></script>
	</head>
	<body>
		<div id="newconf" style="padding:20px;">
			<!--ФОРМА ДЛЯ ЗАПОЛНЕНИЯ-->
			<h3>Генератор конфигураций</h3>
			<label for="text">Создать VLAN номер:</label>
			<input type="text" id="vlan" maxlength="4" placeholder="1234"></br>
			<label for="text">Присвоить VLAN следующий IP адрес:</label>
			<input type="text" id="ip" maxlength="15" placeholder="192.168.1.1"> / 
			<input type="text" id="mask" maxlength="15" placeholder="255.255.255.0"></br>
			<button type="submit" id="confcreate">Создать конфигурацию</button></br></br>
			<!--РЕЗУЛЬТАТ-->
			<h4>Конфиг для Cisco | <button type="submit" id="download">Скачать конфиг</button></br></h4>
			<div id="config"></div>
		</div>
	</body>
</html>
<script src="actions.js"></script>

К страничке подключены два скрипта (в принципе ничего не мешает всё писать в одном файле, но я разделил для наглядности):
// обработка введённых данных
<script src="actions.js"></script>

Ниже листинг скрипта actions.js, который вообще-то мог бы быть в два раза меньше, но я решил добавить кнопку скачивания конфигурации в виде файла и из-за этого он распух. Тем не менее, я думаю это важная и нужная функция, так как конфигурации часто заливаются через tftp.
function begin() {
	confcreate.onclick = function() {
		var vlan = document.getElementById('vlan');
		var ip = document.getElementById('ip');
		var mask = document.getElementById('mask');
		var config = document.getElementById('config');
		var template = config_template;
		template = template.replace(new RegExp('{{VLAN}}','g'),vlan.value);
		template = template.replace(new RegExp('{{IP_ADDR}}','g'),ip.value);
		template = template.replace(new RegExp('{{MASK}}','g'),mask.value);
		config.innerHTML = template;	
	};

	download.onclick = function() {
		downloadInnerText('cisco_config.txt', 'config','text/plain');
	};

	function downloadInnerText(filename, elId, mimeType) {
		var el = document.getElementById(elId);
		var link = document.createElement('a');
		mimeType = mimeType || 'text/plain';
		link.setAttribute('download', filename);
		link.setAttribute('href', 'data:' + mimeType + ';charset=utf-8,' + encodeURIComponent(el.innerText));
		link.click(); 
	}	
};
document.addEventListener("DOMContentLoaded", begin);

//шаблон конфигурации устройства
<script src="config_tempalte.js"></script>

Шаблон можно составить по-разному, но обязательно все части конфигурации должны содержатся в переменных. JavaScript воспринимает конец строки как конец переменной, поэтому приходится экранировать каждую строку обратной чертой. К тому же, в конце каждой строки добавлен HTML тег br для правильного отображения конфигурации на странице и символ окончания текстовой строки \n для корректного экспорта в тестовый файл. Кому-то такой шаблон может показаться не очень эстетичным, но несмотря на кучу «лишних» символов, создавать шаблоны и вносить в него изменения достаточно просто. Большинство текстовых редакторов имеют функцию добавления символов в конец строки. Символами {{}} в шаблоне обрамлены места куда будут подставляться данные. Ниже листинг самого шаблона config_tempalte.js:
var config_template = "!===КОНФИГУРАЦИЯ===</br>\nconf t</br>\n!</br>\ninterface Vlan{{VLAN}}</br>\n description === LAN ===</br>\n ip nat inside</br>\n ip virtual-reassembly in</br>\n ip address {{IP_ADDR}} {{MASK}}</br>\n ip tcp adjust-mss 1442</br>\nexit</br>\n!</br>\nwr mem</br>\n!</br>\n";

Генератор конфигураций готов. Создав три файла и наполнив их указанными мной строчками вы получите такое приложение:


Основная его задача, принимать данные через веб-форму, подставлять их в шаблон, а результат выводить на экран. Всего 65 строчек кода, и мы имеем небольшое, но очень полезное приложение. Создание конфигурационных фалов это дело уникальное и интимное для каждой конкретной компании, поэтому предложить готовое решение на все случаи жизни, наверное, невозможно. Вы можете воспользоваться исходниками что бы написать генератор конфигураций под свои собственные нужды.

Исходники можно взять отсюда: https://github.com/bravoavo/cisco-config-generator

Обратите внимание, что это всего лишь пример, на основе которого каждый может сделать для себя приложение. Я попытался описать общий подход к решению задачи генерации конфигураций на примере оборудования Cisco. JavaScript очень мощный язык программирования и приложив немного усилий вы может доработать данный конфигуратор под свои нужды. В приложении, которое использую я, реализована валидация вводимой информации, генерация паролей, расчет часового пояса, IP адреса и маски сети. Кроме прочего я подключил Bootstrap что бы приложении выглядело более современно и JQuery для большей динамики и анимации. В моем случае это выглядит так:
Поделиться с друзьями
-->

Комментарии (22)


  1. YGeeneY
    03.08.2016 23:21

    Ну не знаю. Проще таки " приблуде" скормить пару аргументов… Ничего страшного в использовании $1 или argparse вроде как нет. Верстать страницы для 3 переменных как то ресрсоемко. Тем более что потом этот конфиг все равно тащить на сервер прийдется. Это по сути та же «приблуда» только со свистоперделками… Если править генерить конфиг, то уже генерить его туда где ему место… И лучше лишние 10 минут потратить на бекап и пробором на целевой сервер, а не верстать формы… Имхо


    1. HunterXXI
      05.08.2016 10:10

      Вопрос подхода, мой скрипт не притендует на звание «панацея года». Почему я написал статью? Потому что мне показалось, что вариант с HTML/JS будет интересен пользователям именно тем, что можно начать процесс автоматизации просто запустив блокнот на любом компьютере в независимости от ОС.


  1. dbellkoff
    04.08.2016 12:14

    Так может перенести это все на Node.js и, с помощью какого ни будь пакета ssh для ноды, заливать эти конфиги на устройство?
    Ну или можно генерировать конфиги в текстовый файл и загружать его на устройство по tftp


    1. HunterXXI
      05.08.2016 10:13

      всё можно и php и python и node, но особенность тикущего примера в его минималистичности и отсутсвиии технологий которые надо устанавливать прежде чем начать разработку. «У тебя есть блокнот и браузер, значит ты уже можешь делать что то полезное». Вот такой посыл.


      1. dbellkoff
        05.08.2016 12:25

        Я это к тому, что у вас есть возможность переложить еще больше рутины на первую линию ТП, выделив под это виртуальный сервер с 1гб оперативной памяти и нарастив функционала

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

        В том виде, в котором скрипт есть сейчас, мне сложно предположить где его можно использовать. Если через вас проходит 1-2 циски в неделю то не вижу смысла автоматизировать этот процесс, если 100 цисок то нужен более серьезный подход чем генерация и заливка конфига в ручном режиме


        1. HunterXXI
          05.08.2016 13:07
          -2

          Это ваше мнение и возможно оно претендует на истину, но я с ним не согласен. Тем более я не согласен с тем, что такой подход бесполезен. Я рад, что у вас есть собственный подход к организации работы, но не стоит считать его единственно возможным. Лично мне удобно так. Да, по 100 устройств в неделю через меня не проходит, но и тема массового обновления в статье не поднималась, так что не надо притягивать за уши к статье какие-то левые задачи.

          Скрипт генерирует конфигурации подставляя значения в шаблон — это его задача. Он с ней справляется. Использовать это в своей работе или нет, решать Вам.


  1. deimond
    04.08.2016 12:14
    -2

    А что мешает открыть этот шаблон в любом приличном текстовом редакторе и заменить все {{IP_ADDR}}, {{MASK} и {{VLAN}} на нужные значения используя «replace all»? Затем «save as» в новый файл, чтоб не перезаписывать файл шаблона. Нормальные текстовые редакторы и regex использовать позволяют если нужно.


    1. HunterXXI
      05.08.2016 10:14
      -1

      ничего, делайте replace all


  1. questor
    04.08.2016 21:28

    Не придумывайте велосипедов, храните в ansible. Шаблонизатор jinja2 точно так же преобразует ваши переменные.


    1. HunterXXI
      05.08.2016 10:04

      GUI друг (хотя вроде и для ansible есть веб-морда). но самое главное ansible это совсем другая парадигма и он больше заточен под развертывание и конфигурирование UNIX ПО нежели сетевых устройств. Я пробовал модуь для Cisco и он работает и да, вероятно можно советовать использовать его, но это уже другой уровень.


  1. kuber
    05.08.2016 08:24

    У вас есть сотрудники, которые имеют доступ к конфигурированию сетевых устройств, но при этом не знают этих несчастных 5-6 команд? Это просто фантастика.
    Я так понимаю, что валидации данных тоже нет? т.е. можно легко забить IP: 999.999.999.999 и ваш генератор и глазом не маргнет.


    1. HunterXXI
      05.08.2016 10:05

      Вы почитайте сначала статью прежде чем комментировать и я вам отвечу на все возникшие вопросы.


      1. kuber
        05.08.2016 11:49

        Перечитал. Изучил код. Никакой валидации в коде нет. Видимо, вы скрыли от нас этот момент в своем проекте. А вот для кого это все создано из статьи так и непонятно.


        1. HunterXXI
          05.08.2016 12:54
          -3

          как-то так. извиняюсь если из статьи не очевидно.

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


          1. kuber
            05.08.2016 13:23

            Это я видел. Вот именно на эту валидацию мне бы и хотелось посмотреть. Вы можете просто показать код?


            1. HunterXXI
              05.08.2016 13:54

              мне нравится такое решение с регуляркой:

              <ul id="ipv4tests"></ul>
              <script>
              function isValidIpv4Addr(ip) {
                return /^(?=\d+\.\d+\.\d+\.\d+$)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.?){4}$/.test(ip);
              }
              var testAddr = ['192.68.35.35','0.0.0.0','255.0.0.0','192.168.1.0','192.168.0.1','255.255.255.0','1.1.1.1','255.255.255.255','249.249.249.249','200.200.200.200','199.199.199.199','100.100.100.100','99.99.99.99','0.0.0.0','9.9.9.9','10.10.10.10','99.99.99.99','100.100.100.100','109.109.109.109','110.110.110.110','199.199.199.199','200.200.200.200','249.249.249.249','250.250.250.250','255.255.255.255','256.256.256.260','192.168.0.0/24','192.168..1','192.168.1','1','1.','1.1','1.1.','1.1.1','1.1.1.','1.1.1.1.','1.1.1.1.1','.1.1.1.1','01.01.01.01','09.09.09.09','1.0.0.1.0','010.1.1.1','123456','123123123123','.127.0.0.1'];
              for (var i = 0; i < testAddr.length; i++) {
                document.getElementById('ipv4tests').innerHTML += '<li>' + testAddr[i] + ' ' + (isValidIpv4Addr(testAddr[i]) ? '<font color="green">VALID!</font>' : '<font color="red">INVALID!</font>') + '</li>';
              }
              </script>
              


              вот кстати хорошая статья на хабре про валидацию была https://habrahabr.ru/post/66931/

              Когда я был маленьким, то использовал подход который подсмотрел в веб интерфейсе маршрутизаторв
              <form action="#">
              <input type="number" id="oktet1" maxlength="3" min="0" max="255"><input type="number" id="oktet2" maxlength="3" min="0" max="255"><input type="number" id="oktet3" maxlength="3" min="0" max="255"><input type="number" id="oktet4" maxlength="3" min="0" max="255">
              <input type="submit">
              </form>
              


              1. kuber
                05.08.2016 16:45

                Хорошо. Я бы хотел увидеть как вы проверяете, что IP-адрес и шлюз из одной подсети?
                Это я к тому, что под валидацией данных можно многое понимать и из статьи непонятно что и как валидируется.


                1. HunterXXI
                  05.08.2016 17:10

                  Что значит ваше

                  Я бы хотел увидеть как вы проверяете, что IP-адрес и шлюз из одной подсети?

                  Я бы тоже много что хотел увидеть. Если нужна помощь в реализации пишите в личку, а не здесь.

                  Это я к тому, что под валидацией данных можно многое понимать и из статьи непонятно что и как валидируется.

                  Вы сами ответили на свой вопрос. В статье нет ни слова про описание валидации данных. И именно потому что
                  под валидацией данных можно многое понимать

                  Каждый решает для себя сам какую информацию будет проверять и по каким критериям. Статья вообще не про реализацию, а про подход. Какого черта я вам это объясняю?


                  1. kuber
                    06.08.2016 06:45

                    >> Если нужна помощь в реализации пишите в личку, а не здесь.
                    Я как раз вам хотел помочь. Мы уже давно реализовали систему, которая самостоятельно изо дня загружает данные с удаленного сервера, берет данные из БД, формирует огромные конфиги (по несколько тысяч строк) и заливает их на сетевые устройства. И для всего этого участие сетевого-инженера вообще не требуется. При этом у меня бы рука не поднялась написать об этой системе статью на хабре, так как я считаю, что это всё слишком легко и элементарно.

                    >> Какого черта я вам это объясняю?
                    Вам нужно стать добрее к людям. Вы всего-то научились генерировать текстовые файлы, а ведете себя как будто построили адронный коллайдер.


                    1. HunterXXI
                      06.08.2016 22:18
                      -1

                      какой же Вы умница.


  1. Imple
    05.08.2016 13:43
    +2

    Для таких вещей уже придуман Netconf/YANG (Wiki, RFC 6020) и продукты которые его реализуют, ну и на худой конец Ansible, который уже давно научился и в Cisco IOS, и в JunOS. Этот подход и отслеживает созданую конфигурацию, и делает всю необходимую валидацию, и даже поддерживает транзакции. Просто «генерировать конфиги», правда, можно и с помощью простенького bash скрипта и sed.


  1. epicf4il
    05.08.2016 17:52
    +1

    Это все классно, когда решаемые задачи ограничиваются «базовой» или «околобазовой» конфигурацией фиксированной группы «статических» устройств.
    ИМХО, было бы много полезнее сделать такой GUI для поиска блоков текущей конфигурации по задаваемым параметрам. Например, указываешь конфигурационный файл, задаешь ip адрес для поиска и тебе выдается: в какой строке, какого ACL используется этот ip, в каком объекте лежит этот ip, какой группе объектов принадлежит этот объект, где используется этот объект и т.д. и т.п. Как по мне, это бы исключило такую задачу как: покдлючение к устройству, вывод конфигурации, копипаст конфигурации в блокнот, Ctrl+F по блокноту нужного ip адреса, выдирание нужных блоков конфига и копипаст в другой файл блокнота. Возможно Вам покажется это интересным и Вы подумаете над реализацией этой идеи.

    Если интересно, то нажми
    Я как то делал такое на python, для ASA (не люблю ASDM), с использованием ciscoconfparse в связке с pexpect (для автоматического подключения к выбранному устройству и загрузки нужных блоков текущей конфигурации, по которым выполняется поиск). И вот как раз, для того что бы запилить нормальный GUI, у меня не хватило энтузиазма. Хватило только на такое:

    image

    Какую именно информацию выдавал скрипт?
    1. Присутствие заданного адреса в правилах NAT и ACL
    2. Присутствие заданного адреса в объектах и этих объектов в правилах NAT и ACL
    3. Присутствие найденных объектов в группах объектов и этих групп в правилах NAT и ACL
    4. Присутствие найденных групп объектов в группах объектов и этих групп в правилах NAT и ACL (и так далее в цикле)
    5. Присутствие заданного адреса в группах объектов и этих групп в правилах NAT и ACL
    6. Присутствие найденных групп объектов в группах объектов и этих групп в правилах NAT и ACL (и так далее в цикле)

    При этом если на ASA включена функция NAMES (автоматическая замена ip адреса на указанное имя), то происходил поиск и по имени, где это необходимо (начиная с версии 8.3(1) необходимо это только в object-group-ах).