Обычно мы можем встретить три проблемы при попытке запустить Python-скрипт на сети Huawei (впрочем, и на любой другой): это отсутствие L3 связности с устройством, это неверные имя пользователя или пароль, и это SSH-неполадки. Можно заметить, что любая из этих проблем остановит накат скрипта и сгенерирует один и тот же лог, большая часть из которого сложна для восприятия. В этой статье я постарался рассказать о небольшом улучшении предыдущего кода, которое сообщит о конкретной ошибке на устройстве, и продолжит накат скрипта дальше.

Запуск кода можно посмотреть на видео демонстрации.

Вывод лога ошибки без применения конструкции try - except - continue
Вывод лога ошибки без применения конструкции try - except - continue

Я буду использовать Python конструкцию try - except - continue. try позволяет протестировать блок кода на ошибки. except (exception или исключения) - это тип данных Python, который позволяет сообщить об ошибке. Большинство исключений уже описаны и встроены в Python, нужно лишь найти подходящий. 

Я также буду использовать оператор continue, чтобы накат скрипта продолжился несмотря на возникновение ошибки. А функция print() выведет заданное сообщение, если сработает то или иное исключение (except). Иными словами, если не удастся подключиться к устройству из списка устройств, то скрипт выведет короткое сообщение почему именно не удалось подключиться, и попытается подключиться к следующему устройству и так далее. Если ошибки не возникает, то код except пропускается. Еще раз подчеркну, что возникновение ошибки без конструкции try - except - continue, во-первых, сразу останавливает накат скрипта, то есть попытки подключения к другим устройствам из списка не происходит, а во-вторых, сгенерированный лог сообщения является длинным и беcсодержательным.

Итак, Python имеет встроенные исключения (except), которые описывают конкретные ошибки. Например:

Ошибка аутентификации - AuthenticationException

Ошибка недоступности - NetMikoTimeoutException

Ошибка SSH - SSHException

Блок кода except срабатывает только, если происходит ошибка. В этот блок входит функция print() и оператор continue. Например, если указать неверный пароль, то на экран будет выведено сообщение “Неверные данные аутентификации: ip-адрес устройства”. Если ни одна из ошибок не случится, то все три блока кода except будут пропущены, и отработает только главное задание скрипта - send_config_set (последняя строчка кода на примере выше).

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

from netmiko.ssh_exception import NetMikoTimeoutException
from paramiko.ssh_exception import SSHException
from netmiko.ssh_exception import AuthenticationException

Весь код приведу в конце статьи. 

Теперь тест в eNSP. В топологии восемь CloudEngine Huawei коммутатор. Из них я включу только три, остальные пять останутся недоступными (при попытке подключиться к ним скрипт должен вывести сообщение “Нет ответа от устройства: ip-адрес”). Первый коммутатор оставлю без ошибок, то есть на нем должно отработать задание автоматизации (накат конфигурации), на втором изменю пароль, а на третьем отключу SSH.

Топология eNSP для тестирования отработки ошибок
Топология eNSP для тестирования отработки ошибок

Изменяю пароль на CE2:

<CE_2>sys

Enter system view, return user view with return command.

[~CE_2]aaa

[~CE_2-aaa]local-user vasyo1 password irreversible-cipher @ghjcnjnF3589866

[*CE_2-aaa]commit

Отключаю SSH на VTY линиях на CE_3:

<CE_3>sys

Enter system view, return user view with return command.

[~CE_3]user-interface vty 0 4

[~CE_3-ui-vty0-4]protocol inbound telnet

[*CE_3-ui-vty0-4]commit

Теперь запущу скрипт:

Применение exception при накате Python-скрипта на Huawei
Применение exception при накате Python-скрипта на Huawei

Первые строчки после Password - это содержание файлов в формате JSON, а именно файла, содержащего команды конфигурации, и файла, содержащего список IP-адресов устройств. Далее в первом красном прямоугольнике успешный накат конфигурации, во втором красном прямоугольнике сообщение о неверно введеных данных аутентификации (где я поменял пароль), и третий прямоугольник сообщает о недоступности SSH (где я разрешил использовать только telnet). Остальные пять коммутаторов: нет ответа от устройства и их IP-адреса (которые я и не включал).

Можно говорить об успешном применении конструкции try - except - continue.

Может посмотреть видео демонстарию наката, исходный код и его описание в статье: Мой друг Netmiko. Часть 2: Три улучшения Python-скрипта.

Полный код:

from getpass import getpass
from netmiko import ConnectHandler
from netmiko.ssh_exception import NetMikoTimeoutException
from paramiko.ssh_exception import SSHException
from netmiko.ssh_exception import AuthenticationException

username = input('Введите имя пользователя SSH: ')
password = getpass()

with open('switch_file_config') as f:
    config_lines = f.read().splitlines()
print (config_lines)

with open('myswitches') as f:
    ip_lines = f.read().splitlines()
print (ip_lines)

