Наверное, многие сетевые инженеры уже поняли, что администрирование сетевого оборудования только через CLI слишком трудоёмко и непродуктивно. Особенно когда под управлением находятся десятки или сотни устройств, часто настроенных по единому шаблону. Удалить локального пользователя со всех устройств, проверить конфигурации всех маршрутизаторов на соответствие каким-то правилам, посчитать количество включенных портов на всех коммутаторах — вот примеры типовых задач, решать которые без автоматизации нецелесообразно.



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


Для начала расскажу, почему я выбрал Python.

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

Во-вторых, крупные производители сетевого оборудования, такие как Cisco, Juniper, Huawei, внедряют поддержку Python на своем оборудовании. У языка есть будущее в сетевой сфере, и его изучение не будет пустой тратой времени.

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

Я занимаюсь проектированием и немного внедрением сетевых проектов. В одном из них потребовалось решить сразу две задачи.

  1. Пройтись по нескольким сотням филиальных маршрутизаторов и убедиться, что они настроены единообразно. Например, что для связи с ЦОД используется интерфейс Tunnel1, а не Tunnel0 или Tunnel99. И что эти интерфейсы настроены одинаково, за исключением их IP-адресов, естественно.
  2. Перенастроить все маршрутизаторы, в том числе добавить статический маршрут через IP-адрес местного провайдера. То есть эта команда будет уникальной для каждого маршрутизатора.

На помощь пришел скрипт на Python. Его разработка и тестирование заняли один день.

Первое, что нужно сделать, это установить Python и крайне желательно PyCharm CE. Скачиваем и устанавливаем Python 3 (сейчас последняя версия 3.6.2). При установке выбираем «Customize installation» и на этапе «Advanced Options» устанавливаем галку напротив «Add Python to environment variables».

PyCharm CE — это бесплатная среда разработки с очень удобным отладчиком. Скачиваем и устанавливаем.

Второй шаг — устанавливаем необходимую библиотеку netmiko. Она нужна для взаимодействия с устройствами по SSH или telnet. Библиотеку устанавливаем из командной строки:

pip install netmiko

Третьим шагом будет подготовка исходных данных и скрипта под наши задачи.

В качестве входных данных будем использовать текстовый файл “ip.txt”. В каждой строчке файла должен быть IP-адрес устройства, к которому мы подключаемся. Через запятую можно указать логин и пароль для конкретного устройства. Если этого не сделать, то будут использоваться те, которые вы введёте при запуске скрипта. Пробелы будут проигнорированы. Если первый символ в строке «#», то она считается комментарием и игнорируется. Вот пример корректного файла:



Сам скрипт логически состоит из двух частей: основной программы и функции doRouter(). Внутри неё выполняется подключение к маршрутизатору, отправка команд в CLI, получение и анализ ответов. Входными данными для функции являются: IP-адрес маршрутизатора, логин и пароль. При возникновении проблем функция вернёт IP-адрес маршрутизатора, мы его запишем в отдельный файл fail.txt. Если всё прошло хорошо, то будет просто выведено сообщение на экран.

Почему нужно выносить взаимодействие с маршрутизаторами в отдельную функцию, а не выполнить всё в цикле в основной программе? Главная причина — продолжительность работы скрипта. Подключение поочередно ко всем маршрутизаторам заняло у меня 4 часа. В основном из-за того, что какие-то из них не отвечали и скрипт долго ждал истечения таймаута. Поэтому запускать мы будем параллельно по 10 экземпляров функций. В моём случае это сократило время выполнения скрипта до 10 минут.

Рассмотрим теперь подробнее основную программу.

Ради безопасности не будем хранить логин и пароль в скрипте. Поэтому выведим на экран приглашение для их ввода. Причем при вводе пароля он не будет отображаться. Эти глобальные переменные используем в процедуре doRouter. У меня были проблемы с работой getpass в PyCharm под Windows. Скрипт работал корректно, только если выполнять его в режиме Debug, а не Run. В командной строке всё работало без нареканий. Также скрипт тестировался в OS X, там проблем в PyCharm замечено не было.

