К сожалению, большая часть сетевого оборудования не имеет никакого API для удаленного управления, а если имеет, то зачастую написание клиента ради отправки нескольких команд совершенно не оправдывает затраченных усилий.
К счастью, уже давно существует инструмент для автоматизации таких задач под названием expect. А еще существует более удобная обертка к нему под названием expect-lite, которую мы сегодня и рассмотрим. Для примера мы напишем скрипт, который будет будет заводить порты коммутатора в нужный нам VLAN.
Добываем софт
- Ставим expect. Системно-зависимо, для UNIX есть в репозитариях/портах, для винды есть сборка с cygwin на сайте из пункта 2.
- Качаем expect-lite с сайта авторов, распаковываем, кладем файл expect-lite в нужное нам место.
Основы
По сути, expect умеет отправлять строки, принимать что-то обратно и выполнять действия на основании принятого. Отправляемые строки начинаются с символом «>>», ожидаемые строки или содержащиеся в них выражения с «<». Если ожидаемая строка не приходит, скрипт завершается. Если использовать «<<» вместо «<», expect будет ожидать точного совпадения полученной строки с указанной. Все, что начинается с «#» считается комментарием и игнорируется.
Скрипту можно передавать параметры в виде аргументов expect-lite вида «var1=value1 var2=value2 …» и потом ссылаться на них в скрипте через $var1 и так далее.
Приступаем
Логинимся на железку
Создадим файл типа portsetup.els и напишем в него следующее:
>>telnet $host <Username >>$user <Password >>$password <> >>enable <Password >>$enablePassword <#
Будем считать, что коммутатор живет по адресу 10.91.19.2, и на нем есть юзер cisco с паролем cisco. Попробуем выполнить:
./expect-lite host=10.91.19.2 user=cisco password=cisco enablePassword=cisco ./portsetup.els
Смотрим на результат:
Const: host = 10.91.19.2 Const: user = cisco Const: password = cisco Const: enablePassword = cisco Warning: Remote Host=none, using Localhost spawn bash INFO: CONST FOUND: host = 10.91.19.2 [dmbaturin@arcueid:~/bin/expect-lite]$ telnet 10.91.19.2 Trying 10.91.19.2... Connected to 10.91.19.2. Escape character is '^]'. User Access Verification Username: INFO: CONST FOUND: user = cisco cisco Password: INFO: CONST FOUND: password = cisco switch>enable Password: INFO: CONST FOUND: enablePassword = cisco switch#exit Connection closed by foreign host. [dmbaturin@arcueid:~/bin/expect-lite]$ ##Overall Result: PASS
Скрипт успешно пообщался с железкой на тему аутентификации. Можно сразу заметить важную особенность: expect игнорирует все полученные строки, кроме явно указанных к ожиданию.
Приступаем к действиям
И тут мы сразу сталкиваемся с проблемой выбора. Порт может быть trunk или access, не писать же два разных скрипта для них. Для этой цели в expect-lite есть условия. Выглядят они следующим образом:
? условие ? действие если условие верно :: действие если условие неверно
Команды можно группировать с помощью квадратных скобок. С группами команд с обеих частях условия у expect-lite какие-то проблемы, поэтому лучше использовать два условия.
# Clear existing config >>default interface $intf <(config) # Enter interface config >>nterface $intf <(config-if) # Access mode ? $mode == access ? [ >>switchport mode access <(config-if) >>switchport access vlan $vlan <(config-if) ] # Trunk mode ? $mode == trunk ? [ >>switchport mode trunk <(config-if) >>switchport trunk allowed vlan $vlan <(config-if) ]
Добавим к этому корректный выход:
>>exit <(config) >>exit <# >>exit # Команда *TERM завершает работу скрипта *TERM
Собираем все вместе
*NOWARN *NODEBUG *NOINFO *NOEXP_INFO # Login to the switch >>telnet $host <Username >>$user <Password >>$password <> # Enter privileged mode >>enable <Password >>$enablePassword <# # Enter configuration mode >>configure terminal <(config) # Clear interface config >>default interface $intf <(config) # Enter interface config >>interface $intf <(config-if) # Configure access mode ? $mode == access ? [ >>switchport mode access <(config-if) >>switchport access vlan $vlan <(config-if) ] # Configure trunk mode ? $mode == trunk ? [ >>switchport mode trunk <(config-if) >>switchport trunk allowed vlan $vlan <(config-if) ] # Exit properly >>exit <(config) >>exit <# >>exit # Terminate the script *TERM
Четыре команды в начале скрипта уменьшают количество выводимых отладочных сообщений до минимума.
Пробуем запустить:
./expect-lite host=10.91.19.2 user=cisco password=cisco enablePassword=cisco mode=access vlan=10 intf="fa 0/19" ./portsetup.els Const: host = 10.91.19.2 Const: user = cisco Const: password = cisco Const: enablePassword = cisco Const: mode = access Const: vlan = 10 Const: intf = fa 0/19 Warning: Remote Host=none, using Localhost spawn bash expect-lite directive: *NOWARN expect-lite directive: *NODEBUG expect-lite directive: *NOINFO expect-lite directive: *NOEXP_INFO [dmbaturin@arcueid:~/bin/expect-lite]$ telnet 10.91.19.2 Trying 10.91.19.2... Connected to 10.91.19.2. Escape character is '^]'. User Access Verification Username: cisco Password: switch>enable Password: switch#configure terminal Enter configuration commands, one per line. End with CNTL/Z. switch(config)#default interface fa 0/19 Interface FastEthernet0/19 set to default configuration switch(config)#interface fa 0/19 switch(config-if)#switchport mode access switch(config-if)#switchport access vlan 10 switch(config-if)#exit switch(config)#exit switch# expect-lite directive: *TERM
Для большинства целей должно хватить. А для дальнейшего ознакомления на сайте автора есть подробная документация.
Метки: expect
Опубликовано: Без рубрики
Супер, спасибо Дань за просвещение!
Так глядишь и я перестану бояться программирования 🙂