for device in ip_lines:
    ip_address_of_device = device
    CE = {
        'device_type': 'huawei',
        'ip':   ip_address_of_device,
        'username': username,
        'password': password
    }

    try:
        ssh_connect = ConnectHandler(**CE)
    except (AuthenticationException):
        print ('Неверные данные аутентификации: ' + ip_address_of_device)
        continue
    except (NetMikoTimeoutException):
        print ('Нет ответа от устройства: ' + ip_address_of_device)
        continue
    except (SSHException):
        print ('SSH недоступен. Проверьте включен ли SSH? ' + ip_address_of_device)
        continue

    output = ssh_connect.send_config_set(config_lines)
    print(f"\n\n-------------- CE_{CE['ip']} --------------")
    print(output)
    print("-------------------- End -------------------")

Литература:

https://stackoverflow.com/questions/5563089/raw-input-function-in-python

https://pynet.twb-tech.com/blog/automation/netmiko.html

https://pyneng.readthedocs.io/en/latest/book/18_ssh_telnet/netmiko.html

https://github.com/ktbyers/netmiko

https://github.com/ktbyers/netmiko/blob/master/netmiko/ssh_dispatcher.py

Udemy.com - Python Network Programming for Network Engineers (Python 3) (David Bombal)

https://www.pythoncentral.io/pythons-range-function-explained

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


  1. ArsenAbakarov
    10.03.2022 20:21

    Это какой-то черновик курсовой работы первокурсника?


    1. vasyo Автор
      10.03.2022 22:30

      Это какой-то тип низкого вопроса, который должен кого-то здесь задеть?


  1. iddqda
    11.03.2022 09:50
    +1

    exeption в python (и не только) тут вряд ли для кого то является открытием.

    А вот что касается решения вашей гипотетической задачи, то я бы посоветовал посмотреть на следующий после netmiko проект Kirk Byers (и +David Barosso) - nornir

    Оно там само об exeptions позаботится и задачи на подключение к устройствам по тредам разложит. Кроме того там реализовано продуманное структурированное inventory.

    При этом в качестве драйвера для подключения к устройствам вместо netmiko удобней использовать scrapli. Особенно для хуавеев. По крайней мере с моими хуавеями так. Они очень долго dh считают по стандартному Kex. Так вот scrapli под капотом использует libssh2 который при подключении считывает ~/.ssh/config куда можно вписать Kex попроще и соответственно побыстрее

    А что это за switch_file_config одинаковый для всех устройств?

    Ведь если Вы уже можете подключиться к утройствам по ssh значит day0 deployment уже закончен. И все неспецифичные настройки тоже можно было провести в нулевой фазе


    1. vasyo Автор
      11.03.2022 11:30
      +2

      Здравствуйте, для меня (не разбирающегося в программировании) это было открытием, и, как я вижу в целом в интернете, информации для Huawei мало, и со всем приходится разбираться самому.

      Спасибо за направление в адрес Kirk Byers. Надеюсь, что после освоения netmiko смогу на него взглянуть.

      Да, конфиг одинаковый для всех устройств и я понимаю, что этим вопросом вы пытаетесь подставить под сомнение целесообразность автоматизации. "Day0 deployment" в данном случае ограничивается только сетевой доступность, которую приходится настраивать в ручном режиме на каждом устройстве. А вот сервисные настройки (например, клиентские VLAN), которые появляются каждый день, их удобнее и быстрее накатывать скриптом. Особенно в топологии кольца (а, как вы могли заметить, именно такая топология здесь представлена). А что если потребуется прописать ACL на всех устройствах, или сменить адрес NTP сервера, и так далее... Что тоже заходить на каждую железку? Думаю, нет


      1. iddqda
        11.03.2022 12:29
        +1

        Kirk Byers - это и есть netmiko. У вас в статье, в используемой литературе, куча ссылок на него :)

        Я же советую взглянуть на два других проекта - nornir и scrapli

        И я не ставил под сомнение целесообразность автоматизации. Я пытался намекнуть что для каждого устройства будут немного свои конфиги и потому ваш вариант накатывать один и тот же файл на все устройства не годится.
        Используйте шаблоны Jinja2


        1. vasyo Автор
          11.03.2022 17:57

          А, спасибо, что поправили - как я и говорил, я в этих нюансах не разбираюсь. Моя задача была помочь таким же, как и я, парням из деревни начать автоматизировать, а не производить революции в индустрии, или выдавать эти безусловные основы за открытие. Но для многих людей (я тому пример) эти основы, действительно, открытия.

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

          Вы точно заметили, что этот конфиг не годится для всех устройств! Как вы могли также заметить, это третий пост про netmiko, и в каждом новом посте скрипт улучшается. Как раз в следующем 4-ом посте я хочу рассказать как для разных видов устройств применять разную конфигурацию в рамках одного скрипта - netmiko это может. А также есть решение и по увеличению скорости работы netmiko - ведь все говорят, что он медленный.