user_name = input("Enter Username: ")
pass_word = getpass()

Потом читаем файл с IP-адресами. Конструкция try…except позволит корректно обработать ошибку чтения файла. На выходе получим массив данных для подключения connection_data, содержащий IP-адрес, логин и пароль.

try:
    f = open('ip.txt')
    connection_data=[]
    filelines = f.read().splitlines()
    for line in filelines:
if line == "": continue
        if line[0] == "#": continue
        conn_data = line.split(',')
        ipaddr=conn_data[0].strip()
        username=global_username
        password=global_password
        if len(conn_data) > 1 and conn_data[1].strip() != "": username = conn_data[1].strip()
        if len(conn_data) > 2 and conn_data[2].strip() != "": password = conn_data[2].strip()
        connection_data.append((ipaddr, username, password))
    f.close()
except:
    sys.exit("Couldn't open or read file ip.txt")

Далее создаём список процессов и запускаем их. Метод создания процессов я задал как “spawn”, чтобы в Windows и OS X скрипт работал одинаково. Количество созданных процессов будет равно количеству IP-адресов. Но выполняться одновременно будут не более 10. В список routers_with_issues записываем то, что вернут функции doRouter. В нашем случае это IP-адреса маршрутизаторов, с которыми были проблемы.

multiprocessing.set_start_method("spawn")
with multiprocessing.Pool(maxtasksperchild=10) as process_pool:
    routers_with_issues = process_pool.map(doRouter, connection_data, 1)
    process_pool.close()
    process_pool.join()

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

В конце создаем/переписываем текстовый файл, в котором у нас будут IP-адреса ненастроенных маршрутизаторов. Также выводим этот список на экран.

failed_file = open('fail.txt', 'w')
for item in routers_with_issues:
    if item != None:
      failed_file.write("%s\n" % item)
      print(item)

Теперь разберем процедуру doRouter(). Первое, что нужно сделать, — обработать входные данные. С помощью ReGex проверяем, что функции был передан корректный IP-адрес.

ip_check = re.findall("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", ip_address)
if ip_check == []:
    print(bcolors.FAIL + "Invalid IP - " + str(ip_address) + bcolors.ENDC)
    return ip_address

Далее создаём словарь с необходимыми для подключения данными и подключаемся к маршрутизатору.

device = {
    'device_type': 'cisco_ios',
    'ip': ip_address.strip(),
    'username': username,
    'password': password,
    'port': 22, }
try:
    config_ok = True

    net_connect = ConnectHandler(**device)

Отправляем команды и анализируем полученный ответ от маршрутизатора. Он будет помещён в переменную cli_response. В этом примере мы проверяем текущие настройки. Результат выводим на экран. Данную часть нужно менять под разные задачи. В этом скрипте проверяем текущую конфигурацию маршрутизатора. Если она корректная, то вносим изменения. Если при проверке обнаружены проблемы, то присваиваем переменной config_ok значение False и не применяем изменения.

cli_response = net_connect.send_command("sh dmvpn | i Interface")
cli_response = cli_response.replace("Interface: ", "")
cli_response = cli_response.replace(", IPv4 NHRP Details", "").strip()
if cli_response != "Tunnel1":
    print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - DMVPN not on Tunnel1.  " + cli_response+ " " + bcolors.ENDC)
    config_ok=False

Тут будут полезны следующие операции работы со строками.

Операция Описание Пример
+ Объединение строк s3 = s1 + s2
>>> print('Happy New ' + str(2017) + ' Year')
Happy New 2017 Year
len(s) Определение длины строки
[] Выделение подстроки (индекс начинается с нуля) s[5] — шестой символ
s[5:7] — символы с шестого по восьмой
s[-1] — последний символ, то же, что s[len(s)-1]
s.split()
s.join()
Разделить строки
Объединить строки
>>> 'Петя, Лёша, Коля'.split(',')
['Петя', 'Лёша', 'Коля']

>>> ','.join({'Петя', 'Лёша', 'Коля'})
'Лёша, Петя, Коля'
str(L)
list(s)
Преобразовать список в строку
Преобразовать строку в список
>>> str(['1', '2', '3'])
"['1', '2', '3']"

>>> list('Test')
['T', 'e', 's', 't']
% Форматирование по шаблону >>> s1, s2 = 'Митя', 'Василиса'
>>> '%s + %s = любовь' % (s1, s2)
'Митя + Василиса = любовь'
f Подстановка переменных >>> a='Максим'
>>> f'Имя {a}'
'Имя Максим'
str.find(substr) Поиск подстроки substr в строке str
Возвращает позицию первой найденной подстроки
>>> 'This is a text'.find('a')
8
str.replace(old, new) Замена подстроки old на подстроку new в строке str >>> newstr = 'This is a text'.replace(' is ', ' is not ')
>>> print(newstr)
This is not a text
str.strip()
str.rstrip()
Удалить пробелы и табуляции в начале и конце (или только в конце) >>> ' This is a text \t\t\t'.strip()
'This is a text'

Чтобы решить задачу по добавлению статического маршрута, для начала нужно определить IP-адрес next-hop. В моем случае самый простой способ — посмотреть адрес next-hop у существующих статических маршрутов.

cli_response2=net_connect.send_command("sh run | i ip route 8.8.8.8 255.255.255.255")
if cli_response2.strip() == "":
    print(str(ip_address)+" — " + bcolors.FAIL + "WARNING — couldn't find static route to 8.8.8.8" + bcolors.ENDC)
    config_ok=False

ip_next_hop = ""
if cli_response2 != "":
    ip_next_hop = cli_response2.split(" ")[4]

if ip_next_hop == "":
    print(str(ip_address)+" — " + bcolors.FAIL + "WARNING — couldn't find next-hop IP address " + bcolors.ENDC)
    config_ok=False

Можно отправлять одну или несколько конфигурационных команд сразу. У меня плохо работала отправка больше 5 команд одновременно, при необходимости можно просто повторить конструкцию несколько раз.

config_commands = ['ip route 1.1.1.1 255.255.255.255 '+ip_next_hop,
                   'ip route 2.2.2.2 255.255.255.255 '+ip_next_hop]
net_connect.send_config_set(config_commands)


Полный скрипт.
import sys
from netmiko import ConnectHandler
from getpass import getpass
import time
import multiprocessing
import re

start_time = time.time()

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

def doRouter(connection_data):

    ip_address = connection_data[0]
    username = connection_data[1]
    password = connection_data[2]

    ip_check = re.findall("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", ip_address)
    if ip_check == []:
        print(bcolors.FAIL + "Invalid IP - " + str(ip_address) + bcolors.ENDC)
        return ip_address

    device = {
        'device_type': 'cisco_ios',
        'ip': ip_address.strip(),
        'username': username,
        'password': password,
        'port': 22, }
    try:
        config_ok = True

        net_connect = ConnectHandler(**device)

        cli_response = net_connect.send_command("sh dmvpn | i Interface")
        cli_response = cli_response.replace("Interface: ", "")
        cli_response = cli_response.replace(", IPv4 NHRP Details", "").strip()
        if cli_response != "Tunnel1":
            print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - DMVPN not on Tunnel1.  " + cli_response+ " " + bcolors.ENDC)
            config_ok=False

        cli_response2=net_connect.send_command("sh run | i ip route 1.1.1.1 255.255.255.255")
        if cli_response2.strip() == "":
            print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - couldn't find static route to 8.8.8.8" + bcolors.ENDC)
            config_ok=False

        ip_next_hop = ""
        if cli_response2 != "":
            ip_next_hop = cli_response2.split(" ")[4]

        if ip_next_hop == "":
            print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - couldn't find next-hop IP address " + bcolors.ENDC)
            config_ok=False


        if config_ok:
            config_commands = ['ip route 1.1.1.1 255.255.255.255 '+ip_next_hop,
                               'ip route 2.2.2.2 255.255.255.255 '+ip_next_hop]
         	    net_connect.send_config_set(config_commands)
            print(str(ip_address) + " - " + "Static routes added")
        else:
            print(str(ip_address) + " - " + bcolors.FAIL + "Routes weren't added because config is incorrect" + bcolors.ENDC)
            return ip_address

        if config_ok:
   	                  net_connect.send_command_expect('write memory')
            print(str(ip_address) + " - " + "Config saved")

        net_connect.disconnect()
    except:
        print(str(ip_address)+" - "+bcolors.FAIL+"Cannot connect to this device."+bcolors.ENDC)
        return ip_address
    print(str(ip_address) + " - " + bcolors.OKGREEN + "Router configured sucessfully" + bcolors.ENDC)


if __name__ == '__main__':

    # Enter valid username and password. Note password is blanked out using the getpass library
    global_username = input("Enter Username: ")
    global_password = getpass()

    try:
        f = open('ip.txt')
        connection_data=[]
        filelines = f.read().splitlines()
        for line in filelines:
            if line == "": continue
            if line[0] == "#": continue
            conn_data = line.split(',')
            ipaddr=conn_data[0].strip()
            username=global_username
            password=global_password
            if len(conn_data) > 1 and conn_data[1].strip() != "": username = conn_data[1].strip()
            if len(conn_data) > 2 and conn_data[2].strip() != "": password = conn_data[2].strip()
            connection_data.append((ipaddr, username, password))
        f.close()
    except:
        sys.exit("Couldn't open or read file ip.txt")

    multiprocessing.set_start_method("spawn")
    with multiprocessing.Pool(maxtasksperchild=10) as process_pool:
        routers_with_issues = process_pool.map(doRouter, connection_data, 1)  # doRouter - function, iplist - argument
        process_pool.close()
        process_pool.join()

    print("\n")
    print("#These routers weren't configured#")

    failed_file = open('fail.txt', 'w')
    for item in routers_with_issues:
        if item != None:
          failed_file.write("%s\n" % item)
          print(item)

    #Completing the script and print running time
    print("\n")
    print("#This script has now completed#")
    print("\n")
    print("--- %s seconds ---" % (time.time() - start_time))

После подготовки скрипта выполнить его можно из командной строки или из PyCharm CE. Из командной строки запускаем командой:

python script.py

Я рекомендую пользоваться PyCharm CE. Там создаём новый проект, файл Python (File > New…) и вставляем в него наш скрипт. В папку со скриптом кладем файл ip.txt и запускаем скрипт (Run > Run)

Получаем следующий результат:

bash ~/PycharmProjects/p4ne $ python3 script.py 
Enter Username: cisco
Password: 
Invalid IP - 10.1.1.256
127.0.0.1 - Cannot connect to this device.
1.1.1.1 - Cannot connect to this device.
10.10.100.227 - Static routes added
10.10.100.227 - Config saved
10.10.100.227 - Router configured sucessfully
10.10.31.170 - WARNING - couldn't find static route to 8.8.8.8
10.10.31.170 - WARNING - couldn't find next-hop IP address 
10.10.31.170 - Routes weren't added because config is incorrect
2.2.2.2 - Cannot connect to this device.


#These routers weren't configured#
10.1.1.256
127.0.0.1
217.112.31.170
1.1.1.1
2.2.2.2


#This script has now completed#

Пару слов о том, как отладить скрипт. Легче всего это делать в PyCharm. Отмечаем строчку, на которой хотим остановить выполнение скрипта, и запускаем выполнение в режиме отладки. После того, как скрипт остановится, можно будет посмотреть текущие значения всех переменных. Проверить, что передаются и принимаются корректные данные. Кнопками «Step Into» или «Step Into My Code» можно пошагово продолжить выполнение скрипта.



Ограничения описанной версии скрипта:

  • тестировался только в Python 3
  • не умеет обрабатывать ситуацию, когда вы в первый раз подключаетесь к маршрутизатору и получаете вопрос вида:

    The authenticity of host '11.22.33.44 (11.22.33.44)' can't be established.
    RSA key fingerprint is SHA256:C+BHaMBjuMIoEewAbjbQbRGdVkjs&840Ve3z4aJo.
    Are you sure you want to continue connecting (yes/no)?

Этот скрипт был написан для решения конкретных задач. Однако он универсален и, надеюсь, поможет ещё кому-нибудь в работе. А самое главное — послужит первым шагом в освоении Python.

При написании скрипта использовались следующие ресурсы:


Александр Гаршин, ведущий инженер-проектировщик систем передачи данных компании «Инфосистемы Джет»

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


  1. manefesto
    29.08.2017 12:40
    +1

    и чем он лучше paramiko?
    Здесь например показано jessenoller.com/blog/2009/02/05/ssh-programming-with-paramiko-completely-different как через AutoAddPolicy() решить вопрос с RSA key fingerprint
    Да, paramiko не умеет работать с telnet, но на большинстве коммутаторов, маршрутизаторов есть поддержка ssh


    1. PO_Habr Автор
      29.08.2017 12:41

      Paramiko хорошая альтернатива. Но конкретно мне нужен был telnet и SSHv1 для ASA, ввезённой без строгого шифрования.


    1. Dimi3
      29.08.2017 16:00
      +1

      «netmiko» это по факту и есть оболочка для «paramiko» (название намекает).
      Просто в ней куски кода, которые сетевики писали раза от раза используя paramiko (распознование конца вывода, смена промпта, непосредственно процесс подключения и т.п.), объеденены в сподручные функции, и он из коробки довольно стабильно (у меня небыло глюков) работает с самыми распространенными осями сетевых устройств.


  1. Numen_Divinum
    29.08.2017 12:41
    +3

    1. karabanov
      29.08.2017 22:28

      Пришёл разместить эту ссылку, а она уже здесь ;-)
      Хороший курс. Рекомендую.


  1. KorP
    29.08.2017 12:48

    Я тут недавно то же писал на эту тему.


  1. Cobolorum
    29.08.2017 12:51
    -3

    Извини «автор» но на рисунке тянущие телегу на квадратных колесах это похоже ваши сотрудники. А мужичек предлагающий колеса это тот кто знает: bash, command line utilities.
    Не гонитесь за популярностью изучайте классику.


    1. PO_Habr Автор
      29.08.2017 13:23
      +2

      Если что-то изучать с нуля, то из бесплатных продуктов Python выглядит наиболее подходящим для сетевого инженера. Кроме изменения конфигурации через CLI его можно использовать для взаимодействия через RestAPI. Кроме того, у Cisco, Huawei и Juniper уже есть встроенный интерпретатор Python в некоторых маршрутизаторах и коммутаторах. Для Cisco это ISR 4000, Nexus 9000. Думаю, этот список будет расширяться.


      1. VFedorV
        29.08.2017 14:34

        а можно детальнее об этом:

        python on Cisco это ISR 4000
        ? настраивал ISR 4331 и не заметил ничего :(


        1. PO_Habr Автор
          29.08.2017 15:01
          +2

          Для ISR нужен отдельный софт из линейки Everest. Сейчас последний — isr4300-universalk9.16.06.01.SPA.bin. С версии Everest 16.5.1b появилась поддержка Python 2.7/3.0 для ISR 4k, CSR, ASR.

          Вот полезная вводная статья:
          https://communities.cisco.com/community/developer/blog/2017/04/17/introducing-python-and-guest-shell-on-ios-xe-165


    1. mklochkov
      29.08.2017 13:29
      +1

      Тут ведь как — если у вас в руках молоток, любая проблема будет казаться гвоздём.
      Автор явно написал — ему нужно было «одинаково под Windows и Mac OS X». И какие есть возможности под Windows? Баша «из коробки» там нет, PowerShell — это свой отдельный мир, можно ещё cygwin поставить (большой, тяжёлый, со своими проблемами). Python в данном случае не худший выбор.


    1. siziyman
      29.08.2017 16:43
      +2

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

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


  1. rSedoy
    29.08.2017 12:51

    небольшой оффтопик: со стилем программирования на python от ученых и инженеров ничего не поделать, надо привыкать ;)


    1. manefesto
      29.08.2017 13:13

      согласен, например это

      print(bcolors.FAIL + "Invalid IP - " + str(ip_address) + bcolors.ENDC)

      очень красиво можно сделать так
      print("%s Invalid IP - %s %s "%(bcolors.FAIL,ip_address,bcolors.ENDC))


      1. rSedoy
        29.08.2017 13:19
        +1

        да там много чего: несоблюдение pep8, общий except, открытие файла по-старому и т.д.


      1. scronheim
        29.08.2017 13:28

        и файлики кошернее открывать через with :)


      1. Taragolis
        29.08.2017 13:43
        +2

        или через format:


        print('{} Invalid IP - {} {}'.format(bcolors.FAIL, ip_address, bcolors.ENDC))


        1. Taus
          29.08.2017 14:24
          +1

          Раз уж на 3.6+

          print(f'{bcolors.FAIL}Invalid IP - {ip_address}{bcolors.ENDC}')


          1. QDeathNick
            29.08.2017 16:15

            Вот это действительно наглядно и красиво.


      1. PO_Habr Автор
        29.08.2017 14:24

        Спасибо за советы. Элегантность кода, надеюсь, появится с опытом.


        1. g0rd1as
          29.08.2017 17:37

          Оно может и некрасиво, но это простительно — вы в конце концов не программист. Главное, чтоб оно корректно работало. а под стандарты и представления о прекрасном можно и потом подогнать, если очень припрет.


      1. varnav
        29.08.2017 15:43

        Мне одному написанное ниже кажется хуже читаемым?


        1. manefesto
          29.08.2017 16:31

          возможно хуже, но правильней



  1. chicagoist
    29.08.2017 14:23

    Я склоняюсь к тому, что Lua удобнее во всех отношениях по сравнению с Python. Для задач администрирования.


    1. PO_Habr Автор
      29.08.2017 14:23
      +1

      С Lua не работал, но насколько я знаю, там нет такого количества доступных библиотек, как для Python. В интернете по запросу cisco+lua находятся в основном статьи про SIP и CUCM. Не поделитесь ссылкой на какую-нибудь полезную статью про использование lua для работы с конфигами сетевых устройств? Будет интересно почитать.


      1. chicagoist
        29.08.2017 23:11

        Со стороны рынка и спроса — конечно Python несомненный лидер.

        С академической точки зрения — Python это бастард.
        К примеру Tcl, или Lua — то есть такие скриптовые языки,
        которые ни на что серьёзное не претендуют, оставаясь именно что языками
        командно-скриптовыми, предназначенными для управления другими программами.
        Опять же, в администрении всё-таки чаще применяется Bourne Shell (при всей
        его дубовости это однозначное must know для эксплуатационщика).
        С моей точки зрения Python не имеет права на существование, как и Perl, и
        Ruby, и вообще любой интерпретируемый (и тем более командно-скриптовой)
        язык, имеющий претензии на роль языка общего назначения.

        Но… рынок труда со мной не согласен. ;-)

        P.S.
        www.ibm.com/developerworks/ru/library/l-lua_3/index.html

        robot-develop.org/archives/3717


        1. mklochkov
          29.08.2017 23:55
          +1

          Опять же, в администрении всё-таки чаще применяется Bourne Shell (при всей его дубовости это однозначное must know для эксплуатационщика).

          Достоинство у него ровно одно — в любой юникс-подобной операционке он есть «из коробки». Никакой алгоритм, подразумевающий работу с данными, организованными более сложно, чем последовательность строк, на нём реализовать невозможно, просто нет соответствующих средств.

          С моей точки зрения Python не имеет права на существование, как и Perl, и Ruby, и вообще любой интерпретируемый (и тем более командно-скриптовой)
          язык, имеющий претензии на роль языка общего назначения.


          А, собственно, почему? Даже спрошу иначе — а где, по вашему, проходит граница между компилируемым и интерпретируемым (Java какая?), а также командно-скриптовым и «не-скриптовым» языками (php какой)?


          1. khim
            30.08.2017 01:59
            +1

            Никакой алгоритм, подразумевающий работу с данными, организованными более сложно, чем последовательность строк, на нём реализовать невозможно, просто нет соответствующих средств.
            Да ладно вам. Я сам лично несколько лет назад писал скрипт, который олавливал зависимости между пакетами и делал удобный инсталлятор с помощью NSIS. Всё на bash, включая топологичествую сортировку, проверки зависимостей и прочее.

            Дополнительный плюс: за 5 лет скрипт никто так и не изуродовал, так как никто просто не знает — с какой стороны к нему подступиться.


  1. andjel
    29.08.2017 14:25

    А может перестать бояться, изобретать велосипед, и освоить настоящий инструмент? :)
    docs.ansible.com/ansible/latest/list_of_network_modules.html


    1. Karroplan
      29.08.2017 14:33
      -1

      ansible — это довольно кривая и хреново документированная надстройка над голым питоном ) вместо того чтоб изучать питон, придется изучать ансибл, причем изучать по слухам, т.к. нормальной информации о том как оно работает нету.
      нормальный инструмент называется HP Network Automation Tool


      1. andjel
        29.08.2017 15:11
        +2

        Годный вброс, но не сработало :)


      1. manefesto
        29.08.2017 16:33

        советую почитать на досуге www.allitebooks.com/ansible-for-devops


        1. Karroplan
          29.08.2017 16:35

          а эта книга актуальна для какой версии ansible?


          1. manefesto
            30.08.2017 08:36

            Для любой, на всякий случай есть docs.ansible.com/ansible/latest/index.html где есть актуальная информация


            1. Karroplan
              30.08.2017 10:44

              уверены? там нет никакой актуальной информации про использование промежуточного hop-off сервера, например.


    1. PO_Habr Автор
      29.08.2017 14:50
      +1

      Это следующий шаг для администрирования. Модули для Ansible пишутся в том числе и на Python, поэтому знакомство с ним лишним не будет. Python сам по себе более гибкий инструмент и позволяет решать более широкий спектр задач. Например, можно написать скрипт, собирающий с оборудования необходимые данные и записывающий их в Excel-файл. И это могут быть не только конфигурации устройств, но и таблицы mac, ARP, RIB, состояние сессий протоколов маршрутизаций.


      1. andjel
        29.08.2017 15:12
        +1

        Можно еще fabric. Вопрос же про изобретение велосипеда :)


  1. missing_thing
    29.08.2017 19:33
    +1

    Используйте библиотеки. Например, вместо regex проверки IP можно использовать docs.python.org/3/library/socket.html#socket.inet_aton


  1. freshik
    29.08.2017 23:36

    Я бы еще посмотрел в сторону NAPALM.


  1. DonAlPAtino
    31.08.2017 16:06

    Сорри за дурацкий вопрос, а под Windows это вообще работоспособно? Сразу все упало с ModuleNotFoundError: No module named 'pyasn1' при том, что
    D:\PycharmProjects\cisco>«C:\Program Files\Python36\Scripts\pip.exe» install pyasn1
    Requirement already satisfied: pyasn1 in c:\program files\python36\lib\site-packages\pyasn1-0.3.3-py3.6.egg
    Долго и нудно с библиотеками шаманить надо?


    1. khim
      31.08.2017 16:24

      Вопрос действительно дурацкий. Я думаю что мало кто подобные вещи в принципе пытается делать под Windows, соотвественно и откуда брать библиотеки — никто не знает. В PIPе pyasn1 есть, но работает ли оно на Windows… попробуйте и узнаете?


    1. PO_Habr Автор
      31.08.2017 20:07

      Я использовал этот скрипт на Windows 10. Также перед публикацией пробовал запустить его на чистой Windows 7, действуя по шагам из статьи. То есть установив только Python 3.6 и библиотеку netmiko. К сожалению, такой ошибки ни разу не встречал. Pyasn1 нужен библиотеке paramiko, которая поставится сама при установке netmiko. Может, попробовать переустановить библиотеки pyasn1, netmiko и paramiko? (pip uninstall/pip install)

      Также выложил скрипт на GitHub. Предлагаю скопировать его оттуда. В скрипте из статьи могут быть лишние символы.
      https://github.com/aagarshin/habr/